diff options
Diffstat (limited to 'vendor/wikimedia/avro/lib/avro/io.php')
-rw-r--r-- | vendor/wikimedia/avro/lib/avro/io.php | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/vendor/wikimedia/avro/lib/avro/io.php b/vendor/wikimedia/avro/lib/avro/io.php new file mode 100644 index 00000000..239e53d8 --- /dev/null +++ b/vendor/wikimedia/avro/lib/avro/io.php @@ -0,0 +1,494 @@ +<?php +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Avro IO object classes + * @package Avro + */ + +/** + * Exceptions associated with AvroIO instances. + * @package Avro + */ +class AvroIOException extends AvroException {} + +/** + * Barebones IO base class to provide common interface for file and string + * access within the Avro classes. + * + * @package Avro + */ +class AvroIO +{ + + /** + * @var string general read mode + */ + const READ_MODE = 'r'; + /** + * @var string general write mode. + */ + const WRITE_MODE = 'w'; + + /** + * @var int set position equal to $offset bytes + */ + const SEEK_CUR = SEEK_CUR; + /** + * @var int set position to current index + $offset bytes + */ + const SEEK_SET = SEEK_SET; + /** + * @var int set position to end of file + $offset bytes + */ + const SEEK_END = SEEK_END; + + /** + * Read $len bytes from AvroIO instance + * @var int $len + * @return string bytes read + */ + public function read($len) + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Append bytes to this buffer. (Nothing more is needed to support Avro.) + * @param str $arg bytes to write + * @returns int count of bytes written. + * @throws AvroIOException if $args is not a string value. + */ + public function write($arg) + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Return byte offset within AvroIO instance + * @return int + */ + public function tell() + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Set the position indicator. The new position, measured in bytes + * from the beginning of the file, is obtained by adding $offset to + * the position specified by $whence. + * + * @param int $offset + * @param int $whence one of AvroIO::SEEK_SET, AvroIO::SEEK_CUR, + * or Avro::SEEK_END + * @returns boolean true + * + * @throws AvroIOException + */ + public function seek($offset, $whence=self::SEEK_SET) + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Flushes any buffered data to the AvroIO object. + * @returns boolean true upon success. + */ + public function flush() + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Returns whether or not the current position at the end of this AvroIO + * instance. + * + * Note is_eof() is <b>not</b> like eof in C or feof in PHP: + * it returns TRUE if the *next* read would be end of file, + * rather than if the *most recent* read read end of file. + * @returns boolean true if at the end of file, and false otherwise + */ + public function is_eof() + { + throw new AvroNotImplementedException('Not implemented'); + } + + /** + * Closes this AvroIO instance. + */ + public function close() + { + throw new AvroNotImplementedException('Not implemented'); + } + +} + +/** + * AvroIO wrapper for string access + * @package Avro + */ +class AvroStringIO extends AvroIO +{ + /** + * @var string + */ + private $string_buffer; + /** + * @var int current position in string + */ + private $current_index; + /** + * @var boolean whether or not the string is closed. + */ + private $is_closed; + + /** + * @param string $str initial value of AvroStringIO buffer. Regardless + * of the initial value, the pointer is set to the + * beginning of the buffer. + * @throws AvroIOException if a non-string value is passed as $str + */ + public function __construct($str = '') + { + $this->is_closed = false; + $this->string_buffer = ''; + $this->current_index = 0; + + if (is_string($str)) + $this->string_buffer .= $str; + else + throw new AvroIOException( + sprintf('constructor argument must be a string: %s', gettype($str))); + } + + /** + * Append bytes to this buffer. + * (Nothing more is needed to support Avro.) + * @param str $arg bytes to write + * @returns int count of bytes written. + * @throws AvroIOException if $args is not a string value. + */ + public function write($arg) + { + $this->check_closed(); + if (is_string($arg)) + return $this->append_str($arg); + throw new AvroIOException( + sprintf('write argument must be a string: (%s) %s', + gettype($arg), var_export($arg, true))); + } + + /** + * @returns string bytes read from buffer + * @todo test for fencepost errors wrt updating current_index + */ + public function read($len) + { + $this->check_closed(); + $read=''; + for($i=$this->current_index; $i<($this->current_index+$len); $i++) + $read .= $this->string_buffer[$i]; + if (strlen($read) < $len) + $this->current_index = $this->length(); + else + $this->current_index += $len; + return $read; + } + + /** + * @returns boolean true if successful + * @throws AvroIOException if the seek failed. + */ + public function seek($offset, $whence=self::SEEK_SET) + { + if (!is_int($offset)) + throw new AvroIOException('Seek offset must be an integer.'); + // Prevent seeking before BOF + switch ($whence) + { + case self::SEEK_SET: + if (0 > $offset) + throw new AvroIOException('Cannot seek before beginning of file.'); + $this->current_index = $offset; + break; + case self::SEEK_CUR: + if (0 > $this->current_index + $whence) + throw new AvroIOException('Cannot seek before beginning of file.'); + $this->current_index += $offset; + break; + case self::SEEK_END: + if (0 > $this->length() + $offset) + throw new AvroIOException('Cannot seek before beginning of file.'); + $this->current_index = $this->length() + $offset; + break; + default: + throw new AvroIOException(sprintf('Invalid seek whence %d', $whence)); + } + + return true; + } + + /** + * @returns int + * @see AvroIO::tell() + */ + public function tell() { return $this->current_index; } + + /** + * @returns boolean + * @see AvroIO::is_eof() + */ + public function is_eof() + { + return ($this->current_index >= $this->length()); + } + + /** + * No-op provided for compatibility with AvroIO interface. + * @returns boolean true + */ + public function flush() { return true; } + + /** + * Marks this buffer as closed. + * @returns boolean true + */ + public function close() + { + $this->check_closed(); + $this->is_closed = true; + return true; + } + + /** + * @throws AvroIOException if the buffer is closed. + */ + private function check_closed() + { + if ($this->is_closed()) + throw new AvroIOException('Buffer is closed'); + } + + /** + * Appends bytes to this buffer. + * @param string $str + * @returns integer count of bytes written. + */ + private function append_str($str) + { + $this->check_closed(); + $this->string_buffer .= $str; + $len = strlen($str); + $this->current_index += $len; + return $len; + } + + /** + * Truncates the truncate buffer to 0 bytes and returns the pointer + * to the beginning of the buffer. + * @returns boolean true + */ + public function truncate() + { + $this->check_closed(); + $this->string_buffer = ''; + $this->current_index = 0; + return true; + } + + /** + * @returns int count of bytes in the buffer + * @internal Could probably memoize length for performance, but + * no need do this yet. + */ + public function length() { return strlen($this->string_buffer); } + + /** + * @returns string + */ + public function __toString() { return $this->string_buffer; } + + + /** + * @returns string + * @uses self::__toString() + */ + public function string() { return $this->__toString(); } + + /** + * @returns boolean true if this buffer is closed and false + * otherwise. + */ + public function is_closed() { return $this->is_closed; } +} + +/** + * AvroIO wrapper for PHP file access functions + * @package Avro + */ +class AvroFile extends AvroIO +{ + /** + * @var string fopen read mode value. Used internally. + */ + const FOPEN_READ_MODE = 'rb'; + + /** + * @var string fopen write mode value. Used internally. + */ + const FOPEN_WRITE_MODE = 'wb'; + + /** + * @var string + */ + private $file_path; + + /** + * @var resource file handle for AvroFile instance + */ + private $file_handle; + + public function __construct($file_path, $mode = self::READ_MODE) + { + /** + * XXX: should we check for file existence (in case of reading) + * or anything else about the provided file_path argument? + */ + $this->file_path = $file_path; + switch ($mode) + { + case self::WRITE_MODE: + $this->file_handle = fopen($this->file_path, self::FOPEN_WRITE_MODE); + if (false == $this->file_handle) + throw new AvroIOException('Could not open file for writing'); + break; + case self::READ_MODE: + $this->file_handle = fopen($this->file_path, self::FOPEN_READ_MODE); + if (false == $this->file_handle) + throw new AvroIOException('Could not open file for reading'); + break; + default: + throw new AvroIOException( + sprintf("Only modes '%s' and '%s' allowed. You provided '%s'.", + self::READ_MODE, self::WRITE_MODE, $mode)); + } + } + + /** + * @returns int count of bytes written + * @throws AvroIOException if write failed. + */ + public function write($str) + { + $len = fwrite($this->file_handle, $str); + if (false === $len) + throw new AvroIOException(sprintf('Could not write to file')); + return $len; + } + + /** + * @param int $len count of bytes to read. + * @returns string bytes read + * @throws AvroIOException if length value is negative or if the read failed + */ + public function read($len) + { + if (0 > $len) + throw new AvroIOException( + sprintf("Invalid length value passed to read: %d", $len)); + + if (0 == $len) + return ''; + + $bytes = fread($this->file_handle, $len); + if (false === $bytes) + throw new AvroIOException('Could not read from file'); + return $bytes; + } + + /** + * @returns int current position within the file + * @throws AvroFileExcpetion if tell failed. + */ + public function tell() + { + $position = ftell($this->file_handle); + if (false === $position) + throw new AvroIOException('Could not execute tell on reader'); + return $position; + } + + /** + * @param int $offset + * @param int $whence + * @returns boolean true upon success + * @throws AvroIOException if seek failed. + * @see AvroIO::seek() + */ + public function seek($offset, $whence = SEEK_SET) + { + $res = fseek($this->file_handle, $offset, $whence); + // Note: does not catch seeking beyond end of file + if (-1 === $res) + throw new AvroIOException( + sprintf("Could not execute seek (offset = %d, whence = %d)", + $offset, $whence)); + return true; + } + + /** + * Closes the file. + * @returns boolean true if successful. + * @throws AvroIOException if there was an error closing the file. + */ + public function close() + { + $res = fclose($this->file_handle); + if (false === $res) + throw new AvroIOException('Error closing file.'); + return $res; + } + + /** + * @returns boolean true if the pointer is at the end of the file, + * and false otherwise. + * @see AvroIO::is_eof() as behavior differs from feof() + */ + public function is_eof() + { + $this->read(1); + if (feof($this->file_handle)) + return true; + $this->seek(-1, self::SEEK_CUR); + return false; + } + + /** + * @returns boolean true if the flush was successful. + * @throws AvroIOException if there was an error flushing the file. + */ + public function flush() + { + $res = fflush($this->file_handle); + if (false === $res) + throw new AvroIOException('Could not flush file.'); + return true; + } + +} |