• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

classes/OLE/OLE.php

Go to the documentation of this file.
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 4249 2004-06-16 14:14:02Z hschottm $
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 'classes/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 ?>

Generated on Fri Dec 13 2013 09:06:35 for ILIAS Release_3_4_x_branch .rev 46804 by  doxygen 1.7.1