summaryrefslogtreecommitdiffstats
path: root/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php566
-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
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLERead.php350
6 files changed, 1839 insertions, 0 deletions
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php
new file mode 100644
index 0000000..1e1fedd
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLE.php
@@ -0,0 +1,566 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared;
+
+// 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\Reader\Exception as ReaderException;
+use PhpOffice\PhpSpreadsheet\Shared\OLE\ChainedBlockStream;
+use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root;
+
+/*
+ * Array for storing OLE instances that are accessed from
+ * OLE_ChainedBlockStream::stream_open().
+ *
+ * @var array
+ */
+$GLOBALS['_OLE_INSTANCES'] = [];
+
+/**
+ * OLE package base class.
+ *
+ * @author Xavier Noguer <xnoguer@php.net>
+ * @author Christian Schmidt <schmidt@php.net>
+ */
+class OLE
+{
+ const OLE_PPS_TYPE_ROOT = 5;
+ const OLE_PPS_TYPE_DIR = 1;
+ const OLE_PPS_TYPE_FILE = 2;
+ const OLE_DATA_SIZE_SMALL = 0x1000;
+ const OLE_LONG_INT_SIZE = 4;
+ const OLE_PPS_SIZE = 0x80;
+
+ /**
+ * The file handle for reading an OLE container.
+ *
+ * @var resource
+ */
+ public $_file_handle;
+
+ /**
+ * Array of PPS's found on the OLE container.
+ *
+ * @var array
+ */
+ public $_list = [];
+
+ /**
+ * Root directory of OLE container.
+ *
+ * @var Root
+ */
+ public $root;
+
+ /**
+ * Big Block Allocation Table.
+ *
+ * @var array (blockId => nextBlockId)
+ */
+ public $bbat;
+
+ /**
+ * Short Block Allocation Table.
+ *
+ * @var array (blockId => nextBlockId)
+ */
+ public $sbat;
+
+ /**
+ * Size of big blocks. This is usually 512.
+ *
+ * @var int number of octets per block
+ */
+ public $bigBlockSize;
+
+ /**
+ * Size of small blocks. This is usually 64.
+ *
+ * @var int number of octets per block
+ */
+ public $smallBlockSize;
+
+ /**
+ * Threshold for big blocks.
+ *
+ * @var int
+ */
+ public $bigBlockThreshold;
+
+ /**
+ * Reads an OLE container from the contents of the file given.
+ *
+ * @acces public
+ *
+ * @param string $file
+ *
+ * @return bool true on success, PEAR_Error on failure
+ */
+ public function read($file)
+ {
+ $fh = fopen($file, 'rb');
+ if (!$fh) {
+ throw new ReaderException("Can't open file $file");
+ }
+ $this->_file_handle = $fh;
+
+ $signature = fread($fh, 8);
+ if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) {
+ throw new ReaderException("File doesn't seem to be an OLE container.");
+ }
+ fseek($fh, 28);
+ if (fread($fh, 2) != "\xFE\xFF") {
+ // This shouldn't be a problem in practice
+ throw new ReaderException('Only Little-Endian encoding is supported.');
+ }
+ // Size of blocks and short blocks in bytes
+ $this->bigBlockSize = 2 ** self::readInt2($fh);
+ $this->smallBlockSize = 2 ** self::readInt2($fh);
+
+ // Skip UID, revision number and version number
+ fseek($fh, 44);
+ // Number of blocks in Big Block Allocation Table
+ $bbatBlockCount = self::readInt4($fh);
+
+ // Root chain 1st block
+ $directoryFirstBlockId = self::readInt4($fh);
+
+ // Skip unused bytes
+ fseek($fh, 56);
+ // Streams shorter than this are stored using small blocks
+ $this->bigBlockThreshold = self::readInt4($fh);
+ // Block id of first sector in Short Block Allocation Table
+ $sbatFirstBlockId = self::readInt4($fh);
+ // Number of blocks in Short Block Allocation Table
+ $sbbatBlockCount = self::readInt4($fh);
+ // Block id of first sector in Master Block Allocation Table
+ $mbatFirstBlockId = self::readInt4($fh);
+ // Number of blocks in Master Block Allocation Table
+ $mbbatBlockCount = self::readInt4($fh);
+ $this->bbat = [];
+
+ // Remaining 4 * 109 bytes of current block is beginning of Master
+ // Block Allocation Table
+ $mbatBlocks = [];
+ for ($i = 0; $i < 109; ++$i) {
+ $mbatBlocks[] = self::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[] = self::readInt4($fh);
+ }
+ // Last block id in each block points to next block
+ $pos = $this->getBlockOffset(self::readInt4($fh));
+ }
+
+ // 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[] = self::readInt4($fh);
+ }
+ }
+
+ // Read short block allocation table (SBAT)
+ $this->sbat = [];
+ $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4;
+ $sbatFh = $this->getStream($sbatFirstBlockId);
+ for ($blockId = 0; $blockId < $shortBlockCount; ++$blockId) {
+ $this->sbat[$blockId] = self::readInt4($sbatFh);
+ }
+ fclose($sbatFh);
+
+ $this->readPpsWks($directoryFirstBlockId);
+
+ return true;
+ }
+
+ /**
+ * @param int $blockId byte offset from beginning of file
+ *
+ * @return int
+ */
+ public function getBlockOffset($blockId)
+ {
+ return 512 + $blockId * $this->bigBlockSize;
+ }
+
+ /**
+ * Returns a stream for use with fread() etc. External callers should
+ * use \PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\File::getStream().
+ *
+ * @param int|OLE\PPS $blockIdOrPps block id or PPS
+ *
+ * @return resource read-only stream
+ */
+ public function getStream($blockIdOrPps)
+ {
+ static $isRegistered = false;
+ if (!$isRegistered) {
+ stream_wrapper_register('ole-chainedblockstream', ChainedBlockStream::class);
+ $isRegistered = true;
+ }
+
+ // Store current instance in global array, so that it can be accessed
+ // in OLE_ChainedBlockStream::stream_open().
+ // Object is removed from self::$instances in OLE_Stream::close().
+ $GLOBALS['_OLE_INSTANCES'][] = $this;
+ $instanceId = end(array_keys($GLOBALS['_OLE_INSTANCES']));
+
+ $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId;
+ if ($blockIdOrPps instanceof OLE\PPS) {
+ $path .= '&blockId=' . $blockIdOrPps->startBlock;
+ $path .= '&size=' . $blockIdOrPps->Size;
+ } else {
+ $path .= '&blockId=' . $blockIdOrPps;
+ }
+
+ return fopen($path, 'rb');
+ }
+
+ /**
+ * Reads a signed char.
+ *
+ * @param resource $fh file handle
+ *
+ * @return int
+ */
+ private static function readInt1($fh)
+ {
+ [, $tmp] = unpack('c', fread($fh, 1));
+
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned short (2 octets).
+ *
+ * @param resource $fh file handle
+ *
+ * @return int
+ */
+ private static function readInt2($fh)
+ {
+ [, $tmp] = unpack('v', fread($fh, 2));
+
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned long (4 octets).
+ *
+ * @param resource $fh file handle
+ *
+ * @return int
+ */
+ private static function readInt4($fh)
+ {
+ [, $tmp] = unpack('V', fread($fh, 4));
+
+ 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.
+ *
+ * @param int $blockId the block id of the first block
+ *
+ * @return bool true on success, PEAR_Error on failure
+ */
+ public function readPpsWks($blockId)
+ {
+ $fh = $this->getStream($blockId);
+ for ($pos = 0; true; $pos += 128) {
+ fseek($fh, $pos, SEEK_SET);
+ $nameUtf16 = fread($fh, 64);
+ $nameLength = self::readInt2($fh);
+ $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2);
+ // Simple conversion from UTF-16LE to ISO-8859-1
+ $name = str_replace("\x00", '', $nameUtf16);
+ $type = self::readInt1($fh);
+ switch ($type) {
+ case self::OLE_PPS_TYPE_ROOT:
+ $pps = new OLE\PPS\Root(null, null, []);
+ $this->root = $pps;
+
+ break;
+ case self::OLE_PPS_TYPE_DIR:
+ $pps = new OLE\PPS(null, null, null, null, null, null, null, null, null, []);
+
+ break;
+ case self::OLE_PPS_TYPE_FILE:
+ $pps = new OLE\PPS\File($name);
+
+ break;
+ default:
+ break;
+ }
+ fseek($fh, 1, SEEK_CUR);
+ $pps->Type = $type;
+ $pps->Name = $name;
+ $pps->PrevPps = self::readInt4($fh);
+ $pps->NextPps = self::readInt4($fh);
+ $pps->DirPps = self::readInt4($fh);
+ fseek($fh, 20, SEEK_CUR);
+ $pps->Time1st = self::OLE2LocalDate(fread($fh, 8));
+ $pps->Time2nd = self::OLE2LocalDate(fread($fh, 8));
+ $pps->startBlock = self::readInt4($fh);
+ $pps->Size = self::readInt4($fh);
+ $pps->No = count($this->_list);
+ $this->_list[] = $pps;
+
+ // check if the PPS tree (starting from root) is complete
+ if (isset($this->root) && $this->ppsTreeComplete($this->root->No)) {
+ break;
+ }
+ }
+ fclose($fh);
+
+ // Initialize $pps->children on directories
+ foreach ($this->_list as $pps) {
+ if ($pps->Type == self::OLE_PPS_TYPE_DIR || $pps->Type == self::OLE_PPS_TYPE_ROOT) {
+ $nos = [$pps->DirPps];
+ $pps->children = [];
+ while ($nos) {
+ $no = array_pop($nos);
+ if ($no != -1) {
+ $childPps = $this->_list[$no];
+ $nos[] = $childPps->PrevPps;
+ $nos[] = $childPps->NextPps;
+ $pps->children[] = $childPps;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * It checks whether the PPS tree is complete (all PPS's read)
+ * starting with the given PPS (not necessarily root).
+ *
+ * @param int $index The index of the PPS from which we are checking
+ *
+ * @return bool Whether the PPS tree for the given PPS is complete
+ */
+ private function ppsTreeComplete($index)
+ {
+ return isset($this->_list[$index]) &&
+ ($pps = $this->_list[$index]) &&
+ ($pps->PrevPps == -1 ||
+ $this->ppsTreeComplete($pps->PrevPps)) &&
+ ($pps->NextPps == -1 ||
+ $this->ppsTreeComplete($pps->NextPps)) &&
+ ($pps->DirPps == -1 ||
+ $this->ppsTreeComplete($pps->DirPps));
+ }
+
+ /**
+ * Checks whether a PPS is a File PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @param int $index The index for the PPS
+ *
+ * @return bool true if it's a File PPS, false otherwise
+ */
+ public function isFile($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Type == self::OLE_PPS_TYPE_FILE;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether a PPS is a Root PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @param int $index the index for the PPS
+ *
+ * @return bool true if it's a Root PPS, false otherwise
+ */
+ public function isRoot($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Type == self::OLE_PPS_TYPE_ROOT;
+ }
+
+ return false;
+ }
+
+ /**
+ * Gives the total number of PPS's found in the OLE container.
+ *
+ * @return int The total number of PPS's found in the OLE container
+ */
+ public function ppsTotal()
+ {
+ return count($this->_list);
+ }
+
+ /**
+ * Gets data from a PPS
+ * If there is no PPS for the index given, it will return an empty string.
+ *
+ * @param int $index The index for the PPS
+ * @param int $position The position from which to start reading
+ * (relative to the PPS)
+ * @param int $length The amount of bytes to read (at most)
+ *
+ * @return string The binary string containing the data requested
+ *
+ * @see OLE_PPS_File::getStream()
+ */
+ public function getData($index, $position, $length)
+ {
+ // if position is not valid return empty string
+ if (!isset($this->_list[$index]) || ($position >= $this->_list[$index]->Size) || ($position < 0)) {
+ return '';
+ }
+ $fh = $this->getStream($this->_list[$index]);
+ $data = stream_get_contents($fh, $length, $position);
+ fclose($fh);
+
+ return $data;
+ }
+
+ /**
+ * Gets the data length from a PPS
+ * If there is no PPS for the index given, it will return 0.
+ *
+ * @param int $index The index for the PPS
+ *
+ * @return int The amount of bytes in data the PPS has
+ */
+ public function getDataLength($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Size;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Utility function to transform ASCII text to Unicode.
+ *
+ * @param string $ascii The ASCII string to transform
+ *
+ * @return string The string in Unicode
+ */
+ public static function ascToUcs($ascii)
+ {
+ $rawname = '';
+ $iMax = strlen($ascii);
+ for ($i = 0; $i < $iMax; ++$i) {
+ $rawname .= $ascii[$i]
+ . "\x00";
+ }
+
+ return $rawname;
+ }
+
+ /**
+ * Utility function
+ * Returns a string for the OLE container with the date given.
+ *
+ * @param int $date A timestamp
+ *
+ * @return string The string for the OLE container
+ */
+ public static function localDateToOLE($date)
+ {
+ if (!isset($date)) {
+ return "\x00\x00\x00\x00\x00\x00\x00\x00";
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = 2 ** 32;
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+ // calculate seconds
+ $big_date = $days * 24 * 3600 + mktime((int) date('H', $date), (int) date('i', $date), (int) date('s', $date), (int) date('m', $date), (int) date('d', $date), (int) date('Y', $date));
+ // multiply just to make MS happy
+ $big_date *= 10000000;
+
+ $high_part = floor($big_date / $factor);
+ // lower 4 bytes
+ $low_part = floor((($big_date / $factor) - $high_part) * $factor);
+
+ // Make HEX string
+ $res = '';
+
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $low_part % 0x100;
+ $res .= pack('c', $hex);
+ $low_part /= 0x100;
+ }
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $high_part % 0x100;
+ $res .= pack('c', $hex);
+ $high_part /= 0x100;
+ }
+
+ return $res;
+ }
+
+ /**
+ * Returns a timestamp from an OLE container's date.
+ *
+ * @param string $oleTimestamp A binary string with the encoded date
+ *
+ * @return int The Unix timestamp corresponding to the string
+ */
+ public static function OLE2LocalDate($oleTimestamp)
+ {
+ if (strlen($oleTimestamp) != 8) {
+ throw new ReaderException('Expecting 8 byte string');
+ }
+
+ // convert to units of 100 ns since 1601:
+ $unpackedTimestamp = unpack('v4', $oleTimestamp);
+ $timestampHigh = (float) $unpackedTimestamp[4] * 65536 + (float) $unpackedTimestamp[3];
+ $timestampLow = (float) $unpackedTimestamp[2] * 65536 + (float) $unpackedTimestamp[1];
+
+ // translate to seconds since 1601:
+ $timestampHigh /= 10000000;
+ $timestampLow /= 10000000;
+
+ // days from 1601 to 1970:
+ $days = 134774;
+
+ // translate to seconds since 1970:
+ $unixTimestamp = floor(65536.0 * 65536.0 * $timestampHigh + $timestampLow - $days * 24 * 3600 + 0.5);
+
+ $iTimestamp = (int) $unixTimestamp;
+
+ // Overflow conditions can't happen on 64-bit system
+ return ($iTimestamp == $unixTimestamp) ? $iTimestamp : ($unixTimestamp >= 0.0 ? PHP_INT_MAX : PHP_INT_MIN);
+ }
+}
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));
+ }
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLERead.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLERead.php
new file mode 100644
index 0000000..16b00bb
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLERead.php
@@ -0,0 +1,350 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Shared;
+
+use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
+
+class OLERead
+{
+ private $data = '';
+
+ // Size of a sector = 512 bytes
+ const BIG_BLOCK_SIZE = 0x200;
+
+ // Size of a short sector = 64 bytes
+ const SMALL_BLOCK_SIZE = 0x40;
+
+ // Size of a directory entry always = 128 bytes
+ const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
+
+ // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
+ const SMALL_BLOCK_THRESHOLD = 0x1000;
+
+ // header offsets
+ const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
+ const ROOT_START_BLOCK_POS = 0x30;
+ const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
+ const EXTENSION_BLOCK_POS = 0x44;
+ const NUM_EXTENSION_BLOCK_POS = 0x48;
+ const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
+
+ // property storage offsets (directory offsets)
+ const SIZE_OF_NAME_POS = 0x40;
+ const TYPE_POS = 0x42;
+ const START_BLOCK_POS = 0x74;
+ const SIZE_POS = 0x78;
+
+ public $wrkbook;
+
+ public $summaryInformation;
+
+ public $documentSummaryInformation;
+
+ /**
+ * @var int
+ */
+ private $numBigBlockDepotBlocks;
+
+ /**
+ * @var int
+ */
+ private $rootStartBlock;
+
+ /**
+ * @var int
+ */
+ private $sbdStartBlock;
+
+ /**
+ * @var int
+ */
+ private $extensionBlock;
+
+ /**
+ * @var int
+ */
+ private $numExtensionBlocks;
+
+ /**
+ * @var string
+ */
+ private $bigBlockChain;
+
+ /**
+ * @var string
+ */
+ private $smallBlockChain;
+
+ /**
+ * @var string
+ */
+ private $entry;
+
+ /**
+ * @var int
+ */
+ private $rootentry;
+
+ /**
+ * @var array
+ */
+ private $props = [];
+
+ /**
+ * Read the file.
+ *
+ * @param $pFilename string Filename
+ */
+ public function read($pFilename): void
+ {
+ File::assertFile($pFilename);
+
+ // Get the file identifier
+ // Don't bother reading the whole file until we know it's a valid OLE file
+ $this->data = file_get_contents($pFilename, false, null, 0, 8);
+
+ // Check OLE identifier
+ $identifierOle = pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1);
+ if ($this->data != $identifierOle) {
+ throw new ReaderException('The filename ' . $pFilename . ' is not recognised as an OLE file');
+ }
+
+ // Get the file data
+ $this->data = file_get_contents($pFilename);
+
+ // Total number of sectors used for the SAT
+ $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
+
+ // SecID of the first sector of the directory stream
+ $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);
+
+ // SecID of the first sector of the SSAT (or -2 if not extant)
+ $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
+
+ // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
+ $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);
+
+ // Total number of sectors used by MSAT
+ $this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
+
+ $bigBlockDepotBlocks = [];
+ $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
+
+ $bbdBlocks = $this->numBigBlockDepotBlocks;
+
+ if ($this->numExtensionBlocks != 0) {
+ $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
+ }
+
+ for ($i = 0; $i < $bbdBlocks; ++$i) {
+ $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+ for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
+ $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
+ $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
+
+ for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
+ $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+ $bbdBlocks += $blocksToRead;
+ if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
+ $this->extensionBlock = self::getInt4d($this->data, $pos);
+ }
+ }
+
+ $pos = 0;
+ $this->bigBlockChain = '';
+ $bbs = self::BIG_BLOCK_SIZE / 4;
+ for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
+ $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
+
+ $this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs);
+ $pos += 4 * $bbs;
+ }
+
+ $pos = 0;
+ $sbdBlock = $this->sbdStartBlock;
+ $this->smallBlockChain = '';
+ while ($sbdBlock != -2) {
+ $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
+
+ $this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
+ $pos += 4 * $bbs;
+
+ $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4);
+ }
+
+ // read the directory stream
+ $block = $this->rootStartBlock;
+ $this->entry = $this->readData($block);
+
+ $this->readPropertySets();
+ }
+
+ /**
+ * Extract binary stream data.
+ *
+ * @param int $stream
+ *
+ * @return string
+ */
+ public function getStream($stream)
+ {
+ if ($stream === null) {
+ return null;
+ }
+
+ $streamData = '';
+
+ if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
+ $rootdata = $this->readData($this->props[$this->rootentry]['startBlock']);
+
+ $block = $this->props[$stream]['startBlock'];
+
+ while ($block != -2) {
+ $pos = $block * self::SMALL_BLOCK_SIZE;
+ $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
+
+ $block = self::getInt4d($this->smallBlockChain, $block * 4);
+ }
+
+ return $streamData;
+ }
+ $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
+ if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
+ ++$numBlocks;
+ }
+
+ if ($numBlocks == 0) {
+ return '';
+ }
+
+ $block = $this->props[$stream]['startBlock'];
+
+ while ($block != -2) {
+ $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+ $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+ $block = self::getInt4d($this->bigBlockChain, $block * 4);
+ }
+
+ return $streamData;
+ }
+
+ /**
+ * Read a standard stream (by joining sectors using information from SAT).
+ *
+ * @param int $bl Sector ID where the stream starts
+ *
+ * @return string Data for standard stream
+ */
+ private function readData($bl)
+ {
+ $block = $bl;
+ $data = '';
+
+ while ($block != -2) {
+ $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+ $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+ $block = self::getInt4d($this->bigBlockChain, $block * 4);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Read entries in the directory stream.
+ */
+ private function readPropertySets(): void
+ {
+ $offset = 0;
+
+ // loop through entires, each entry is 128 bytes
+ $entryLen = strlen($this->entry);
+ while ($offset < $entryLen) {
+ // entry data (128 bytes)
+ $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
+
+ // size in bytes of name
+ $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS + 1]) << 8);
+
+ // type of entry
+ $type = ord($d[self::TYPE_POS]);
+
+ // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
+ // sectorID of first sector of the short-stream container stream, if this entry is root entry
+ $startBlock = self::getInt4d($d, self::START_BLOCK_POS);
+
+ $size = self::getInt4d($d, self::SIZE_POS);
+
+ $name = str_replace("\x00", '', substr($d, 0, $nameSize));
+
+ $this->props[] = [
+ 'name' => $name,
+ 'type' => $type,
+ 'startBlock' => $startBlock,
+ 'size' => $size,
+ ];
+
+ // tmp helper to simplify checks
+ $upName = strtoupper($name);
+
+ // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
+ if (($upName === 'WORKBOOK') || ($upName === 'BOOK')) {
+ $this->wrkbook = count($this->props) - 1;
+ } elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {
+ // Root entry
+ $this->rootentry = count($this->props) - 1;
+ }
+
+ // Summary information
+ if ($name == chr(5) . 'SummaryInformation') {
+ $this->summaryInformation = count($this->props) - 1;
+ }
+
+ // Additional Document Summary information
+ if ($name == chr(5) . 'DocumentSummaryInformation') {
+ $this->documentSummaryInformation = count($this->props) - 1;
+ }
+
+ $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
+ }
+ }
+
+ /**
+ * Read 4 bytes of data at specified position.
+ *
+ * @param string $data
+ * @param int $pos
+ *
+ * @return int
+ */
+ private static function getInt4d($data, $pos)
+ {
+ if ($pos < 0) {
+ // Invalid position
+ throw new ReaderException('Parameter pos=' . $pos . ' is invalid.');
+ }
+
+ $len = strlen($data);
+ if ($len < $pos + 4) {
+ $data .= str_repeat("\0", $pos + 4 - $len);
+ }
+
+ // FIX: represent numbers correctly on 64-bit system
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+ // Changed by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+ $_or_24 = ord($data[$pos + 3]);
+ if ($_or_24 >= 128) {
+ // negative number
+ $_ord_24 = -abs((256 - $_or_24) << 24);
+ } else {
+ $_ord_24 = ($_or_24 & 127) << 24;
+ }
+
+ return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
+ }
+}