1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * Uncompress a file that was compressed in the Gzip format 6 * 7 * PHP versions 4 and 5 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA 22 * 23 * @category File Formats 24 * @package File_Archive 25 * @author Vincent Lascaux <vincentlascaux@php.net> 26 * @copyright 1997-2005 The PHP Group 27 * @license http://www.gnu.org/copyleft/lesser.html LGPL 28 * @version CVS: $Id: Gzip.php,v 1.27 2005/06/19 20:09:57 vincentlascaux Exp $ 29 * @link http://pear.php.net/package/File_Archive 30 */ 31 32require_once "File/Archive/Reader/Archive.php"; 33require_once "File/Archive/Writer/Files.php"; 34 35/** 36 * Uncompress a file that was compressed in the Gzip format 37 */ 38class File_Archive_Reader_Gzip extends File_Archive_Reader_Archive 39{ 40 var $nbRead = 0; 41 var $filePos = 0; 42 var $gzfile = null; 43 var $tmpName = null; 44 45 /** 46 * @see File_Archive_Reader::close() 47 */ 48 function close($innerClose = true) 49 { 50 if ($this->gzfile !== null) { 51 gzclose($this->gzfile); 52 } 53 if ($this->tmpName !== null) { 54 unlink($this->tmpName); 55 } 56 57 $this->nbRead = 0; 58 $this->filePos = 0; 59 $this->gzfile = null; 60 $this->tmpName = null; 61 62 return parent::close($innerClose); 63 } 64 65 /** 66 * @see File_Archive_Reader::next() 67 */ 68 function next() 69 { 70 if (!parent::next()) { 71 return false; 72 } 73 74 $this->nbRead++; 75 $this->filePos = 0; 76 if ($this->nbRead > 1) { 77 return false; 78 } 79 80 $dataFilename = $this->source->getDataFilename(); 81 if ($dataFilename !== null) 82 { 83 $this->tmpName = null; 84 $this->gzfile = gzopen($dataFilename, 'r'); 85 } else { 86 $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far'); 87 88 //Generate the tmp data 89 $dest = new File_Archive_Writer_Files(); 90 $dest->newFile($this->tmpName); 91 $this->source->sendData($dest); 92 $dest->close(); 93 94 $this->gzfile = gzopen($this->tmpName, 'r'); 95 } 96 97 return true; 98 } 99 100 /** 101 * Return the name of the single file contained in the archive 102 * deduced from the name of the archive (the extension is removed) 103 * 104 * @see File_Archive_Reader::getFilename() 105 */ 106 function getFilename() 107 { 108 $name = $this->source->getFilename(); 109 $slashPos = strrpos($name, '/'); 110 if ($slashPos !== false) { 111 $name = substr($name, $slashPos+1); 112 } 113 $dotPos = strrpos($name, '.'); 114 if ($dotPos !== false && $dotPos > 0) { 115 $name = substr($name, 0, $dotPos); 116 } 117 118 return $name; 119 } 120 121 /** 122 * @see File_Archive_Reader::getData() 123 */ 124 function getData($length = -1) 125 { 126 if ($length == -1) { 127 $data = ''; 128 do 129 { 130 $newData = gzread($this->gzfile, 8192); 131 $data .= $newData; 132 } while ($newData != ''); 133 } else if ($length == 0) { 134 return ''; 135 } else { 136 $data = gzread($this->gzfile, $length); 137 } 138 139 $this->filePos += strlen($data); 140 return $data == '' ? null : $data; 141 } 142 143 /** 144 * @see File_Archive_Reader::skip() 145 */ 146 function skip($length = -1) 147 { 148 if($length == -1) { 149 do 150 { 151 $tmp = gzread($this->gzfile, 8192); 152 $this->filePos += strlen($tmp); 153 } while ($tmp != ''); 154 } else { 155 if (@gzseek($this->gzfile, $this->filePos + $length) === -1) { 156 return parent::skip($length); 157 } else { 158 $this->filePos += $length; 159 return $length; 160 } 161 } 162 } 163 164 /** 165 * @see File_Archive_Reader::rewind() 166 */ 167 function rewind($length = -1) 168 { 169 if ($length == -1) { 170 if (@gzseek($this->gzfile, 0) === -1) { 171 return parent::rewind($length); 172 } else { 173 $tmp = $this->filePos; 174 $this->filePos = 0; 175 return $tmp; 176 } 177 } else { 178 $length = min($length, $this->filePos); 179 if (@gzseek($this->gzfile, $this->filePos - $length) === -1) { 180 return parent::rewind($length); 181 } else { 182 $this->filePos -= $length; 183 return $length; 184 } 185 } 186 } 187 188 /** 189 * @see File_Archive_Reader::tell() 190 */ 191 function tell() 192 { 193 return $this->filePos; 194 } 195 196 /** 197 * @see File_Archive_Reader::makeAppendWriter() 198 */ 199 function makeAppendWriter() 200 { 201 return PEAR::raiseError('Unable to append files to a gzip archive'); 202 } 203 204 /** 205 * @see File_Archive_Reader::makeWriterRemoveFiles() 206 */ 207 function makeWriterRemoveFiles($pred) 208 { 209 return PEAR::raiseError('Unable to remove files from a gzip archive'); 210 } 211 212 /** 213 * @see File_Archive_Reader::makeWriterRemoveBlocks() 214 */ 215 function makeWriterRemoveBlocks($blocks, $seek = 0) 216 { 217 require_once "File/Archive/Writer/Gzip.php"; 218 219 if ($this->nbRead == 0) { 220 return PEAR::raiseError('No file selected'); 221 } 222 223 //Uncompress data to a temporary file 224 $tmp = tmpfile(); 225 $expectedPos = $this->filePos + $seek; 226 $this->rewind(); 227 228 //Read the begining of the file 229 while ($this->filePos < $expectedPos && 230 ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) { 231 fwrite($tmp, $data); 232 } 233 234 $keep = false; 235 foreach ($blocks as $length) { 236 if ($keep) { 237 $expectedPos = $this->filePos + $length; 238 while ($this->filePos < $expectedPos && 239 ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) { 240 fwrite($tmp, $data); 241 } 242 } else { 243 $this->skip($length); 244 } 245 $keep = !$keep; 246 } 247 if ($keep) { 248 //Read the end of the file 249 while(($data = $this->getData(8192)) !== null) { 250 fwrite($tmp, $data); 251 } 252 } 253 fseek($tmp, 0); 254 255 //Create the writer 256 $this->source->rewind(); 257 $innerWriter = $this->source->makeWriterRemoveBlocks(array()); //Truncate the source 258 unset($this->source); 259 $writer = new File_Archive_Writer_Gzip(null, $innerWriter); 260 261 //And compress data from the temporary file 262 while (!feof($tmp)) { 263 $data = fread($tmp, 8192); 264 $writer->writeData($data); 265 } 266 fclose($tmp); 267 268 //Do not close inner writer since makeWriter was called 269 $this->close(); 270 271 return $writer; 272 } 273 274} 275 276?>