buffer - Memory buffer manager¶
Overview¶
This module provides a MemoryBuffer class for managing raw memory buffers,
offering a convenient and consistent API for reading and writing various data types
(integers of different sizes, strings with different termination/prefixing styles, raw bytes).
It’s particularly useful for tasks involving binary data serialization/deserialization,
such as implementing network protocols or handling custom file formats.
The underlying memory storage can be customized via a BufferFactory. Two factories
are provided:
BytesBufferFactory: Uses Python’s built-inbytearray.CTypesBufferFactory: Usesctypes.create_string_bufferfor potentially different memory characteristics or C-level interoperability.
Example:
from firebird.base.buffer import MemoryBuffer, ByteOrder
# Create a buffer (default uses bytearray)
buf = MemoryBuffer(10) # Initial size 10 bytes
# Write data
buf.write_short(258) # Write 2 bytes (0x0102 in little-endian)
buf.write_pascal_string("Hi") # Write 1 byte length (2) + "Hi"
buf.write(b'\\x0A\\x0B') # Write raw bytes
# Reset position to read
buf.pos = 0
# Read data
num = buf.read_short()
s = buf.read_pascal_string()
extra = buf.read(2)
print(f"Number: {num}") # Output: Number: 258
print(f"String: '{s}'") # Output: String: 'Hi'
print(f"Extra bytes: {extra}") # Output: Extra bytes: b'\\n\\x0b'
print(f"Final position: {buf.pos}") # Output: Final position: 7
print(f"Raw buffer: {buf.get_raw()}") # Output: Raw buffer: bytearray(b'\\x02\\x01\\x02Hi\\n\\x0b\\x00\\x00\\x00')
MemoryBuffer¶
- class firebird.base.buffer.MemoryBuffer(init: int | bytes, size: int | None = None, *, factory: type[~firebird.base.buffer.BufferFactory] = <class 'firebird.base.buffer.BytesBufferFactory'>, eof_marker: int | None = None, max_size: int | ~firebird.base.types.Sentinel = UNLIMITED, byteorder: ~firebird.base.types.ByteOrder = ByteOrder.LITTLE)[source]¶
Bases:
objectGeneric memory buffer manager.
- Parameters:
init (int | bytes) – Must be an integer which specifies the size of the array, or a
bytesobject which will be used to initialize the array items.size (int | None) – Size of the array. The argument value is used only when
initis abytesobject.factory (type[BufferFactory]) – Factory object used to create/resize the internal memory buffer.
eof_marker (int | None) – Value that indicates the end of data. Could be None.
max_size (int | Sentinel) – If specified, the buffer couldn’t grow beyond specified number of bytes.
byteorder (ByteOrder) – The byte order used to read/write numbers.
- clear() None[source]¶
Fills the buffer with zeros and resets the position in buffer to zero.
- Return type:
None
- get_raw() bytes | bytearray[source]¶
Return the underlying buffer’s content as
bytesorbytearray.Use this method for generic access to the raw buffer content instead of accessing the
rawattribute directly, as the type ofrawcan vary depending on the buffer factory used.
- is_eof() bool[source]¶
Check if the current position is at or past the end of data.
End of data is defined as being beyond the buffer’s current length, or positioned exactly on a byte matching
self.eof_marker(if defined).- Returns:
True if at end-of-data, False otherwise.
- Return type:
- read(size: int = -1) bytes[source]¶
Read specified number of bytes from current position, or all remaining data.
Advances the position by the number of bytes read.
- Parameters:
size (int) – Number of bytes to read. If negative, reads all data from the current position to the end of the buffer (default: -1).
- Returns:
The bytes read.
- Raises:
BufferError – If
sizerequests more bytes than available from the current position.- Return type:
- read_bytes() bytes | bytearray[source]¶
Read content of binary cluster (2 bytes data length followed by data).
- Returns:
The bytes read.
- Raises:
BufferError – If the end of the buffer is reached before end of data.
- Return type:
- read_number(size: int, *, signed=False) int[source]¶
Read a number of
sizebytes from current position usingself.byteorder.Advances the position by
size.- Parameters:
size (int) – The number of bytes representing the number.
signed – Whether to interpret the bytes as a signed integer (default: False).
- Returns:
The integer value read.
- Raises:
BufferError – When
sizeis specified, but there is not enough bytes to read.- Return type:
- read_pascal_string(*, encoding: str = 'ascii', errors: str = 'strict') str[source]¶
Read Pascal string (1 byte length followed by string data).
- Parameters:
- Returns:
The decoded string.
- Raises:
BufferError – If the end of the buffer is reached before end of string.
UnicodeDecodeError – If the read bytes cannot be decoded using
encoding.
- Return type:
- read_sized_int(*, signed: bool = False) int[source]¶
Read number cluster (2 byte length followed by data).
- read_sized_string(*, encoding: str = 'ascii', errors: str = 'strict') str[source]¶
Read sized string (2 byte length followed by data).
- Parameters:
- Returns:
The decoded string.
- Raises:
BufferError – If the end of the buffer is reached before end of string.
UnicodeDecodeError – If the read bytes cannot be decoded using
encoding.
- Return type:
- read_string(*, encoding: str = 'ascii', errors: str = 'strict') str[source]¶
Read bytes until a null terminator (0x00) is found, decode, and return string.
Advances the position past the null terminator.
- Parameters:
- Returns:
The decoded string (excluding the null terminator).
- Raises:
BufferError – If the end of the buffer is reached before a null terminator.
UnicodeDecodeError – If the read bytes cannot be decoded using
encoding.
- Return type:
- resize(size: int) None[source]¶
Resize buffer to the specified length. Content is preserved up to the minimum of the old and new sizes. New space is uninitialized (depends on factory).
- Parameters:
size (int) – The new size in bytes.
- Raises:
BufferError – On attempt to resize beyond
self.max_size.- Return type:
None
- write(data: bytes) None[source]¶
Write raw bytes at the current position and advance position.
Ensures buffer has enough space, resizing if necessary and allowed.
- Parameters:
data (bytes) – The bytes to write.
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_bigint(value: int) None[source]¶
Write 8 byte number (c_ulonglong).
- Parameters:
value (int) – The integer value to write.
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_int(value: int) None[source]¶
Write 4 byte number (c_uint).
- Parameters:
value (int) – The integer value to write.
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_number(value: int, size: int, *, signed: bool = False) None[source]¶
Write number with specified size (in bytes).
- Parameters:
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_pascal_string(value: str, *, encoding: str = 'ascii', errors: str = 'strict') None[source]¶
Write Pascal string (2 byte length followed by data).
- Parameters:
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_short(value: int) None[source]¶
Write 2 byte number (c_ushort).
- Parameters:
value (int) – The integer value to write.
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_sized_string(value: str, *, encoding: str = 'ascii', errors: str = 'strict') None[source]¶
Write sized string (2 byte length followed by data).
- Parameters:
- Raises:
BufferError – If resizing is needed but exceeds
max_size.- Return type:
None
- write_string(value: str, *, encoding: str = 'ascii', errors: str = 'strict') None[source]¶
Encode string, write bytes followed by a null terminator (0x00).
- Parameters:
- Raises:
BufferError – If resizing is needed but exceeds
max_size.UnicodeEncodeError – If
valuecannot be encoded usingencoding.
- Return type:
None
- factory: BufferFactory¶
-
- Type:
Buffer factory instance used by manager [default
Buffer factories¶
- class firebird.base.buffer.BufferFactory(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol defining the interface for creating and managing memory buffers.
Allows
MemoryBufferto work with different underlying buffer types (likebytearrayorctypesarrays).- clear(buffer: Any) None[source]¶
Fill the buffer entirely with null bytes (zeros).
- Argument:
buffer: A memory buffer previously created by this factory’s
create()method.
- Parameters:
buffer (Any) –
- Return type:
None
- create(init_or_size: int | bytes, size: int | None = None) Any[source]¶
Create and return a mutable byte buffer object.
- Parameters:
- Returns:
The created mutable buffer object (e.g.,
bytearray,ctypes.c_char_Array).- Return type:
- get_raw(buffer: Any) bytes | bytearray[source]¶
Return the buffer’s content as a standard
bytesorbytearray.This method is necessary to provide a consistent way to access the raw byte sequence, as the buffer object returned by
createmight be of a different type (e.g.,ctypesarrays have arawattribute).- Argument:
buffer: A memory buffer previously created by this factory’s
create()method.
- class firebird.base.buffer.BytesBufferFactory[source]¶
Bases:
objectBuffer factory using Python’s
bytearrayfor storage.- clear(buffer: bytearray) None[source]¶
Fills the bytearray buffer with zero bytes.
- Parameters:
buffer (bytearray) –
- Return type:
None
- create(init_or_size: int | bytes, size: int | None = None) bytearray[source]¶
This function creates a mutable character buffer. The returned object is a
bytearray.- Parameters:
- Return type:
Important
Although arguments are the same as for
ctypes.create_string_buffer, the behavior is different when new buffer is initialized from bytes:If there are more bytes than specified
size, this function copies onlysizebytes into new buffer. Thecreate_string_bufferraises an excpetion.Unlike
create_string_bufferwhensizeis NOT specified, the buffer is NOT made one item larger than its length so that the last element in the array is a NUL termination character.
- class firebird.base.buffer.CTypesBufferFactory[source]¶
Bases:
objectBuffer factory using
ctypes.create_string_buffer(array of c_char).- clear(buffer: bytearray, init: int = 0) None[source]¶
Fills the ctypes buffer with a specified byte value using
memset.
- create(init_or_size: int | bytes, size: int | None = None) bytearray[source]¶
This function creates a
ctypesmutable character buffer. The returned object is an array ofctypes.c_char.- Parameters:
- Return type:
Important
Although arguments are the same as for
ctypes.create_string_buffer, the behavior is different when new buffer is initialized from bytes:If there are more bytes than specified
size, this function copies onlysizebytes into new buffer. Thecreate_string_bufferraises an excpetion.Unlike
create_string_bufferwhensizeis NOT specified, the buffer is NOT made one item larger than its length so that the last element in the array is a NUL termination character.