Skip to content

Commit

Permalink
Changes to comply MS documentation (#25)
Browse files Browse the repository at this point in the history
* removed signed int manipulation,
constants as in MS documentation,
comments for better readability,
readStream() implementation,
many minor fixes

* fixed the minor version in the binary test data

* replaced $stream to $fh in the readStream()
  • Loading branch information
risototh authored Feb 22, 2021
1 parent a515ea2 commit 1ee17e4
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 132 deletions.
99 changes: 53 additions & 46 deletions OLE.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,22 @@
/**
* Constants for OLE package
*/
define('OLE_PPS_TYPE_ROOT', 5);
define('OLE_PPS_TYPE_DIR', 1);
define('OLE_PPS_TYPE_FILE', 2);
define('OLE_DATA_SIZE_SMALL', 0x1000);
define('OLE_LONG_INT_SIZE', 4);
define('OLE_PPS_SIZE', 0x80);
define('OLE_PPS_TYPE_ROOT', 0x05);
define('OLE_PPS_TYPE_DIR', 0x01);
define('OLE_PPS_TYPE_FILE', 0x02);
define('OLE_DATA_SIZE_SMALL', 0x1000);
define('OLE_LONG_INT_SIZE', 4);
define('OLE_PPS_SIZE', 0x80);
define('OLE_DIFSECT', 0xFFFFFFFC);
define('OLE_FATSECT', 0xFFFFFFFD);
define('OLE_ENDOFCHAIN', 0xFFFFFFFE);
define('OLE_FREESECT', 0xFFFFFFFF);
define('OLE_LITTLE_ENDIAN', 0xFFFE);
define('OLE_VERSION_MAJOR_3', 0x0003);
define('OLE_VERSION_MINOR', 0x003E);
define('OLE_SECTOR_SHIFT_3', 0x0009);
define('OLE_MINI_SECTOR_SHIFT', 0x0006);
define('OLE_CFB_SIGNATURE', "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1");

if (!class_exists('PEAR')) {
require_once 'PEAR.php';
Expand Down Expand Up @@ -133,14 +143,27 @@ function read($file)
if (!$fh) {
return $this->raiseError("Can't open file $file");
}

return $this->readStream($fh);
}

/**
* Reads an OLE container from the contents of the stream given.
*
* @access public
* @param resource $fh
* @return mixed true on success, PEAR_Error on failure
*/
function readStream($fh)
{
$this->_file_handle = $fh;

$signature = fread($fh, 8);
if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) {
if (OLE_CFB_SIGNATURE != $signature) {
return $this->raiseError("File doesn't seem to be an OLE container.");
}
fseek($fh, 28);
if (fread($fh, 2) != "\xFE\xFF") {
if ($this->_readInt2($fh) != OLE_LITTLE_ENDIAN) {
// This shouldn't be a problem in practice
return $this->raiseError("Only Little-Endian encoding is supported.");
}
Expand All @@ -165,7 +188,7 @@ function read($file)
// Number of blocks in Short Block Allocation Table
$sbbatBlockCount = $this->_readInt4($fh);
// Block id of first sector in Master Block Allocation Table
$mbatFirstBlockId = $this->_readSignedInt4($fh);
$mbatFirstBlockId = $this->_readInt4($fh);
// Number of blocks in Master Block Allocation Table
$mbbatBlockCount = $this->_readInt4($fh);
$this->bbat = array();
Expand All @@ -174,27 +197,32 @@ function read($file)
// Block Allocation Table
$mbatBlocks = array();
for ($i = 0; $i < 109; $i++) {
$mbatBlocks[] = $this->_readSignedInt4($fh);
$mbatBlocks[] = $this->_readInt4($fh);
}

// Read rest of Master Block Allocation Table (if any is left)
$pos = $this->_getBlockOffset($mbatFirstBlockId);
for ($i = 0; $i < $mbbatBlockCount; $i++) {
fseek($fh, $pos);
for ($j = 0; $j < $this->bigBlockSize / 4 - 1; $j++) {
$mbatBlocks[] = $this->_readInt4($fh);
$mbatBlocks[] = $this->_readInt4($fh); // ffix - invalid block address check
}
// Last block id in each block points to next block
$pos = $this->_getBlockOffset($this->_readInt4($fh));
$chainBlock = $this->_readInt4($fh);
if ($chainBlock === OLE_ENDOFCHAIN) { // ENDOFCHAIN
break;
}
$pos = $this->_getBlockOffset($chainBlock);
}


// Read Big Block Allocation Table according to chain specified by
// $mbatBlocks
for ($i = 0; $i < $bbatBlockCount; $i++) {
$pos = $this->_getBlockOffset($mbatBlocks[$i]);
fseek($fh, $pos);
for ($j = 0 ; $j < $this->bigBlockSize / 4; $j++) {
$this->bbat[] = $this->_readSignedInt4($fh);
$this->bbat[] = $this->_readInt4($fh);
}
}

Expand All @@ -207,8 +235,9 @@ function read($file)
// missing
return false;
}

for ($blockId = 0; $blockId < $shortBlockCount; $blockId++) {
$this->sbat[$blockId] = $this->_readSignedInt4($sbatFh);
$this->sbat[$blockId] = $this->_readInt4($sbatFh);
}
fclose($sbatFh);

Expand Down Expand Up @@ -296,27 +325,6 @@ function _readInt4($fh)
return $tmp;
}

/**
* Reads a signed long (4 octets).
* @param resource file handle
* @return int
* @access private
*/
function _readSignedInt4($fh)
{
$tmp = $this->_readInt4($fh);

if (PHP_INT_SIZE == 4) {
// will overflow into a proper value
return $tmp;
}

// L stands for unsigned long, l for signed long
list(, $tmp) = unpack("s", pack("L", $tmp));

return $tmp;
}

/**
* Gets information about all PPS's on the OLE container from the PPS WK's
* creates an OLE_PPS object for each one.
Expand Down Expand Up @@ -353,16 +361,16 @@ function _readPpsWks($blockId)
default:
continue 2;
}
fseek($fh, 1, SEEK_CUR);
fseek($fh, 1, SEEK_CUR); // skip Color Flag
$pps->Type = $type;
$pps->Name = $name;
$pps->PrevPps = $this->_readSignedInt4($fh);
$pps->NextPps = $this->_readSignedInt4($fh);
$pps->DirPps = $this->_readSignedInt4($fh);
fseek($fh, 20, SEEK_CUR);
$pps->PrevPps = $this->_readInt4($fh); // Left Sibling ID
$pps->NextPps = $this->_readInt4($fh); // Right Sibling ID
$pps->DirPps = $this->_readInt4($fh); // Child ID
fseek($fh, 20, SEEK_CUR); // skip CLSID (16 bytes) + State Bits
$pps->Time1st = OLE::OLE2LocalDate(fread($fh, 8));
$pps->Time2nd = OLE::OLE2LocalDate(fread($fh, 8));
$pps->_StartBlock = $this->_readSignedInt4($fh);
$pps->_StartBlock = $this->_readInt4($fh);
$pps->Size = $this->_readInt4($fh);
$pps->No = count($this->_list);
$this->_list[] = $pps;
Expand All @@ -387,7 +395,7 @@ function _readPpsWks($blockId)
$pps->children = array();
while ($nos) {
$no = array_pop($nos);
if ($no != -1) {
if ($no != OLE_FREESECT) {
$childPps = $this->_list[$no];
$nos[] = $childPps->PrevPps;
$nos[] = $childPps->NextPps;
Expand All @@ -412,11 +420,11 @@ function _ppsTreeComplete($index)
{
return isset($this->_list[$index]) &&
($pps = $this->_list[$index]) &&
($pps->PrevPps == -1 ||
($pps->PrevPps == OLE_FREESECT ||
$this->_ppsTreeComplete($pps->PrevPps)) &&
($pps->NextPps == -1 ||
($pps->NextPps == OLE_FREESECT ||
$this->_ppsTreeComplete($pps->NextPps)) &&
($pps->DirPps == -1 ||
($pps->DirPps == OLE_FREESECT ||
$this->_ppsTreeComplete($pps->DirPps));
}

Expand Down Expand Up @@ -606,4 +614,3 @@ static function OLE2LocalDate($string)
return floor($big_date);
}
}
?>
9 changes: 3 additions & 6 deletions OLE/ChainedBlockStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function stream_open($path, $mode, $options, &$openedPath)

// Block id refers to small blocks
$rootPos = 0;
while ($blockId != -2) {
while ($blockId != OLE_ENDOFCHAIN) {
$pos = $rootPos + $blockId * $this->ole->smallBlockSize;

$blockId = $this->ole->sbat[$blockId];
Expand All @@ -119,7 +119,7 @@ function stream_open($path, $mode, $options, &$openedPath)
}
} else {
// Block id refers to big blocks
while ($blockId != -2) {
while ($blockId != OLE_ENDOFCHAIN) {
$pos = $this->ole->_getBlockOffset($blockId);
fseek($this->ole->_file_handle, $pos);
$this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
Expand All @@ -139,7 +139,6 @@ function stream_open($path, $mode, $options, &$openedPath)

/**
* Implements support for fclose().
* @return string
*/
function stream_close()
{
Expand Down Expand Up @@ -204,7 +203,7 @@ function stream_seek($offset, $whence)
$this->pos = $offset;
} elseif ($whence == SEEK_CUR && -$offset <= $this->pos) {
$this->pos += $offset;
} elseif ($whence == SEEK_END && -$offset <= sizeof($this->data)) {
} elseif ($whence == SEEK_END && -$offset <= strlen($this->data)) {
$this->pos = strlen($this->data) + $offset;
} else {
return false;
Expand Down Expand Up @@ -245,5 +244,3 @@ function stream_flush()
// bool dir_rewinddir ( void )
// bool dir_closedir ( void )
}

?>
7 changes: 3 additions & 4 deletions OLE/PPS.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,15 @@ function _getPpsWk()
static function _savePpsSetPnt(&$raList, $to_save, $depth = 0)
{
if ( !is_array($to_save) || (count($to_save) == 0) ) {
return 0xFFFFFFFF;
return OLE_FREESECT;
}
elseif( count($to_save) == 1 ) {
$cnt = count($raList);
// If the first entry, it's the root... Don't clone it!
$raList[$cnt] = ( $depth == 0 ) ? $to_save[0] : clone $to_save[0];
$raList[$cnt]->No = $cnt;
$raList[$cnt]->PrevPps = 0xFFFFFFFF;
$raList[$cnt]->NextPps = 0xFFFFFFFF;
$raList[$cnt]->PrevPps = OLE_FREESECT;
$raList[$cnt]->NextPps = OLE_FREESECT;
$raList[$cnt]->DirPps = self::_savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++);
return $cnt;
}
Expand All @@ -242,4 +242,3 @@ static function _savePpsSetPnt(&$raList, $to_save, $depth = 0)
}
}
}
?>
3 changes: 1 addition & 2 deletions OLE/PPS/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function __construct($name)
*
* @access public
* @param string $dir The dir to be used as temp dir
* @return true if given dir is valid, false otherwise
* @return boolean true if given dir is valid, false otherwise
*/
function setTempDir($dir)
{
Expand Down Expand Up @@ -128,4 +128,3 @@ function getStream()
$this->ole->getStream($this);
}
}
?>
Loading

0 comments on commit 1ee17e4

Please sign in to comment.