|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 00003 // +----------------------------------------------------------------------+ 00004 // | PHP Version 4 | 00005 // +----------------------------------------------------------------------+ 00006 // | Copyright (c) 1997-2002 The PHP Group | 00007 // +----------------------------------------------------------------------+ 00008 // | This source file is subject to version 2.02 of the PHP license, | 00009 // | that is bundled with this package in the file LICENSE, and is | 00010 // | available at through the world-wide-web at | 00011 // | http://www.php.net/license/2_02.txt. | 00012 // | If you did not receive a copy of the PHP license and are unable to | 00013 // | obtain it through the world-wide-web, please send a note to | 00014 // | license@php.net so we can mail you a copy immediately. | 00015 // +----------------------------------------------------------------------+ 00016 // | Author: Xavier Noguer <xnoguer@php.net> | 00017 // | Based on OLE::Storage_Lite by Kawai, Takanori | 00018 // +----------------------------------------------------------------------+ 00019 // 00020 // $Id: OLE.php,v 1.4 2010/12/14 17:35:47 moodlerobot Exp $ 00021 00022 00026 define('OLE_PPS_TYPE_ROOT', 5); 00027 define('OLE_PPS_TYPE_DIR', 1); 00028 define('OLE_PPS_TYPE_FILE', 2); 00029 define('OLE_DATA_SIZE_SMALL', 0x1000); 00030 define('OLE_LONG_INT_SIZE', 4); 00031 define('OLE_PPS_SIZE', 0x80); 00032 00033 require_once('PEAR.php'); 00034 require_once 'OLE/PPS.php'; 00035 00043 class OLE extends PEAR 00044 { 00049 var $_file_handle; 00050 00055 var $_list; 00056 00062 function OLE() 00063 { 00064 $this->_list = array(); 00065 } 00066 00074 function read($file) 00075 { 00076 /* consider storing offsets as constants */ 00077 $big_block_size_offset = 30; 00078 $iBdbCnt_offset = 44; 00079 $bd_start_offset = 68; 00080 00081 $fh = @fopen($file, "r"); 00082 if ($fh == false) { 00083 return $this->raiseError("Can't open file $file"); 00084 } 00085 $this->_file_handle = $fh; 00086 00087 /* begin reading OLE attributes */ 00088 fseek($fh, 0); 00089 $signature = fread($fh, 8); 00090 if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) { 00091 return $this->raiseError("File doesn't seem to be an OLE container."); 00092 } 00093 fseek($fh, $big_block_size_offset); 00094 $packed_array = unpack("v", fread($fh, 2)); 00095 $big_block_size = pow(2, $packed_array['']); 00096 00097 $packed_array = unpack("v", fread($fh, 2)); 00098 $small_block_size = pow(2, $packed_array['']); 00099 $i1stBdL = ($big_block_size - 0x4C) / OLE_LONG_INT_SIZE; 00100 00101 fseek($fh, $iBdbCnt_offset); 00102 $packed_array = unpack("V", fread($fh, 4)); 00103 $iBdbCnt = $packed_array['']; 00104 00105 $packed_array = unpack("V", fread($fh, 4)); 00106 $pps_wk_start = $packed_array['']; 00107 00108 fseek($fh, $bd_start_offset); 00109 $packed_array = unpack("V", fread($fh, 4)); 00110 $bd_start = $packed_array['']; 00111 $packed_array = unpack("V", fread($fh, 4)); 00112 $bd_count = $packed_array['']; 00113 $packed_array = unpack("V", fread($fh, 4)); 00114 $iAll = $packed_array['']; // this may be wrong 00115 /* create OLE_PPS objects from */ 00116 $ret = $this->_readPpsWks($pps_wk_start, $big_block_size); 00117 if (PEAR::isError($ret)) { 00118 return $ret; 00119 } 00120 return true; 00121 } 00122 00129 function _OLE() 00130 { 00131 fclose($this->_file_handle); 00132 } 00133 00143 function _readPpsWks($pps_wk_start, $big_block_size) 00144 { 00145 $pointer = ($pps_wk_start + 1) * $big_block_size; 00146 while (1) 00147 { 00148 fseek($this->_file_handle, $pointer); 00149 $pps_wk = fread($this->_file_handle, OLE_PPS_SIZE); 00150 if (strlen($pps_wk) != OLE_PPS_SIZE) { 00151 break; // Excel likes to add a trailing byte sometimes 00152 //return $this->raiseError("PPS at $pointer seems too short: ".strlen($pps_wk)); 00153 } 00154 $name_length = unpack("c", substr($pps_wk, 64, 2)); // FIXME (2 bytes??) 00155 $name_length = $name_length[''] - 2; 00156 $name = substr($pps_wk, 0, $name_length); 00157 $type = unpack("c", substr($pps_wk, 66, 1)); 00158 if (($type[''] != OLE_PPS_TYPE_ROOT) and 00159 ($type[''] != OLE_PPS_TYPE_DIR) and 00160 ($type[''] != OLE_PPS_TYPE_FILE)) 00161 { 00162 return $this->raiseError("PPS at $pointer has unknown type: {$type['']}"); 00163 } 00164 $prev = unpack("V", substr($pps_wk, 68, 4)); 00165 $next = unpack("V", substr($pps_wk, 72, 4)); 00166 $dir = unpack("V", substr($pps_wk, 76, 4)); 00167 // there is no magic number, it can take different values. 00168 //$magic = unpack("V", strrev(substr($pps_wk, 92, 4))); 00169 $time_1st = substr($pps_wk, 100, 8); 00170 $time_2nd = substr($pps_wk, 108, 8); 00171 $start_block = unpack("V", substr($pps_wk, 116, 4)); 00172 $size = unpack("V", substr($pps_wk, 120, 4)); 00173 // _data member will point to position in file!! 00174 // OLE_PPS object is created with an empty children array!! 00175 $this->_list[] = new OLE_PPS(null, '', $type[''], $prev[''], $next[''], 00176 $dir[''], OLE::OLE2LocalDate($time_1st), 00177 OLE::OLE2LocalDate($time_2nd), 00178 ($start_block[''] + 1) * $big_block_size, array()); 00179 // give it a size 00180 $this->_list[count($this->_list) - 1]->Size = $size['']; 00181 // check if the PPS tree (starting from root) is complete 00182 if ($this->_ppsTreeComplete(0)) { 00183 break; 00184 } 00185 $pointer += OLE_PPS_SIZE; 00186 } 00187 } 00188 00197 function _ppsTreeComplete($index) 00198 { 00199 if ($this->_list[$index]->NextPps != -1) { 00200 if (!isset($this->_list[$this->_list[$index]->NextPps])) { 00201 return false; 00202 } 00203 else { 00204 return $this->_ppsTreeComplete($this->_list[$index]->NextPps); 00205 } 00206 } 00207 if ($this->_list[$index]->DirPps != -1) { 00208 if (!isset($this->_list[$this->_list[$index]->DirPps])) { 00209 return false; 00210 } 00211 else { 00212 return $this->_ppsTreeComplete($this->_list[$index]->DirPps); 00213 } 00214 } 00215 return true; 00216 } 00217 00226 function isFile($index) 00227 { 00228 if (isset($this->_list[$index])) { 00229 return ($this->_list[$index]->Type == OLE_PPS_TYPE_FILE); 00230 } 00231 return false; 00232 } 00233 00242 function isRoot($index) 00243 { 00244 if (isset($this->_list[$index])) { 00245 return ($this->_list[$index]->Type == OLE_PPS_TYPE_ROOT); 00246 } 00247 return false; 00248 } 00249 00256 function ppsTotal() 00257 { 00258 return count($this->_list); 00259 } 00260 00272 function getData($index, $position, $length) 00273 { 00274 // if position is not valid return empty string 00275 if (!isset($this->_list[$index]) or ($position >= $this->_list[$index]->Size) or ($position < 0)) { 00276 return ''; 00277 } 00278 // Beware!!! _data member is actually a position 00279 fseek($this->_file_handle, $this->_list[$index]->_data + $position); 00280 return fread($this->_file_handle, $length); 00281 } 00282 00291 function getDataLength($index) 00292 { 00293 if (isset($this->_list[$index])) { 00294 return $this->_list[$index]->Size; 00295 } 00296 return 0; 00297 } 00298 00307 function Asc2Ucs($ascii) 00308 { 00309 $rawname = ''; 00310 for ($i = 0; $i < strlen($ascii); $i++) { 00311 $rawname .= $ascii{$i}."\x00"; 00312 } 00313 return $rawname; 00314 } 00315 00325 function LocalDate2OLE($date = null) 00326 { 00327 if (!isset($date)) { 00328 return "\x00\x00\x00\x00\x00\x00\x00\x00"; 00329 } 00330 00331 // factor used for separating numbers into 4 bytes parts 00332 $factor = pow(2,32); 00333 00334 // days from 1-1-1601 until the beggining of UNIX era 00335 $days = 134774; 00336 // calculate seconds 00337 $big_date = $days*24*3600 + gmmktime(date("H",$date),date("i",$date),date("s",$date), 00338 date("m",$date),date("d",$date),date("Y",$date)); 00339 // multiply just to make MS happy 00340 $big_date *= 10000000; 00341 00342 $high_part = floor($big_date/$factor); 00343 // lower 4 bytes 00344 $low_part = floor((($big_date/$factor) - $high_part)*$factor); 00345 00346 // Make HEX string 00347 $res = ''; 00348 00349 for ($i=0; $i<4; $i++) 00350 { 00351 $hex = $low_part % 0x100; 00352 $res .= pack('c', $hex); 00353 $low_part /= 0x100; 00354 } 00355 for ($i=0; $i<4; $i++) 00356 { 00357 $hex = $high_part % 0x100; 00358 $res .= pack('c', $hex); 00359 $high_part /= 0x100; 00360 } 00361 return $res; 00362 } 00363 00372 function OLE2LocalDate($string) 00373 { 00374 if (strlen($string) != 8) { 00375 return new PEAR_Error("Expecting 8 byte string"); 00376 } 00377 00378 // factor used for separating numbers into 4 bytes parts 00379 $factor = pow(2,32); 00380 $high_part = 0; 00381 for ($i=0; $i<4; $i++) 00382 { 00383 $al = unpack('C', $string{(7 - $i)}); 00384 $high_part += $al['']; 00385 if ($i < 3) { 00386 $high_part *= 0x100; 00387 } 00388 } 00389 $low_part = 0; 00390 for ($i=4; $i<8; $i++) 00391 { 00392 $al = unpack('C', $string{(7 - $i)}); 00393 $low_part += $al['']; 00394 if ($i < 7) { 00395 $low_part *= 0x100; 00396 } 00397 } 00398 $big_date = ($high_part*$factor) + $low_part; 00399 // translate to seconds 00400 $big_date /= 10000000; 00401 00402 // days from 1-1-1601 until the beggining of UNIX era 00403 $days = 134774; 00404 00405 // translate to seconds from beggining of UNIX era 00406 $big_date -= $days*24*3600; 00407 return floor($big_date); 00408 } 00409 } 00410 ?>