-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from HandsomeMatt/master
Add Int64 type, methods ReadInt64() and ReadUInt64() and PHP unit tests.
- Loading branch information
Showing
5 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
<?php | ||
|
||
namespace PhpBinaryReader\Type; | ||
|
||
use PhpBinaryReader\BinaryReader; | ||
use PhpBinaryReader\BitMask; | ||
use PhpBinaryReader\Endian; | ||
|
||
class Int64 implements TypeInterface | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
private $endianBig = 'N'; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
private $endianLittle = 'V'; | ||
|
||
/** | ||
* Returns an Unsigned 64-bit Integer | ||
* | ||
* @param \PhpBinaryReader\BinaryReader $br | ||
* @param null $length | ||
* @return int | ||
* @throws \OutOfBoundsException | ||
*/ | ||
public function read(BinaryReader &$br, $length = null) | ||
{ | ||
if (!$br->canReadBytes(8)) { | ||
throw new \OutOfBoundsException('Cannot read 64-bit int, it exceeds the boundary of the file'); | ||
} | ||
|
||
$endian = $br->getEndian() == Endian::ENDIAN_BIG ? $this->endianBig : $this->endianLittle; | ||
$firstSegment = $br->readFromHandle(4); | ||
$secondSegment = $br->readFromHandle(4); | ||
|
||
$firstHalf = unpack($endian, $firstSegment)[1]; | ||
$secondHalf = unpack($endian, $secondSegment)[1]; | ||
|
||
if ($br->getEndian() == Endian::ENDIAN_BIG) { | ||
$value = bcadd($secondHalf, bcmul($firstHalf, "4294967296")); | ||
} else { | ||
$value = bcadd($firstHalf, bcmul($secondHalf, "4294967296")); | ||
} | ||
|
||
if ($br->getCurrentBit() != 0) { | ||
$value = $this->bitReader($br, $value); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
/** | ||
* Returns a Signed 64-Bit Integer | ||
* | ||
* @param \PhpBinaryReader\BinaryReader $br | ||
* @return int | ||
*/ | ||
public function readSigned(&$br) | ||
{ | ||
$value = $this->read($br); | ||
if (bccomp($value, bcpow(2, 63)) >= 0) { | ||
$value = bcsub($value, bcpow(2, 64)); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
/** | ||
* @param \PhpBinaryReader\BinaryReader $br | ||
* @param int $data | ||
* @return int | ||
*/ | ||
private function bitReader(&$br, $data) | ||
{ | ||
$bitmask = new BitMask(); | ||
$loMask = $bitmask->getMask($br->getCurrentBit(), BitMask::MASK_LO); | ||
$hiMask = $bitmask->getMask($br->getCurrentBit(), BitMask::MASK_HI); | ||
$hiBits = ($br->getNextByte() & $hiMask) << 56; | ||
$miBits = ($data & 0xFFFFFFFFFFFFFF00) >> (8 - $br->getCurrentBit()); | ||
$loBits = ($data & $loMask); | ||
$br->setNextByte($data & 0xFF); | ||
|
||
return $hiBits | $miBits | $loBits; | ||
} | ||
|
||
/** | ||
* @param string $endianBig | ||
*/ | ||
public function setEndianBig($endianBig) | ||
{ | ||
$this->endianBig = $endianBig; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getEndianBig() | ||
{ | ||
return $this->endianBig; | ||
} | ||
|
||
/** | ||
* @param string $endianLittle | ||
*/ | ||
public function setEndianLittle($endianLittle) | ||
{ | ||
$this->endianLittle = $endianLittle; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getEndianLittle() | ||
{ | ||
return $this->endianLittle; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
<?php | ||
|
||
namespace PhpBinaryReader\Type; | ||
|
||
use PhpBinaryReader\AbstractTestCase; | ||
use PhpBinaryReader\BinaryReader; | ||
use PhpBinaryReader\Endian; | ||
|
||
/** | ||
* @coversDefaultClass \PhpBinaryReader\Type\Int64 | ||
*/ | ||
class Int64Test extends AbstractTestCase | ||
{ | ||
/** | ||
* @var Int64 | ||
*/ | ||
public $int64; | ||
|
||
public function setUp() | ||
{ | ||
$this->int64 = new Int64(); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testUnsignedReaderWithBigEndian($brBig, $brLittle) | ||
{ | ||
$this->assertEquals(12885059444, $this->int64->read($brBig)); | ||
$this->assertEquals(7310314309530157055, $this->int64->read($brBig)); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testSignedReaderWithBigEndian($brBig, $brLittle) | ||
{ | ||
$brBig->setPosition(12); | ||
$this->assertEquals(-3229614080, $this->int64->readSigned($brBig)); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testReaderWithLittleEndian($brBig, $brLittle) | ||
{ | ||
$this->assertEquals(8387672839590772739, $this->int64->read($brLittle)); | ||
$this->assertEquals(18446744069975864165, $this->int64->read($brLittle)); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testSignedReaderWithLittleEndian($brBig, $brLittle) | ||
{ | ||
$brLittle->setPosition(12); | ||
$this->assertEquals(4575657225703391231, $this->int64->readSigned($brLittle)); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testBitReaderWithBigEndian($brBig, $brLittle) | ||
{ | ||
$brBig->setPosition(6); | ||
$brBig->readBits(4); | ||
$this->assertEquals(504403158265495567, $this->int64->read($brBig)); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testBitReaderWithLittleEndian($brBig, $brLittle) | ||
{ | ||
$brLittle->setPosition(6); | ||
$brLittle->readBits(4); | ||
$this->assertEquals(504403158265495567, $this->int64->read($brLittle)); | ||
} | ||
|
||
/** | ||
* @expectedException \OutOfBoundsException | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testOutOfBoundsExceptionIsThrownWithBigEndian($brBig, $brLittle) | ||
{ | ||
$brBig->readBits(360); | ||
$this->int64->read($brBig); | ||
} | ||
|
||
/** | ||
* @expectedException \OutOfBoundsException | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testOutOfBoundsExceptionIsThrownWithLittleEndian($brBig, $brLittle) | ||
{ | ||
$brLittle->readBits(360); | ||
$this->int64->read($brLittle); | ||
} | ||
|
||
/** | ||
* @dataProvider binaryReaders | ||
*/ | ||
public function testAlternateMachineByteOrderSigned($brBig, $brLittle) | ||
{ | ||
$brLittle->setMachineByteOrder(Endian::ENDIAN_BIG); | ||
$brLittle->setEndian(Endian::ENDIAN_LITTLE); | ||
$this->assertEquals(8387672839590772739, $this->int64->readSigned($brLittle)); | ||
} | ||
|
||
public function testEndian() | ||
{ | ||
$this->int64->setEndianBig('X'); | ||
$this->assertEquals('X', $this->int64->getEndianBig()); | ||
|
||
$this->int64->setEndianLittle('Y'); | ||
$this->assertEquals('Y', $this->int64->getEndianLittle()); | ||
} | ||
|
||
} |