mirror of
https://github.com/Rogiel/php-mpq
synced 2025-12-06 08:23:05 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4549549eec | |||
| 5a8edbf7fc | |||
| 7f516c051a |
@@ -42,19 +42,18 @@ abstract class BaseHashing implements Hashing {
|
||||
|
||||
public function hash($string) {
|
||||
$seed1 = 0x7FED7FED;
|
||||
$seed2 = ((0xEEEE << 16) | 0xEEEE);
|
||||
$seed2 = 0xEEEEEEEE;
|
||||
$strLen = strlen($string);
|
||||
|
||||
for ($i = 0;$i < $strLen;$i++) {
|
||||
$next = ord(strtoupper(substr($string, $i, 1)));
|
||||
|
||||
$seed1 = CryptoUtils::$cryptTable[($this->hashType << 8) + $next] ^ (CryptoUtils::uPlus($seed1,$seed2));
|
||||
$seed2 = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($next,$seed1),$seed2),$seed2 << 5),3);
|
||||
$seed1 = CryptoUtils::$cryptTable[($this->hashType << 8) + $next] ^ (CryptoUtils::uPlus($seed1,$seed2)) & 0xFFFFFFFF;
|
||||
$seed2 = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($next,$seed1),$seed2),$seed2 << 5),3) & 0xFFFFFFFF;
|
||||
}
|
||||
return $seed1;
|
||||
}
|
||||
|
||||
|
||||
// function that adds up two integers without allowing them to overflow to floats
|
||||
private function uPlus($o1, $o2) {
|
||||
$o1h = ($o1 >> 16) & 0xFFFF;
|
||||
|
||||
@@ -52,6 +52,11 @@ class MPQFile {
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $parsed;
|
||||
|
||||
/**
|
||||
* @var UserData
|
||||
*/
|
||||
@@ -74,18 +79,25 @@ class MPQFile {
|
||||
|
||||
public function __construct(Stream $stream) {
|
||||
$this->stream = $stream;
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private function parse() {
|
||||
public function isParsed() {
|
||||
return $this->parsed;
|
||||
}
|
||||
|
||||
public function parse() {
|
||||
if($this->isParsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parser = new BinaryStreamParser($this->stream);
|
||||
|
||||
$signature = $this->parseSignature($parser);
|
||||
if($signature == "MPQ27") {
|
||||
$this->userData = UserData::parse($parser);
|
||||
$this->stream->seek($this->userData->getHeaderOffset());
|
||||
$this->stream->seek($this->getUserDataOffset());
|
||||
}
|
||||
|
||||
$signature = $this->parseSignature($parser);
|
||||
@@ -95,15 +107,17 @@ class MPQFile {
|
||||
|
||||
$this->hashTable = $this->parseHashTable();
|
||||
$this->blockTable = $this->parseBlockTable();
|
||||
|
||||
$this->parsed = true;
|
||||
}
|
||||
|
||||
private function parseHashTable() {
|
||||
$hashing = new FileKeyHashing();
|
||||
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(hash table)')));
|
||||
$parser = new BinaryStreamParser($encryptedStream);
|
||||
$parser->seek($this->userData->getHeaderOffset() + $this->header->getHashTablePos());
|
||||
$parser->seek($this->getUserDataOffset() + $this->getHeader()->getHashTablePos());
|
||||
$hashes = array();
|
||||
for($i = 0; $i<$this->header->getHashTableSize(); $i++) {
|
||||
for($i = 0; $i<$this->getHeader()->getHashTableSize(); $i++) {
|
||||
$hashes[$i] = Hash::parse($parser);
|
||||
}
|
||||
return new HashTable($hashes);
|
||||
@@ -113,10 +127,15 @@ class MPQFile {
|
||||
$hashing = new FileKeyHashing();
|
||||
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(block table)')));
|
||||
$parser = new BinaryStreamParser($encryptedStream);
|
||||
$parser->seek($this->userData->getHeaderOffset() + $this->header->getBlockTablePos());
|
||||
$parser->seek($this->getUserDataOffset() + $this->getHeader()->getBlockTablePos());
|
||||
$blocks = array();
|
||||
for($i = 0; $i<$this->header->getBlockTableSize(); $i++) {
|
||||
$blocks[$i] = Block::parse($parser);
|
||||
|
||||
// $offsetFix = 0;
|
||||
for($i = 0; $i<$this->getHeader()->getBlockTableSize(); $i++) {
|
||||
$block = $blocks[$i] = Block::parse($parser);
|
||||
// if($block->getSize() == 0) {
|
||||
// $offsetFix++;
|
||||
// }
|
||||
}
|
||||
return new BlockTable($blocks);
|
||||
}
|
||||
@@ -132,6 +151,16 @@ class MPQFile {
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private function getUserDataOffset() {
|
||||
$userData = $this->getUserData();
|
||||
if($userData === null) {
|
||||
return 0;
|
||||
}
|
||||
return $userData->getHeaderOffset();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param $fileName
|
||||
* @return null|Hash
|
||||
@@ -143,7 +172,7 @@ class MPQFile {
|
||||
$hashA = $hashingA->hash($fileName);
|
||||
$hashB = $hashingB->hash($fileName);
|
||||
|
||||
return $this->hashTable->findHashByHash($hashA, $hashB);
|
||||
return $this->getHashTable()->findHashByHash($hashA, $hashB);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +184,7 @@ class MPQFile {
|
||||
if($hash == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $this->getBlockTable()->getBlock($hash->getBlockIndex());
|
||||
}
|
||||
|
||||
@@ -165,7 +195,7 @@ class MPQFile {
|
||||
}
|
||||
|
||||
$stream = clone $this->stream;
|
||||
$stream->seek($this->userData->getHeaderOffset() + $block->getFilePos());
|
||||
$stream->seek($this->getUserDataOffset() + $block->getFilePos());
|
||||
$parser = new BinaryStreamParser($stream);
|
||||
|
||||
$sectors = array();
|
||||
@@ -173,7 +203,7 @@ class MPQFile {
|
||||
$blockSize = $block->getCompressedSize();
|
||||
$fileSize = $block->getSize();
|
||||
|
||||
for ($i = $fileSize;$i > 0;$i -= $this->header->getBlockSize()) {
|
||||
for ($i = $fileSize; $i > 0; $i -= $blockSize) {
|
||||
$sectors[] = $parser->readUInt32();
|
||||
$blockSize -= 4;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace Rogiel\MPQ\Stream\Block;
|
||||
|
||||
|
||||
use Rogiel\MPQ\Compression\BZIPCompression;
|
||||
use Rogiel\MPQ\Compression\DeflateCompression;
|
||||
use Rogiel\MPQ\Exception\Compression\CompressionException;
|
||||
use Rogiel\MPQ\Metadata\Block;
|
||||
use Rogiel\MPQ\MPQFile;
|
||||
use Rogiel\MPQ\Stream\CompressedStream;
|
||||
@@ -93,6 +95,7 @@ class BlockStream implements Stream {
|
||||
$this->position = 0;
|
||||
$this->buffer = NULL;
|
||||
$this->currentSector = $this->sectors[0];
|
||||
$this->positionInSector = 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
@@ -113,8 +116,9 @@ class BlockStream implements Stream {
|
||||
$bytes = $this->block->getSize() - $this->position;
|
||||
}
|
||||
|
||||
if($this->buffer == NULL) {
|
||||
if($this->buffer === NULL) {
|
||||
$this->buffer = $this->readSector($this->currentSector);
|
||||
$this->positionInSector = 0;
|
||||
} else if($this->positionInSector >= strlen($this->buffer)) {
|
||||
$this->currentSector = $this->sectors[$this->currentSector->getIndex() + 1];
|
||||
$this->buffer = $this->readSector($this->currentSector);
|
||||
@@ -163,27 +167,19 @@ class BlockStream implements Stream {
|
||||
|
||||
private function createCompressedStream() {
|
||||
$stream = $this->stream;
|
||||
if($this->block->isCompressed()) {
|
||||
|
||||
if($this->block->isCompressed() && $this->block->getSize() > $this->block->getCompressedSize()) {
|
||||
$parser = new BinaryStreamParser($this->stream);
|
||||
$compressionType = $parser->readByte();
|
||||
switch ($compressionType) {
|
||||
case 0x10:
|
||||
return new CompressedStream($stream, new BZIPCompression());
|
||||
break;
|
||||
case 0x00: return $stream;
|
||||
case 0x02: return new CompressedStream($stream, new DeflateCompression());
|
||||
case 0x10: return new CompressedStream($stream, new BZIPCompression());
|
||||
default:
|
||||
throw new CompressionException(sprintf('Invalid compression format: %s', $compressionType));
|
||||
}
|
||||
}
|
||||
return $stream;
|
||||
}
|
||||
|
||||
private function computeSectors($start, $length) {
|
||||
$sectors = array();
|
||||
foreach($this->sectors as $sector) {
|
||||
/** @var $sector Sector */
|
||||
if($sector->contains($start, $length)) {
|
||||
$sectors[] = $sector;
|
||||
}
|
||||
}
|
||||
return $sectors;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user