# pycsla-binary: Python implementation of CSLA .NET binary serialisation # Copyright (C) 2025 Lee Yingtong Li (RunasSudo) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import io import struct from typing import List from .known_types import CslaKnownTypes from .serialization_info import SerializationInfo class CslaBinaryWriter: """Writes SerializationInfo objects into binary-serialised CSLA data""" @classmethod def write_to_bytes(cls, serialisation_infos: List[SerializationInfo]) -> bytes: stream = io.BytesIO() writer = cls(stream) writer.write(serialisation_infos) return stream.getvalue() # -------------- # Implementation def __init__(self, stream: io.BufferedIOBase): self.stream = stream self.keywords_dictionary = [] def write(self, serialisation_infos: List[SerializationInfo]): # Reverse of CslaBinaryReader.Read self.write_int32(len(serialisation_infos)) for info in serialisation_infos: # Write ReferenceID self.write_int32(info.reference_id) # Write TypeName self.write_object_system_string(info.type_name) # Write children self.write_int32(len(info.children)) for child in info.children: self.write_object_system_string(child.name) self.write_object_bool(child.is_dirty) self.write_object_int32(child.reference_id) # Write field values self.write_int32(len(info.values)) for value in info.values: self.write_object_system_string(value.name) self.write_object_system_string(value.enum_type_name or '') self.write_object_bool(value.is_dirty) self.write_object(value.value) def write_7bit_encoded_int(self, value): # BinaryWriter.Write7BitEncodedInt # "The integer of the value parameter is written out seven bits at a time, starting with the seven least-significant bits. The high bit of a byte indicates whether there are more bytes to be written after this one." while True: value_7lsb = value & 0b01111111 value >>= 7 if value == 0: # Final byte self.stream.write(bytes([value_7lsb])) return else: # Further bytes remaining self.stream.write(bytes([value_7lsb | 0b10000000])) def write_int32(self, value): # BinaryWriter.WriteInt32 self.stream.write(struct.pack('