diff --git a/README.md b/README.md index acc25f9..f632e22 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,9 @@ I intentionally needed that for writing a PHP Client for [TrafficCop](https://gi But the source grows so I decided to move it into an own package. You can also call this a [pack()](http://www.php.net/manual/en/function.pack.php) wrapper. -## Install - -Installation should be done via [composer](http://packagist.org/). - +## Install Via Composer ``` -{ - "require": { - "TrafficCophp/ByteBuffer": "dev-master" - } -} +composer require t3ran13/ByteBuffer ``` ## Example @@ -32,7 +25,7 @@ use TrafficCophp\ByteBuffer\ByteBuffer; $channel = 'channel_one'; $message = 'php'; -$buffer = new ByteBuffer(4 + 1 + 4 + strlen($channel) + strlen($message)); +$buffer = new ByteBuffer(); $buffer->writeInt32BE($buffer->length(), 0); $buffer->writeInt8(0x1, 4); $buffer->writeInt32BE(strlen($channel), 5); diff --git a/src/TrafficCophp/ByteBuffer/Buffer.php b/src/TrafficCophp/ByteBuffer/Buffer.php deleted file mode 100644 index 065db0e..0000000 --- a/src/TrafficCophp/ByteBuffer/Buffer.php +++ /dev/null @@ -1,147 +0,0 @@ -lengthMap = new LengthMap(); - if (is_string($argument)) { - $this->initializeStructs(strlen($argument), $argument); - } else if (is_int($argument)) { - $this->initializeStructs($argument, pack(self::DEFAULT_FORMAT.$argument)); - } else { - throw new \InvalidArgumentException('Constructor argument must be an binary string or integer'); - } - } - - protected function initializeStructs($length, $content) { - $this->buffer = new \SplFixedArray($length); - for ($i = 0; $i < $length; $i++) { - $this->buffer[$i] = $content[$i]; - } - } - - protected function insert($format, $value, $offset, $length) { - $bytes = pack($format, $value); - for ($i = 0; $i < strlen($bytes); $i++) { - $this->buffer[$offset++] = $bytes[$i]; - } - } - - protected function extract($format, $offset, $length) { - $encoded = ''; - for ($i = 0; $i < $length; $i++) { - $encoded .= $this->buffer->offsetGet($offset + $i); - } - if ($format == 'N'&& PHP_INT_SIZE <= 4) { - list(, $h, $l) = unpack('n*', $encoded); - $result = ($l + ($h * 0x010000)); - } else if ($format == 'V' && PHP_INT_SIZE <= 4) { - list(, $h, $l) = unpack('v*', $encoded); - $result = ($h + ($l * 0x010000)); - } else { - list(, $result) = unpack($format, $encoded); - } - return $result; - } - - protected function checkForOverSize($excpected_max, $actual) { - if ($actual > $excpected_max) { - throw new \InvalidArgumentException(sprintf('%d exceeded limit of %d', $actual, $excpected_max)); - } - } - - public function __toString() { - $buf = ''; - foreach ($this->buffer as $bytes) { - $buf .= $bytes; - } - return $buf; - } - - public function length() { - return $this->buffer->getSize(); - } - - public function write($string, $offset) { - $length = strlen($string); - $this->insert('a' . $length, $string, $offset, $length); - } - - public function writeInt8($value, $offset) { - $format = 'C'; - $this->checkForOverSize(0xff, $value); - $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function writeInt16BE($value, $offset) { - $format = 'n'; - $this->checkForOverSize(0xffff, $value); - $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function writeInt16LE($value, $offset) { - $format = 'v'; - $this->checkForOverSize(0xffff, $value); - $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function writeInt32BE($value, $offset) { - $format = 'N'; - $this->checkForOverSize(0xffffffff, $value); - $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function writeInt32LE($value, $offset) { - $format = 'V'; - $this->checkForOverSize(0xffffffff, $value); - $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function read($offset, $length) { - $format = 'a' . $length; - return $this->extract($format, $offset, $length); - } - - public function readInt8($offset) { - $format = 'C'; - return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function readInt16BE($offset) { - $format = 'n'; - return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function readInt16LE($offset) { - $format = 'v'; - return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function readInt32BE($offset) { - $format = 'N'; - return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); - } - - public function readInt32LE($offset) { - $format = 'V'; - return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); - } - -} \ No newline at end of file diff --git a/src/TrafficCophp/ByteBuffer/ByteBuffer.php b/src/TrafficCophp/ByteBuffer/ByteBuffer.php new file mode 100644 index 0000000..01cb20c --- /dev/null +++ b/src/TrafficCophp/ByteBuffer/ByteBuffer.php @@ -0,0 +1,232 @@ +lengthMap = new LengthMap(); + $this->initializeStructs($capacity); + } + + protected function initializeStructs($length) { + if ($length === self::DEFAULT_CAPACITY) { + $this->buffer = []; + } else { + $this->buffer = new \SplFixedArray($length); + } + } + + protected function insert($format, $value, $offset, $length) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $bytes = pack($format, $value); + for ($i = 0; $i < strlen($bytes); $i++) { + $this->buffer[$offset++] = $bytes[$i]; + } + $this->currentOffset = $offset; + } + + protected function extract($format, $offset, $length) { + $encoded = ''; + for ($i = 0; $i < $length; $i++) { + $encoded .= $this->buffer[$offset + $i]; + } + if ($format == 'N'&& PHP_INT_SIZE <= 4) { + list(, $h, $l) = unpack('n*', $encoded); + $result = ($l + ($h * 0x010000)); + } else if ($format == 'V' && PHP_INT_SIZE <= 4) { + list(, $h, $l) = unpack('v*', $encoded); + $result = ($h + ($l * 0x010000)); + } else { + list(, $result) = unpack($format, $encoded); + } + return $result; + } + + protected function checkForOverSize($excpected_max, $actual) { + if ($actual > $excpected_max) { + throw new \InvalidArgumentException(sprintf('%d exceeded limit of %d', $actual, $excpected_max)); + } + } + + public function __toString() { + $buf = ''; + foreach ($this->buffer as $bytes) { + $buf .= $bytes; + } + return $buf; + } + + public function setByteRaw($value, $offset = null) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $this->buffer[$offset++] = $value; + $this->currentOffset = $offset; + } + + public function getBufferArray() { + return $this->buffer; + } + + public function getBuffer($format, $offset, $length) { + $buf = ''; + foreach ($this->buffer as $index => $bytes) { + if ($offset <= $index && $index < ($offset + $length)) { + $buf .= unpack($format . '*', $bytes)[1]; + } + } +// return $this->extract($format, $offset, $length); + return $buf; + } + + public function length() { + return count($this->buffer); + } + + public function setCurrentOffset($offset) { + $this->currentOffset = $offset; + } + + public function getCurrentOffset() { + return $this->currentOffset; + } + + public function write($string, $offset = null) { + $length = strlen($string); + $this->insert('a' . $length, $string, $offset, $length); + } + + public function writeByte($byte, $offset = null) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $this->buffer[$offset++] = $byte; + $this->currentOffset = $offset; + } + + public function writeVStringLE($value, $offset = null) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $bytes = unpack('c*', $value); //string to bytes in int + $total = count($bytes); + for ($i = 0; $i < $total; $i++) { + $this->buffer[$offset++] = pack('H*', base_convert($bytes[$i+1], 10, 16)); + } + $this->currentOffset = $offset; + } + + public function writeVHexStringBE($value, $offset = null) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $symbols = str_split($value, 2); //string to bytes in int + $total = count($symbols); + for ($i = 0; $i < $total; $i++) { + $this->buffer[$offset++] = hex2bin($symbols[$i]); + } + $this->currentOffset = $offset; + } + + + public function writeVStringBE($value, $offset = null) { + if ($offset === null) { + $offset = $this->currentOffset; + } + $bytes = unpack('c*', $value); //string to bytes in int + $total = count($bytes); + for ($i = 0; $i < $total; $i++) { + $this->buffer[$offset++] = pack('h*', base_convert($bytes[$i+1], 10, 16)); + } + $this->currentOffset = $offset; + } + + public function writeInt8($value, $offset = null) { + $format = 'C'; + $this->checkForOverSize(0xff, $value); + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function writeInt16BE($value, $offset = null) { + $format = 'n'; + $this->checkForOverSize(0xffff, $value); + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function writeInt16BE2($value, $offset = null) { + $format = 's'; + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function writeInt16LE($value, $offset = null) { + $format = 'v'; + $this->checkForOverSize(0xffff, $value); + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function writeInt32BE($value, $offset = null) { + $format = 'N'; + $this->checkForOverSize(0xffffffff, $value); + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function writeInt32LE($value, $offset = null) { + $format = 'V'; + $this->checkForOverSize(0xffffffff, $value); + $this->insert($format, $value, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function read($offset, $length) { + $format = 'a' . $length; + return $this->extract($format, $offset, $length); + } + + public function readInt8($offset) { + $format = 'C'; + return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function readInt16BE($offset) { + $format = 'n'; + return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function readInt16LE($offset) { + $format = 'v'; + return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function readInt32BE($offset) { + $format = 'N'; + return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); + } + + public function readInt32LE($offset) { + $format = 'V'; + return $this->extract($format, $offset, $this->lengthMap->getLengthFor($format)); + } + +} \ No newline at end of file diff --git a/tests/TrafficCophp/ByteBuffer/BufferTest.php b/tests/TrafficCophp/ByteBuffer/BufferTest.php index 2c3925a..63f9b8c 100644 --- a/tests/TrafficCophp/ByteBuffer/BufferTest.php +++ b/tests/TrafficCophp/ByteBuffer/BufferTest.php @@ -1,130 +1,130 @@ writeInt32LE(0xfeedface, 0); $this->assertSame(pack('Vx', 0xfeedface), (string) $buffer); } public function testSurroundedEmptyByte() { - $buffer = new Buffer(9); + $buffer = new ByteBuffer(9); $buffer->writeInt32BE(0xfeedface, 0); $buffer->writeInt32BE(0xcafebabe, 5); $this->assertSame(pack('NxN', 0xfeedface, 0xcafebabe), (string) $buffer); } public function testTooSmallBuffer() { - $buffer = new Buffer(4); + $buffer = new ByteBuffer(4); $buffer->writeInt32BE(0xfeedface, 0); $this->setExpectedException('RuntimeException'); $buffer->writeInt32LE(0xfeedface, 4); } public function testTwo4ByteIntegers() { - $buffer = new Buffer(8); + $buffer = new ByteBuffer(8); $buffer->writeInt32BE(0xfeedface, 0); $buffer->writeInt32LE(0xfeedface, 4); $this->assertSame(pack('NV', 0xfeedface, 0xfeedface), (string) $buffer); } public function testWritingString() { - $buffer = new Buffer(10); + $buffer = new ByteBuffer(10); $buffer->writeInt32BE(0xcafebabe, 0); $buffer->write('please', 4); $this->assertSame(pack('Na6', 0xcafebabe, 'please'), (string) $buffer); } public function testTooLongIntegers() { - $buffer = new Buffer(12); + $buffer = new ByteBuffer(12); $this->setExpectedException('InvalidArgumentException'); $buffer->writeInt32BE(0xfeedfacefeed, 0); } public function testLength() { - $buffer = new Buffer(8); + $buffer = new ByteBuffer(8); $this->assertEquals(8, $buffer->length()); } public function testWriteInt8() { - $buffer = new Buffer(1); + $buffer = new ByteBuffer(1); $buffer->writeInt8(0xfe, 0); $this->assertSame(pack('C', 0xfe), (string) $buffer); } public function testWriteInt16BE() { - $buffer = new Buffer(2); + $buffer = new ByteBuffer(2); $buffer->writeInt16BE(0xbabe, 0); $this->assertSame(pack('n', 0xbabe), (string) $buffer); } public function testWriteInt16LE() { - $buffer = new Buffer(2); + $buffer = new ByteBuffer(2); $buffer->writeInt16LE(0xabeb, 0); $this->assertSame(pack('v', 0xabeb), (string) $buffer); } public function testWriteInt32BE() { - $buffer = new Buffer(4); + $buffer = new ByteBuffer(4); $buffer->writeInt32BE(0xfeedface, 0); $this->assertSame(pack('N', 0xfeedface), (string) $buffer); } public function testWriteInt32LE() { - $buffer = new Buffer(4); + $buffer = new ByteBuffer(4); $buffer->writeInt32LE(0xfeedface, 0); $this->assertSame(pack('V', 0xfeedface), (string) $buffer); } public function testReaderBufferInitializeLenght() { - $buffer = new Buffer(pack('V', 0xfeedface)); + $buffer = new ByteBuffer(pack('V', 0xfeedface)); $this->assertEquals(4, $buffer->length()); } public function testReadInt8() { - $buffer = new Buffer(pack('C', 0xfe)); + $buffer = new ByteBuffer(pack('C', 0xfe)); $this->assertSame(0xfe, $buffer->readInt8(0)); } public function testReadInt16BE() { - $buffer = new Buffer(pack('n', 0xbabe)); + $buffer = new ByteBuffer(pack('n', 0xbabe)); $this->assertSame(0xbabe, $buffer->readInt16BE(0)); } public function testReadInt16LE() { - $buffer = new Buffer(pack('v', 0xabeb)); + $buffer = new ByteBuffer(pack('v', 0xabeb)); $this->assertSame(0xabeb, $buffer->readInt16LE(0)); } public function testReadInt32BE() { - $buffer = new Buffer(pack('N', 0xfeedface)); + $buffer = new ByteBuffer(pack('N', 0xfeedface)); $this->assertSame(0xfeedface, $buffer->readInt32BE(0)); } public function testReadInt32LE() { - $buffer = new Buffer(pack('V', 0xfeedface)); + $buffer = new ByteBuffer(pack('V', 0xfeedface)); $this->assertSame(0xfeedface, $buffer->readInt32LE(0)); } public function testRead() { - $buffer = new Buffer(pack('a7', 'message')); + $buffer = new ByteBuffer(pack('a7', 'message')); $this->assertSame('message', $buffer->read(0, 7)); } public function testComplexRead() { - $buffer = new Buffer(pack('Na7', 0xfeedface, 'message')); + $buffer = new ByteBuffer(pack('Na7', 0xfeedface, 'message')); $this->assertSame(0xfeedface, $buffer->readInt32BE(0)); $this->assertSame('message', $buffer->read(4, 7)); } public function testWritingAndReadingOnTheSameBuffer() { - $buffer = new Buffer(10); + $buffer = new ByteBuffer(10); $int32be = 0xfeedface; $string = 'hello!'; $buffer->writeInt32BE($int32be, 0); @@ -135,12 +135,12 @@ public function testWritingAndReadingOnTheSameBuffer() { public function testInvalidConstructorWithArray() { $this->setExpectedException('\InvalidArgumentException'); - $buffer = new Buffer(array('asdf')); + $buffer = new ByteBuffer(array('asdf')); } public function testInvalidConstructorWithFloat() { $this->setExpectedException('\InvalidArgumentException'); - $buffer = new Buffer(324.23); + $buffer = new ByteBuffer(324.23); } } \ No newline at end of file