"""Little-endian .NET BinaryReader/BinaryWriter helpers.""" from __future__ import annotations import struct from typing import BinaryIO def read_7bit_int(stream: BinaryIO) -> int: value = 0 shift = 0 while True: raw = stream.read(1) if not raw: raise EOFError("truncated .NET 7-bit int") value |= (raw[0] & 0x7F) << shift if not raw[0] & 0x80: return value shift += 7 if shift > 35: raise ValueError("invalid .NET 7-bit int") def write_7bit_int(stream: BinaryIO, value: int) -> None: if value < 0: raise ValueError("7-bit int must be non-negative") while value >= 0x80: stream.write(bytes([(value & 0x7F) | 0x80])) value >>= 7 stream.write(bytes([value & 0x7F])) def read_dotnet_string(stream: BinaryIO) -> str: length = read_7bit_int(stream) raw = stream.read(length) if len(raw) != length: raise EOFError("truncated .NET string") return raw.decode("utf-8") def write_dotnet_string(stream: BinaryIO, text: str) -> None: raw = text.encode("utf-8") write_7bit_int(stream, len(raw)) stream.write(raw) def read_i32(stream: BinaryIO) -> int: raw = stream.read(4) if len(raw) != 4: raise EOFError("truncated int32") return struct.unpack(" int: raw = stream.read(8) if len(raw) != 8: raise EOFError("truncated int64") return struct.unpack(" bool: raw = stream.read(1) if not raw: raise EOFError("truncated bool") return raw[0] != 0 def write_bool(stream: BinaryIO, value: bool) -> None: stream.write(b"\x01" if value else b"\x00")