1<?php 2 3/** 4 * This file contains the BinaryReader class. 5 * For more information see the class description below. 6 * 7 * @author Peter Bathory <peter.bathory@cartographia.hu> 8 * @since 2016-02-18 9 * 10 * This code is open-source and licenced under the Modified BSD License. 11 * For the full copyright and license information, please view the LICENSE 12 * file that was distributed with this source code. 13 */ 14 15namespace geoPHP\Adapter; 16 17/** 18 * Helper class BinaryReader 19 * 20 * A simple binary reader supporting both byte orders 21 */ 22class BinaryReader 23{ 24 25 const BIG_ENDIAN = 0; 26 const LITTLE_ENDIAN = 1; 27 28 private $buffer; 29 30 private $endianness = 0; 31 32 /** 33 * BinaryReader constructor. 34 * Opens a memory buffer with the given input 35 * 36 * @param string $input 37 */ 38 public function __construct($input) 39 { 40// if (@is_readable($input)) { 41// $this->buffer = fopen($input, 'r+'); 42// } else { 43 $this->buffer = fopen('php://memory', 'x+'); 44 fwrite($this->buffer, (string) $input); 45 fseek($this->buffer, 0); 46// } 47 } 48 49 /** 50 * Closes the memory buffer 51 */ 52 public function close() 53 { 54 fclose($this->buffer); 55 } 56 57 /** 58 * @param int $endian self::BIG_ENDIAN or self::LITTLE_ENDIAN 59 */ 60 public function setEndianness($endian) 61 { 62 $this->endianness = $endian === self::BIG_ENDIAN ? self::BIG_ENDIAN : self::LITTLE_ENDIAN; 63 } 64 65 /** 66 * @return int Returns 0 if reader is in BigEndian mode or 1 if in LittleEndian mode 67 */ 68 public function getEndianness() 69 { 70 return $this->endianness; 71 } 72 73 /** 74 * Reads a signed 8-bit integer from the buffer 75 * @return int|null 76 */ 77 public function readSInt8() 78 { 79 $char = fread($this->buffer, 1); 80 return $char !== '' ? current(unpack("c", $char)) : null; 81 } 82 83 /** 84 * Reads an unsigned 8-bit integer from the buffer 85 * @return int|null 86 */ 87 public function readUInt8() 88 { 89 $char = fread($this->buffer, 1); 90 return $char !== '' ? current(unpack("C", $char)) : null; 91 } 92 93 /** 94 * Reads an unsigned 32-bit integer from the buffer 95 * @return int|null 96 */ 97 public function readUInt32() 98 { 99 $int32 = fread($this->buffer, 4); 100 return $int32 !== '' ? current(unpack($this->endianness == self::LITTLE_ENDIAN ? 'V' : 'N', $int32)) : null; 101 } 102 103 /** 104 * Reads one or more double values from the buffer 105 * @param int $length How many double values to read. Default is 1 106 * @return float[] 107 */ 108 public function readDoubles($length = 1) 109 { 110 $bin = fread($this->buffer, $length); 111 return $this->endianness == self::LITTLE_ENDIAN 112 ? array_values(unpack("d*", $bin)) 113 : array_reverse(unpack("d*", strrev($bin))); 114 } 115 116 /** 117 * Reads an unsigned base-128 varint from the buffer 118 * 119 * Ported from https://github.com/cschwarz/wkx/blob/master/lib/binaryreader.js 120 * 121 * @return int 122 */ 123 public function readUVarInt() 124 { 125 $result = 0; 126 $bytesRead = 0; 127 128 do { 129 $nextByte = $this->readUInt8(); 130 $result += ($nextByte & 0x7F) << (7 * $bytesRead); 131 $bytesRead++; 132 } while ($nextByte >= 0x80); 133 return $result; 134 } 135 136 /** 137 * Reads a signed base-128 varint from the buffer 138 * 139 * @return int 140 */ 141 public function readSVarInt() 142 { 143 return self::zigZagDecode($this->readUVarInt()); 144 } 145 146 /** 147 * ZigZag decoding maps unsigned integers to signed integers 148 * 149 * @param int $value Encrypted positive integer value 150 * @return int Decoded signed integer 151 */ 152 public static function zigZagDecode($value) 153 { 154 return ($value & 1) === 0 ? $value >> 1 : -($value >> 1) - 1; 155 } 156} 157