/** * Initializes the instance. * * @param string $string The raw string containing the data to be read. */ public function __construct($string) { parent::__construct($string); $this->buffer = 0; $this->bufferSize = 0; }
/** * Initializes the instance. * * @param CHM $chm The parent CHM file. * * @throws Exception Throws an Exception in case of errors. */ public function __construct(CHM $chm) { parent::__construct($chm); $controlDataEntry = $chm->getEntryByPath('::DataSpace/Storage/MSCompressed/ControlData'); if ($controlDataEntry === null) { throw new Exception("Missing required entry: '::DataSpace/Storage/MSCompressed/ControlData'"); } if ($controlDataEntry->getContentSectionIndex() !== 0) { throw new Exception("The content of the entry '{$controlDataEntry->getPath()}' should be in section 0, but it's in section {$controlDataEntry->getContentSectionIndex()}"); } $controlDataReader = new StringReader($controlDataEntry->getContents()); $lzxc = new LZXC($controlDataReader); $this->resetInterval = $lzxc->getResetInterval(); $this->windowSize = $lzxc->getWindowSize() * 32768; $this->cachedBlocks = new LRUCache(1 + $lzxc->getCacheSize() << 2); $resetTableEntry = $chm->getEntryByPath('::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable'); if ($resetTableEntry === null) { throw new Exception("Missing required entry: '::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable'"); } if ($resetTableEntry->getContentSectionIndex() !== 0) { throw new Exception("The content of the entry '{$resetTableEntry->getPath()}' should be in section 0, but it's in section {$resetTableEntry->getContentSectionIndex()}"); } $resetTableReader = new StringReader($resetTableEntry->getContents()); $resetTableVersion = $resetTableReader->readUInt32(); if ($resetTableVersion !== 2) { throw new Exception("Unsupported LZX Reset Table version: {$resetTableVersion}"); } $addressTableSize = $resetTableReader->readUInt32(); /* Size of table entry (8) */ $resetTableReader->readUInt32(); /* Header length (40) */ $resetTableReader->readUInt32(); $this->uncompressedLength = $resetTableReader->readUInt64(); $this->compressedLength = $resetTableReader->readUInt64(); $this->blockSize = $resetTableReader->readUInt64(); // We do not support block sizes bigger than 32-bit integers $this->addressTable = array(); for ($i = 0; $i < $addressTableSize; ++$i) { $this->addressTable[$i] = $resetTableReader->readUInt64(); } $contentEntry = $chm->getEntryByPath('::DataSpace/Storage/MSCompressed/Content'); if ($contentEntry === null) { throw new Exception("Missing required entry: '::DataSpace/Storage/MSCompressed/Content"); } if ($this->compressedLength > $contentEntry->getLength()) { throw new Exception("Compressed section size should be {$this->compressedLength}, but it's {$contentEntry->getLength()}"); } $this->sectionOffset = $chm->getITSF()->getContentOffset() + $contentEntry->getOffset(); }
/** * Retrieve the list of the data sections contained in this CHM. * * @throws Exception Throws an Exception in case of errors. */ protected function retrieveSectionList() { $nameList = $this->getEntryByPath('::DataSpace/NameList'); if ($nameList === null) { throw new Exception("Missing required entry: '::DataSpace/NameList'"); } if ($nameList->getContentSectionIndex() !== 0) { throw new Exception("The content of the entry '{$nameList->getPath()}' should be in section 0, but it's in section {$nameList->getContentSection()}"); } $nameListReader = new StringReader($nameList->getContents()); /* Length */ $nameListReader->readUInt16(); $numSections = $nameListReader->readUInt16(); if ($numSections === 0) { throw new Exception('No content section defined.'); } for ($i = 0; $i < $numSections; ++$i) { $nameLength = $nameListReader->readUInt16(); $utf16name = $nameListReader->readString($nameLength * 2); $nameListReader->readUInt16(); $name = iconv('UTF-16LE', 'UTF-8', $utf16name); switch ($name) { case 'Uncompressed': break; case 'MSCompressed': if ($i === 0) { throw new Exception('First data section should be Uncompressed'); } else { $this->sections[$i] = new Section\MSCompressedSection($this); } break; default: throw new Exception("Unknown data section: {$name}"); } } }