1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * Uncompress a file that was compressed in the Bzip2 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: Bzip2.php,v 1.19 2005/07/26 09:06:03 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 Bzip2 format 37 */ 38class File_Archive_Reader_Bzip2 extends File_Archive_Reader_Archive 39{ 40 var $nbRead = 0; 41 var $bzfile = null; 42 var $tmpName = null; 43 var $filePos = 0; 44 45 /** 46 * @see File_Archive_Reader::close() 47 */ 48 function close($innerClose = true) 49 { 50 if ($this->bzfile !== null) 51 bzclose($this->bzfile); 52 if ($this->tmpName !== null) 53 unlink($this->tmpName); 54 55 $this->bzfile = null; 56 $this->tmpName = null; 57 $this->nbRead = 0; 58 $this->filePos = 0; 59 return parent::close($innerClose); 60 } 61 62 /** 63 * @see File_Archive_Reader::next() 64 */ 65 function next() 66 { 67 if (!parent::next()) { 68 return false; 69 } 70 71 $this->nbRead++; 72 if ($this->nbRead > 1) { 73 return false; 74 } 75 76 $dataFilename = $this->source->getDataFilename(); 77 if ($dataFilename !== null) 78 { 79 $this->tmpName = null; 80 $this->bzfile = @bzopen($dataFilename, 'r'); 81 if ($this->bzfile === false) { 82 return PEAR::raiseError("bzopen failed to open $dataFilename"); 83 } 84 } else { 85 $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far'); 86 87 //Generate the tmp data 88 $dest = new File_Archive_Writer_Files(); 89 $dest->newFile($this->tmpName); 90 $this->source->sendData($dest); 91 $dest->close(); 92 93 $this->bzfile = bzopen($this->tmpName, 'r'); 94 } 95 96 return true; 97 } 98 /** 99 * Return the name of the single file contained in the archive 100 * deduced from the name of the archive (the extension is removed) 101 * 102 * @see File_Archive_Reader::getFilename() 103 */ 104 function getFilename() 105 { 106 $name = $this->source->getFilename(); 107 $pos = strrpos($name, "."); 108 if ($pos === false || $pos === 0) { 109 return $name; 110 } else { 111 return substr($name, 0, $pos); 112 } 113 } 114 /** 115 * @see File_Archive_Reader::getData() 116 */ 117 function getData($length = -1) 118 { 119 if ($length == -1) { 120 $data = ''; 121 do { 122 $newData = bzread($this->bzfile); 123 $data .= $newData; 124 } while ($newData != ''); 125 $this->filePos += strlen($data); 126 } else if ($length == 0) { 127 return ''; 128 } else { 129 $data = ''; 130 131 //The loop is here to correct what appears to be a bzread bug 132 while (strlen($data) < $length) { 133 $newData = bzread($this->bzfile, $length - strlen($data)); 134 if ($newData == '') { 135 break; 136 } 137 $data .= $newData; 138 } 139 $this->filePos += strlen($data); 140 } 141 142 return $data == '' ? null : $data; 143 } 144 145 /** 146 * @see File_Archive_Reader::rewind 147 */ 148 function rewind($length = -1) 149 { 150 $before = $this->filePos; 151 152 bzclose($this->bzfile); 153 if ($this->tmpName === null) { 154 $this->bzfile = bzopen($this->source->getDataFilename(), 'r'); 155 } else { 156 $this->bzfile = bzopen($this->tmpName, 'r'); 157 } 158 $this->filePos = 0; 159 160 if ($length != -1) { 161 $this->skip($before - $length); 162 } 163 return $before - $this->filePos; 164 } 165 166 /** 167 * @see File_Archive_Reader::tell() 168 */ 169 function tell() 170 { 171 return $this->filePos; 172 } 173 174 /** 175 * @see File_Archive_Reader::makeAppendWriter() 176 */ 177 function makeAppendWriter() 178 { 179 return PEAR::raiseError('Unable to append files to a bzip2 archive'); 180 } 181 182 /** 183 * @see File_Archive_Reader::makeWriterRemoveFiles() 184 */ 185 function makeWriterRemoveFiles($pred) 186 { 187 return PEAR::raiseError('Unable to remove files from a bzip2 archive'); 188 } 189 190 /** 191 * @see File_Archive_Reader::makeWriterRemoveBlocks() 192 */ 193 function makeWriterRemoveBlocks($blocks, $seek = 0) 194 { 195 require_once "File/Archive/Writer/Bzip2.php"; 196 197 if ($this->nbRead == 0) { 198 return PEAR::raiseError('No file selected'); 199 } 200 201 //Uncompress data to a temporary file 202 $tmp = tmpfile(); 203 $expectedPos = $this->filePos + $seek; 204 205 $this->rewind(); 206 207 //Read the begining of the file 208 while ($this->filePos < $expectedPos && 209 ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) { 210 fwrite($tmp, $data); 211 } 212 213 $keep = false; 214 foreach ($blocks as $length) { 215 if ($keep) { 216 $expectedPos = $this->filePos + $length; 217 while ($this->filePos < $expectedPos && 218 ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) { 219 fwrite($tmp, $data); 220 } 221 } else { 222 $this->skip($length); 223 } 224 $keep = !$keep; 225 } 226 if ($keep) { 227 //Read the end of the file 228 while(($data = $this->getData(8192)) !== null) { 229 fwrite($tmp, $data); 230 } 231 } 232 fseek($tmp, 0); 233 234 //Create the writer 235 $this->source->rewind(); 236 $innerWriter = $this->source->makeWriterRemoveBlocks(array()); //Truncate the source 237 unset($this->source); 238 $writer = new File_Archive_Writer_Bzip2(null, $innerWriter); 239 240 //And compress data from the temporary file 241 while (!feof($tmp)) { 242 $data = fread($tmp, 8192); 243 $writer->writeData($data); 244 } 245 fclose($tmp); 246 247 //Do not close inner writer since makeWriter was called 248 $this->close(); 249 250 return $writer; 251 } 252} 253 254?>