Skip to content

Commit

Permalink
Merge pull request #14 from HandsomeMatt/master
Browse files Browse the repository at this point in the history
Add Int64 type, methods ReadInt64() and ReadUInt64() and PHP unit tests.
  • Loading branch information
mdurrant authored Dec 8, 2016
2 parents 23e08d5 + 7e6c078 commit 9abf18d
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Methods

**readInt32()** returns a 32-bit signed integer

**readUInt64()** returns a 64-bit unsigned integer

**readInt64()** returns a 64-bit signed integer

**readSingle()** returns a 4-bytes floating-point

**readUBits($length)** returns a variable length of bits (unsigned)
Expand Down
31 changes: 31 additions & 0 deletions src/BinaryReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpBinaryReader\Type\Int8;
use PhpBinaryReader\Type\Int16;
use PhpBinaryReader\Type\Int32;
use PhpBinaryReader\Type\Int64;
use PhpBinaryReader\Type\Single;
use PhpBinaryReader\Type\Str;

Expand Down Expand Up @@ -78,6 +79,11 @@ class BinaryReader
*/
private $int32Reader;

/**
* @var \PhpBinaryReader\Type\Int64
*/
private $int64Reader;

/**
* @var \PhpBinaryReader\Type\Single
*/
Expand Down Expand Up @@ -109,6 +115,7 @@ public function __construct($input, $endian = Endian::ENDIAN_LITTLE)
$this->int8Reader = new Int8();
$this->int16Reader = new Int16();
$this->int32Reader = new Int32();
$this->int64Reader = new Int64();
$this->singleReader = new Single();
}

Expand Down Expand Up @@ -213,6 +220,22 @@ public function readUInt32()
return $this->int32Reader->read($this);
}

/**
* @return int
*/
public function readInt64()
{
return $this->int64Reader->readSigned($this);
}

/**
* @return int
*/
public function readUInt64()
{
return $this->int64Reader->read($this);
}

/**
* @return float
*/
Expand Down Expand Up @@ -435,6 +458,14 @@ public function getInt32Reader()
return $this->int32Reader;
}

/**
* @return \PhpBinaryReader\Type\Int64
*/
public function getInt64Reader()
{
return $this->int64Reader;
}

/**
* @return \PhpBinaryReader\Type\Single
*/
Expand Down
120 changes: 120 additions & 0 deletions src/Type/Int64.php
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;
}
}
16 changes: 16 additions & 0 deletions test/BinaryReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@ public function testInt32($brBig, $brLittle)
$this->assertEquals(3, $brLittle->readUInt32());
}

/**
* @dataProvider binaryReaders
*/
public function testInt64($brBig, $brLittle)
{
$this->assertEquals(12885059444, $brBig->readInt64());
$this->assertEquals(8387672839590772739, $brLittle->readInt64());

$brLittle->setPosition(0);
$brBig->setPosition(0);

$this->assertEquals(12885059444, $brBig->readUInt64());
$this->assertEquals(8387672839590772739, $brLittle->readUInt64());
}

/**
* @param \PhpBinaryReader\BinaryReader $brBig
* @param \PhpBinaryReader\BinaryReader $brLittle
Expand Down Expand Up @@ -321,6 +336,7 @@ public function testReaders()
$this->assertInstanceOf('\PhpBinaryReader\Type\Byte', $brBig->getByteReader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Int16', $brBig->getInt16Reader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Int32', $brBig->getInt32Reader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Int64', $brBig->getInt64Reader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Int8', $brBig->getInt8Reader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Str', $brBig->getStringReader());
$this->assertInstanceOf('\PhpBinaryReader\Type\Single', $brBig->getSingleReader());
Expand Down
119 changes: 119 additions & 0 deletions test/Type/Int64Test.php
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());
}

}

0 comments on commit 9abf18d

Please sign in to comment.