Skip to content

Commit a40e04c

Browse files
committed
Merge pull request #6 from jwpage/use_resources
Use file resources for BinaryReader
2 parents 6a55be9 + c6fa791 commit a40e04c

16 files changed

Lines changed: 594 additions & 467 deletions

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ You probably wouldn't be here if you hadn't run into a scenario where you needed
1010
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
1111
well do our best to make it as painless as possible.
1212

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

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

2828
Example Usage
2929
---
30-
```
30+
31+
```php
3132
$fileData = file_get_contents('somefile.bin');
3233
$br = new BinaryReader($fileData, Endian::ENDIAN_LITTLE);
34+
// or
35+
$fileResource = fopen('somefile.bin', 'rb');
36+
$br = new BinaryReader($fileResource, Endian::ENDIAN_LITTLE);
37+
3338
$magic = $br->readUInt32();
3439
$offset = $br->readUInt16();
3540
$length = $br->readUInt16();
@@ -38,7 +43,7 @@ $length = $br->readUInt16();
3843

3944
Methods
4045
---
41-
**__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.
46+
**__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.
4247

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

src/BinaryReader.php

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class BinaryReader
1818
private $machineByteOrder = Endian::ENDIAN_LITTLE;
1919

2020
/**
21-
* @var string
21+
* @var resource
2222
*/
23-
private $inputString;
23+
private $inputHandle;
2424

2525
/**
2626
* @var int
@@ -78,16 +78,21 @@ class BinaryReader
7878
private $int32Reader;
7979

8080
/**
81-
* @param string $str
81+
* @param string|resource $input
8282
* @param int|string $endian
8383
* @throws \InvalidArgumentException
8484
*/
85-
public function __construct($str, $endian = Endian::ENDIAN_LITTLE)
85+
public function __construct($input, $endian = Endian::ENDIAN_LITTLE)
8686
{
87-
$this->eofPosition = strlen($str);
87+
if (!is_resource($input)) {
88+
$this->setInputString($input);
89+
} else {
90+
$this->setInputHandle($input);
91+
}
92+
93+
$this->eofPosition = fstat($this->getInputHandle())['size'];
8894

8995
$this->setEndian($endian);
90-
$this->setInputString($str);
9196
$this->setNextByte(false);
9297
$this->setCurrentBit(0);
9398
$this->setPosition(0);
@@ -227,12 +232,34 @@ public function getMachineByteOrder()
227232
}
228233

229234
/**
230-
* @param string $inputString
235+
* @param resource $inputHandle
236+
* @return $this
237+
*/
238+
public function setInputHandle($inputHandle)
239+
{
240+
$this->inputHandle = $inputHandle;
241+
242+
return $this;
243+
}
244+
245+
/**
246+
* @return resource
247+
*/
248+
public function getInputHandle()
249+
{
250+
return $this->inputHandle;
251+
}
252+
253+
/**
254+
* @param string $inputString
231255
* @return $this
232256
*/
233257
public function setInputString($inputString)
234258
{
235-
$this->inputString = $inputString;
259+
$handle = fopen('php://memory', 'br+');
260+
fwrite($handle, $inputString);
261+
rewind($handle);
262+
$this->inputHandle = $handle;
236263

237264
return $this;
238265
}
@@ -242,7 +269,11 @@ public function setInputString($inputString)
242269
*/
243270
public function getInputString()
244271
{
245-
return $this->inputString;
272+
$handle = $this->getInputHandle();
273+
$str = stream_get_contents($handle);
274+
rewind($handle);
275+
276+
return $str;
246277
}
247278

248279
/**
@@ -271,6 +302,7 @@ public function getNextByte()
271302
public function setPosition($position)
272303
{
273304
$this->position = $position;
305+
fseek($this->getInputHandle(), $position);
274306

275307
return $this;
276308
}

src/Type/Bit.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function read(BinaryReader &$br, $length)
7676

7777
if ($bits != 0) {
7878
$code = $this->getSigned() ? 'c' : 'C';
79-
$data = unpack($code, substr($br->getInputString(), $br->getPosition(), 1));
79+
$data = unpack($code, fread($br->getInputHandle(), 1));
8080
$br->setNextByte($data[1]);
8181
$br->setPosition($br->getPosition() + 1);
8282
$result |= $br->getNextByte() & $bitmask->getMask($bits, BitMask::MASK_LO);

src/Type/Byte.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function read(BinaryReader &$br, $length = null)
2828
throw new \OutOfBoundsException('Cannot read bytes, it exceeds the boundary of the file');
2929
}
3030

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

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

src/Type/Int16.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function read(BinaryReader &$br, $length = null)
3333
}
3434

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

3838
$data = unpack($endian, $segment);
3939
$data = $data[1];

src/Type/Int32.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function read(BinaryReader &$br, $length = null)
3333
}
3434

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

3838
$data = unpack($endian, $segment);
3939
$data = $data[1];

src/Type/Int8.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function read(BinaryReader &$br, $length = null)
2727
throw new \OutOfBoundsException('Cannot read 32-bit int, it exceeds the boundary of the file');
2828
}
2929

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

3232
$data = unpack($this->getEndian(), $segment);
3333
$data = $data[1];

src/Type/String.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function read(BinaryReader &$br, $length)
2424
throw new \OutOfBoundsException('Cannot read string, it exceeds the boundary of the file');
2525
}
2626

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

3030
return $str;

test/AbstractTestCase.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace PhpBinaryReader;
4+
5+
class AbstractTestCase extends \PHPUnit_Framework_TestCase
6+
{
7+
// Data provider for creating both File and String based binary readers.
8+
public function binaryReaders()
9+
{
10+
$fileBig = __DIR__ . '/asset/testfile-big.bin';
11+
$fileLittle = __DIR__ . '/asset/testfile-little.bin';
12+
13+
$dataBig = fopen($fileBig, 'rb');
14+
$dataLittle = fopen($fileLittle, 'rb');
15+
16+
$brBigFile = new BinaryReader(fopen($fileBig, 'rb'), Endian::ENDIAN_BIG);
17+
$brLittleFile = new BinaryReader(fopen($fileLittle, 'rb'), Endian::ENDIAN_LITTLE);
18+
19+
$brBigStr = new BinaryReader(file_get_contents($fileBig), Endian::ENDIAN_BIG);
20+
$brLittleStr = new BinaryReader(file_get_contents($fileLittle), Endian::ENDIAN_LITTLE);
21+
22+
return [
23+
[$brBigFile, $brLittleFile],
24+
[$brBigStr, $brLittleStr],
25+
];
26+
}
27+
}

0 commit comments

Comments
 (0)