<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Amf * @subpackage Util * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id$ */ /** * Utility class to walk through a data stream byte by byte with conventional names * * @package Zend_Amf * @subpackage Util * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Amf_Util_BinaryStream { /** * @var string Byte stream */ protected $_stream; /** * @var int Length of stream */ protected $_streamLength; /** * @var bool BigEndian encoding? */ protected $_bigEndian; /** * @var int Current position in stream */ protected $_needle; /** * @var bool str* functions overloaded using mbstring.func_overload? */ protected $_mbStringFunctionsOverloaded; /** * Constructor * * Create a reference to a byte stream that is going to be parsed or created * by the methods in the class. Detect if the class should use big or * little Endian encoding. * * @param string $stream use '' if creating a new stream or pass a string if reading. * @return void */ public function __construct($stream) { if (!is_string($stream)) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Inputdata is not of type String'); } $this->_stream = $stream; $this->_needle = 0; $this->_mbStringFunctionsOverloaded = function_exists('mb_strlen') && (ini_get('mbstring.func_overload') !== '') && ((int)ini_get('mbstring.func_overload') & 2); $this->_streamLength = $this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream); $this->_bigEndian = (pack('l', 1) === "\x00\x00\x00\x01"); } /** * Returns the current stream * * @return string */ public function getStream() { return $this->_stream; } /** * Read the number of bytes in a row for the length supplied. * * @todo Should check that there are enough bytes left in the stream we are about to read. * @param int $length * @return string * @throws Zend_Amf_Exception for buffer underrun */ public function readBytes($length) { if (($length + $this->_needle) > $this->_streamLength) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $length); } $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, $length, '8bit') : substr($this->_stream, $this->_needle, $length); $this->_needle+= $length; return $bytes; } /** * Write any length of bytes to the stream * * Usually a string. * * @param string $bytes * @return Zend_Amf_Util_BinaryStream */ public function writeBytes($bytes) { $this->_stream.= $bytes; return $this; } /** * Reads a signed byte * * @return int Value is in the range of -128 to 127. * @throws Zend_Amf_Exception */ public function readByte() { if (($this->_needle + 1) > $this->_streamLength) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception( 'Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $this->_streamLength ); } return ord($this->_stream{$this->_needle++}); } /** * Writes the passed string into a signed byte on the stream. * * @param string $stream * @return Zend_Amf_Util_BinaryStream */ public function writeByte($stream) { $this->_stream.= pack('c', $stream); return $this; } /** * Reads a signed 32-bit integer from the data stream. * * @return int Value is in the range of -2147483648 to 2147483647 */ public function readInt() { return ($this->readByte() << 8) + $this->readByte(); } /** * Write an the integer to the output stream as a 32 bit signed integer * * @param int $stream * @return Zend_Amf_Util_BinaryStream */ public function writeInt($stream) { $this->_stream.= pack('n', $stream); return $this; } /** * Reads a UTF-8 string from the data stream * * @return string A UTF-8 string produced by the byte representation of characters */ public function readUtf() { $length = $this->readInt(); return $this->readBytes($length); } /** * Wite a UTF-8 string to the outputstream * * @param string $stream * @return Zend_Amf_Util_BinaryStream */ public function writeUtf($stream) { $this->writeInt($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream)); $this->_stream.= $stream; return $this; } /** * Read a long UTF string * * @return string */ public function readLongUtf() { $length = $this->readLong(); return $this->readBytes($length); } /** * Write a long UTF string to the buffer * * @param string $stream * @return Zend_Amf_Util_BinaryStream */ public function writeLongUtf($stream) { $this->writeLong($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream)); $this->_stream.= $stream; } /** * Read a long numeric value * * @return double */ public function readLong() { return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); } /** * Write long numeric value to output stream * * @param int|string $stream * @return Zend_Amf_Util_BinaryStream */ public function writeLong($stream) { $this->_stream.= pack('N', $stream); return $this; } /** * Read a 16 bit unsigned short. * * @todo This could use the unpack() w/ S,n, or v * @return double */ public function readUnsignedShort() { $byte1 = $this->readByte(); $byte2 = $this->readByte(); return (($byte1 << 8) | $byte2); } /** * Reads an IEEE 754 double-precision floating point number from the data stream. * * @return double Floating point number */ public function readDouble() { $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, 8, '8bit') : substr($this->_stream, $this->_needle, 8); $this->_needle+= 8; if (!$this->_bigEndian) { $bytes = strrev($bytes); } $double = unpack('dflt', $bytes); return $double['flt']; } /** * Writes an IEEE 754 double-precision floating point number from the data stream. * * @param string|double $stream * @return Zend_Amf_Util_BinaryStream */ public function writeDouble($stream) { $stream = pack('d', $stream); if (!$this->_bigEndian) { $stream = strrev($stream); } $this->_stream.= $stream; return $this; } }