File indexing completed on 2024-12-22 05:36:27

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Amf
0017  * @subpackage Util
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * Utility class to walk through a data stream byte by byte with conventional names
0025  *
0026  * @package    Zend_Amf
0027  * @subpackage Util
0028  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0029  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0030  */
0031 class Zend_Amf_Util_BinaryStream
0032 {
0033     /**
0034      * @var string Byte stream
0035      */
0036     protected $_stream;
0037 
0038     /**
0039      * @var int Length of stream
0040      */
0041     protected $_streamLength;
0042 
0043     /**
0044      * @var bool BigEndian encoding?
0045      */
0046     protected $_bigEndian;
0047 
0048     /**
0049      * @var int Current position in stream
0050      */
0051     protected $_needle;
0052 
0053     /**
0054      * @var bool str* functions overloaded using mbstring.func_overload?
0055      */
0056     protected $_mbStringFunctionsOverloaded;
0057 
0058     /**
0059      * Constructor
0060      *
0061      * Create a reference to a byte stream that is going to be parsed or created
0062      * by the methods in the class. Detect if the class should use big or
0063      * little Endian encoding.
0064      *
0065      * @param  string $stream use '' if creating a new stream or pass a string if reading.
0066      * @return void
0067      */
0068     public function __construct($stream)
0069     {
0070         if (!is_string($stream)) {
0071             // require_once 'Zend/Amf/Exception.php';
0072             throw new Zend_Amf_Exception('Inputdata is not of type String');
0073         }
0074 
0075         $this->_stream       = $stream;
0076         $this->_needle       = 0;
0077         $this->_mbStringFunctionsOverloaded = function_exists('mb_strlen') && (ini_get('mbstring.func_overload') !== '') && ((int)ini_get('mbstring.func_overload') & 2);
0078         $this->_streamLength = $this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream);
0079         $this->_bigEndian    = (pack('l', 1) === "\x00\x00\x00\x01");
0080     }
0081 
0082     /**
0083      * Returns the current stream
0084      *
0085      * @return string
0086      */
0087     public function getStream()
0088     {
0089         return $this->_stream;
0090     }
0091 
0092     /**
0093      * Read the number of bytes in a row for the length supplied.
0094      *
0095      * @todo   Should check that there are enough bytes left in the stream we are about to read.
0096      * @param  int $length
0097      * @return string
0098      * @throws Zend_Amf_Exception for buffer underrun
0099      */
0100     public function readBytes($length)
0101     {
0102         if (($length + $this->_needle) > $this->_streamLength) {
0103             // require_once 'Zend/Amf/Exception.php';
0104             throw new Zend_Amf_Exception('Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $length);
0105         }
0106         $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, $length, '8bit') : substr($this->_stream, $this->_needle, $length);
0107         $this->_needle+= $length;
0108         return $bytes;
0109     }
0110 
0111     /**
0112      * Write any length of bytes to the stream
0113      *
0114      * Usually a string.
0115      *
0116      * @param  string $bytes
0117      * @return Zend_Amf_Util_BinaryStream
0118      */
0119     public function writeBytes($bytes)
0120     {
0121         $this->_stream.= $bytes;
0122         return $this;
0123     }
0124 
0125     /**
0126      * Reads a signed byte
0127      *
0128      * @return int Value is in the range of -128 to 127.
0129      * @throws Zend_Amf_Exception
0130      */
0131     public function readByte()
0132     {
0133         if (($this->_needle + 1) > $this->_streamLength) {
0134             // require_once 'Zend/Amf/Exception.php';
0135             throw new Zend_Amf_Exception(
0136                 'Buffer underrun at needle position: '
0137                 . $this->_needle
0138                 . ' while requesting length: '
0139                 . $this->_streamLength
0140             );
0141         }
0142 
0143         return ord($this->_stream{$this->_needle++});
0144     }
0145 
0146     /**
0147      * Writes the passed string into a signed byte on the stream.
0148      *
0149      * @param  string $stream
0150      * @return Zend_Amf_Util_BinaryStream
0151      */
0152     public function writeByte($stream)
0153     {
0154         $this->_stream.= pack('c', $stream);
0155         return $this;
0156     }
0157 
0158     /**
0159      * Reads a signed 32-bit integer from the data stream.
0160      *
0161      * @return int Value is in the range of -2147483648 to 2147483647
0162      */
0163     public function readInt()
0164     {
0165         return ($this->readByte() << 8) + $this->readByte();
0166     }
0167 
0168     /**
0169      * Write an the integer to the output stream as a 32 bit signed integer
0170      *
0171      * @param  int $stream
0172      * @return Zend_Amf_Util_BinaryStream
0173      */
0174     public function writeInt($stream)
0175     {
0176         $this->_stream.= pack('n', $stream);
0177         return $this;
0178     }
0179 
0180     /**
0181      * Reads a UTF-8 string from the data stream
0182      *
0183      * @return string A UTF-8 string produced by the byte representation of characters
0184      */
0185     public function readUtf()
0186     {
0187         $length = $this->readInt();
0188         return $this->readBytes($length);
0189     }
0190 
0191     /**
0192      * Wite a UTF-8 string to the outputstream
0193      *
0194      * @param  string $stream
0195      * @return Zend_Amf_Util_BinaryStream
0196      */
0197     public function writeUtf($stream)
0198     {
0199         $this->writeInt($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream));
0200         $this->_stream.= $stream;
0201         return $this;
0202     }
0203 
0204 
0205     /**
0206      * Read a long UTF string
0207      *
0208      * @return string
0209      */
0210     public function readLongUtf()
0211     {
0212         $length = $this->readLong();
0213         return $this->readBytes($length);
0214     }
0215 
0216     /**
0217      * Write a long UTF string to the buffer
0218      *
0219      * @param  string $stream
0220      * @return Zend_Amf_Util_BinaryStream
0221      */
0222     public function writeLongUtf($stream)
0223     {
0224         $this->writeLong($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream));
0225         $this->_stream.= $stream;
0226     }
0227 
0228     /**
0229      * Read a long numeric value
0230      *
0231      * @return double
0232      */
0233     public function readLong()
0234     {
0235         return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
0236     }
0237 
0238     /**
0239      * Write long numeric value to output stream
0240      *
0241      * @param  int|string $stream
0242      * @return Zend_Amf_Util_BinaryStream
0243      */
0244     public function writeLong($stream)
0245     {
0246         $this->_stream.= pack('N', $stream);
0247         return $this;
0248     }
0249 
0250     /**
0251      * Read a 16 bit unsigned short.
0252      *
0253      * @todo   This could use the unpack() w/ S,n, or v
0254      * @return double
0255      */
0256     public function readUnsignedShort()
0257     {
0258         $byte1 = $this->readByte();
0259         $byte2 = $this->readByte();
0260         return (($byte1 << 8) | $byte2);
0261     }
0262 
0263     /**
0264      * Reads an IEEE 754 double-precision floating point number from the data stream.
0265      *
0266      * @return double Floating point number
0267      */
0268     public function readDouble()
0269     {
0270         $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, 8, '8bit') : substr($this->_stream, $this->_needle, 8);
0271         $this->_needle+= 8;
0272 
0273         if (!$this->_bigEndian) {
0274             $bytes = strrev($bytes);
0275         }
0276 
0277         $double = unpack('dflt', $bytes);
0278         return $double['flt'];
0279     }
0280 
0281     /**
0282      * Writes an IEEE 754 double-precision floating point number from the data stream.
0283      *
0284      * @param  string|double $stream
0285      * @return Zend_Amf_Util_BinaryStream
0286      */
0287     public function writeDouble($stream)
0288     {
0289         $stream = pack('d', $stream);
0290         if (!$this->_bigEndian) {
0291             $stream = strrev($stream);
0292         }
0293         $this->_stream.= $stream;
0294         return $this;
0295     }
0296 
0297 }