summaryrefslogtreecommitdiffstats
path: root/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE')
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php196
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS.php237
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/File.php64
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php426
4 files changed, 923 insertions, 0 deletions
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php
new file mode 100644
index 0000000..7b98370
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php
@@ -0,0 +1,196 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared\OLE;
+
+use PhpOffice\PhpSpreadsheet\Shared\OLE;
+
+class ChainedBlockStream
+{
+ /**
+ * The OLE container of the file that is being read.
+ *
+ * @var OLE
+ */
+ public $ole;
+
+ /**
+ * Parameters specified by fopen().
+ *
+ * @var array
+ */
+ public $params;
+
+ /**
+ * The binary data of the file.
+ *
+ * @var string
+ */
+ public $data;
+
+ /**
+ * The file pointer.
+ *
+ * @var int byte offset
+ */
+ public $pos;
+
+ /**
+ * Implements support for fopen().
+ * For creating streams using this wrapper, use OLE_PPS_File::getStream().
+ *
+ * @param string $path resource name including scheme, e.g.
+ * ole-chainedblockstream://oleInstanceId=1
+ * @param string $mode only "r" is supported
+ * @param int $options mask of STREAM_REPORT_ERRORS and STREAM_USE_PATH
+ * @param string &$openedPath absolute path of the opened stream (out parameter)
+ *
+ * @return bool true on success
+ */
+ public function stream_open($path, $mode, $options, &$openedPath) // @codingStandardsIgnoreLine
+ {
+ if ($mode != 'r') {
+ if ($options & STREAM_REPORT_ERRORS) {
+ trigger_error('Only reading is supported', E_USER_WARNING);
+ }
+
+ return false;
+ }
+
+ // 25 is length of "ole-chainedblockstream://"
+ parse_str(substr($path, 25), $this->params);
+ if (!isset($this->params['oleInstanceId'], $this->params['blockId'], $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']])) {
+ if ($options & STREAM_REPORT_ERRORS) {
+ trigger_error('OLE stream not found', E_USER_WARNING);
+ }
+
+ return false;
+ }
+ $this->ole = $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']];
+
+ $blockId = $this->params['blockId'];
+ $this->data = '';
+ 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);
+ }
+ } else {
+ // Block id refers to big blocks
+ while ($blockId != -2) {
+ $pos = $this->ole->getBlockOffset($blockId);
+ fseek($this->ole->_file_handle, $pos);
+ $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
+ $blockId = $this->ole->bbat[$blockId];
+ }
+ }
+ if (isset($this->params['size'])) {
+ $this->data = substr($this->data, 0, $this->params['size']);
+ }
+
+ if ($options & STREAM_USE_PATH) {
+ $openedPath = $path;
+ }
+
+ return true;
+ }
+
+ /**
+ * Implements support for fclose().
+ */
+ public function stream_close(): void // @codingStandardsIgnoreLine
+ {
+ $this->ole = null;
+ unset($GLOBALS['_OLE_INSTANCES']);
+ }
+
+ /**
+ * Implements support for fread(), fgets() etc.
+ *
+ * @param int $count maximum number of bytes to read
+ *
+ * @return string
+ */
+ public function stream_read($count) // @codingStandardsIgnoreLine
+ {
+ if ($this->stream_eof()) {
+ return false;
+ }
+ $s = substr($this->data, $this->pos, $count);
+ $this->pos += $count;
+
+ return $s;
+ }
+
+ /**
+ * Implements support for feof().
+ *
+ * @return bool TRUE if the file pointer is at EOF; otherwise FALSE
+ */
+ public function stream_eof() // @codingStandardsIgnoreLine
+ {
+ return $this->pos >= strlen($this->data);
+ }
+
+ /**
+ * Returns the position of the file pointer, i.e. its offset into the file
+ * stream. Implements support for ftell().
+ *
+ * @return int
+ */
+ public function stream_tell() // @codingStandardsIgnoreLine
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Implements support for fseek().
+ *
+ * @param int $offset byte offset
+ * @param int $whence SEEK_SET, SEEK_CUR or SEEK_END
+ *
+ * @return bool
+ */
+ public function stream_seek($offset, $whence) // @codingStandardsIgnoreLine
+ {
+ if ($whence == SEEK_SET && $offset >= 0) {
+ $this->pos = $offset;
+ } elseif ($whence == SEEK_CUR && -$offset <= $this->pos) {
+ $this->pos += $offset;
+ } elseif ($whence == SEEK_END && -$offset <= count($this->data)) {
+ $this->pos = strlen($this->data) + $offset;
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Implements support for fstat(). Currently the only supported field is
+ * "size".
+ *
+ * @return array
+ */
+ public function stream_stat() // @codingStandardsIgnoreLine
+ {
+ return [
+ 'size' => strlen($this->data),
+ ];
+ }
+
+ // Methods used by stream_wrapper_register() that are not implemented:
+ // bool stream_flush ( void )
+ // int stream_write ( string data )
+ // bool rename ( string path_from, string path_to )
+ // bool mkdir ( string path, int mode, int options )
+ // bool rmdir ( string path, int options )
+ // bool dir_opendir ( string path, int options )
+ // array url_stat ( string path, int flags )
+ // string dir_readdir ( void )
+ // bool dir_rewinddir ( void )
+ // bool dir_closedir ( void )
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS.php
new file mode 100644
index 0000000..1832521
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS.php
@@ -0,0 +1,237 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared\OLE;
+
+// vim: set expandtab tabstop=4 shiftwidth=4:
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Author: Xavier Noguer <xnoguer@php.net> |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+use PhpOffice\PhpSpreadsheet\Shared\OLE;
+
+/**
+ * Class for creating PPS's for OLE containers.
+ *
+ * @author Xavier Noguer <xnoguer@php.net>
+ */
+class PPS
+{
+ /**
+ * The PPS index.
+ *
+ * @var int
+ */
+ public $No;
+
+ /**
+ * The PPS name (in Unicode).
+ *
+ * @var string
+ */
+ public $Name;
+
+ /**
+ * The PPS type. Dir, Root or File.
+ *
+ * @var int
+ */
+ public $Type;
+
+ /**
+ * The index of the previous PPS.
+ *
+ * @var int
+ */
+ public $PrevPps;
+
+ /**
+ * The index of the next PPS.
+ *
+ * @var int
+ */
+ public $NextPps;
+
+ /**
+ * The index of it's first child if this is a Dir or Root PPS.
+ *
+ * @var int
+ */
+ public $DirPps;
+
+ /**
+ * A timestamp.
+ *
+ * @var int
+ */
+ public $Time1st;
+
+ /**
+ * A timestamp.
+ *
+ * @var int
+ */
+ public $Time2nd;
+
+ /**
+ * Starting block (small or big) for this PPS's data inside the container.
+ *
+ * @var int
+ */
+ public $startBlock;
+
+ /**
+ * The size of the PPS's data (in bytes).
+ *
+ * @var int
+ */
+ public $Size;
+
+ /**
+ * The PPS's data (only used if it's not using a temporary file).
+ *
+ * @var string
+ */
+ public $_data;
+
+ /**
+ * Array of child PPS's (only used by Root and Dir PPS's).
+ *
+ * @var array
+ */
+ public $children = [];
+
+ /**
+ * Pointer to OLE container.
+ *
+ * @var OLE
+ */
+ public $ole;
+
+ /**
+ * The constructor.
+ *
+ * @param int $No The PPS index
+ * @param string $name The PPS name
+ * @param int $type The PPS type. Dir, Root or File
+ * @param int $prev The index of the previous PPS
+ * @param int $next The index of the next PPS
+ * @param int $dir The index of it's first child if this is a Dir or Root PPS
+ * @param int $time_1st A timestamp
+ * @param int $time_2nd A timestamp
+ * @param string $data The (usually binary) source data of the PPS
+ * @param array $children Array containing children PPS for this PPS
+ */
+ public function __construct($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children)
+ {
+ $this->No = $No;
+ $this->Name = $name;
+ $this->Type = $type;
+ $this->PrevPps = $prev;
+ $this->NextPps = $next;
+ $this->DirPps = $dir;
+ $this->Time1st = $time_1st;
+ $this->Time2nd = $time_2nd;
+ $this->_data = $data;
+ $this->children = $children;
+ if ($data != '') {
+ $this->Size = strlen($data);
+ } else {
+ $this->Size = 0;
+ }
+ }
+
+ /**
+ * Returns the amount of data saved for this PPS.
+ *
+ * @return int The amount of data (in bytes)
+ */
+ public function getDataLen()
+ {
+ if (!isset($this->_data)) {
+ return 0;
+ }
+
+ return strlen($this->_data);
+ }
+
+ /**
+ * Returns a string with the PPS's WK (What is a WK?).
+ *
+ * @return string The binary string
+ */
+ public function getPpsWk()
+ {
+ $ret = str_pad($this->Name, 64, "\x00");
+
+ $ret .= pack('v', strlen($this->Name) + 2) // 66
+ . pack('c', $this->Type) // 67
+ . pack('c', 0x00) //UK // 68
+ . pack('V', $this->PrevPps) //Prev // 72
+ . pack('V', $this->NextPps) //Next // 76
+ . pack('V', $this->DirPps) //Dir // 80
+ . "\x00\x09\x02\x00" // 84
+ . "\x00\x00\x00\x00" // 88
+ . "\xc0\x00\x00\x00" // 92
+ . "\x00\x00\x00\x46" // 96 // Seems to be ok only for Root
+ . "\x00\x00\x00\x00" // 100
+ . OLE::localDateToOLE($this->Time1st) // 108
+ . OLE::localDateToOLE($this->Time2nd) // 116
+ . pack('V', isset($this->startBlock) ? $this->startBlock : 0) // 120
+ . pack('V', $this->Size) // 124
+ . pack('V', 0); // 128
+
+ return $ret;
+ }
+
+ /**
+ * Updates index and pointers to previous, next and children PPS's for this
+ * PPS. I don't think it'll work with Dir PPS's.
+ *
+ * @param array &$raList Reference to the array of PPS's for the whole OLE
+ * container
+ * @param mixed $to_save
+ * @param mixed $depth
+ *
+ * @return int The index for this PPS
+ */
+ public static function savePpsSetPnt(&$raList, $to_save, $depth = 0)
+ {
+ if (!is_array($to_save) || (empty($to_save))) {
+ return 0xFFFFFFFF;
+ } 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]->DirPps = self::savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++);
+ } else {
+ $iPos = floor(count($to_save) / 2);
+ $aPrev = array_slice($to_save, 0, $iPos);
+ $aNext = array_slice($to_save, $iPos + 1);
+ $cnt = count($raList);
+ // If the first entry, it's the root... Don't clone it!
+ $raList[$cnt] = ($depth == 0) ? $to_save[$iPos] : clone $to_save[$iPos];
+ $raList[$cnt]->No = $cnt;
+ $raList[$cnt]->PrevPps = self::savePpsSetPnt($raList, $aPrev, $depth++);
+ $raList[$cnt]->NextPps = self::savePpsSetPnt($raList, $aNext, $depth++);
+ $raList[$cnt]->DirPps = self::savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++);
+ }
+
+ return $cnt;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/File.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/File.php
new file mode 100644
index 0000000..006da1f
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/File.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
+
+// vim: set expandtab tabstop=4 shiftwidth=4:
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Author: Xavier Noguer <xnoguer@php.net> |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+use PhpOffice\PhpSpreadsheet\Shared\OLE;
+use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
+
+/**
+ * Class for creating File PPS's for OLE containers.
+ *
+ * @author Xavier Noguer <xnoguer@php.net>
+ */
+class File extends PPS
+{
+ /**
+ * The constructor.
+ *
+ * @param string $name The name of the file (in Unicode)
+ *
+ * @see OLE::ascToUcs()
+ */
+ public function __construct($name)
+ {
+ parent::__construct(null, $name, OLE::OLE_PPS_TYPE_FILE, null, null, null, null, null, '', []);
+ }
+
+ /**
+ * Initialization method. Has to be called right after OLE_PPS_File().
+ *
+ * @return mixed true on success
+ */
+ public function init()
+ {
+ return true;
+ }
+
+ /**
+ * Append data to PPS.
+ *
+ * @param string $data The data to append
+ */
+ public function append($data): void
+ {
+ $this->_data .= $data;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php
new file mode 100644
index 0000000..0be80e9
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php
@@ -0,0 +1,426 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
+
+// vim: set expandtab tabstop=4 shiftwidth=4:
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Author: Xavier Noguer <xnoguer@php.net> |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+use PhpOffice\PhpSpreadsheet\Shared\OLE;
+use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
+
+/**
+ * Class for creating Root PPS's for OLE containers.
+ *
+ * @author Xavier Noguer <xnoguer@php.net>
+ */
+class Root extends PPS
+{
+ /**
+ * @var resource
+ */
+ private $fileHandle;
+
+ /**
+ * @var int
+ */
+ private $smallBlockSize;
+
+ /**
+ * @var int
+ */
+ private $bigBlockSize;
+
+ /**
+ * @param int $time_1st A timestamp
+ * @param int $time_2nd A timestamp
+ * @param File[] $raChild
+ */
+ public function __construct($time_1st, $time_2nd, $raChild)
+ {
+ parent::__construct(null, OLE::ascToUcs('Root Entry'), OLE::OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild);
+ }
+
+ /**
+ * Method for saving the whole OLE container (including files).
+ * In fact, if called with an empty argument (or '-'), it saves to a
+ * temporary file and then outputs it's contents to stdout.
+ * If a resource pointer to a stream created by fopen() is passed
+ * it will be used, but you have to close such stream by yourself.
+ *
+ * @param resource $fileHandle the name of the file or stream where to save the OLE container
+ *
+ * @return bool true on success
+ */
+ public function save($fileHandle)
+ {
+ $this->fileHandle = $fileHandle;
+
+ // Initial Setting for saving
+ $this->bigBlockSize = 2 ** (
+ (isset($this->bigBlockSize)) ? self::adjust2($this->bigBlockSize) : 9
+ );
+ $this->smallBlockSize = 2 ** (
+ (isset($this->smallBlockSize)) ? self::adjust2($this->smallBlockSize) : 6
+ );
+
+ // Make an array of PPS's (for Save)
+ $aList = [];
+ PPS::savePpsSetPnt($aList, [$this]);
+ // calculate values for header
+ [$iSBDcnt, $iBBcnt, $iPPScnt] = $this->calcSize($aList); //, $rhInfo);
+ // Save Header
+ $this->saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
+
+ // Make Small Data string (write SBD)
+ $this->_data = $this->makeSmallData($aList);
+
+ // Write BB
+ $this->saveBigData($iSBDcnt, $aList);
+ // Write PPS
+ $this->savePps($aList);
+ // Write Big Block Depot and BDList and Adding Header informations
+ $this->saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
+
+ return true;
+ }
+
+ /**
+ * Calculate some numbers.
+ *
+ * @param array $raList Reference to an array of PPS's
+ *
+ * @return float[] The array of numbers
+ */
+ private function calcSize(&$raList)
+ {
+ // Calculate Basic Setting
+ [$iSBDcnt, $iBBcnt, $iPPScnt] = [0, 0, 0];
+ $iSmallLen = 0;
+ $iSBcnt = 0;
+ $iCount = count($raList);
+ for ($i = 0; $i < $iCount; ++$i) {
+ if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) {
+ $raList[$i]->Size = $raList[$i]->getDataLen();
+ if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) {
+ $iSBcnt += floor($raList[$i]->Size / $this->smallBlockSize)
+ + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0);
+ } else {
+ $iBBcnt += (floor($raList[$i]->Size / $this->bigBlockSize) +
+ (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0));
+ }
+ }
+ }
+ $iSmallLen = $iSBcnt * $this->smallBlockSize;
+ $iSlCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE);
+ $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt) ? 1 : 0);
+ $iBBcnt += (floor($iSmallLen / $this->bigBlockSize) +
+ (($iSmallLen % $this->bigBlockSize) ? 1 : 0));
+ $iCnt = count($raList);
+ $iBdCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE;
+ $iPPScnt = (floor($iCnt / $iBdCnt) + (($iCnt % $iBdCnt) ? 1 : 0));
+
+ return [$iSBDcnt, $iBBcnt, $iPPScnt];
+ }
+
+ /**
+ * Helper function for caculating a magic value for block sizes.
+ *
+ * @param int $i2 The argument
+ *
+ * @return float
+ *
+ * @see save()
+ */
+ private static function adjust2($i2)
+ {
+ $iWk = log($i2) / log(2);
+
+ return ($iWk > floor($iWk)) ? floor($iWk) + 1 : $iWk;
+ }
+
+ /**
+ * Save OLE header.
+ *
+ * @param int $iSBDcnt
+ * @param int $iBBcnt
+ * @param int $iPPScnt
+ */
+ private function saveHeader($iSBDcnt, $iBBcnt, $iPPScnt): void
+ {
+ $FILE = $this->fileHandle;
+
+ // Calculate Basic Setting
+ $iBlCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE;
+ $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE;
+
+ $iBdExL = 0;
+ $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
+ $iAllW = $iAll;
+ $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
+ $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0);
+
+ // Calculate BD count
+ if ($iBdCnt > $i1stBdL) {
+ while (1) {
+ ++$iBdExL;
+ ++$iAllW;
+ $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
+ $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0);
+ if ($iBdCnt <= ($iBdExL * $iBlCnt + $i1stBdL)) {
+ break;
+ }
+ }
+ }
+
+ // Save Header
+ fwrite(
+ $FILE,
+ "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . pack('v', 0x3b)
+ . pack('v', 0x03)
+ . pack('v', -2)
+ . pack('v', 9)
+ . pack('v', 6)
+ . pack('v', 0)
+ . "\x00\x00\x00\x00"
+ . "\x00\x00\x00\x00"
+ . pack('V', $iBdCnt)
+ . pack('V', $iBBcnt + $iSBDcnt) //ROOT START
+ . pack('V', 0)
+ . pack('V', 0x1000)
+ . pack('V', $iSBDcnt ? 0 : -2) //Small Block Depot
+ . pack('V', $iSBDcnt)
+ );
+ // Extra BDList Start, Count
+ if ($iBdCnt < $i1stBdL) {
+ fwrite(
+ $FILE,
+ pack('V', -2) // Extra BDList Start
+ . pack('V', 0)// Extra BDList Count
+ );
+ } else {
+ fwrite($FILE, pack('V', $iAll + $iBdCnt) . pack('V', $iBdExL));
+ }
+
+ // BDList
+ for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) {
+ fwrite($FILE, pack('V', $iAll + $i));
+ }
+ if ($i < $i1stBdL) {
+ $jB = $i1stBdL - $i;
+ for ($j = 0; $j < $jB; ++$j) {
+ fwrite($FILE, (pack('V', -1)));
+ }
+ }
+ }
+
+ /**
+ * Saving big data (PPS's with data bigger than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL).
+ *
+ * @param int $iStBlk
+ * @param array &$raList Reference to array of PPS's
+ */
+ private function saveBigData($iStBlk, &$raList): void
+ {
+ $FILE = $this->fileHandle;
+
+ // cycle through PPS's
+ $iCount = count($raList);
+ for ($i = 0; $i < $iCount; ++$i) {
+ if ($raList[$i]->Type != OLE::OLE_PPS_TYPE_DIR) {
+ $raList[$i]->Size = $raList[$i]->getDataLen();
+ if (($raList[$i]->Size >= OLE::OLE_DATA_SIZE_SMALL) || (($raList[$i]->Type == OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data))) {
+ fwrite($FILE, $raList[$i]->_data);
+
+ if ($raList[$i]->Size % $this->bigBlockSize) {
+ fwrite($FILE, str_repeat("\x00", $this->bigBlockSize - ($raList[$i]->Size % $this->bigBlockSize)));
+ }
+ // Set For PPS
+ $raList[$i]->startBlock = $iStBlk;
+ $iStBlk +=
+ (floor($raList[$i]->Size / $this->bigBlockSize) +
+ (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0));
+ }
+ }
+ }
+ }
+
+ /**
+ * get small data (PPS's with data smaller than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL).
+ *
+ * @param array &$raList Reference to array of PPS's
+ *
+ * @return string
+ */
+ private function makeSmallData(&$raList)
+ {
+ $sRes = '';
+ $FILE = $this->fileHandle;
+ $iSmBlk = 0;
+
+ $iCount = count($raList);
+ for ($i = 0; $i < $iCount; ++$i) {
+ // Make SBD, small data string
+ if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) {
+ if ($raList[$i]->Size <= 0) {
+ continue;
+ }
+ if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) {
+ $iSmbCnt = floor($raList[$i]->Size / $this->smallBlockSize)
+ + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0);
+ // Add to SBD
+ $jB = $iSmbCnt - 1;
+ for ($j = 0; $j < $jB; ++$j) {
+ fwrite($FILE, pack('V', $j + $iSmBlk + 1));
+ }
+ fwrite($FILE, pack('V', -2));
+
+ // Add to Data String(this will be written for RootEntry)
+ $sRes .= $raList[$i]->_data;
+ if ($raList[$i]->Size % $this->smallBlockSize) {
+ $sRes .= str_repeat("\x00", $this->smallBlockSize - ($raList[$i]->Size % $this->smallBlockSize));
+ }
+ // Set for PPS
+ $raList[$i]->startBlock = $iSmBlk;
+ $iSmBlk += $iSmbCnt;
+ }
+ }
+ }
+ $iSbCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE);
+ if ($iSmBlk % $iSbCnt) {
+ $iB = $iSbCnt - ($iSmBlk % $iSbCnt);
+ for ($i = 0; $i < $iB; ++$i) {
+ fwrite($FILE, pack('V', -1));
+ }
+ }
+
+ return $sRes;
+ }
+
+ /**
+ * Saves all the PPS's WKs.
+ *
+ * @param array $raList Reference to an array with all PPS's
+ */
+ private function savePps(&$raList): void
+ {
+ // Save each PPS WK
+ $iC = count($raList);
+ for ($i = 0; $i < $iC; ++$i) {
+ fwrite($this->fileHandle, $raList[$i]->getPpsWk());
+ }
+ // Adjust for Block
+ $iCnt = count($raList);
+ $iBCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE;
+ if ($iCnt % $iBCnt) {
+ fwrite($this->fileHandle, str_repeat("\x00", ($iBCnt - ($iCnt % $iBCnt)) * OLE::OLE_PPS_SIZE));
+ }
+ }
+
+ /**
+ * Saving Big Block Depot.
+ *
+ * @param int $iSbdSize
+ * @param int $iBsize
+ * @param int $iPpsCnt
+ */
+ private function saveBbd($iSbdSize, $iBsize, $iPpsCnt): void
+ {
+ $FILE = $this->fileHandle;
+ // Calculate Basic Setting
+ $iBbCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE;
+ $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE;
+
+ $iBdExL = 0;
+ $iAll = $iBsize + $iPpsCnt + $iSbdSize;
+ $iAllW = $iAll;
+ $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
+ $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0);
+ // Calculate BD count
+ if ($iBdCnt > $i1stBdL) {
+ while (1) {
+ ++$iBdExL;
+ ++$iAllW;
+ $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
+ $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0);
+ if ($iBdCnt <= ($iBdExL * $iBbCnt + $i1stBdL)) {
+ break;
+ }
+ }
+ }
+
+ // Making BD
+ // Set for SBD
+ if ($iSbdSize > 0) {
+ for ($i = 0; $i < ($iSbdSize - 1); ++$i) {
+ fwrite($FILE, pack('V', $i + 1));
+ }
+ fwrite($FILE, pack('V', -2));
+ }
+ // Set for B
+ for ($i = 0; $i < ($iBsize - 1); ++$i) {
+ fwrite($FILE, pack('V', $i + $iSbdSize + 1));
+ }
+ fwrite($FILE, pack('V', -2));
+
+ // Set for PPS
+ for ($i = 0; $i < ($iPpsCnt - 1); ++$i) {
+ fwrite($FILE, pack('V', $i + $iSbdSize + $iBsize + 1));
+ }
+ fwrite($FILE, pack('V', -2));
+ // Set for BBD itself ( 0xFFFFFFFD : BBD)
+ for ($i = 0; $i < $iBdCnt; ++$i) {
+ fwrite($FILE, pack('V', 0xFFFFFFFD));
+ }
+ // Set for ExtraBDList
+ for ($i = 0; $i < $iBdExL; ++$i) {
+ fwrite($FILE, pack('V', 0xFFFFFFFC));
+ }
+ // Adjust for Block
+ if (($iAllW + $iBdCnt) % $iBbCnt) {
+ $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
+ for ($i = 0; $i < $iBlock; ++$i) {
+ fwrite($FILE, pack('V', -1));
+ }
+ }
+ // Extra BDList
+ if ($iBdCnt > $i1stBdL) {
+ $iN = 0;
+ $iNb = 0;
+ for ($i = $i1stBdL; $i < $iBdCnt; $i++, ++$iN) {
+ if ($iN >= ($iBbCnt - 1)) {
+ $iN = 0;
+ ++$iNb;
+ fwrite($FILE, pack('V', $iAll + $iBdCnt + $iNb));
+ }
+ fwrite($FILE, pack('V', $iBsize + $iSbdSize + $iPpsCnt + $i));
+ }
+ if (($iBdCnt - $i1stBdL) % ($iBbCnt - 1)) {
+ $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1));
+ for ($i = 0; $i < $iB; ++$i) {
+ fwrite($FILE, pack('V', -1));
+ }
+ }
+ fwrite($FILE, pack('V', -2));
+ }
+ }
+}