mirror of
https://github.com/Rogiel/php-mpq
synced 2025-12-06 08:23:05 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fb5f167c4 | |||
|
|
76cb5fb090 | ||
| b01a84d46b | |||
| a8091dfa7d | |||
| 4549549eec | |||
| 5a8edbf7fc | |||
| 7f516c051a | |||
| 2669ee5738 | |||
| aeb01ce902 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,8 @@
|
|||||||
# Created by .ignore support plugin (hsz.mobi)
|
|
||||||
### Composer template
|
### Composer template
|
||||||
composer.phar
|
composer.phar
|
||||||
vendor/
|
vendor/
|
||||||
composer.lock
|
composer.lock
|
||||||
|
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||||
|
.idea/
|
||||||
|
|||||||
25
LICENSE.md
Normal file
25
LICENSE.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# BSD 2-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2020, Rogiel Sulzbach
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@@ -13,6 +13,7 @@ The recommended way of installing this library is using Composer.
|
|||||||
use Rogiel\MPQ\MPQFile;
|
use Rogiel\MPQ\MPQFile;
|
||||||
|
|
||||||
$file = MPQFile::parseFile(__DIR__.'/test.SC2Replay');
|
$file = MPQFile::parseFile(__DIR__.'/test.SC2Replay');
|
||||||
|
$file->parse();
|
||||||
$stream = $file->openStream('replay.details');
|
$stream = $file->openStream('replay.details');
|
||||||
while($data = $stream->readBytes(100)) {
|
while($data = $stream->readBytes(100)) {
|
||||||
echo $data;
|
echo $data;
|
||||||
|
|||||||
@@ -15,7 +15,15 @@
|
|||||||
"Rogiel\\MPQ\\": "src/"
|
"Rogiel\\MPQ\\": "src/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Rogiel\\MPQ\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.4"
|
"php": ">=5.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
phpunit.xml
Normal file
29
phpunit.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnFailure="false"
|
||||||
|
syntaxCheck="false"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
>
|
||||||
|
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="MPQ Test Suite">
|
||||||
|
<directory>./tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="false">
|
||||||
|
<directory suffix=".php">/src</directory>
|
||||||
|
<exclude>
|
||||||
|
<directory suffix=".php">/src/Exception</directory>
|
||||||
|
</exclude>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
</phpunit>
|
||||||
@@ -29,14 +29,30 @@
|
|||||||
namespace Rogiel\MPQ\Compression;
|
namespace Rogiel\MPQ\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\Compression\InvalidInputDataException;
|
||||||
|
|
||||||
class BZIPCompression implements Compression {
|
class BZIPCompression implements Compression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function compress($data, $length) {
|
public function compress($data, $length) {
|
||||||
return bzcompress(substr($data, 0, $length));
|
$output = @bzcompress(substr($data, 0, $length));
|
||||||
|
if(!is_string($output)) {
|
||||||
|
throw new InvalidInputDataException('The compression input data is invalid.', $output);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function decompress($data, $length) {
|
public function decompress($data, $length) {
|
||||||
return bzdecompress(substr($data, 0, $length));
|
$output = @bzdecompress(substr($data, 0, $length));
|
||||||
|
if(!is_string($output)) {
|
||||||
|
throw new InvalidInputDataException('The decompression input data is invalid.', $output);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,9 +29,30 @@
|
|||||||
namespace Rogiel\MPQ\Compression;
|
namespace Rogiel\MPQ\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\Compression\InvalidInputDataException;
|
||||||
|
|
||||||
interface Compression {
|
interface Compression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compresses a block of data
|
||||||
|
*
|
||||||
|
* @param $data string the block of data to be compressed
|
||||||
|
* @param $length integer the length of the block to be compressed
|
||||||
|
* @return string the compressed data
|
||||||
|
*
|
||||||
|
* @throws InvalidInputDataException if the uncompressed data is invalid and cannot be compressed
|
||||||
|
*/
|
||||||
public function compress($data, $length);
|
public function compress($data, $length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompresses a block of data
|
||||||
|
*
|
||||||
|
* @param $data string the block of data to be decompressed
|
||||||
|
* @param $length integer the length of the block to be decompressed
|
||||||
|
* @return string the decompressed data
|
||||||
|
*
|
||||||
|
* @throws InvalidInputDataException if the compressed data is invalid and cannot be decompressed
|
||||||
|
*/
|
||||||
public function decompress($data, $length);
|
public function decompress($data, $length);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,14 +29,30 @@
|
|||||||
namespace Rogiel\MPQ\Compression;
|
namespace Rogiel\MPQ\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\Compression\InvalidInputDataException;
|
||||||
|
|
||||||
class DeflateCompression implements Compression {
|
class DeflateCompression implements Compression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function compress($data, $length) {
|
public function compress($data, $length) {
|
||||||
return gzdeflate(substr($data, 0, $length));
|
$output = @gzdeflate(substr($data, 0, $length));
|
||||||
|
if(!is_string($output)) {
|
||||||
|
throw new InvalidInputDataException('The compression input data is invalid.', $output);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function decompress($data, $length) {
|
public function decompress($data, $length) {
|
||||||
return gzinflate($data, $length);
|
$output = @gzinflate(substr($data, 0, $length), $length);
|
||||||
|
if($output === false) {
|
||||||
|
throw new InvalidInputDataException('The decompression input data is invalid.', $output);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,56 +29,96 @@
|
|||||||
namespace Rogiel\MPQ\Encryption;
|
namespace Rogiel\MPQ\Encryption;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidBlockSizeException;
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidKeyException;
|
||||||
use Rogiel\MPQ\Util\CryptoUtils;
|
use Rogiel\MPQ\Util\CryptoUtils;
|
||||||
|
|
||||||
class DefaultEncryption implements Encryption {
|
class DefaultEncryption implements Encryption {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encryption/decryption key
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $key;
|
private $key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encryption/decryption seed
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $seed;
|
private $seed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DefaultEncryption constructor.
|
||||||
|
* @param $key string the encryption key. The key must have exactly 10 bytes
|
||||||
|
*/
|
||||||
public function __construct($key) {
|
public function __construct($key) {
|
||||||
$this->key = $key;
|
|
||||||
$this->seed = ((0xEEEE << 16) | 0xEEEE);
|
|
||||||
CryptoUtils::initTable();
|
CryptoUtils::initTable();
|
||||||
|
$this->reset($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function reset($key) {
|
public function reset($key) {
|
||||||
|
if(strlen($key) != 10) {
|
||||||
|
throw new InvalidKeyException(sprintf('The key is expected to have 10 bytes, %i given.', strlen($key)));
|
||||||
|
}
|
||||||
|
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
$this->seed = ((0xEEEE << 16) | 0xEEEE);
|
$this->seed = ((0xEEEE << 16) | 0xEEEE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function decrypt($string, $length) {
|
public function decrypt($string, $length) {
|
||||||
|
if($length % 4 != 0) {
|
||||||
|
throw new InvalidBlockSizeException(sprintf('The block size is invalid. Input expected to be a multiple of 4, %s given', $length));
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->createBlockArray($string, $length);
|
$data = $this->createBlockArray($string, $length);
|
||||||
|
|
||||||
$datalen = $length / 4;
|
$blocks = $length / 4;
|
||||||
for($i = 0;$i < $datalen;$i++) {
|
for($block = 0;$block < $blocks; $block++) {
|
||||||
$this->seed = CryptoUtils::uPlus($this->seed,CryptoUtils::$cryptTable[0x400 + ($this->key & 0xFF)]);
|
$this->seed = CryptoUtils::uPlus($this->seed,CryptoUtils::$cryptTable[0x400 + ($this->key & 0xFF)]);
|
||||||
$ch = $data[$i] ^ (CryptoUtils::uPlus($this->key,$this->seed));
|
$ch = $data[$block] ^ (CryptoUtils::uPlus($this->key,$this->seed));
|
||||||
|
|
||||||
$this->key = (CryptoUtils::uPlus(((~$this->key) << 0x15), 0x11111111)) | (CryptoUtils::rShift($this->key,0x0B));
|
$this->key = (CryptoUtils::uPlus(((~$this->key) << 0x15), 0x11111111)) | (CryptoUtils::rShift($this->key,0x0B));
|
||||||
$this->seed = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($ch,$this->seed),($this->seed << 5)),3);
|
$this->seed = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($ch,$this->seed),($this->seed << 5)),3);
|
||||||
$data[$i] = $ch & ((0xFFFF << 16) | 0xFFFF);
|
$data[$block] = $ch & ((0xFFFF << 16) | 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->createDataStream($data, $length / 4);
|
return $this->createDataStream($data, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function encrypt($data, $length) {
|
/**
|
||||||
$key = clone $this->key;
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
$seed = ((0xEEEE << 16) | 0xEEEE);
|
public function encrypt($string, $length) {
|
||||||
$datalen = $length;
|
if($length % 4 != 0) {
|
||||||
for($i = 0;$i < $datalen;$i++) {
|
throw new InvalidBlockSizeException(sprintf('The block size is invalid. Input expected to be a multiple of 4, %s given', $length));
|
||||||
$seed = CryptoUtils::uPlus($seed,CryptoUtils::$cryptTable[0x400 + ($key & 0xFF)]);
|
|
||||||
$ch = $data[$i] ^ (CryptoUtils::uPlus($key,$seed));
|
|
||||||
|
|
||||||
$key = (CryptoUtils::uPlus(((~$key) << 0x15), 0x11111111)) | (CryptoUtils::rShift($key,0x0B));
|
|
||||||
$seed = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($data[$i],$seed),($seed << 5)),3);
|
|
||||||
$data[$i] = $ch & ((0xFFFF << 16) | 0xFFFF);
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->createBlockArray($string, $length);
|
||||||
|
|
||||||
|
$blocks = $length / 4;
|
||||||
|
for($block = 0;$block < $blocks; $block++) {
|
||||||
|
$this->seed = CryptoUtils::uPlus($this->seed,CryptoUtils::$cryptTable[0x400 + ($this->key & 0xFF)]);
|
||||||
|
$ch = $data[$block] ^ (CryptoUtils::uPlus($this->key,$this->seed));
|
||||||
|
|
||||||
|
$this->key = (CryptoUtils::uPlus(((~$this->key) << 0x15), 0x11111111)) | (CryptoUtils::rShift($this->key,0x0B));
|
||||||
|
$this->seed = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($data[$block],$this->seed),($this->seed << 5)),3);
|
||||||
|
$data[$block] = $ch & ((0xFFFF << 16) | 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createDataStream($data, $length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function getBlockSize() {
|
public function getBlockSize() {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,47 @@
|
|||||||
|
|
||||||
namespace Rogiel\MPQ\Encryption;
|
namespace Rogiel\MPQ\Encryption;
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidBlockSizeException;
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidKeyException;
|
||||||
|
|
||||||
interface Encryption {
|
interface Encryption {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the encryption context
|
||||||
|
*
|
||||||
|
* @param $key string the new encryption key
|
||||||
|
*
|
||||||
|
* @throws InvalidKeyException if the given key is invalid
|
||||||
|
*/
|
||||||
public function reset($key);
|
public function reset($key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a block of data
|
||||||
|
*
|
||||||
|
* @param $data string the data block
|
||||||
|
* @param $length integer the data block size
|
||||||
|
* @return string the encrypted block
|
||||||
|
*
|
||||||
|
* @throws InvalidBlockSizeException if the block size is incorrect
|
||||||
|
*/
|
||||||
public function encrypt($data, $length);
|
public function encrypt($data, $length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a block of data
|
||||||
|
*
|
||||||
|
* @param $data string the data block
|
||||||
|
* @param $length integer the data block size
|
||||||
|
* @return string the decrypted block
|
||||||
|
*
|
||||||
|
* @throws InvalidBlockSizeException if the block size is incorrect
|
||||||
|
*/
|
||||||
public function decrypt($data, $length);
|
public function decrypt($data, $length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cipher block size
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
public function getBlockSize();
|
public function getBlockSize();
|
||||||
|
|
||||||
}
|
}
|
||||||
35
src/Exception/Compression/CompressionException.php
Normal file
35
src/Exception/Compression/CompressionException.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Compression;
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\MPQException;
|
||||||
|
|
||||||
|
class CompressionException extends MPQException {
|
||||||
|
|
||||||
|
}
|
||||||
34
src/Exception/Compression/InvalidInputDataException.php
Normal file
34
src/Exception/Compression/InvalidInputDataException.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidInputDataException extends CompressionException {
|
||||||
|
|
||||||
|
}
|
||||||
35
src/Exception/Encryption/EncryptionException.php
Normal file
35
src/Exception/Encryption/EncryptionException.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Encryption;
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\MPQException;
|
||||||
|
|
||||||
|
class EncryptionException extends MPQException {
|
||||||
|
|
||||||
|
}
|
||||||
33
src/Exception/Encryption/InvalidBlockSizeException.php
Normal file
33
src/Exception/Encryption/InvalidBlockSizeException.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Encryption;
|
||||||
|
|
||||||
|
class InvalidBlockSizeException extends EncryptionException {
|
||||||
|
|
||||||
|
}
|
||||||
33
src/Exception/Encryption/InvalidKeyException.php
Normal file
33
src/Exception/Encryption/InvalidKeyException.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Encryption;
|
||||||
|
|
||||||
|
class InvalidKeyException extends EncryptionException {
|
||||||
|
|
||||||
|
}
|
||||||
35
src/Exception/Hashing/HashingException.php
Normal file
35
src/Exception/Hashing/HashingException.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception\Hashing;
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Exception\MPQException;
|
||||||
|
|
||||||
|
class HashingException extends MPQException {
|
||||||
|
|
||||||
|
}
|
||||||
34
src/Exception/MPQException.php
Normal file
34
src/Exception/MPQException.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class MPQException extends \Exception {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,19 +42,18 @@ abstract class BaseHashing implements Hashing {
|
|||||||
|
|
||||||
public function hash($string) {
|
public function hash($string) {
|
||||||
$seed1 = 0x7FED7FED;
|
$seed1 = 0x7FED7FED;
|
||||||
$seed2 = ((0xEEEE << 16) | 0xEEEE);
|
$seed2 = 0xEEEEEEEE;
|
||||||
$strLen = strlen($string);
|
$strLen = strlen($string);
|
||||||
|
|
||||||
for ($i = 0;$i < $strLen;$i++) {
|
for ($i = 0;$i < $strLen;$i++) {
|
||||||
$next = ord(strtoupper(substr($string, $i, 1)));
|
$next = ord(strtoupper(substr($string, $i, 1)));
|
||||||
|
|
||||||
$seed1 = CryptoUtils::$cryptTable[($this->hashType << 8) + $next] ^ (CryptoUtils::uPlus($seed1,$seed2));
|
$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);
|
$seed2 = CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus(CryptoUtils::uPlus($next,$seed1),$seed2),$seed2 << 5),3) & 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
return $seed1;
|
return $seed1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function that adds up two integers without allowing them to overflow to floats
|
// function that adds up two integers without allowing them to overflow to floats
|
||||||
private function uPlus($o1, $o2) {
|
private function uPlus($o1, $o2) {
|
||||||
$o1h = ($o1 >> 16) & 0xFFFF;
|
$o1h = ($o1 >> 16) & 0xFFFF;
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ class MPQFile {
|
|||||||
*/
|
*/
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private $parsed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var UserData
|
* @var UserData
|
||||||
*/
|
*/
|
||||||
@@ -74,36 +79,50 @@ class MPQFile {
|
|||||||
|
|
||||||
public function __construct(Stream $stream) {
|
public function __construct(Stream $stream) {
|
||||||
$this->stream = $stream;
|
$this->stream = $stream;
|
||||||
$this->parse();
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
$this->stream->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private function parse() {
|
public function isParsed() {
|
||||||
|
return $this->parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse() {
|
||||||
|
if($this->isParsed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$parser = new BinaryStreamParser($this->stream);
|
$parser = new BinaryStreamParser($this->stream);
|
||||||
|
|
||||||
$signature = $this->parseSignature($parser);
|
$signature = $this->parseSignature($parser);
|
||||||
if($signature == "MPQ27") {
|
if($signature == "MPQ27") {
|
||||||
$this->userData = UserData::parse($parser);
|
$this->userData = UserData::parse($parser);
|
||||||
$this->stream->seek($this->userData->getHeaderOffset());
|
$this->stream->seek($this->getUserDataOffset());
|
||||||
}
|
|
||||||
|
|
||||||
$signature = $this->parseSignature($parser);
|
$signature = $this->parseSignature($parser);
|
||||||
|
}
|
||||||
|
|
||||||
if($signature == "MPQ26") {
|
if($signature == "MPQ26") {
|
||||||
$this->header = Header::parse($parser);
|
$this->header = Header::parse($parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->hashTable = $this->parseHashTable();
|
$this->hashTable = $this->parseHashTable();
|
||||||
$this->blockTable = $this->parseBlockTable();
|
$this->blockTable = $this->parseBlockTable();
|
||||||
|
|
||||||
|
$this->parsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseHashTable() {
|
private function parseHashTable() {
|
||||||
$hashing = new FileKeyHashing();
|
$hashing = new FileKeyHashing();
|
||||||
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(hash table)')));
|
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(hash table)')));
|
||||||
$parser = new BinaryStreamParser($encryptedStream);
|
$parser = new BinaryStreamParser($encryptedStream);
|
||||||
$parser->seek($this->userData->getHeaderOffset() + $this->header->getHashTablePos());
|
$parser->seek($this->getUserDataOffset() + $this->getHeader()->getHashTablePos());
|
||||||
$hashes = array();
|
$hashes = array();
|
||||||
for($i = 0; $i<$this->header->getHashTableSize(); $i++) {
|
for($i = 0; $i<$this->getHeader()->getHashTableSize(); $i++) {
|
||||||
$hashes[$i] = Hash::parse($parser);
|
$hashes[$i] = Hash::parse($parser);
|
||||||
}
|
}
|
||||||
return new HashTable($hashes);
|
return new HashTable($hashes);
|
||||||
@@ -113,11 +132,17 @@ class MPQFile {
|
|||||||
$hashing = new FileKeyHashing();
|
$hashing = new FileKeyHashing();
|
||||||
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(block table)')));
|
$encryptedStream = new EncryptedStream($this->stream, new DefaultEncryption($hashing->hash('(block table)')));
|
||||||
$parser = new BinaryStreamParser($encryptedStream);
|
$parser = new BinaryStreamParser($encryptedStream);
|
||||||
$parser->seek($this->userData->getHeaderOffset() + $this->header->getBlockTablePos());
|
$parser->seek($this->getUserDataOffset() + $this->getHeader()->getBlockTablePos());
|
||||||
$blocks = array();
|
$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);
|
return new BlockTable($blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +157,16 @@ class MPQFile {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function getUserDataOffset() {
|
||||||
|
$userData = $this->getUserData();
|
||||||
|
if($userData === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return $userData->getHeaderOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $fileName
|
* @param $fileName
|
||||||
* @return null|Hash
|
* @return null|Hash
|
||||||
@@ -143,7 +178,7 @@ class MPQFile {
|
|||||||
$hashA = $hashingA->hash($fileName);
|
$hashA = $hashingA->hash($fileName);
|
||||||
$hashB = $hashingB->hash($fileName);
|
$hashB = $hashingB->hash($fileName);
|
||||||
|
|
||||||
return $this->hashTable->findHashByHash($hashA, $hashB);
|
return $this->getHashTable()->findHashByHash($hashA, $hashB);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,6 +190,7 @@ class MPQFile {
|
|||||||
if($hash == NULL) {
|
if($hash == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getBlockTable()->getBlock($hash->getBlockIndex());
|
return $this->getBlockTable()->getBlock($hash->getBlockIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,15 +201,15 @@ class MPQFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$stream = clone $this->stream;
|
$stream = clone $this->stream;
|
||||||
$stream->seek($this->userData->getHeaderOffset() + $block->getFilePos());
|
$stream->seek($this->getUserDataOffset() + $block->getFilePos());
|
||||||
$parser = new BinaryStreamParser($stream);
|
$parser = new BinaryStreamParser($stream);
|
||||||
|
|
||||||
$sectors = array();
|
$sectors = array();
|
||||||
if($block->isChecksumed() || !$block->isSingleUnit()) {
|
if($block->isChecksumed() || !$block->isSingleUnit()) {
|
||||||
$blockSize = $block->getCompressedSize();
|
$blockSize = 512 * (1 << $this->getHeader()->getBlockSize());
|
||||||
$fileSize = $block->getSize();
|
$fileSize = $block->getSize();
|
||||||
|
|
||||||
for ($i = $fileSize;$i > 0;$i -= $this->header->getBlockSize()) {
|
for ($i = $fileSize; $i > 0; $i -= $blockSize) {
|
||||||
$sectors[] = $parser->readUInt32();
|
$sectors[] = $parser->readUInt32();
|
||||||
$blockSize -= 4;
|
$blockSize -= 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ class Hash {
|
|||||||
$hash->name1 = $parser->readUInt32();
|
$hash->name1 = $parser->readUInt32();
|
||||||
$hash->name2 = $parser->readUInt32();
|
$hash->name2 = $parser->readUInt32();
|
||||||
$hash->locale = $parser->readUInt16();
|
$hash->locale = $parser->readUInt16();
|
||||||
// echo $hash->locale;
|
|
||||||
// die();
|
|
||||||
|
|
||||||
$hash->platform = $parser->readUInt16();
|
$hash->platform = $parser->readUInt16();
|
||||||
$hash->blockIndex = $parser->readUInt32();
|
$hash->blockIndex = $parser->readUInt32();
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,12 @@ namespace Rogiel\MPQ\Stream\Block;
|
|||||||
|
|
||||||
|
|
||||||
use Rogiel\MPQ\Compression\BZIPCompression;
|
use Rogiel\MPQ\Compression\BZIPCompression;
|
||||||
|
use Rogiel\MPQ\Compression\DeflateCompression;
|
||||||
|
use Rogiel\MPQ\Exception\Compression\CompressionException;
|
||||||
use Rogiel\MPQ\Metadata\Block;
|
use Rogiel\MPQ\Metadata\Block;
|
||||||
use Rogiel\MPQ\MPQFile;
|
use Rogiel\MPQ\MPQFile;
|
||||||
use Rogiel\MPQ\Stream\CompressedStream;
|
use Rogiel\MPQ\Stream\CompressedStream;
|
||||||
|
use Rogiel\MPQ\Stream\MemoryStream;
|
||||||
use Rogiel\MPQ\Stream\Parser\BinaryStreamParser;
|
use Rogiel\MPQ\Stream\Parser\BinaryStreamParser;
|
||||||
use Rogiel\MPQ\Stream\Stream;
|
use Rogiel\MPQ\Stream\Stream;
|
||||||
|
|
||||||
@@ -93,6 +96,7 @@ class BlockStream implements Stream {
|
|||||||
$this->position = 0;
|
$this->position = 0;
|
||||||
$this->buffer = NULL;
|
$this->buffer = NULL;
|
||||||
$this->currentSector = $this->sectors[0];
|
$this->currentSector = $this->sectors[0];
|
||||||
|
$this->positionInSector = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
@@ -106,16 +110,21 @@ class BlockStream implements Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function readBytes($bytes) {
|
public function readBytes($bytes) {
|
||||||
if($this->position >= $this->block->getSize()) {
|
if($this->eof()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(($this->position + $bytes) > $this->block->getSize()) {
|
if(($this->position + $bytes) > $this->block->getSize()) {
|
||||||
$bytes = $this->block->getSize() - $this->position;
|
$bytes = $this->block->getSize() - $this->position;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->buffer == NULL) {
|
if($this->buffer === NULL) {
|
||||||
$this->buffer = $this->readSector($this->currentSector);
|
$this->buffer = $this->readSector($this->currentSector);
|
||||||
|
$this->positionInSector = 0;
|
||||||
} else if($this->positionInSector >= strlen($this->buffer)) {
|
} else if($this->positionInSector >= strlen($this->buffer)) {
|
||||||
|
if(!isset($this->sectors[$this->currentSector->getIndex() + 1])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$this->currentSector = $this->sectors[$this->currentSector->getIndex() + 1];
|
$this->currentSector = $this->sectors[$this->currentSector->getIndex() + 1];
|
||||||
$this->buffer = $this->readSector($this->currentSector);
|
$this->buffer = $this->readSector($this->currentSector);
|
||||||
$this->positionInSector = 0;
|
$this->positionInSector = 0;
|
||||||
@@ -146,40 +155,41 @@ class BlockStream implements Stream {
|
|||||||
$this->position += $bytes;
|
$this->position += $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function eof() {
|
||||||
|
return $this->position >= $this->block->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private function readSector(Sector $sector) {
|
private function readSector(Sector $sector) {
|
||||||
$this->stream->seek($this->file->getUserData()->getHeaderOffset()
|
$this->stream->seek($this->file->getUserDataOffset()
|
||||||
+ $this->block->getFilePos()
|
+ $this->block->getFilePos()
|
||||||
+ $sector->getStart());
|
+ $sector->getStart());
|
||||||
|
|
||||||
$compressedStream = $this->createCompressedStream();
|
$compressedStream = $this->createCompressedStream($sector);
|
||||||
return $compressedStream->readBytes($sector->getLength());
|
return $compressedStream->readBytes($this->block->getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createCompressedStream() {
|
private function createCompressedStream(Sector $sector) {
|
||||||
$stream = $this->stream;
|
$stream = $this->stream;
|
||||||
if($this->block->isCompressed()) {
|
|
||||||
|
if($this->block->isCompressed() && $this->block->getSize() > $this->block->getCompressedSize()) {
|
||||||
$parser = new BinaryStreamParser($this->stream);
|
$parser = new BinaryStreamParser($this->stream);
|
||||||
$compressionType = $parser->readByte();
|
$compressionType = $parser->readByte();
|
||||||
switch ($compressionType) {
|
switch ($compressionType) {
|
||||||
case 0x10:
|
case 0x00: return $stream;
|
||||||
return new CompressedStream($stream, new BZIPCompression());
|
case 0x02: {
|
||||||
break;
|
$len = $parser->readUInt16();
|
||||||
|
$blockData = $stream->readBytes($len);
|
||||||
|
return new MemoryStream(gzinflate($blockData));
|
||||||
|
}
|
||||||
|
// 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;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -86,4 +86,11 @@ class CompressedStream implements Stream{
|
|||||||
$this->stream->skip($position);
|
$this->stream->skip($position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function eof() {
|
||||||
|
return $this->stream->eof();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -107,4 +107,11 @@ class EncryptedStream implements Stream{
|
|||||||
$this->bufferPointer = 0xFF;
|
$this->bufferPointer = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function eof() {
|
||||||
|
return $this->stream->eof();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -40,13 +40,21 @@ class FileStream implements Stream {
|
|||||||
$this->handle = fopen($file, 'r');
|
$this->handle = fopen($file, 'r');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __clone() {
|
||||||
|
$this->handle = fopen($this->file, 'r');
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function close() {
|
public function close() {
|
||||||
fclose($this->handle);
|
@fclose($this->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,10 +85,11 @@ class FileStream implements Stream {
|
|||||||
fseek($this->handle, $position, SEEK_CUR);
|
fseek($this->handle, $position, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
public function __clone() {
|
*/
|
||||||
return new FileStream($this->file);
|
public function eof() {
|
||||||
|
return feof($this->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -77,4 +77,11 @@ class MemoryStream implements Stream {
|
|||||||
$this->pointer += $position;
|
$this->pointer += $position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function eof() {
|
||||||
|
return strlen($this->data) >= $this->pointer;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -69,4 +69,19 @@ class BinaryStreamParser {
|
|||||||
return $this->stream->readBytes($size);
|
return $this->stream->readBytes($size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function readCString($debug=false) {
|
||||||
|
$str = '';
|
||||||
|
while(true) {
|
||||||
|
$c = $this->stream->readBytes(1);
|
||||||
|
if($c == "\0") {
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
$str .= (string) $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eof() {
|
||||||
|
return $this->stream->eof();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -64,4 +64,11 @@ interface Stream {
|
|||||||
*/
|
*/
|
||||||
public function skip($bytes);
|
public function skip($bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the stream has already reached the EOF
|
||||||
|
*
|
||||||
|
* @return boolean if the end of file has been reached
|
||||||
|
*/
|
||||||
|
public function eof();
|
||||||
|
|
||||||
}
|
}
|
||||||
42
tests/AbstractTestCase.php
Normal file
42
tests/AbstractTestCase.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Stream\MemoryStream;
|
||||||
|
use Rogiel\MPQ\Stream\Parser\BinaryStreamParser;
|
||||||
|
|
||||||
|
abstract class AbstractTestCase extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
protected function createMemoryParser($string) {
|
||||||
|
$stream = new MemoryStream($string);
|
||||||
|
return new BinaryStreamParser($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
tests/Compression/BZIPCompressionTest.php
Normal file
86
tests/Compression/BZIPCompressionTest.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Compression\BZIPCompression;
|
||||||
|
use Rogiel\MPQ\Exception\Compression\InvalidInputDataException;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class BZIPCompressionTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_COMPRESSED_DATA = "425a6834314159265359065c89da0000009780400000400080060490002000310c082031a916c41d41e2ee48a70a1200cb913b40";
|
||||||
|
const TEST_UNCOMPRESSED_DATA = "Hello World";
|
||||||
|
|
||||||
|
public function testCompress() {
|
||||||
|
$compression = new BZIPCompression();
|
||||||
|
$compressed = $compression->compress(
|
||||||
|
self::TEST_UNCOMPRESSED_DATA, strlen(self::TEST_UNCOMPRESSED_DATA)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_COMPRESSED_DATA), $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecompress() {
|
||||||
|
$compression = new BZIPCompression();
|
||||||
|
$compressed = $compression->decompress(
|
||||||
|
hex2bin(self::TEST_COMPRESSED_DATA), strlen(hex2bin(self::TEST_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(self::TEST_UNCOMPRESSED_DATA, $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_COMPRESSED_DATA = "425a683417724538509000000000";
|
||||||
|
|
||||||
|
public function testEmptyCompress() {
|
||||||
|
$compression = new BZIPCompression();
|
||||||
|
$compressed = $compression->compress("", 0);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_EMPTY_COMPRESSED_DATA), $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmptyDecompress() {
|
||||||
|
$compression = new BZIPCompression();
|
||||||
|
$compressed = $compression->decompress(
|
||||||
|
hex2bin(self::TEST_EMPTY_COMPRESSED_DATA), strlen(hex2bin(self::TEST_EMPTY_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
$this->assertEquals("", $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_INVALID_COMPRESSED_DATA = "425a6417724538509000000000";
|
||||||
|
|
||||||
|
public function testInvalidDecompress() {
|
||||||
|
$this->setExpectedException(InvalidInputDataException::class);
|
||||||
|
$compression = new BZIPCompression();
|
||||||
|
$compression->decompress(
|
||||||
|
hex2bin(self::TEST_INVALID_COMPRESSED_DATA), strlen(hex2bin(self::TEST_INVALID_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
85
tests/Compression/DeflateCompressionTest.php
Normal file
85
tests/Compression/DeflateCompressionTest.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Compression;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Compression\DeflateCompression;
|
||||||
|
use Rogiel\MPQ\Exception\Compression\InvalidInputDataException;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class DeflateCompressionTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_COMPRESSED_DATA = "f348cdc9c95708cf2fca490100";
|
||||||
|
const TEST_UNCOMPRESSED_DATA = "Hello World";
|
||||||
|
|
||||||
|
public function testCompress() {
|
||||||
|
$compression = new DeflateCompression();
|
||||||
|
$compressed = $compression->compress(
|
||||||
|
self::TEST_UNCOMPRESSED_DATA, strlen(self::TEST_UNCOMPRESSED_DATA)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_COMPRESSED_DATA), $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecompress() {
|
||||||
|
$compression = new DeflateCompression();
|
||||||
|
$compressed = $compression->decompress(
|
||||||
|
hex2bin(self::TEST_COMPRESSED_DATA), strlen(hex2bin(self::TEST_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(self::TEST_UNCOMPRESSED_DATA, $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_COMPRESSED_DATA = "0300";
|
||||||
|
|
||||||
|
public function testEmptyCompress() {
|
||||||
|
$compression = new DeflateCompression();
|
||||||
|
$compressed = $compression->compress("", 0);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_EMPTY_COMPRESSED_DATA), $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmptyDecompress() {
|
||||||
|
$compression = new DeflateCompression();
|
||||||
|
$compressed = $compression->decompress(
|
||||||
|
hex2bin(self::TEST_EMPTY_COMPRESSED_DATA), strlen(hex2bin(self::TEST_EMPTY_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
$this->assertEquals("", $compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_INVALID_COMPRESSED_DATA = NULL;
|
||||||
|
|
||||||
|
public function testInvalidDecompress() {
|
||||||
|
$this->setExpectedException(InvalidInputDataException::class);
|
||||||
|
$compression = new DeflateCompression();
|
||||||
|
$compression->decompress(
|
||||||
|
hex2bin(self::TEST_INVALID_COMPRESSED_DATA), strlen(hex2bin(self::TEST_INVALID_COMPRESSED_DATA))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
tests/Encryption/DefaultEncryptionTest.php
Normal file
122
tests/Encryption/DefaultEncryptionTest.php
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Encryption;
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Encryption\DefaultEncryption;
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidBlockSizeException;
|
||||||
|
use Rogiel\MPQ\Exception\Encryption\InvalidKeyException;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class DefaultEncryptionTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_KEY = "c89a7de0c5fea9caf3f0";
|
||||||
|
|
||||||
|
const TEST_SINGLE_BLOCK_PLAIN_TEXT_STRING = "3ef8cc61";
|
||||||
|
const TEST_SINGLE_BLOCK_CIPHER_TEXT_STRING = "b86de569";
|
||||||
|
|
||||||
|
public function testSingleBlockEncrypt() {
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$cipher = $encryption->encrypt(
|
||||||
|
hex2bin(self::TEST_SINGLE_BLOCK_PLAIN_TEXT_STRING), strlen(hex2bin(self::TEST_SINGLE_BLOCK_PLAIN_TEXT_STRING))
|
||||||
|
);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_SINGLE_BLOCK_CIPHER_TEXT_STRING), $cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSingleBlockDencrypt() {
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$plain = $encryption->decrypt(
|
||||||
|
hex2bin(self::TEST_SINGLE_BLOCK_CIPHER_TEXT_STRING), strlen(hex2bin(self::TEST_SINGLE_BLOCK_CIPHER_TEXT_STRING))
|
||||||
|
);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_SINGLE_BLOCK_PLAIN_TEXT_STRING), $plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_MULTIPLE_BLOCKS_PLAIN_TEXT_STRING = "87d1d07454135b170e89045025ed1e8309ee2f14aaaab586d9e81505a8ba72c5";
|
||||||
|
const TEST_MULTIPLE_BLOCKS_CIPHER_TEXT_STRING = "0144f97cc3492b88aed652bb914e8748c58871e1aea753ff04fe731f7cce9a38";
|
||||||
|
|
||||||
|
public function testMultipleBlocksEncrypt() {
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$cipher = $encryption->encrypt(
|
||||||
|
hex2bin(self::TEST_MULTIPLE_BLOCKS_PLAIN_TEXT_STRING), strlen(hex2bin(self::TEST_MULTIPLE_BLOCKS_PLAIN_TEXT_STRING))
|
||||||
|
);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_MULTIPLE_BLOCKS_CIPHER_TEXT_STRING), $cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleBlocksDencrypt() {
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$plain = $encryption->decrypt(
|
||||||
|
hex2bin(self::TEST_MULTIPLE_BLOCKS_CIPHER_TEXT_STRING), strlen(hex2bin(self::TEST_MULTIPLE_BLOCKS_CIPHER_TEXT_STRING))
|
||||||
|
);
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_MULTIPLE_BLOCKS_PLAIN_TEXT_STRING), $plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function testBlocklSize() {
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$this->assertEquals(4, $encryption->getBlockSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const TEST_SMALL_KEY = "c89a7de0c5fea9ca";
|
||||||
|
|
||||||
|
public function testSmallKey() {
|
||||||
|
$this->setExpectedException(InvalidKeyException::class);
|
||||||
|
new DefaultEncryption(hex2bin(self::TEST_SMALL_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_LARGE_KEY = "c89a7de0c5fea9cac89a7de0c5fea9ca";
|
||||||
|
|
||||||
|
public function testLargeKey() {
|
||||||
|
$this->setExpectedException(InvalidKeyException::class);
|
||||||
|
new DefaultEncryption(hex2bin(self::TEST_LARGE_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_INVALID_BLOCK_SIZE_PLAIN_TEXT_STRING = "3ef8cc";
|
||||||
|
const TEST_INVALID_BLOCK_SIZE_CIPHER_TEXT_STRING = "b86de5";
|
||||||
|
|
||||||
|
public function testInvalidBlockSizeEncrypt() {
|
||||||
|
$this->setExpectedException(InvalidBlockSizeException::class);
|
||||||
|
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$plain = $encryption->encrypt(
|
||||||
|
hex2bin(self::TEST_INVALID_BLOCK_SIZE_PLAIN_TEXT_STRING), strlen(hex2bin(self::TEST_INVALID_BLOCK_SIZE_PLAIN_TEXT_STRING))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidBlockSizeDencrypt() {
|
||||||
|
$this->setExpectedException(InvalidBlockSizeException::class);
|
||||||
|
|
||||||
|
$encryption = new DefaultEncryption(hex2bin(self::TEST_KEY));
|
||||||
|
$plain = $encryption->decrypt(
|
||||||
|
hex2bin(self::TEST_INVALID_BLOCK_SIZE_CIPHER_TEXT_STRING), strlen(hex2bin(self::TEST_INVALID_BLOCK_SIZE_CIPHER_TEXT_STRING))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
tests/Hashing/FileKeyHashingTest.php
Normal file
63
tests/Hashing/FileKeyHashingTest.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Hashing;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Hashing\FileKeyHashing;
|
||||||
|
use Rogiel\MPQ\Hashing\Hashing;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class FileKeyHashingTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Hashing
|
||||||
|
*/
|
||||||
|
private $hashing;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->hashing = new FileKeyHashing();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_PLAIN_TEXT = "b99cb06efcddccdf861494b2b431a592";
|
||||||
|
const TEST_HASHED_TEXT = 3812245591;
|
||||||
|
|
||||||
|
public function testHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_PLAIN_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_TEXT, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_TEXT = "";
|
||||||
|
const TEST_HASHED_EMPTY = 2146271213;
|
||||||
|
|
||||||
|
public function testEmptyHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_EMPTY_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_EMPTY, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
tests/Hashing/NameAHashingTest.php
Normal file
63
tests/Hashing/NameAHashingTest.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Hashing;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Hashing\NameAHashing;
|
||||||
|
use Rogiel\MPQ\Hashing\Hashing;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class NameAHashingTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Hashing
|
||||||
|
*/
|
||||||
|
private $hashing;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->hashing = new NameAHashing();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_PLAIN_TEXT = "b99cb06efcddccdf861494b2b431a592";
|
||||||
|
const TEST_HASHED_TEXT = 1258300789;
|
||||||
|
|
||||||
|
public function testHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_PLAIN_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_TEXT, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_TEXT = "";
|
||||||
|
const TEST_HASHED_EMPTY = 2146271213;
|
||||||
|
|
||||||
|
public function testEmptyHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_EMPTY_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_EMPTY, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
tests/Hashing/NameBHashingTest.php
Normal file
63
tests/Hashing/NameBHashingTest.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Hashing;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Hashing\NameBHashing;
|
||||||
|
use Rogiel\MPQ\Hashing\Hashing;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class NameBHashingTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Hashing
|
||||||
|
*/
|
||||||
|
private $hashing;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->hashing = new NameBHashing();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_PLAIN_TEXT = "b99cb06efcddccdf861494b2b431a592";
|
||||||
|
const TEST_HASHED_TEXT = 2342994917;
|
||||||
|
|
||||||
|
public function testHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_PLAIN_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_TEXT, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_TEXT = "";
|
||||||
|
const TEST_HASHED_EMPTY = 2146271213;
|
||||||
|
|
||||||
|
public function testEmptyHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_EMPTY_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_EMPTY, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
tests/Hashing/TableOffsetHashingTest.php
Normal file
63
tests/Hashing/TableOffsetHashingTest.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Hashing;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Hashing\TableOffsetHashing;
|
||||||
|
use Rogiel\MPQ\Hashing\Hashing;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class TableOffsetHashingTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Hashing
|
||||||
|
*/
|
||||||
|
private $hashing;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->hashing = new TableOffsetHashing();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_PLAIN_TEXT = "b99cb06efcddccdf861494b2b431a592";
|
||||||
|
const TEST_HASHED_TEXT = 4211952812;
|
||||||
|
|
||||||
|
public function testHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_PLAIN_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_TEXT, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EMPTY_TEXT = "";
|
||||||
|
const TEST_HASHED_EMPTY = 2146271213;
|
||||||
|
|
||||||
|
public function testEmptyHash() {
|
||||||
|
$hash = $this->hashing->hash(hex2bin(self::TEST_EMPTY_TEXT));
|
||||||
|
$this->assertEquals(self::TEST_HASHED_EMPTY, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
170
tests/Metadata/BlockTest.php
Normal file
170
tests/Metadata/BlockTest.php
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Metadata;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Metadata\Block;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class BlockTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000000"; /* flags */
|
||||||
|
|
||||||
|
public function testParse() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(8208, $block->getFilePos());
|
||||||
|
$this->assertEquals(1048576, $block->getCompressedSize());
|
||||||
|
$this->assertEquals(1048576, $block->getSize());
|
||||||
|
$this->assertEquals(0, $block->getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_IMPLODED_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00010000"; /* flags */
|
||||||
|
|
||||||
|
public function testImplodedFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_IMPLODED_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isImploded());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_COMPRESSED_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00020000"; /* flags */
|
||||||
|
|
||||||
|
public function testCompressedFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_COMPRESSED_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isCompressed());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_ENCRYPTED_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000100"; /* flags */
|
||||||
|
|
||||||
|
public function testEncryptedFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_ENCRYPTED_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isEncrypted());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_FIX_KEY_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000200"; /* flags */
|
||||||
|
|
||||||
|
public function testKeyBasedOnPositionFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_FIX_KEY_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isKeyBasedOnPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_PATCHED_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00001000"; /* flags */
|
||||||
|
|
||||||
|
public function testPatchedFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_PATCHED_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isPatched());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_SINGLE_UNIT_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000001"; /* flags */
|
||||||
|
|
||||||
|
public function testSingleUnitFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_SINGLE_UNIT_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isSingleUnit());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_DELETE_MARKER_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000002"; /* flags */
|
||||||
|
|
||||||
|
public function testDeleteMarkerFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_DELETE_MARKER_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isDeleted());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_CHECKSUMED_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000004"; /* flags */
|
||||||
|
|
||||||
|
public function testChecksumedFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_CHECKSUMED_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isChecksumed());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_EXISTS_BLOCK_DATA =
|
||||||
|
"10200000". /* file position */
|
||||||
|
"00001000". /* compressed size */
|
||||||
|
"00001000". /* size */
|
||||||
|
"00000080"; /* flags */
|
||||||
|
|
||||||
|
public function testExistsFlag() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_EXISTS_BLOCK_DATA));
|
||||||
|
$block = Block::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(true, $block->isExisting());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
tests/Metadata/HashTest.php
Normal file
54
tests/Metadata/HashTest.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Metadata;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Metadata\Hash;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class HashTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_HASH_DATA =
|
||||||
|
"10200000". /* name 1 */
|
||||||
|
"00001000". /* name 2 */
|
||||||
|
"00001000". /* locale/platform */
|
||||||
|
"DEAD0000"; /* block index */
|
||||||
|
|
||||||
|
public function testParse() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_HASH_DATA));
|
||||||
|
$hash = Hash::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(8208, $hash->getName1());
|
||||||
|
$this->assertEquals(1048576, $hash->getName2());
|
||||||
|
$this->assertEquals(0, $hash->getLocale());
|
||||||
|
$this->assertEquals(16, $hash->getPlatform());
|
||||||
|
$this->assertEquals(44510, $hash->getBlockIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
55
tests/Metadata/UserDataTest.php
Normal file
55
tests/Metadata/UserDataTest.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Metadata;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Metadata\UserData;
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class UserDataTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
const TEST_USER_RAW_DATA = "67685b0ba71a3e0c4783877483b6c41cddae8669eb33b9ada05452e362dadd16739e84f2683ff3ff550608dae02ac3d8cd4b0bbcdfa353146f3d9516f327f490d678fbe06b725ced05e405e6476e70ee3bdb217fd02ec1db0a2a374ef6d9d000a66ad6c53e69d1841a95837f5adcf33214b03c277f5c0e49ce2a0623232061573de9352a43eb1f9c9294940e4e98b272e66095a0ceb11c830779f8cc04a2224c1ec2bb510f74f96a2e212eda9156bd1edb7144d37480bd746098f4b25f117b41ffede36645c0413d6880eeb07b60b6915b3d1dfdcfc9cbc10d3ffcd9f0e8f19127210c20d38308e0ebcd672c6741679a772d17893975b4024b640e513aa5bca1ce3c38c180c9eb416e98d93d68fbda47e884ddc4af60c6194ddc3664b05f8d7bd5f4cb0a4ba4aaf213c4c4ddbe978c901bfdc6a8ec0533693b5961dc398a48629b299d9a6e5fc6e33e7d5e41e5b38e80f7c559496d70fb5759a77c0b8a2580976cb7a9578c232b891cc1e14623b37a5274cf3474f7350717522279487483956d3ec9dc73aea5656ba44ca243c913fab9feb5085f41a5ad08d31371d230eb6a6334490263c248c6207e4624dac5ff2777e25686446161024539826f54be01579dbea2877f25165f33b78803915f733bbcda0364f8b1a4ac04ba3556286ca22c946c2aacaf2810fd909b8d4be4fb9133c8b55fb742";
|
||||||
|
|
||||||
|
const TEST_USER_DATA =
|
||||||
|
"00020000". /* size */
|
||||||
|
"00040000". /* header offset */
|
||||||
|
"01000000". /* user data header */
|
||||||
|
self::TEST_USER_RAW_DATA; /* data */
|
||||||
|
|
||||||
|
public function testParse() {
|
||||||
|
$parser = $this->createMemoryParser(hex2bin(self::TEST_USER_DATA));
|
||||||
|
$userData = UserData::parse($parser);
|
||||||
|
|
||||||
|
$this->assertEquals(512, $userData->getSize());
|
||||||
|
$this->assertEquals(1024, $userData->getHeaderOffset());
|
||||||
|
$this->assertEquals(1, $userData->getHeader());
|
||||||
|
$this->assertEquals(hex2bin(self::TEST_USER_RAW_DATA), $userData->getRawContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
82
tests/Stream/Parser/BinaryStreamParserTest.php
Normal file
82
tests/Stream/Parser/BinaryStreamParserTest.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, Rogiel Sulzbach
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Rogiel\MPQ\Tests\Stream\Parser;
|
||||||
|
|
||||||
|
|
||||||
|
use Rogiel\MPQ\Tests\AbstractTestCase;
|
||||||
|
|
||||||
|
class BinaryStreamParserTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
public function testReadByte() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("00FF")
|
||||||
|
);
|
||||||
|
$this->assertEquals(0x00, $parser->readByte());
|
||||||
|
$this->assertEquals(0xFF, $parser->readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReadBytes() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("00FF")
|
||||||
|
);
|
||||||
|
$this->assertEquals(hex2bin("00FF"), $parser->readBytes(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReadUInt32() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("0000BEEF")
|
||||||
|
);
|
||||||
|
$this->assertEquals(4022206464, $parser->readUInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReadUInt16() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("0E0A")
|
||||||
|
);
|
||||||
|
$this->assertEquals(2574, $parser->readUInt16());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSkip() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("DEADBEEF")
|
||||||
|
);
|
||||||
|
$parser->skip(2);
|
||||||
|
$this->assertEquals(0xBE, $parser->readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSeek() {
|
||||||
|
$parser = $this->createMemoryParser(
|
||||||
|
hex2bin("DEADBEEF")
|
||||||
|
);
|
||||||
|
$parser->seek(3);
|
||||||
|
$this->assertEquals(0xEF, $parser->readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user