Skip to content

Commit

Permalink
Merge pull request #6 from jwpage/use_resources
Browse files Browse the repository at this point in the history
Use file resources for BinaryReader
  • Loading branch information
mdurrant committed Aug 22, 2014
2 parents 6a55be9 + c6fa791 commit a40e04c
Show file tree
Hide file tree
Showing 16 changed files with 594 additions and 467 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ You probably wouldn't be here if you hadn't run into a scenario where you needed
binary data. The honest truth is PHP really stinks at this stuff, but as long as we're going to be using it we may as
well do our best to make it as painless as possible.

The purpose of this binary reader is to accept a string of file contents and provide a set of methods inspired by .NET
to traverse it.
The purpose of this binary reader is to accept a string of file contents or file resource and provide a set of methods
inspired by .NET to traverse it.

Note on Endians
---
The reader is designed to work on little endian machines, which is going to apply to most scenarios as all x86 and x86-64
machines are little endian. If you have somehow found yourself on a big endian machine, you need to inform the class or
you may not be able to properly read signed integers in the file you're parsing.
```
```php
$fileData = file_get_contents('somefile.bin');
$br = new BinaryReader($fileData);
$br->setMachineByteOrder(Endian::ENDIAN_BIG);
Expand All @@ -27,9 +27,14 @@ $br->setMachineByteOrder(Endian::ENDIAN_BIG);

Example Usage
---
```

```php
$fileData = file_get_contents('somefile.bin');
$br = new BinaryReader($fileData, Endian::ENDIAN_LITTLE);
// or
$fileResource = fopen('somefile.bin', 'rb');
$br = new BinaryReader($fileResource, Endian::ENDIAN_LITTLE);

$magic = $br->readUInt32();
$offset = $br->readUInt16();
$length = $br->readUInt16();
Expand All @@ -38,7 +43,7 @@ $length = $br->readUInt16();

Methods
---
**__construct($str, $endian)** a string must be provided to use this class, an endian is optional (string [big|little], or use the constants in the Endian class), it will default to little if not provided.
**__construct($input, $endian)** a string or file resource must be provided to use this class, an endian is optional (string [big|little], or use the constants in the Endian class), it will default to little if not provided.

**readUInt8()** returns a single 8 bit byte as an unsigned integer

Expand Down
50 changes: 41 additions & 9 deletions src/BinaryReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class BinaryReader
private $machineByteOrder = Endian::ENDIAN_LITTLE;

/**
* @var string
* @var resource
*/
private $inputString;
private $inputHandle;

/**
* @var int
Expand Down Expand Up @@ -78,16 +78,21 @@ class BinaryReader
private $int32Reader;

/**
* @param string $str
* @param string|resource $input
* @param int|string $endian
* @throws \InvalidArgumentException
*/
public function __construct($str, $endian = Endian::ENDIAN_LITTLE)
public function __construct($input, $endian = Endian::ENDIAN_LITTLE)
{
$this->eofPosition = strlen($str);
if (!is_resource($input)) {
$this->setInputString($input);
} else {
$this->setInputHandle($input);
}

$this->eofPosition = fstat($this->getInputHandle())['size'];

$this->setEndian($endian);
$this->setInputString($str);
$this->setNextByte(false);
$this->setCurrentBit(0);
$this->setPosition(0);
Expand Down Expand Up @@ -227,12 +232,34 @@ public function getMachineByteOrder()
}

/**
* @param string $inputString
* @param resource $inputHandle
* @return $this
*/
public function setInputHandle($inputHandle)
{
$this->inputHandle = $inputHandle;

return $this;
}

/**
* @return resource
*/
public function getInputHandle()
{
return $this->inputHandle;
}

/**
* @param string $inputString
* @return $this
*/
public function setInputString($inputString)
{
$this->inputString = $inputString;
$handle = fopen('php://memory', 'br+');
fwrite($handle, $inputString);
rewind($handle);
$this->inputHandle = $handle;

return $this;
}
Expand All @@ -242,7 +269,11 @@ public function setInputString($inputString)
*/
public function getInputString()
{
return $this->inputString;
$handle = $this->getInputHandle();
$str = stream_get_contents($handle);
rewind($handle);

return $str;
}

