Source code for mcap.data_stream
import struct
import zlib
from typing import IO, Optional, Union
from .exceptions import EndOfFile
from .opcode import Opcode
_U8 = struct.Struct("<B")
_U16 = struct.Struct("<H")
_U32 = struct.Struct("<I")
_U64 = struct.Struct("<Q")
_RECORD_PREFIX = struct.Struct("<BQ")
[docs]
class ReadDataStream:
def __init__(self, stream: IO[bytes], calculate_crc: bool = False):
self._count = 0
self._stream = stream
self._crc: Optional[int] = None
if calculate_crc:
self._crc = 0
@property
def count(self) -> int:
return self._count
[docs]
def read(self, length: int) -> bytes:
if length == 0:
return b""
data = self._stream.read(length)
self._count += len(data)
if self._crc is not None:
self._crc = zlib.crc32(data, self._crc)
if data == b"":
raise EndOfFile()
return data
[docs]
def checksum(self) -> int:
if self._crc is not None:
return self._crc
else:
raise RuntimeError("requested checksum where calculate_crc == false")
[docs]
def read1(self) -> int:
return _U8.unpack(self.read(1))[0]
[docs]
def read2(self) -> int:
return _U16.unpack(self.read(2))[0]
[docs]
def read4(self) -> int:
return _U32.unpack(self.read(4))[0]
[docs]
def read8(self) -> int:
return _U64.unpack(self.read(8))[0]
[docs]
def read_prefixed_string(self) -> str:
length = self.read4()
return str(self.read(length), "utf-8")
[docs]
class RecordBuilder:
"""Accumulates serialized records in a bytearray: appends are amortized O(1) and
a record's length is patched in with a slice assignment.
"""
def __init__(self) -> None:
self.buffer = bytearray()
self._record_start_offset = 0
@property
def count(self) -> int:
return len(self.buffer)
[docs]
def start_record(self, opcode: Opcode):
self._record_start_offset = len(self.buffer)
self.buffer += _RECORD_PREFIX.pack(opcode, 0) # placeholder size
[docs]
def finish_record(self):
start = self._record_start_offset
length = len(self.buffer) - start - 9
self.buffer[start + 1 : start + 9] = _U64.pack(length)
[docs]
def end(self) -> bytearray:
"""Hands over the buffer and starts a new one."""
buf = self.buffer
self.buffer = bytearray()
return buf
[docs]
def write(self, data: Union[bytes, bytearray, memoryview]):
self.buffer += data
[docs]
def write_prefixed_string(self, value: str):
bytes = value.encode()
self.write4(len(bytes))
self.buffer += bytes
[docs]
def write1(self, value: int):
self.buffer += _U8.pack(value)
[docs]
def write2(self, value: int):
self.buffer += _U16.pack(value)
[docs]
def write4(self, value: int):
self.buffer += _U32.pack(value)
[docs]
def write8(self, value: int):
self.buffer += _U64.pack(value)