def from_bytes(bytes_rep, offset=0): required_size = 1 + 8 if not required_size + offset <= len(bytes_rep): error_msg = 'Byte array too small to hold a float' raise BinsonException(error_msg) float_val, = struct.unpack_from('<d', bytes_rep, offset + 1) return BinsonFloat(float_val), 9
def __get(self, field, expected_type): """ :param field: :param expected_type: :return: """ if field not in self.value: raise BinsonException( 'Binson object does not contain field name "%s"' % field) value = self.value[field] if not isinstance(value, expected_type): raise BinsonException( 'Field name "%s" does not contain expected field' % field) if not isinstance(value, (BinsonArray, BinsonObject)): value = value.get_value() return value
def from_bytes(bytes_rep, offset=0): if not bytes_rep[offset] in BinsonString.identifiers(): error_msg = 'Expected string length identifier' error_msg += ' (0x14, 0x15, 0x16)' error_msg += ' but got {}'.format(bytes_rep[offset]) raise BinsonException(error_msg) bytes_rep, consumed = from_bytes_with_identifier( bytes_rep, offset, bytes_rep[offset] + 0x04) str_val = bytes_rep.decode('utf8') return BinsonString(str_val), consumed
def from_bytes(bytes_rep, offset=0): from pybinson.binson_values import get_parser if not offset < len(bytes_rep): error_msg = 'Byte array too small to hold a binson object.' raise BinsonException(error_msg) orig_offset = offset if not bytes_rep[offset] in BinsonObject.identifiers(): raise BinsonException('Unexpected start of binson object.') offset += 1 dict_rep = {} prev_name = '' length = len(bytes_rep) while offset < length: # End of object if bytes_rep[offset] == 0x41: offset += 1 consumed = offset - orig_offset return pybinson.binson.Binson(dict_rep), consumed # Parse field name (BinsonString) name, consumed = BinsonString.from_bytes(bytes_rep, offset) name = name.get_value() offset += consumed if name <= prev_name: error_msg = 'Fields names not in lexicographical order' error_msg += ' when parsing. Current: {}'.format(name) error_msg += ', previous: {}'.format(prev_name) raise BinsonException(error_msg) if not offset < length: break identifier = bytes_rep[offset] parser = get_parser(identifier) binson_value, consumed = parser(bytes_rep, offset) offset += consumed dict_rep[name] = binson_value prev_name = name # We should never end ep here if it is a valid binson object raise BinsonException('Unexpected end of byte array')
def from_bytes_with_identifier(bytes_rep, offset, forced_identifier): """ :param bytes_rep: :param offset: :param forced_identifier: :return: """ identifier = forced_identifier storage_size = (1 << (identifier & 0x0F)) required_size = 1 + storage_size if not required_size + offset <= len(bytes_rep): raise BinsonException('Byte array too small to hold integer.') unpack = BinsonInteger.UNPACK_VALUES[identifier] int_val, = struct.unpack_from(unpack, bytes_rep, offset + 1) expected_size = BinsonInteger.int_size(int_val) if not expected_size == storage_size: error_msg = 'Expected storage size {}'.format(expected_size) error_msg += ' but got storage size {}.'.format(storage_size) raise BinsonException(error_msg) return BinsonInteger(int_val), required_size
def __init__(self, array=None): from pybinson.binson_values import binsonify_value if not array: array = [] if not isinstance(array, list): error_msg = 'Value of type {}'.format(type(array)) error_msg += ' cannot be represented as binson.' raise BinsonException(error_msg) super(BinsonArray, self).__init__(array) for i in range(0, len(self.value)): self.value[i] = binsonify_value(self.value[i])
def deserialize(bytes_rep, offset=0, check_trailing_garbage=True): """ :param bytes_rep: :param offset: :param check_trailing_garbage: :return: """ binson, consumed = pybinson.binson.Binson.from_bytes(bytes_rep, offset) if check_trailing_garbage: if not offset + consumed == len(bytes_rep): error_msg = 'Detected garbage after object end.' raise BinsonException(error_msg) return binson
def from_bytes_with_identifier(bytes_rep, offset, forced_identifier): """ :param bytes_rep: :param offset: :param forced_identifier: :return: """ identifier = forced_identifier # First we have the length of the byte representation forced_identifier = identifier - 0x08 length, consumed = BinsonInteger.from_bytes_with_identifier( bytes_rep, offset, forced_identifier) length = length.get_value() if not length >= 0: error_msg = 'A byte array cannot have negative length' raise BinsonException(error_msg) required_size = consumed + length if not required_size + offset <= len(bytes_rep): error_msg = 'Buffer too small for specified length' raise BinsonException(error_msg) bytes_val = bytes_rep[offset + consumed:offset + consumed + length] return bytes_val, required_size
def int_size(int_val): """ :param int_val: :return: """ if -2**7 <= int_val < 2**7: return 1 if -2**15 <= int_val < 2**15: return 2 if -2**31 <= int_val < 2**31: return 4 if -2**63 <= int_val < 2**63: return 8 raise BinsonException('Integer too large to fit in 8 bytes.')
def get_parser(identifier): """ :param identifier: :return: """ ret_parser = None for parser in BINSON_VALUES: if identifier in parser.identifiers(): ret_parser = parser.from_bytes break if not ret_parser: error_msg = 'Value 0x%02x' % identifier error_msg += ' is not a valid binson identifier.' raise BinsonException(error_msg) return ret_parser
def binsonify_value(value): """ :param value: :return: """ binson_rep = None if isinstance(value, BinsonValue): binson_rep = value else: for binson_value in BINSON_VALUES: if isinstance(value, binson_value.instances()): binson_rep = binson_value(value) break if not binson_rep: error_msg = 'Value of type {}'.format(type(value)) error_msg += ' cannot be represented as binson.' raise BinsonException(error_msg) return binson_rep
def from_bytes(bytes_rep, offset=0): from pybinson import binson_values orig_offset = offset offset += 1 array = [] while offset < len(bytes_rep): # End array if bytes_rep[offset] == 0x43: offset += 1 consumed = offset - orig_offset return BinsonArray(array), consumed identifier = bytes_rep[offset] parser = binson_values.get_parser(identifier) binson_value, consumed = parser(bytes_rep, offset) array.append(binson_value) offset += consumed raise BinsonException('Unexpected end of byte array')