From:  hornetfighter+pear@hotmail.com ("hfig")
Date:  17 Jul 2018 14:17:40 Hong Kong Time
Newsgroup:  news.php.net/php.pear.bugs
Subject:  

[PEAR-BUG] Bug #21243 [Com]: small blocks ("mini stream") handling is broken

NNTP-Posting-Host:  null

Edit report at http://pear.php.net/bugs/bug.php?id=21243&edit=1

 ID:               21243
 Comment by:       hfig
 Reported By:      hornetfighter+pear at hotmail dot com
 Summary:          small blocks ("mini stream") handling is broken
 Status:           Open
 Type:             Bug
 Package:          OLE
 Operating System: Any
 Package Version:  1.0.0RC3
 PHP Version:      Irrelevant
 New Comment:

Fix submitted as a PR - https://github.com/pear/OLE/pull/10


Previous Comments:
------------------------------------------------------------------------

[2017-09-26 11:33:00] tacituseu

actually it should be:
$pos = $blockId * $this->ole->smallBlockSize;

------------------------------------------------------------------------

[2017-09-26 11:31:12] tacituseu

2.1.
$pos = $rootPos + $blockId * $this->ole->bigBlockSize;
should be:
$pos = $rootPos + $blockId * $this->ole->smallBlockSize;

------------------------------------------------------------------------

[2017-09-26 11:12:16] tacituseu

Description:
------------
In OLE\ChainedBlockStream.php::stream_open() there is this:

if (isset($this->params['size']) && $this->params['size'] < $this->ole-
>bigBlockThreshold && $blockId != $this->ole->root->startBlock) {
		// Block id refers to small blocks
		$rootPos = $this->ole->_getBlockOffset($this->ole->root-
>startBlock);
		while ($blockId != -2) {
				$pos = $rootPos + $blockId * $this->ole-
>bigBlockSize;
				$blockId = $this->ole->sbat[$blockId];
				fseek($this->ole->_file_handle, $pos);
				$this->data .= fread($this->ole->_file_handle, 
$this->ole->bigBlockSize);

		}
}

Problems:
1. small blocks ([MS-CFB].pdf: "mini stream") isn't a continuous space,

but a stream itself:
$rootPos = $this->ole->_getBlockOffset($this->ole->root->startBlock);
will work only for simple documents that don't contain entries with size

larger than $this->ole->bigBlockThreshold

what you want is in OLE.php::_readPpsWks():

$this->_list[] = $pps; 
if ($type == OLE_PPS_TYPE_ROOT) {
	$this->_small_handle = $this->getStream($pps->startBlock);
}
and then use it in point 2

Reference: [MS-CFB].pdf 2.6.1 Root Directory Entry

2. wrong block size used for fread
fread($this->ole->_file_handle, $this->ole->bigBlockSize);
should be:
fread($this->ole->_small_handle, $this->ole->smallBlockSize);

Test script:
---------------
$obj = new OLE();
$obj->read('ole.xls');
foreach ($obj->_list as $idx => $pps) if ($obj->isFile($idx)) {
  $dlen = $olz->getDataLength($idx);
  $data = $olz->getData($idx, 0, $dlen);
  var_dump($data);
}

Expected result:
----------------
data corresponding to given entry

Actual result:
--------------
data corresponding to given entry for some entries (up to first big
block entry 
which breaks assumption of continuity for small stream)

------------------------------------------------------------------------


-- 
Edit this bug report at http://pear.php.net/bugs/bug.php?id=21243&edit=1