diff --git a/Classes/PHPExcel/Reader/Excel5.php b/Classes/PHPExcel/Reader/Excel5.php
index 8dc8d6c7..601c492d 100644
--- a/Classes/PHPExcel/Reader/Excel5.php
+++ b/Classes/PHPExcel/Reader/Excel5.php
@@ -159,6 +159,13 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
const XLS_Type_PAGELAYOUTVIEW = 0x088b;
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.
@@ -379,6 +386,40 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
*/
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
@@ -531,7 +572,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
case self::XLS_Type_BOOLERR:
case self::XLS_Type_LABEL:
$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
$this->_pos += 4 + $length;
@@ -1051,7 +1092,63 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
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
@@ -1404,7 +1501,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefault()
{
$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
$this->_pos += 4 + $length;
@@ -1419,7 +1516,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
{
// echo 'Read Cell Annotation
';
$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
$this->_pos += 4 + $length;
@@ -1481,7 +1578,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readTextObject()
{
$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
$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
* 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()
{
$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
$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) {
- // offset: 0; size: 2; 16-bit hash value of password
- $password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
- }
- throw new PHPExcel_Reader_Exception('Cannot read encrypted file');
+ // Decryption required from the record after next onwards
+ $this->_encryptionStartPos = $this->_pos + self::_GetInt2d($this->_data, $this->_pos + 2);
}
+ /**
+ * 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
@@ -1594,7 +1825,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readCodepage()
{
$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
$this->_pos += 4 + $length;
@@ -1621,7 +1852,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDateMode()
{
$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
$this->_pos += 4 + $length;
@@ -1640,7 +1871,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFont()
{
$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
$this->_pos += 4 + $length;
@@ -1738,7 +1969,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFormat()
{
$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
$this->_pos += 4 + $length;
@@ -1776,7 +2007,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readXf()
{
$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
$this->_pos += 4 + $length;
@@ -2062,7 +2293,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readXfExt()
{
$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
$this->_pos += 4 + $length;
@@ -2239,7 +2470,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readStyle()
{
$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
$this->_pos += 4 + $length;
@@ -2280,7 +2511,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPalette()
{
$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
$this->_pos += 4 + $length;
@@ -2313,14 +2544,15 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheet()
{
$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
$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
switch (ord($recordData{4})) {
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()
{
$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
$this->_pos += 4 + $length;
@@ -2420,7 +2652,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readExternName()
{
$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
$this->_pos += 4 + $length;
@@ -2455,7 +2687,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readExternSheet()
{
$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
$this->_pos += 4 + $length;
@@ -2492,7 +2724,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefinedName()
{
$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
$this->_pos += 4 + $length;
@@ -2754,7 +2986,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPrintGridlines()
{
$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
$this->_pos += 4 + $length;
@@ -2773,7 +3005,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefaultRowHeight()
{
$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
$this->_pos += 4 + $length;
@@ -2791,7 +3023,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetPr()
{
$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
$this->_pos += 4 + $length;
@@ -2818,7 +3050,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHorizontalPageBreaks()
{
$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
$this->_pos += 4 + $length;
@@ -2847,7 +3079,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readVerticalPageBreaks()
{
$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
$this->_pos += 4 + $length;
@@ -2875,7 +3107,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHeader()
{
$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
$this->_pos += 4 + $length;
@@ -2903,7 +3135,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFooter()
{
$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
$this->_pos += 4 + $length;
@@ -2930,7 +3162,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHcenter()
{
$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
$this->_pos += 4 + $length;
@@ -2950,7 +3182,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readVcenter()
{
$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
$this->_pos += 4 + $length;
@@ -2970,7 +3202,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLeftMargin()
{
$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
$this->_pos += 4 + $length;
@@ -2988,7 +3220,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRightMargin()
{
$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
$this->_pos += 4 + $length;
@@ -3006,7 +3238,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readTopMargin()
{
$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
$this->_pos += 4 + $length;
@@ -3024,7 +3256,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBottomMargin()
{
$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
$this->_pos += 4 + $length;
@@ -3042,7 +3274,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPageSetup()
{
$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
$this->_pos += 4 + $length;
@@ -3100,7 +3332,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readProtect()
{
$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
$this->_pos += 4 + $length;
@@ -3123,7 +3355,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readScenProtect()
{
$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
$this->_pos += 4 + $length;
@@ -3147,7 +3379,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readObjectProtect()
{
$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
$this->_pos += 4 + $length;
@@ -3171,7 +3403,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPassword()
{
$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
$this->_pos += 4 + $length;
@@ -3190,7 +3422,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDefColWidth()
{
$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
$this->_pos += 4 + $length;
@@ -3209,7 +3441,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readColInfo()
{
$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
$this->_pos += 4 + $length;
@@ -3268,7 +3500,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRow()
{
$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
$this->_pos += 4 + $length;
@@ -3338,7 +3570,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRk()
{
$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
$this->_pos += 4 + $length;
@@ -3383,7 +3615,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLabelSst()
{
$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
$this->_pos += 4 + $length;
@@ -3461,7 +3693,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMulRk()
{
$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
$this->_pos += 4 + $length;
@@ -3516,7 +3748,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readNumber()
{
$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
$this->_pos += 4 + $length;
@@ -3558,7 +3790,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readFormula()
{
$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
$this->_pos += 4 + $length;
@@ -3699,7 +3931,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSharedFmla()
{
$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
$this->_pos += 4 + $length;
@@ -3732,7 +3964,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readString()
{
$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
$this->_pos += 4 + $length;
@@ -3760,7 +3992,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBoolErr()
{
$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
$this->_pos += 4 + $length;
@@ -3819,7 +4051,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMulBlank()
{
$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
$this->_pos += 4 + $length;
@@ -3861,7 +4093,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readLabel()
{
$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
$this->_pos += 4 + $length;
@@ -3904,7 +4136,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readBlank()
{
$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
$this->_pos += 4 + $length;
@@ -3951,7 +4183,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readObj()
{
$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
$this->_pos += 4 + $length;
@@ -3996,7 +4228,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readWindow2()
{
$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
$this->_pos += 4 + $length;
@@ -4063,7 +4295,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
*/
private function _readPageLayoutView(){
$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
$this->_pos += 4 + $length;
@@ -4102,7 +4334,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readScl()
{
$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
$this->_pos += 4 + $length;
@@ -4124,7 +4356,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readPane()
{
$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
$this->_pos += 4 + $length;
@@ -4152,7 +4384,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSelection()
{
$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
$this->_pos += 4 + $length;
@@ -4229,7 +4461,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readMergedCells()
{
$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
$this->_pos += 4 + $length;
@@ -4252,7 +4484,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readHyperLink()
{
$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
$this->_pos += 4 + $length;
@@ -4428,7 +4660,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDataValidations()
{
$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
$this->_pos += 4 + $length;
@@ -4441,7 +4673,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readDataValidation()
{
$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
$this->_pos += 4 + $length;
@@ -4601,7 +4833,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetLayout()
{
$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
$this->_pos += 4 + $length;
@@ -4641,7 +4873,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readSheetProtection()
{
$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
$this->_pos += 4 + $length;
@@ -4742,7 +4974,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readRangeProtection()
{
$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
$this->_pos += 4 + $length;
@@ -4886,7 +5118,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
private function _readContinue()
{
$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
// 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);
// offset: 2; size: 2; length
$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;
diff --git a/Classes/PHPExcel/Reader/Excel5/MD5.php b/Classes/PHPExcel/Reader/Excel5/MD5.php
new file mode 100644
index 00000000..62e05156
--- /dev/null
+++ b/Classes/PHPExcel/Reader/Excel5/MD5.php
@@ -0,0 +1,229 @@
+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;
+ }
+}
diff --git a/Classes/PHPExcel/Reader/Excel5/RC4.php b/Classes/PHPExcel/Reader/Excel5/RC4.php
new file mode 100644
index 00000000..492e1b47
--- /dev/null
+++ b/Classes/PHPExcel/Reader/Excel5/RC4.php
@@ -0,0 +1,88 @@
+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;
+ }
+}