blob: e8e81b7fa4c19e9b8229a96d8d2cb76436f57b98 [file]
# 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.
"""Input for byte array."""
import struct
class MemorySliceInput:
"""Input for byte array."""
def __init__(self, data: bytes):
self.data = data
self._position = 0
def position(self) -> int:
"""Get current position."""
return self._position
def set_position(self, position: int) -> None:
"""Set current position."""
if position < 0 or position > len(self.data):
raise IndexError(f"Position {position} out of bounds [0, {len(self.data)}]")
self._position = position
def is_readable(self) -> bool:
"""Check if there are more bytes to read."""
return self.available() > 0
def available(self) -> int:
"""Get number of available bytes."""
return len(self.data) - self._position
def read_byte(self) -> int:
"""Read a single byte."""
if self._position >= len(self.data):
raise IndexError("No more bytes available")
value = self.data[self._position]
self._position += 1
return value
def read_unsigned_byte(self) -> int:
"""Read an unsigned byte."""
return self.read_byte() & 0xFF
def read_int(self) -> int:
"""Read a 4-byte integer (big-endian)."""
if self._position + 4 > len(self.data):
raise IndexError("Not enough bytes to read int")
value = struct.unpack('>I', self.data[self._position:self._position + 4])[0]
self._position += 4
return value
def read_var_len_int(self) -> int:
"""Read a variable-length integer."""
result = 0
offset = 0
while offset < 32:
b = self.read_unsigned_byte()
result |= (b & 0x7F) << offset
if (b & 0x80) == 0:
return result
offset += 7
raise ValueError("Malformed integer")
def read_long(self) -> int:
"""Read an 8-byte long (big-endian)."""
if self._position + 8 > len(self.data):
raise IndexError("Not enough bytes to read long")
value = struct.unpack('>Q', self.data[self._position:self._position + 8])[0]
self._position += 8
return value
def read_var_len_long(self) -> int:
"""Read a variable-length long."""
result = 0
offset = 0
while offset < 64:
b = self.read_unsigned_byte()
result |= (b & 0x7F) << offset
if (b & 0x80) == 0:
return result
offset += 7
raise ValueError("Malformed long")
def read_slice(self, length: int) -> bytes:
"""Read a slice of bytes."""
if self._position + length > len(self.data):
raise IndexError(f"Not enough bytes to read slice of length {length}")
value = self.data[self._position:self._position + length]
self._position += length
return value