Implement Excel 5 RC4 stream decryption

The decryption functions and objects implemented here are are
based on the source of Spreadsheet-ParseExcel:
http://search.cpan.org/~jmcnamara/Spreadsheet-ParseExcel/
This commit is contained in:
Trevor North 2013-10-29 11:25:36 +00:00
parent f86458630f
commit 233021529c
3 changed files with 622 additions and 73 deletions

View File

@ -159,6 +159,13 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
const XLS_Type_PAGELAYOUTVIEW = 0x088b; const XLS_Type_PAGELAYOUTVIEW = 0x088b;
const XLS_Type_UNKNOWN = 0xffff; const XLS_Type_UNKNOWN = 0xffff;
// Encryption type
const MS_BIFF_CRYPTO_NONE = 0;
const MS_BIFF_CRYPTO_XOR = 1;
const MS_BIFF_CRYPTO_RC4 = 2;
// Size of stream blocks when using RC4 encryption
const REKEY_BLOCK = 0x400;
/** /**
* Summary Information stream data. * Summary Information stream data.
@ -379,6 +386,40 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
*/ */
private $_sharedFormulaParts; private $_sharedFormulaParts;
/**
* The type of encryption in use
*
* @var int
*/
private $_encryption = 0;
/**
* The position in the stream after which contents are encrypted
*
* @var int
*/
private $_encryptionStartPos = false;
/**
* The current RC4 decryption object
*
* @var PHPExcel_Reader_Excel5_RC4
*/
private $_rc4Key = null;
/**
* The position in the stream that the RC4 decryption object was left at
*
* @var int
*/
private $_rc4Pos = 0;
/**
* The current MD5 context state
*
* @var string
*/
private $_md5Ctxt = null;
/** /**
* Create a new PHPExcel_Reader_Excel5 instance * Create a new PHPExcel_Reader_Excel5 instance
@ -531,7 +572,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
case self::XLS_Type_BOOLERR: case self::XLS_Type_BOOLERR:
case self::XLS_Type_LABEL: case self::XLS_Type_LABEL:
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1051,7 +1092,63 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
return $this->_phpExcel; return $this->_phpExcel;
} }
/**
* Read record data from stream, decrypting as required
*
* @param string $data Data stream to read from
* @param int $pos Position to start reading from
* @param int $length Record data length
*
* @return string Record data
*/
private function _readRecordData($data, $pos, $len)
{
$data = substr($data, $pos, $len);
// File not encrypted, or record before encryption start point
if ($this->_encryption == self::MS_BIFF_CRYPTO_NONE || $pos < $this->_encryptionStartPos) {
return $data;
}
$recordData = '';
if ($this->_encryption == self::MS_BIFF_CRYPTO_RC4) {
$oldBlock = floor($this->_rc4Pos / self::REKEY_BLOCK);
$block = floor($pos / self::REKEY_BLOCK);
$endBlock = floor(($pos + $len) / self::REKEY_BLOCK);
// Spin an RC4 decryptor to the right spot. If we have a decryptor sitting
// at a point earlier in the current block, re-use it as we can save some time.
if ($block != $oldBlock || $pos < $this->_rc4Pos || !$this->_rc4Key) {
$this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
$step = $pos % self::REKEY_BLOCK;
} else {
$step = $pos - $this->_rc4Pos;
}
$this->_rc4Key->RC4(str_repeat("\0", $step));
// Decrypt record data (re-keying at the end of every block)
while ($block != $endBlock) {
$step = self::REKEY_BLOCK - ($pos % self::REKEY_BLOCK);
$recordData .= $this->_rc4Key->RC4(substr($data, 0, $step));
$data = substr($data, $step);
$pos += $step;
$len -= $step;
$block++;
$this->_rc4Key = $this->_makeKey($block, $this->_md5Ctxt);
}
$recordData .= $this->_rc4Key->RC4(substr($data, 0, $len));
// Keep track of the position of this decryptor.
// We'll try and re-use it later if we can to speed things up
$this->_rc4Pos = $pos + $len;
} elseif ($this->_encryption == self::MS_BIFF_CRYPTO_XOR) {
throw new PHPExcel_Reader_Exception('XOr encryption not supported');
}
return $recordData;
}
/** /**
* Use OLE reader to extract the relevant data streams from the OLE file * Use OLE reader to extract the relevant data streams from the OLE file
@ -1404,7 +1501,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefault() private function _readDefault()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
// $recordData = substr($this->_data, $this->_pos + 4, $length); // $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1419,7 +1516,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
{ {
// echo '<b>Read Cell Annotation</b><br />'; // echo '<b>Read Cell Annotation</b><br />';
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1481,7 +1578,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readTextObject() private function _readTextObject()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1565,22 +1662,156 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
* *
* -- "OpenOffice.org's Documentation of the Microsoft * -- "OpenOffice.org's Documentation of the Microsoft
* Excel File Format" * Excel File Format"
*
* The decryption functions and objects used from here on in
* are based on the source of Spreadsheet-ParseExcel:
* http://search.cpan.org/~jmcnamara/Spreadsheet-ParseExcel/
*/ */
private function _readFilepass() private function _readFilepass()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length);
if ($length != 54) {
throw new PHPExcel_Reader_Exception('Unexpected file pass record length');
}
$recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
if (!$this->_verifyPassword(
'VelvetSweatshop',
substr($recordData, 6, 16),
substr($recordData, 22, 16),
substr($recordData, 38, 16),
$this->_md5Ctxt
)) {
throw new \Exception('Decryption password incorrect');
}
$this->_encryption = self::MS_BIFF_CRYPTO_RC4;
if (!$this->_readDataOnly) { // Decryption required from the record after next onwards
// offset: 0; size: 2; 16-bit hash value of password $this->_encryptionStartPos = $this->_pos + self::_GetInt2d($this->_data, $this->_pos + 2);
$password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
}
throw new PHPExcel_Reader_Exception('Cannot read encrypted file');
} }
/**
* Make an RC4 decryptor for the given block
*
* @var int $block Block for which to create decrypto
* @var string $valContext MD5 context state
*
* @return PHPExcel_Reader_Excel5_RC4
*/
private function _makeKey($block, $valContext)
{
$pwarray = str_repeat("\0", 64);
for ($i = 0; $i < 5; $i++) {
$pwarray[$i] = $valContext[$i];
}
$pwarray[5] = chr($block & 0xff);
$pwarray[6] = chr(($block >> 8) & 0xff);
$pwarray[7] = chr(($block >> 16) & 0xff);
$pwarray[8] = chr(($block >> 24) & 0xff);
$pwarray[9] = "\x80";
$pwarray[56] = "\x48";
$md5 = new PHPExcel_Reader_Excel5_MD5();
$md5->add($pwarray);
$s = $md5->getContext();
return new PHPExcel_Reader_Excel5_RC4($s);
}
/**
* Verify RC4 file password
*
* @var string $password Password to check
* @var string $docid Document id
* @var string $salt_data Salt data
* @var string $hashedsalt_data Hashed salt data
* @var string &$valContext Set to the MD5 context of the value
*
* @return bool Success
*/
private function _verifyPassword($password, $docid, $salt_data, $hashedsalt_data, &$valContext)
{
$pwarray = str_repeat("\0", 64);
for ($i = 0; $i < strlen($password); $i++) {
$o = ord(substr($password, $i, 1));
$pwarray[2 * $i] = chr($o & 0xff);
$pwarray[2 * $i + 1] = chr(($o >> 8) & 0xff);
}
$pwarray[2 * $i] = chr(0x80);
$pwarray[56] = chr(($i << 4) & 0xff);
$md5 = new PHPExcel_Reader_Excel5_MD5();
$md5->add($pwarray);
$mdContext1 = $md5->getContext();
$offset = 0;
$keyoffset = 0;
$tocopy = 5;
$md5->reset();
while ($offset != 16) {
if ((64 - $offset) < 5) {
$tocopy = 64 - $offset;
}
for ($i = 0; $i <= $tocopy; $i++) {
$pwarray[$offset + $i] = $mdContext1[$keyoffset + $i];
}
$offset += $tocopy;
if ($offset == 64) {
$md5->add($pwarray);
$keyoffset = $tocopy;
$tocopy = 5 - $tocopy;
$offset = 0;
continue;
}
$keyoffset = 0;
$tocopy = 5;
for ($i = 0; $i < 16; $i++) {
$pwarray[$offset + $i] = $docid[$i];
}
$offset += 16;
}
$pwarray[16] = "\x80";
for ($i = 0; $i < 47; $i++) {
$pwarray[17 + $i] = "\0";
}
$pwarray[56] = "\x80";
$pwarray[57] = "\x0a";
$md5->add($pwarray);
$valContext = $md5->getContext();
$key = $this->_makeKey(0, $valContext);
$salt = $key->RC4($salt_data);
$hashedsalt = $key->RC4($hashedsalt_data);
$salt .= "\x80" . str_repeat("\0", 47);
$salt[56] = "\x80";
$md5->reset();
$md5->add($salt);
$mdContext2 = $md5->getContext();
return $mdContext2 == $hashedsalt;
}
/** /**
* CODEPAGE * CODEPAGE
@ -1594,7 +1825,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readCodepage() private function _readCodepage()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1621,7 +1852,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDateMode() private function _readDateMode()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1640,7 +1871,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFont() private function _readFont()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1738,7 +1969,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFormat() private function _readFormat()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -1776,7 +2007,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readXf() private function _readXf()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2062,7 +2293,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readXfExt() private function _readXfExt()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2239,7 +2470,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readStyle() private function _readStyle()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2280,7 +2511,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPalette() private function _readPalette()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2313,14 +2544,15 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheet() private function _readSheet()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// offset: 0; size: 4; absolute stream position of the BOF record of the sheet
// NOTE: not encrypted
$rec_offset = self::_GetInt4d($this->_data, $this->_pos + 4);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
// offset: 0; size: 4; absolute stream position of the BOF record of the sheet
$rec_offset = self::_GetInt4d($recordData, 0);
// offset: 4; size: 1; sheet state // offset: 4; size: 1; sheet state
switch (ord($recordData{4})) { switch (ord($recordData{4})) {
case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break; case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE; break;
@ -2356,7 +2588,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readExternalBook() private function _readExternalBook()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2420,7 +2652,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readExternName() private function _readExternName()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2455,7 +2687,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readExternSheet() private function _readExternSheet()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2492,7 +2724,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefinedName() private function _readDefinedName()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2754,7 +2986,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPrintGridlines() private function _readPrintGridlines()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2773,7 +3005,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefaultRowHeight() private function _readDefaultRowHeight()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2791,7 +3023,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetPr() private function _readSheetPr()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2818,7 +3050,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHorizontalPageBreaks() private function _readHorizontalPageBreaks()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2847,7 +3079,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readVerticalPageBreaks() private function _readVerticalPageBreaks()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2875,7 +3107,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHeader() private function _readHeader()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2903,7 +3135,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFooter() private function _readFooter()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2930,7 +3162,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHcenter() private function _readHcenter()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2950,7 +3182,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readVcenter() private function _readVcenter()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2970,7 +3202,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLeftMargin() private function _readLeftMargin()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -2988,7 +3220,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRightMargin() private function _readRightMargin()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3006,7 +3238,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readTopMargin() private function _readTopMargin()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3024,7 +3256,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBottomMargin() private function _readBottomMargin()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3042,7 +3274,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPageSetup() private function _readPageSetup()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3100,7 +3332,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readProtect() private function _readProtect()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3123,7 +3355,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readScenProtect() private function _readScenProtect()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3147,7 +3379,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readObjectProtect() private function _readObjectProtect()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3171,7 +3403,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPassword() private function _readPassword()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3190,7 +3422,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefColWidth() private function _readDefColWidth()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3209,7 +3441,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readColInfo() private function _readColInfo()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3268,7 +3500,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRow() private function _readRow()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3338,7 +3570,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRk() private function _readRk()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3383,7 +3615,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLabelSst() private function _readLabelSst()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3461,7 +3693,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMulRk() private function _readMulRk()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3516,7 +3748,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readNumber() private function _readNumber()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3558,7 +3790,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFormula() private function _readFormula()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3699,7 +3931,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSharedFmla() private function _readSharedFmla()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3732,7 +3964,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readString() private function _readString()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3760,7 +3992,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBoolErr() private function _readBoolErr()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3819,7 +4051,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMulBlank() private function _readMulBlank()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3861,7 +4093,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLabel() private function _readLabel()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3904,7 +4136,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBlank() private function _readBlank()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3951,7 +4183,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readObj() private function _readObj()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -3996,7 +4228,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readWindow2() private function _readWindow2()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4063,7 +4295,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
*/ */
private function _readPageLayoutView(){ private function _readPageLayoutView(){
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4102,7 +4334,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readScl() private function _readScl()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4124,7 +4356,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPane() private function _readPane()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4152,7 +4384,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSelection() private function _readSelection()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4229,7 +4461,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMergedCells() private function _readMergedCells()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4252,7 +4484,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHyperLink() private function _readHyperLink()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer forward to next record // move stream pointer forward to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4428,7 +4660,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDataValidations() private function _readDataValidations()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer forward to next record // move stream pointer forward to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4441,7 +4673,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDataValidation() private function _readDataValidation()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer forward to next record // move stream pointer forward to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4601,7 +4833,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetLayout() private function _readSheetLayout()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4641,7 +4873,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetProtection() private function _readSheetProtection()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4742,7 +4974,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRangeProtection() private function _readRangeProtection()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// move stream pointer to next record // move stream pointer to next record
$this->_pos += 4 + $length; $this->_pos += 4 + $length;
@ -4886,7 +5118,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readContinue() private function _readContinue()
{ {
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$recordData = substr($this->_data, $this->_pos + 4, $length); $recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);
// check if we are reading drawing data // check if we are reading drawing data
// this is in case a free CONTINUE record occurs in other circumstances we are unaware of // this is in case a free CONTINUE record occurs in other circumstances we are unaware of
@ -4951,7 +5183,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
$identifier = self::_GetInt2d($this->_data, $this->_pos); $identifier = self::_GetInt2d($this->_data, $this->_pos);
// offset: 2; size: 2; length // offset: 2; size: 2; length
$length = self::_GetInt2d($this->_data, $this->_pos + 2); $length = self::_GetInt2d($this->_data, $this->_pos + 2);
$data .= substr($this->_data, $this->_pos + 4, $length); $data .= $this->_readRecordData($this->_data, $this->_pos + 4, $length);
$spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length; $spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;

View File

@ -0,0 +1,229 @@
<?php
/**
* PHPExcel
*
* Copyright (c) 2006 - 2013 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category PHPExcel
* @package PHPExcel_Reader_Excel5
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version ##VERSION##, ##DATE##
*/
/**
* PHPExcel_Reader_Excel5_MD5
*
* @category PHPExcel
* @package PHPExcel_Reader_Excel5
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
*/
class PHPExcel_Reader_Excel5_MD5
{
// Context
private $a;
private $b;
private $c;
private $d;
/**
* MD5 stream constructor
*/
public function __construct()
{
$this->reset();
}
/**
* Reset the MD5 stream context
*/
public function reset()
{
$this->a = 0x67452301;
$this->b = 0xEFCDAB89;
$this->c = 0x98BADCFE;
$this->d = 0x10325476;
}
/**
* Get MD5 stream context
*
* @return string
*/
public function getContext()
{
$s = '';
foreach (array('a', 'b', 'c', 'd') as $i) {
$v = $this->{$i};
$s .= chr($v & 0xff);
$s .= chr(($v >> 8) & 0xff);
$s .= chr(($v >> 16) & 0xff);
$s .= chr(($v >> 24) & 0xff);
}
return $s;
}
/**
* Add data to context
*
* @param string $data Data to add
*/
public function add($data)
{
$words = array_values(unpack('V16', $data));
$A = $this->a;
$B = $this->b;
$C = $this->c;
$D = $this->d;
/* ROUND 1 */
self::FF($A, $B, $C, $D, $words[0], 7, 0xd76aa478);
self::FF($D, $A, $B, $C, $words[1], 12, 0xe8c7b756);
self::FF($C, $D, $A, $B, $words[2], 17, 0x242070db);
self::FF($B, $C, $D, $A, $words[3], 22, 0xc1bdceee);
self::FF($A, $B, $C, $D, $words[4], 7, 0xf57c0faf);
self::FF($D, $A, $B, $C, $words[5], 12, 0x4787c62a);
self::FF($C, $D, $A, $B, $words[6], 17, 0xa8304613);
self::FF($B, $C, $D, $A, $words[7], 22, 0xfd469501);
self::FF($A, $B, $C, $D, $words[8], 7, 0x698098d8);
self::FF($D, $A, $B, $C, $words[9], 12, 0x8b44f7af);
self::FF($C, $D, $A, $B, $words[10], 17, 0xffff5bb1);
self::FF($B, $C, $D, $A, $words[11], 22, 0x895cd7be);
self::FF($A, $B, $C, $D, $words[12], 7, 0x6b901122);
self::FF($D, $A, $B, $C, $words[13], 12, 0xfd987193);
self::FF($C, $D, $A, $B, $words[14], 17, 0xa679438e);
self::FF($B, $C, $D, $A, $words[15], 22, 0x49b40821);
/* ROUND 2 */
self::GG($A, $B, $C, $D, $words[1], 5, 0xf61e2562);
self::GG($D, $A, $B, $C, $words[6], 9, 0xc040b340);
self::GG($C, $D, $A, $B, $words[11], 14, 0x265e5a51);
self::GG($B, $C, $D, $A, $words[0], 20, 0xe9b6c7aa);
self::GG($A, $B, $C, $D, $words[5], 5, 0xd62f105d);
self::GG($D, $A, $B, $C, $words[10], 9, 0x02441453);
self::GG($C, $D, $A, $B, $words[15], 14, 0xd8a1e681);
self::GG($B, $C, $D, $A, $words[4], 20, 0xe7d3fbc8);
self::GG($A, $B, $C, $D, $words[9], 5, 0x21e1cde6);
self::GG($D, $A, $B, $C, $words[14], 9, 0xc33707d6);
self::GG($C, $D, $A, $B, $words[3], 14, 0xf4d50d87);
self::GG($B, $C, $D, $A, $words[8], 20, 0x455a14ed);
self::GG($A, $B, $C, $D, $words[13], 5, 0xa9e3e905);
self::GG($D, $A, $B, $C, $words[2], 9, 0xfcefa3f8);
self::GG($C, $D, $A, $B, $words[7], 14, 0x676f02d9);
self::GG($B, $C, $D, $A, $words[12], 20, 0x8d2a4c8a);
/* ROUND 3 */
self::HH($A, $B, $C, $D, $words[5], 4, 0xfffa3942);
self::HH($D, $A, $B, $C, $words[8], 11, 0x8771f681);
self::HH($C, $D, $A, $B, $words[11], 16, 0x6d9d6122);
self::HH($B, $C, $D, $A, $words[14], 23, 0xfde5380c);
self::HH($A, $B, $C, $D, $words[1], 4, 0xa4beea44);
self::HH($D, $A, $B, $C, $words[4], 11, 0x4bdecfa9);
self::HH($C, $D, $A, $B, $words[7], 16, 0xf6bb4b60);
self::HH($B, $C, $D, $A, $words[10], 23, 0xbebfbc70);
self::HH($A, $B, $C, $D, $words[13], 4, 0x289b7ec6);
self::HH($D, $A, $B, $C, $words[0], 11, 0xeaa127fa);
self::HH($C, $D, $A, $B, $words[3], 16, 0xd4ef3085);
self::HH($B, $C, $D, $A, $words[6], 23, 0x04881d05);
self::HH($A, $B, $C, $D, $words[9], 4, 0xd9d4d039);
self::HH($D, $A, $B, $C, $words[12], 11, 0xe6db99e5);
self::HH($C, $D, $A, $B, $words[15], 16, 0x1fa27cf8);
self::HH($B, $C, $D, $A, $words[2], 23, 0xc4ac5665);
/* ROUND 4 */
self::II($A, $B, $C, $D, $words[0], 6, 0xf4292244);
self::II($D, $A, $B, $C, $words[7], 10, 0x432aff97);
self::II($C, $D, $A, $B, $words[14], 15, 0xab9423a7);
self::II($B, $C, $D, $A, $words[5], 21, 0xfc93a039);
self::II($A, $B, $C, $D, $words[12], 6, 0x655b59c3);
self::II($D, $A, $B, $C, $words[3], 10, 0x8f0ccc92);
self::II($C, $D, $A, $B, $words[10], 15, 0xffeff47d);
self::II($B, $C, $D, $A, $words[1], 21, 0x85845dd1);
self::II($A, $B, $C, $D, $words[8], 6, 0x6fa87e4f);
self::II($D, $A, $B, $C, $words[15], 10, 0xfe2ce6e0);
self::II($C, $D, $A, $B, $words[6], 15, 0xa3014314);
self::II($B, $C, $D, $A, $words[13], 21, 0x4e0811a1);
self::II($A, $B, $C, $D, $words[4], 6, 0xf7537e82);
self::II($D, $A, $B, $C, $words[11], 10, 0xbd3af235);
self::II($C, $D, $A, $B, $words[2], 15, 0x2ad7d2bb);
self::II($B, $C, $D, $A, $words[9], 21, 0xeb86d391);
$this->a = ($this->a + $A) & 0xffffffff;
$this->b = ($this->b + $B) & 0xffffffff;
$this->c = ($this->c + $C) & 0xffffffff;
$this->d = ($this->d + $D) & 0xffffffff;
}
private static function F($X, $Y, $Z)
{
$calc = (($X & $Y) | ((~ $X) & $Z)); // X AND Y OR NOT X AND Z
return $calc;
}
private static function G($X, $Y, $Z)
{
$calc = (($X & $Z) | ($Y & (~ $Z))); // X AND Z OR Y AND NOT Z
return $calc;
}
private static function H($X, $Y, $Z)
{
$calc = ($X ^ $Y ^ $Z); // X XOR Y XOR Z
return $calc;
}
private static function I($X, $Y, $Z)
{
$calc = ($Y ^ ($X | (~ $Z))) ; // Y XOR (X OR NOT Z)
return $calc;
}
private static function FF(&$A, $B, $C, $D, $M, $s, $t)
{
$A = ($A + self::F($B, $C, $D) + $M + $t) & 0xffffffff;
$A = self::rotate($A, $s);
$A = ($B + $A) & 0xffffffff;
}
private static function GG(&$A, $B, $C, $D, $M, $s, $t)
{
$A = ($A + self::G($B, $C, $D) + $M + $t) & 0xffffffff;
$A = self::rotate($A, $s);
$A = ($B + $A) & 0xffffffff;
}
private static function HH(&$A, $B, $C, $D, $M, $s, $t)
{
$A = ($A + self::H($B, $C, $D) + $M + $t) & 0xffffffff;
$A = self::rotate($A, $s);
$A = ($B + $A) & 0xffffffff;
}
private static function II(&$A, $B, $C, $D, $M, $s, $t)
{
$A = ($A + self::I($B, $C, $D) + $M + $t) & 0xffffffff;
$A = self::rotate($A, $s);
$A = ($B + $A) & 0xffffffff;
}
private static function rotate ($decimal, $bits)
{
return (($decimal << $bits) | ($decimal >> (32 - $bits))) & 0xffffffff;
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* PHPExcel
*
* Copyright (c) 2006 - 2013 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category PHPExcel
* @package PHPExcel_Reader_Excel5
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version ##VERSION##, ##DATE##
*/
/**
* PHPExcel_Reader_Excel5_RC4
*
* @category PHPExcel
* @package PHPExcel_Reader_Excel5
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
*/
class PHPExcel_Reader_Excel5_RC4
{
// Context
var $s = array();
var $i = 0;
var $j = 0;
/**
* RC4 stream decryption/encryption constrcutor
*
* @param string $key Encryption key/passphrase
*/
public function __construct($key)
{
$len = strlen($key);
for ($this->i = 0; $this->i < 256; $this->i++) {
$this->s[$this->i] = $this->i;
}
$this->j = 0;
for ($this->i = 0; $this->i < 256; $this->i++) {
$this->j = ($this->j + $this->s[$this->i] + ord($key[$this->i % $len])) % 256;
$t = $this->s[$this->i];
$this->s[$this->i] = $this->s[$this->j];
$this->s[$this->j] = $t;
}
$this->i = $this->j = 0;
}
/**
* Symmetric decryption/encryption function
*
* @param string $data Data to encrypt/decrypt
*
* @return string
*/
public function RC4($data)
{
$len = strlen($data);
for ($c = 0; $c < $len; $c++) {
$this->i = ($this->i + 1) % 256;
$this->j = ($this->j + $this->s[$this->i]) % 256;
$t = $this->s[$this->i];
$this->s[$this->i] = $this->s[$this->j];
$this->s[$this->j] = $t;
$t = ($this->s[$this->i] + $this->s[$this->j]) % 256;
$data[$c] = chr(ord($data[$c]) ^ $this->s[$t]);
}
return $data;
}
}