/**
Expand Down Expand Up @@ -271,6 +302,7 @@ public function getNextByte()
public function setPosition($position)
{
$this->position = $position;
fseek($this->getInputHandle(), $position);

return $this;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Type/Bit.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function read(BinaryReader &$br, $length)

if ($bits != 0) {
$code = $this->getSigned() ? 'c' : 'C';
$data = unpack($code, substr($br->getInputString(), $br->getPosition(), 1));
$data = unpack($code, fread($br->getInputHandle(), 1));
$br->setNextByte($data[1]);
$br->setPosition($br->getPosition() + 1);
$result |= $br->getNextByte() & $bitmask->getMask($bits, BitMask::MASK_LO);
Expand Down
2 changes: 1 addition & 1 deletion src/Type/Byte.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function read(BinaryReader &$br, $length = null)
throw new \OutOfBoundsException('Cannot read bytes, it exceeds the boundary of the file');
}

$segment = substr($br->getInputString(), $br->getPosition(), $length);
$segment = fread($br->getInputHandle(), $length);

$br->setPosition($br->getPosition() + $length);

Expand Down
2 changes: 1 addition & 1 deletion src/Type/Int16.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function read(BinaryReader &$br, $length = null)
}

$endian = $br->getEndian() == Endian::ENDIAN_BIG ? $this->getEndianBig() : $this->getEndianLittle();
$segment = substr($br->getInputString(), $br->getPosition(), 2);
$segment = fread($br->getInputHandle(), 2);

$data = unpack($endian, $segment);
$data = $data[1];
Expand Down
2 changes: 1 addition & 1 deletion src/Type/Int32.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function read(BinaryReader &$br, $length = null)
}

$endian = $br->getEndian() == Endian::ENDIAN_BIG ? $this->getEndianBig() : $this->getEndianLittle();
$segment = substr($br->getInputString(), $br->getPosition(), 4);
$segment = fread($br->getInputHandle(), 4);

$data = unpack($endian, $segment);
$data = $data[1];
Expand Down
2 changes: 1 addition & 1 deletion src/Type/Int8.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function read(BinaryReader &$br, $length = null)
throw new \OutOfBoundsException('Cannot read 32-bit int, it exceeds the boundary of the file');
}

$segment = substr($br->getInputString(), $br->getPosition(), 1);
$segment = fread($br->getInputHandle(), 1);

$data = unpack($this->getEndian(), $segment);
$data = $data[1];
Expand Down
2 changes: 1 addition & 1 deletion src/Type/String.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function read(BinaryReader &$br, $length)
throw new \OutOfBoundsException('Cannot read string, it exceeds the boundary of the file');
}

$str = substr($br->getInputString(), $br->getPosition(), $length);
$str = fread($br->getInputHandle(), $length);
$br->setPosition($br->getPosition() + $length);

return $str;
Expand Down
27 changes: 27 additions & 0 deletions test/AbstractTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace PhpBinaryReader;

class AbstractTestCase extends \PHPUnit_Framework_TestCase
{
// Data provider for creating both File and String based binary readers.
public function binaryReaders()
{
$fileBig = __DIR__ . '/asset/testfile-big.bin';
$fileLittle = __DIR__ . '/asset/testfile-little.bin';

$dataBig = fopen($fileBig, 'rb');
$dataLittle = fopen($fileLittle, 'rb');

$brBigFile = new BinaryReader(fopen($fileBig, 'rb'), Endian::ENDIAN_BIG);
$brLittleFile = new BinaryReader(fopen($fileLittle, 'rb'), Endian::ENDIAN_LITTLE);

$brBigStr = new BinaryReader(file_get_contents($fileBig), Endian::ENDIAN_BIG);
$brLittleStr = new BinaryReader(file_get_contents($fileLittle), Endian::ENDIAN_LITTLE);

return [
[$brBigFile, $brLittleFile],
[$brBigStr, $brLittleStr],
];
}
}

0 comments on commit a40e04c

Please sign in to comment.