diff --git a/README.md b/README.md index dfae616..ac8318c 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ Methods **readSingle()** returns a 4-bytes floating-point +**readDouble()** returns a 8-bytes signed double + **readUBits($length)** returns a variable length of bits (unsigned) **readBits($length)** returns a variable length of bits (signed) diff --git a/src/BinaryReader.php b/src/BinaryReader.php index 8e2d4a0..7c7ac54 100644 --- a/src/BinaryReader.php +++ b/src/BinaryReader.php @@ -5,6 +5,7 @@ use PhpBinaryReader\Exception\InvalidDataException; use PhpBinaryReader\Type\Bit; use PhpBinaryReader\Type\Byte; +use PhpBinaryReader\Type\Double; use PhpBinaryReader\Type\Int8; use PhpBinaryReader\Type\Int16; use PhpBinaryReader\Type\Int32; @@ -89,6 +90,11 @@ class BinaryReader */ private $singleReader; + /** + * @var \PhpBinaryReader\Type\Double + */ + private $doubleReader; + /** * @param string|resource $input * @param int|string $endian @@ -117,6 +123,7 @@ public function __construct($input, $endian = Endian::ENDIAN_LITTLE) $this->int32Reader = new Int32(); $this->int64Reader = new Int64(); $this->singleReader = new Single(); + $this->doubleReader = new Double(); } /** @@ -244,6 +251,11 @@ public function readSingle() return $this->singleReader->read($this); } + public function readDouble() + { + return $this->doubleReader->read($this); + } + /** * @param int $length * @return string @@ -474,6 +486,14 @@ public function getSingleReader() return $this->singleReader; } + /** + * @return \PhpBinaryReader\Type\Double + */ + public function getDoubleReader() + { + return $this->doubleReader; + } + /** * @return \PhpBinaryReader\Type\Str */ diff --git a/src/Type/Double.php b/src/Type/Double.php new file mode 100644 index 0000000..7b2f60f --- /dev/null +++ b/src/Type/Double.php @@ -0,0 +1,53 @@ +canReadBytes(8)) { + throw new \OutOfBoundsException('Cannot read 8-bytes double, it exceeds the boundary of the file'); + } + + $segment = $br->readFromHandle(8); + if ($br->getCurrentBit() !== 0) { + $data = unpack('N', $segment)[1]; + $data = $this->bitReader($br, $data); + $endian = $br->getMachineByteOrder() === $br->getEndian() ? 'N' : 'V'; + $segment = pack($endian, $data); + } elseif ($br->getMachineByteOrder() !== $br->getEndian()) { + $segment = strrev($segment); + } + + $value = unpack('d', $segment)[1]; + return $value; + } + + /** + * @param \PhpBinaryReader\BinaryReader $br + * @param int $data + * + * @return int + */ + private function bitReader(BinaryReader $br, $data) + { + $mask = 0x7FFFFFFFFFFFFFFF >> ($br->getCurrentBit() - 1); + $value = (($data >> (8 - $br->getCurrentBit())) & $mask) | ($br->getNextByte() << (56 + $br->getCurrentBit())); + $br->setNextByte($data & 0xFF); + return $value; + } +} \ No newline at end of file diff --git a/test/BinaryReaderTest.php b/test/BinaryReaderTest.php index cd02d96..fbcb3e4 100644 --- a/test/BinaryReaderTest.php +++ b/test/BinaryReaderTest.php @@ -147,6 +147,24 @@ public function testSingle(BinaryReader $brBig, BinaryReader $brLittle) $this->assertEquals(-1.0, $brLittle->readSingle()); } + /** + * @param \PhpBinaryReader\BinaryReader $brBig + * @param \PhpBinaryReader\BinaryReader $brLittle + * + * @dataProvider binaryReaders + */ + public function testDouble(BinaryReader $brBig, BinaryReader $brLittle) + { + $brBig->setPosition(16); + $brLittle->setPosition(16); + + $this->assertEquals(1.0, $brBig->readDouble()); + $this->assertEquals(1.0, $brLittle->readDouble()); + + $this->assertEquals(-1.0, $brBig->readDouble()); + $this->assertEquals(-1.0, $brLittle->readDouble()); + } + /** * @dataProvider binaryReaders */ @@ -340,5 +358,6 @@ public function testReaders() $this->assertInstanceOf('\PhpBinaryReader\Type\Int8', $brBig->getInt8Reader()); $this->assertInstanceOf('\PhpBinaryReader\Type\Str', $brBig->getStringReader()); $this->assertInstanceOf('\PhpBinaryReader\Type\Single', $brBig->getSingleReader()); + $this->assertInstanceOf('\PhpBinaryReader\Type\Double', $brBig->getDoubleReader()); } }