diff --git a/nbproject/project.properties b/nbproject/project.properties index 78c2af4..bcd6e9e 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,2 +1,7 @@ +include.path=${php.global.include.path} source.encoding=UTF-8 -version=4 +src.dir=src +tags.asp=false +tags.short=true +test.src.dir=tests +web.root=. diff --git a/src/Zend/Io/Exception.php b/src/Zend/Io/Exception.php new file mode 100644 index 0000000..52318a0 --- /dev/null +++ b/src/Zend/Io/Exception.php @@ -0,0 +1,38 @@ + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_Exception extends Zend_Exception +{} diff --git a/src/Zend/Io/FileReader.php b/src/Zend/Io/FileReader.php new file mode 100644 index 0000000..d4c470c --- /dev/null +++ b/src/Zend/Io/FileReader.php @@ -0,0 +1,65 @@ + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_FileReader extends Zend_Io_Reader +{ + /** + * Constructs the Zend_Io_FileReader class with given path to the file. By + * default the file is opened in read (rb) mode. + * + * @param string $filename The path to the file. + * @throws Zend_Io_Exception if the file cannot be read + */ + public function __construct($filename, $mode = null) + { + if ($mode === null) + $mode = 'rb'; + if (!file_exists($filename) || !is_readable($filename) || + ($fd = fopen($filename, $mode)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open file for reading: ' . $filename); + } + parent::__construct($fd); + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/src/Zend/Io/FileWriter.php b/src/Zend/Io/FileWriter.php new file mode 100644 index 0000000..f1d27bc --- /dev/null +++ b/src/Zend/Io/FileWriter.php @@ -0,0 +1,65 @@ + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_FileWriter extends Zend_Io_Writer +{ + /** + * Constructs the Zend_Io_FileWriter class with given path to the file. By + * default the file is opened in write mode without altering its content + * (ie r+b mode if the file exists, and wb mode if not). + * + * @param string $filename The path to the file. + * @throws Zend_Io_Exception if the file cannot be written + */ + public function __construct($filename, $mode = null) + { + if ($mode === null) + $mode = file_exists($filename) ? 'r+b' : 'wb'; + if (($fd = fopen($filename, $mode)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open file for writing: ' . $filename); + } + parent::__construct($fd); + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/src/Zend/Io/Reader.php b/src/Zend/Io/Reader.php new file mode 100644 index 0000000..d058de8 --- /dev/null +++ b/src/Zend/Io/Reader.php @@ -0,0 +1,675 @@ + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_Reader +{ + const MACHINE_ENDIAN_ORDER = 0; + const LITTLE_ENDIAN_ORDER = 1; + const BIG_ENDIAN_ORDER = 2; + + /** + * The endianess of the current machine. + * + * @var integer + */ + private static $_endianess = 0; + + /** + * The resource identifier of the stream. + * + * @var resource + */ + protected $_fd = null; + + /** + * Size of the underlying stream. + * + * @var integer + */ + protected $_size = 0; + + /** + * Constructs the Zend_Io_Reader class with given open file descriptor. + * + * @param resource $fd The file descriptor. + * @throws Zend_Io_Exception if given file descriptor is not valid + */ + public function __construct($fd) + { + if (!is_resource($fd) || + !in_array(get_resource_type($fd), array('stream'))) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Invalid resource type (only resources of type stream are supported)'); + } + + $this->_fd = $fd; + + $offset = $this->getOffset(); + fseek($this->_fd, 0, SEEK_END); + $this->_size = ftell($this->_fd); + fseek($this->_fd, $offset); + } + + /** + * Default destructor. + */ + public function __destruct() {} + + /** + * Checks whether there is more to be read from the stream. Returns + * true if the end has not yet been reached; false + * otherwise. + * + * @return boolean + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function available() + { + return $this->getOffset() < $this->getSize(); + } + + /** + * Returns the current point of operation. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function getOffset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return ftell($this->_fd); + } + + /** + * Sets the point of operation, ie the cursor offset value. The offset may + * also be set to a negative value when it is interpreted as an offset from + * the end of the stream instead of the beginning. + * + * @param integer $offset The new point of operation. + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function setOffset($offset) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); + } + + /** + * Returns the stream size in bytes. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + /** + * Returns the underlying stream file descriptor. + * + * @return resource + */ + public function getFileDescriptor() + { + return $this->_fd; + } + + /** + * Jumps size amount of bytes in the stream. + * + * @param integer $size The amount of bytes. + * @return void + * @throws Zend_Io_Exception if size attribute is negative or if + * an I/O error occurs + */ + public function skip($size) + { + if ($size < 0) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Size cannot be negative'); + } + if ($size == 0) { + return; + } + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $size, SEEK_CUR); + } + + /** + * Reads length amount of bytes from the stream. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public function read($length) + { + if ($length < 0) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Length cannot be negative'); + } + if ($length == 0) { + return ''; + } + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return fread($this->_fd, $length); + } + + /** + * Reads 1 byte from the stream and returns binary data as an 8-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt8() + { + list(, $int) = unpack('c*', $this->read(1)); + return $int; + } + + /** + * Reads 1 byte from the stream and returns binary data as an unsigned 8-bit + * integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt8() + { + list(, $int) = unpack('C*', $this->read(1)); + return $int; + } + + /** + * Returns machine endian ordered binary data as signed 16-bit integer. + * + * @param string $value The binary data string. + * @return integer + */ + private function _fromInt16($value) + { + list(, $int) = unpack('s*', $value); + return $int; + } + + /** + * Reads 2 bytes from the stream and returns little-endian ordered binary + * data as signed 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt16LE() + { + if ($this->_isBigEndian()) { + return $this->_fromInt16(strrev($this->read(2))); + } else { + return $this->_fromInt16($this->read(2)); + } + } + + /** + * Reads 2 bytes from the stream and returns big-endian ordered binary data + * as signed 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt16BE() + { + if ($this->_isLittleEndian()) { + return $this->_fromInt16(strrev($this->read(2))); + } else { + return $this->_fromInt16($this->read(2)); + } + } + + /** + * Returns machine endian ordered binary data as unsigned 16-bit integer. + * + * @param string $value The binary data string. + * @param integer $order The byte order of the binary data string. + * @return integer + */ + private function _fromUInt16($value, $order = 0) + { + list(, $int) = unpack + (($order == self::BIG_ENDIAN_ORDER ? 'n' : + ($order == self::LITTLE_ENDIAN_ORDER ? 'v' : 'S')) . '*', + $value); + return $int; + } + + /** + * Reads 2 bytes from the stream and returns little-endian ordered binary + * data as unsigned 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt16LE() + { + return $this->_fromUInt16($this->read(2), self::LITTLE_ENDIAN_ORDER); + } + + /** + * Reads 2 bytes from the stream and returns big-endian ordered binary data + * as unsigned 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt16BE() + { + return $this->_fromUInt16($this->read(2), self::BIG_ENDIAN_ORDER); + } + + /** + * Returns machine-endian ordered binary data as signed 32-bit integer. + * + * @param string $value The binary data string. + * @return integer + */ + private final function _fromInt32($value) + { + list(, $int) = unpack('l*', $value); + return $int; + } + + /** + * Reads 4 bytes from the stream and returns little-endian ordered binary + * data as signed 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt32LE() + { + if ($this->_isBigEndian()) + return $this->_fromInt32(strrev($this->read(4))); + else + return $this->_fromInt32($this->read(4)); + } + + /** + * Reads 4 bytes from the stream and returns big-endian ordered binary data + * as signed 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt32BE() + { + if ($this->_isLittleEndian()) + return $this->_fromInt32(strrev($this->read(4))); + else + return $this->_fromInt32($this->read(4)); + } + + /** + * Reads 4 bytes from the stream and returns little-endian ordered binary + * data as unsigned 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt32LE() + { + if (PHP_INT_SIZE < 8) { + list(, $lo, $hi) = unpack('v*', $this->read(4)); + return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo + } else { + list(, $int) = unpack('V*', $this->read(4)); + return $int; + } + } + + /** + * Reads 4 bytes from the stream and returns big-endian ordered binary data + * as unsigned 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt32BE() + { + if (PHP_INT_SIZE < 8) { + list(, $hi, $lo) = unpack('n*', $this->read(4)); + return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo + } else { + list(, $int) = unpack('N*', $this->read(4)); + return $int; + } + } + + /** + * Reads 8 bytes from the stream and returns little-endian ordered binary + * data as 64-bit float. + * + * {@internal PHP does not support 64-bit integers as the long + * integer is of 32-bits but using aritmetic operations it is implicitly + * converted into floating point which is of 64-bits long.} + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt64LE() + { + list(, $lolo, $lohi, $hilo, $hihi) = unpack('v*', $this->read(8)); + return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + + ($lohi * (0xffff+1) + $lolo); + } + + /** + * Reads 8 bytes from the stream and returns big-endian ordered binary data + * as 64-bit float. + * + * {@internal PHP does not support 64-bit integers as the long integer is of + * 32-bits but using aritmetic operations it is implicitly converted into + * floating point which is of 64-bits long.} + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt64BE() + { + list(, $hihi, $hilo, $lohi, $lolo) = unpack('n*', $this->read(8)); + return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + + ($lohi * (0xffff+1) + $lolo); + } + +// TODO: How to determine float size? +// +// /** +// * Returns machine endian ordered binary data as a floating point number. +// * +// * @param string $value The binary data string. +// * @return float +// */ +// private function _fromFloat($value) +// { +// list(, $float) = unpack('f*', $value); +// return $float; +// } +// +// /** +// * Reads machine dependent size of bytes from the stream and returns +// * little-endian ordered binary data as a floating point number. +// * +// * @return float +// * @throws Zend_Io_Exception if an I/O error occurs +// */ +// public final function readFloatLE() +// { +// if ($this->_isBigEndian()) +// return $this->_fromFloat(strrev($this->read(?))); +// else +// return $this->_fromFloat($this->read(?)); +// } +// +// /** +// * Reads machine dependent size of bytes from the stream and returns +// * big-endian ordered binary data as a float point number. +// * +// * @return float +// * @throws Zend_Io_Exception if an I/O error occurs +// */ +// public final function readFloatBE() +// { +// if ($this->_isLittleEndian()) +// return $this->_fromFloat(strrev($this->read(?))); +// else +// return $this->_fromFloat($this->read(?)); +// } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as string. Removes terminating zero. + * + * @param integer $length The amount of bytes. + * @param string $charList The list of characters you want to strip. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readString8($length, $charList = "\0") + { + return rtrim($this->read($length), $charList); + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as multibyte Unicode string. Removes terminating zero. + * + * The byte order is possibly determined from the byte order mark included + * in the binary data string. The order parameter is updated if the BOM is + * found. + * + * @param integer $length The amount of bytes. + * @param integer $order The endianess of the string. + * @param integer $trimOrder Whether to remove the byte order mark read the + * string. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readString16($length, &$order = null, $trimOrder = false) + { + $value = $this->read($length); + + if (strlen($value) < 2) { + return ''; + } + + if (ord($value[0]) == 0xfe && ord($value[1]) == 0xff) { + $order = self::BIG_ENDIAN_ORDER; + if ($trimOrder) { + $value = substr($value, 2); + } + } + if (ord($value[0]) == 0xff && ord($value[1]) == 0xfe) { + $order = self::LITTLE_ENDIAN_ORDER; + if ($trimOrder) { + $value = substr($value, 2); + } + } + + return substr($value, -2) == "\0\0" ? substr($value, 0, -2) : $value; + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as hexadecimal string having high nibble first. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readHHex($length) + { + list($hex) = unpack('H*0', $this->read($length)); + return $hex; + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as hexadecimal string having low nibble first. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readLHex($length) + { + list($hex) = unpack('h*0', $this->read($length)); + return $hex; + } + + /** + * Reads 16 bytes from the stream and returns the little-endian ordered + * binary data as mixed-ordered hexadecimal GUID string. + * + * @return string + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readGuid() + { + $C = @unpack('V1V/v2v/N2N', $this->read(16)); + list($hex) = @unpack('H*0', pack + ('NnnNN', $C['V'], $C['v1'], $C['v2'], $C['N1'], $C['N2'])); + + /* Fixes a bug in PHP versions earlier than Jan 25 2006 */ + if (implode('', unpack('H*', pack('H*', 'a'))) == 'a00') { + $hex = substr($hex, 0, -1); + } + + return preg_replace + ('/^(.{8})(.{4})(.{4})(.{4})/', "\\1-\\2-\\3-\\4-", $hex); + } + + /** + * Resets the stream. Attempts to reset it in some way appropriate to the + * particular stream, for example by repositioning it to its starting point. + * + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function reset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, 0); + } + + /** + * Closes the stream. Once a stream has been closed, further calls to read + * methods will throw an exception. Closing a previously-closed stream, + * however, has no effect. + * + * @return void + */ + public function close() + { + if ($this->_fd !== null) { + @fclose($this->_fd); + $this->_fd = null; + } + } + + /** + * Returns the current machine endian order. + * + * @return integer + */ + private function _getEndianess() + { + if (self::$_endianess === 0) { + self::$_endianess = $this->_fromInt32("\x01\x00\x00\x00") == 1 ? + self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; + } + return self::$_endianess; + } + + /** + * Returns whether the current machine endian order is little endian. + * + * @return boolean + */ + private function _isLittleEndian() + { + return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; + } + + /** + * Returns whether the current machine endian order is big endian. + * + * @return boolean + */ + private function _isBigEndian() + { + return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func + (array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } +} diff --git a/src/Zend/Io/StringReader.php b/src/Zend/Io/StringReader.php new file mode 100644 index 0000000..3d40af7 --- /dev/null +++ b/src/Zend/Io/StringReader.php @@ -0,0 +1,67 @@ + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_StringReader extends Zend_Io_Reader +{ + /** + * Constructs the Zend_Io_StringReader class with given source string. + * + * @param string $data The string to use as the source. + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function __construct($data) + { + if (($this->_fd = fopen('php://memory', 'w+b')) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open php://memory stream'); + } + if ($data !== null && is_string($data)) { + if (($this->_size = fwrite($this->_fd, $data, $tagSize)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to write data to php://memory stream'); + } + fseek($this->_fd, 0); + } + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/src/Zend/Io/StringWriter.php b/src/Zend/Io/StringWriter.php new file mode 100644 index 0000000..b35caa6 --- /dev/null +++ b/src/Zend/Io/StringWriter.php @@ -0,0 +1,67 @@ + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_StringWriter extends Zend_Io_Writer +{ + /** + * Constructs the Zend_Io_StringWriter class with given source string. + * + * @param string $data The string to use as the source. + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function __construct($data = null) + { + if (($this->_fd = fopen('php://memory', 'w+b')) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open php://memory stream'); + } + if ($data !== null && is_string($data)) { + if (($this->_size = fwrite($this->_fd, $data, $tagSize)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to write data to php://memory stream'); + } + fseek($this->_fd, 0); + } + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/src/Zend/Io/Writer.php b/src/Zend/Io/Writer.php new file mode 100644 index 0000000..63e6288 --- /dev/null +++ b/src/Zend/Io/Writer.php @@ -0,0 +1,624 @@ + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Io_Writer +{ + const MACHINE_ENDIAN_ORDER = 0; + const LITTLE_ENDIAN_ORDER = 1; + const BIG_ENDIAN_ORDER = 2; + + /** + * The endianess of the current machine. + * + * @var integer + */ + private static $_endianess = 0; + + /** + * The resource identifier of the stream. + * + * @var resource + */ + protected $_fd = null; + + /** + * Size of the underlying stream. + * + * @var integer + */ + protected $_size = 0; + + /** + * Constructs the Zend_Io_Writer class with given open file descriptor. + * + * @param resource $fd The file descriptor. + * @throws Zend_Io_Exception if file descriptor is not valid + */ + public function __construct($fd) + { + if (!is_resource($fd) || + !in_array(get_resource_type($fd), array('stream'))) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Invalid resource type (only resources of type stream are supported)'); + } + + $this->_fd = $fd; + + $offset = $this->getOffset(); + fseek($this->_fd, 0, SEEK_END); + $this->_size = ftell($this->_fd); + fseek($this->_fd, $offset); + } + + /** + * Default destructor. + */ + public function __destruct() {} + + /** + * Returns the current point of operation. + * + * @return integer + * @throws Zend_Io_Exception if the stream is closed + */ + public function getOffset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return ftell($this->_fd); + } + + /** + * Sets the point of operation, ie the cursor offset value. The offset may + * also be set to a negative value when it is interpreted as an offset from + * the end of the stream instead of the beginning. + * + * @param integer $offset The new point of operation. + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function setOffset($offset) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); + } + + /** + * Returns the stream size in bytes. + * + * @return integer + * @throws Zend_Io_Exception if the stream is closed + */ + public function getSize() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return $this->_size; + } + + /** + * Sets the stream size in bytes, and truncates if required. + * + * @param integer $size The new size + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function setSize($size) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + ftruncate($this->_fd, $size); + } + + /** + * Returns the underlying stream file descriptor. + * + * @return resource + */ + public function getFileDescriptor() + { + return $this->_fd; + } + + /** + * Writes value up to length bytes to the stream. + * + * @param string $value The value to write to the stream. + * @param integer $length The number of bytes to write. Defaults to the + * length of the given value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public function write($value, $length = null) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fwrite($this->_fd, $value, $length === null ? strlen($value) : $length); + return $this; + } + + /** + * Writes an 8-bit integer as binary data to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt8($value) + { + return $this->write(pack('c*', $value)); + } + + /** + * Writes an unsigned 8-bit integer as binary data to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt8() + { + return $this->write(pack('C*', $value)); + } + + /** + * Returns signed 16-bit integer as machine endian ordered binary data. + * + * @param integer $value The input value. + * @return string + */ + private function _toInt16($value) + { + return pack('s*', $value); + } + + /** + * Writes a signed 16-bit integer as little-endian ordered binary data to + * the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt16LE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toInt16($value))); + } else { + return $this->write($this->_toInt16($value)); + } + } + + /** + * Returns signed 16-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt16BE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toInt16($value))); + } else { + return $this->write($this->_toInt16($value)); + } + } + + /** + * Writes unsigned 16-bit integer as little-endian ordered binary data + * to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt16LE($value) + { + return $this->write(pack('v*', $value)); + } + + /** + * Writes unsigned 16-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt16BE($value) + { + return $this->write(pack('n*', $value)); + } + + /** + * Returns signed 32-bit integer as machine-endian ordered binary data. + * + * @param integer $value The input value. + * @return string + */ + private final function _toInt32($value) + { + return pack('l*', $value); + } + + /** + * Writes signed 32-bit integer as little-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt32LE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toInt32($value))); + } else { + return $this->write($this->_toInt32($value)); + } + } + + /** + * Writes signed 32-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt32BE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toInt32($value))); + } else { + return $this->write($this->_toInt32($value)); + } + } + + /** + * Writes unsigned 32-bit integer as little-endian ordered binary data to + * the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt32LE($value) + { + return $this->write(pack('V*', $value)); + } + + /** + * Writes unsigned 32-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt32BE($value) + { + return $this->write(pack('N*', $value)); + } + + /** + * Writes 64-bit float as little-endian ordered binary data string to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt64LE($value) + { + return $this->write(pack('V*', $value & 0xffffffff, $value / (0xffffffff+1))); + } + + /** + * Writes 64-bit float as big-endian ordered binary data string to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt64BE($value) + { + return $this->write(pack('N*', $value / (0xffffffff+1), $value & 0xffffffff)); + } + + /** + * Returns a floating point number as machine endian ordered binary data. + * + * @param float $value The input value. + * @return string + */ + private function _toFloat($value) + { + return pack('f*', $value); + } + + /** + * Writes a floating point number as little-endian ordered binary data to + * the stream. + * + * @param float $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeFloatLE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toFloat($value))); + } else { + return $this->write($this->_toFloat($value)); + } + } + + /** + * Writes a floating point number as big-endian ordered binary data to the + * stream. + * + * @param float $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeFloatBE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toFloat($value))); + } else { + return $this->write($this->_toFloat($value)); + } + } + + /** + * Writes string as binary data padded to given length with zeros. If + * length is smaller than the length of the string, it is + * considered as the length of the padding. + * + * @param string $value The input value. + * @param integer $length The length to which to pad the value. + * @param string $padding The padding character. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeString8($value, $length = null, $padding = "\0") + { + if ($length === null) { + $length = strlen($value); + } + if ($length < ($tmp = strlen($value))) { + $length = $tmp + $length; + } + return $this->write(str_pad($value, $length, $padding)); + } + + /** + * Writes the multibyte string as binary data with given byte order mark + * (BOM) and padded to given length with zeros. Length is given in unicode + * characters so each character adds two zeros to the string. If length is + * smaller than the length of the string, it is considered as the length of + * the padding. + * + * If byte order mark is null no mark is inserted to the binary + * data. + * + * @param string $value The input value. + * @param integer $order The byte order of the binary data string. + * @param integer $length The length to which to pad the value. + * @param string $padding The padding character. + * @return string + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeString16 + ($value, $order = null, $length = null, $padding = "\0") + { + if ($length === null) { + $length = (int)(strlen($value) / 2); + } + if ($length < ($tmp = strlen($value) / 2)) { + $length = $tmp + $length; + } + if ($order == self::BIG_ENDIAN_ORDER && + !(ord($value[0]) == 0xfe && ord($value[1]) == 0xff)) { + $value = 0xfeff . $value; + $length++; + } + if ($order == self::LITTLE_ENDIAN_ORDER && + !(ord($value[0]) == 0xff && ord($value[1]) == 0xfe)) { + $value = 0xfffe . $value; + $length++; + } + return $this->write(str_pad($value, $length * 2, $padding)); + } + + /** + * Writes hexadecimal string having high nibble first as binary data to the + * stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if length attribute is negative or + * if the stream is closed + */ + public final function writeHHex($length) + { + return $this->write(pack('H*', $value)); + } + + /** + * Writes hexadecimal string having low nibble first as binary data to the + * stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if length attribute is negative or + * if the stream is closed + */ + public final function writeLHex($length) + { + return $this->write(pack('h*', $value)); + } + + /** + * Writes big-endian ordered hexadecimal GUID string as little-endian + * ordered binary data string to the stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeGuid() + { + $string = ''; + $C = preg_split('/-/', $value); + return $this->write + (pack + ('V1v2N2', hexdec($C[0]), hexdec($C[1]), hexdec($C[2]), + hexdec($C[3] . substr($C[4], 0, 4)), hexdec(substr($C[4], 4)))); + } + + /** + * Forces write of all buffered output to the underlying resource. + * + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function flush() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fflush($this->_fd); + } + + /** + * Closes the stream. Once a stream has been closed, further calls to write + * methods will throw an exception. Closing a previously-closed stream, + * however, has no effect. + * + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function close() + { + if ($this->_fd !== null) { + @fclose($this->_fd); + $this->_fd = null; + } + } + + /** + * Returns the current machine endian order. + * + * @return integer + */ + private function _getEndianess() + { + if (self::$_endianess === 0) { + self::$_endianess = $this->_toInt32("\x01\x00\x00\x00") == 1 ? + self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; + } + return self::$_endianess; + } + + /** + * Returns whether the current machine endian order is little endian. + * + * @return boolean + */ + private function _isLittleEndian() + { + return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; + } + + /** + * Returns whether the current machine endian order is big endian. + * + * @return boolean + */ + private function _isBigEndian() + { + return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func + (array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } +}