lang/php/lib/IO/AvroStringIO.php (134 lines of code) (raw):

<?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 * * https://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. */ namespace Apache\Avro\IO; use Apache\Avro\AvroIO; /** * 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 string $arg bytes to write * @returns int count of bytes written. * @throws AvroIOException if $args is not a string value. */ public function write($arg) { $this->checkClosed(); if (is_string($arg)) { return $this->appendStr($arg); } throw new AvroIOException( sprintf( 'write argument must be a string: (%s) %s', gettype($arg), var_export($arg, true) ) ); } /** * @throws AvroIOException if the buffer is closed. */ private function checkClosed() { if ($this->isClosed()) { throw new AvroIOException('Buffer is closed'); } } /** * @returns boolean true if this buffer is closed and false * otherwise. */ public function isClosed() { return $this->is_closed; } /** * Appends bytes to this buffer. * @param string $str * @returns integer count of bytes written. */ private function appendStr($str) { $this->checkClosed(); $this->string_buffer .= $str; $len = strlen($str); $this->current_index += $len; return $len; } /** * @returns string bytes read from buffer * @todo test for fencepost errors wrt updating current_index */ public function read($len) { $this->checkClosed(); $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 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 boolean true if successful * @throws AvroIOException if the seek failed. */ public function seek($offset, $whence = self::SEEK_SET): bool { 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::isEof() */ public function isEof() { 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->checkClosed(); $this->is_closed = true; return true; } /** * Truncates the truncate buffer to 0 bytes and returns the pointer * to the beginning of the buffer. * @returns boolean true */ public function truncate() { $this->checkClosed(); $this->string_buffer = ''; $this->current_index = 0; return true; } /** * @returns string * @uses self::__toString() */ public function string() { return (string) $this; } /** * @returns string */ public function __toString() { return $this->string_buffer; } }