Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
5a75d84f8f
|
|
@ -4,13 +4,16 @@
|
|||
.Trashes
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
composer.phar
|
||||
.idea
|
||||
_build
|
||||
phpunit.xml
|
||||
composer.lock
|
||||
composer.phar
|
||||
vendor
|
||||
/report
|
||||
/samples/resources
|
||||
/samples/results
|
||||
/.settings
|
||||
phpword.ini
|
||||
/.buildpath
|
||||
/.idea
|
||||
/.project
|
||||
/.settings
|
||||
/build
|
||||
/vendor
|
||||
/phpunit.bat
|
||||
/.project
|
||||
|
|
@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
|
|||
|
||||
## 0.12.0 - Not yet released
|
||||
|
||||
This release added form fields (textinput, checkbox, and dropdown), drawing shapes (arc, curve, line, polyline, rect, oval), and basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) elements along with some new styles.
|
||||
This release added form fields (textinput, checkbox, and dropdown), drawing shapes (arc, curve, line, polyline, rect, oval), and basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) elements along with some new styles. Basic MsDoc reader is introduced.
|
||||
|
||||
### Features
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap
|
|||
- SDT: Ability to add structured document tag elements (comboBox, dropDownList, date) - @ivanlanin
|
||||
- Paragraph: Support for paragraph with borders - @ivanlanin GH-294
|
||||
- Word2007 Writer : Support for RTL - @Progi1984 GH-331
|
||||
- MsDOC Reader: Basic MsDOC Reader - @Progi1984 GH-23 GH-287
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
include_once 'Sample_Header.php';
|
||||
|
||||
// Read contents
|
||||
$name = basename(__FILE__, '.php');
|
||||
$source = "resources/{$name}.doc";
|
||||
echo date('H:i:s'), " Reading contents from `{$source}`", EOL;
|
||||
$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc');
|
||||
|
||||
// (Re)write contents
|
||||
$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf');
|
||||
foreach ($writers as $writer => $extension) {
|
||||
echo date('H:i:s'), " Write to {$writer} format", EOL;
|
||||
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer);
|
||||
$xmlWriter->save("{$name}.{$extension}");
|
||||
rename("{$name}.{$extension}", "results/{$name}.{$extension}");
|
||||
}
|
||||
|
||||
include_once 'Sample_Footer.php';
|
||||
|
|
@ -2,6 +2,9 @@
|
|||
/**
|
||||
* Footer file
|
||||
*/
|
||||
if (CLI) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<script src="bootstrap/js/jquery.min.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
|
||||
/**
|
||||
* Header file
|
||||
*/
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,46 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
* PHPWord
|
||||
*
|
||||
* @link https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2010-2014 PHPWord contributors
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
* @copyright 2014 PHPWord
|
||||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord;
|
||||
|
||||
use PhpOffice\PhpWord\Exception\Exception;
|
||||
use PhpOffice\PhpWord\Writer\WriterInterface;
|
||||
use PhpOffice\PhpWord\Reader\ReaderInterface;
|
||||
|
||||
/**
|
||||
* IO Factory
|
||||
* IO factory
|
||||
*/
|
||||
abstract class IOFactory
|
||||
{
|
||||
/**
|
||||
* Create new writer
|
||||
*
|
||||
* @param \PhpOffice\PhpWord\PhpWord $phpWord
|
||||
* @param PhpWord $phpWord
|
||||
* @param string $name
|
||||
* @return \PhpOffice\PhpWord\Writer\WriterInterface
|
||||
* @return WriterInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
|
||||
{
|
||||
return self::createObject('Writer', $name, $phpWord);
|
||||
if ($name !== 'WriterInterface' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') {
|
||||
throw new Exception("\"{$name}\" is not a valid writer.");
|
||||
}
|
||||
|
||||
$fqName = "PhpOffice\\PhpWord\\Writer\\{$name}";
|
||||
return new $fqName($phpWord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new reader
|
||||
*
|
||||
* @param string $name
|
||||
* @return \PhpOffice\PhpWord\Reader\ReaderInterface
|
||||
* @return ReaderInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createReader($name = 'Word2007')
|
||||
{
|
||||
|
|
@ -65,7 +66,6 @@ abstract class IOFactory
|
|||
throw new Exception("\"{$name}\" is not a valid {$type}.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads PhpWord from file
|
||||
*
|
||||
|
|
@ -77,10 +77,8 @@ abstract class IOFactory
|
|||
{
|
||||
/** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */
|
||||
$reader = self::createReader($readerName);
|
||||
|
||||
return $reader->load($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it's a concrete class (not abstract nor interface)
|
||||
*
|
||||
|
|
@ -90,7 +88,6 @@ abstract class IOFactory
|
|||
private static function isConcreteClass($class)
|
||||
{
|
||||
$reflection = new \ReflectionClass($class);
|
||||
|
||||
return !$reflection->isAbstract() && !$reflection->isInterface();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,115 +1,217 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
* PHPWord
|
||||
*
|
||||
* @link https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2010-2014 PHPWord contributors
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
* @copyright 2014 PHPWord
|
||||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Common drawing functions; Use 'Converter'
|
||||
*
|
||||
* @deprecated 0.12.0
|
||||
* @codeCoverageIgnore
|
||||
* Common drawing functions
|
||||
*/
|
||||
class Drawing
|
||||
{
|
||||
/**
|
||||
* Convert pixels to EMU
|
||||
*
|
||||
* @param integer $value Value in pixels
|
||||
* @param integer $pValue Value in pixels
|
||||
* @return double Value in EMU
|
||||
*/
|
||||
public static function pixelsToEMU($value = 0)
|
||||
public static function pixelsToEMU($pValue = 0)
|
||||
{
|
||||
return Converter::pixelToEmu($value);
|
||||
return round($pValue * 9525);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert EMU to pixels
|
||||
*
|
||||
* @param integer $value Value in EMU
|
||||
* @param integer $pValue Value in EMU
|
||||
* @return integer Value in pixels
|
||||
*/
|
||||
public static function emuToPixels($value = 0)
|
||||
public static function emuToPixels($pValue = 0)
|
||||
{
|
||||
return Converter::emuToPixel($value);
|
||||
if ($pValue != 0) {
|
||||
return round($pValue / 9525);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixels to points
|
||||
*
|
||||
* @param integer $value Value in pixels
|
||||
* @param integer $pValue Value in pixels
|
||||
* @return double Value in points
|
||||
*/
|
||||
public static function pixelsToPoints($value = 0)
|
||||
public static function pixelsToPoints($pValue = 0)
|
||||
{
|
||||
return Converter::pixelToPoint($value);
|
||||
return $pValue * 0.67777777;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert points width to pixels
|
||||
*
|
||||
* @param integer $value Value in points
|
||||
* @param integer $pValue Value in points
|
||||
* @return integer Value in pixels
|
||||
*/
|
||||
public static function pointsToPixels($value = 0)
|
||||
public static function pointsToPixels($pValue = 0)
|
||||
{
|
||||
return Converter::pointToPixel($value);
|
||||
if ($pValue != 0) {
|
||||
return $pValue * 1.333333333;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degrees to angle
|
||||
*
|
||||
* @param integer $value Degrees
|
||||
* @param integer $pValue Degrees
|
||||
* @return integer Angle
|
||||
*/
|
||||
public static function degreesToAngle($value = 0)
|
||||
public static function degreesToAngle($pValue = 0)
|
||||
{
|
||||
return Converter::degreeToAngle($value);
|
||||
return (integer)round($pValue * 60000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert angle to degrees
|
||||
*
|
||||
* @param integer $value Angle
|
||||
* @param integer $pValue Angle
|
||||
* @return integer Degrees
|
||||
*/
|
||||
public static function angleToDegrees($value = 0)
|
||||
public static function angleToDegrees($pValue = 0)
|
||||
{
|
||||
return Converter::angleToDegree($value);
|
||||
if ($pValue != 0) {
|
||||
return round($pValue / 60000);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixels to centimeters
|
||||
*
|
||||
* @param integer $value Value in pixels
|
||||
* @param integer $pValue Value in pixels
|
||||
* @return double Value in centimeters
|
||||
*/
|
||||
public static function pixelsToCentimeters($value = 0)
|
||||
public static function pixelsToCentimeters($pValue = 0)
|
||||
{
|
||||
return Converter::pixelToCm($value);
|
||||
return $pValue * 0.028;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeters width to pixels
|
||||
*
|
||||
* @param integer $value Value in centimeters
|
||||
* @param integer $pValue Value in centimeters
|
||||
* @return integer Value in pixels
|
||||
*/
|
||||
public static function centimetersToPixels($value = 0)
|
||||
public static function centimetersToPixels($pValue = 0)
|
||||
{
|
||||
return Converter::cmToPixel($value);
|
||||
if ($pValue != 0) {
|
||||
return $pValue / 0.028;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert centimeters width to twips
|
||||
*
|
||||
* @param integer $pValue
|
||||
*/
|
||||
public static function centimetersToTwips($pValue = 0)
|
||||
{
|
||||
if ($pValue != 0) {
|
||||
return $pValue * 566.928;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to centimeters
|
||||
*
|
||||
* @param integer $pValue
|
||||
*/
|
||||
public static function twipsToCentimeters($pValue = 0)
|
||||
{
|
||||
if ($pValue != 0) {
|
||||
return $pValue / 566.928;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inches width to twips
|
||||
*
|
||||
* @param integer $pValue
|
||||
*/
|
||||
public static function inchesToTwips($pValue = 0)
|
||||
{
|
||||
if ($pValue != 0) {
|
||||
return $pValue * 1440;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to inches
|
||||
*
|
||||
* @param integer $pValue
|
||||
*/
|
||||
public static function twipsToInches($pValue = 0)
|
||||
{
|
||||
if ($pValue != 0) {
|
||||
return $pValue / 1440;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert twips width to pixels
|
||||
*
|
||||
* @param integer $pValue
|
||||
*/
|
||||
public static function twipsToPixels($pValue = 0)
|
||||
{
|
||||
if ($pValue != 0) {
|
||||
return round($pValue / 15.873984);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML hexadecimal to RGB
|
||||
*
|
||||
* @param string $pValue HTML Color in hexadecimal
|
||||
* @return array Value in RGB
|
||||
*/
|
||||
public static function htmlToRGB($pValue)
|
||||
{
|
||||
if ($pValue[0] == '#') {
|
||||
$pValue = substr($pValue, 1);
|
||||
}
|
||||
|
||||
if (strlen($pValue) == 6) {
|
||||
list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]);
|
||||
} elseif (strlen($pValue) == 3) {
|
||||
list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$colorR = hexdec($colorR);
|
||||
$colorG = hexdec($colorG);
|
||||
$colorB = hexdec($colorB);
|
||||
|
||||
return array($colorR, $colorG, $colorB);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,313 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPWord
|
||||
*
|
||||
* @link https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2014 PHPWord
|
||||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
|
||||
use PhpOffice\PhpWord\Exception\Exception;
|
||||
|
||||
defined('IDENTIFIER_OLE') ||
|
||||
define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
|
||||
|
||||
class OLERead
|
||||
{
|
||||
private $data = '';
|
||||
|
||||
// OLE identifier
|
||||
const IDENTIFIER_OLE = IDENTIFIER_OLE;
|
||||
|
||||
// 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 $wrkdocument = null;
|
||||
public $wrk1Table = null;
|
||||
public $wrkData = null;
|
||||
public $wrkObjectPool = null;
|
||||
public $summaryInformation = null;
|
||||
public $docSummaryInfos = null;
|
||||
|
||||
|
||||
/**
|
||||
* Read the file
|
||||
*
|
||||
* @param $sFileName string Filename
|
||||
* @throws Exception
|
||||
*/
|
||||
public function read($sFileName)
|
||||
{
|
||||
// Check if file exists and is readable
|
||||
if (!is_readable($sFileName)) {
|
||||
throw new Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
|
||||
}
|
||||
|
||||
// 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($sFileName, false, null, 0, 8);
|
||||
|
||||
// Check OLE identifier
|
||||
if ($this->data != self::IDENTIFIER_OLE) {
|
||||
throw new Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
|
||||
}
|
||||
|
||||
// Get the file data
|
||||
$this->data = file_get_contents($sFileName);
|
||||
|
||||
// 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 = array();
|
||||
$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
|
||||
*
|
||||
* @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;
|
||||
} else {
|
||||
$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 $blSectorId Sector ID where the stream starts
|
||||
* @return string Data for standard stream
|
||||
*/
|
||||
private function readData($blSectorId)
|
||||
{
|
||||
$block = $blSectorId;
|
||||
$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()
|
||||
{
|
||||
$offset = 0;
|
||||
|
||||
// loop through entires, each entry is 128 bytes
|
||||
$entryLen = strlen($this->entry);
|
||||
while ($offset < $entryLen) {
|
||||
// entry data (128 bytes)
|
||||
$data = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
|
||||
|
||||
// size in bytes of name
|
||||
$nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS+1]) << 8);
|
||||
|
||||
// type of entry
|
||||
$type = ord($data[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($data, self::START_BLOCK_POS);
|
||||
|
||||
$size = self::getInt4d($data, self::SIZE_POS);
|
||||
|
||||
$name = str_replace("\x00", "", substr($data, 0, $nameSize));
|
||||
|
||||
|
||||
$this->props[] = array (
|
||||
'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)
|
||||
// print_r($upName.PHP_EOL);
|
||||
if (($upName === 'WORDDOCUMENT')) {
|
||||
$this->wrkdocument = count($this->props) - 1;
|
||||
} elseif ($upName === '1TABLE') {
|
||||
$this->wrk1Table = count($this->props) - 1;
|
||||
} elseif ($upName === 'DATA') {
|
||||
$this->wrkData = count($this->props) - 1;
|
||||
} elseif ($upName === 'OBJECTPOOL') {
|
||||
$this->wrkObjectPoolelseif = count($this->props) - 1;
|
||||
} elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {
|
||||
$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->docSummaryInfos = 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)
|
||||
{
|
||||
// FIX: represent numbers correctly on 64-bit system
|
||||
// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
|
||||
// Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
|
||||
$or24 = ord($data[$pos + 3]);
|
||||
if ($or24 >= 128) {
|
||||
// negative number
|
||||
$ord24 = -abs((256 - $or24) << 24);
|
||||
} else {
|
||||
$ord24 = ($or24 & 127) << 24;
|
||||
}
|
||||
return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue