def deserialize(cls, stream: BitStreamReader): """Deserialize metadata extension""" retval = {} while stream.bytesLeft(): metadataType = stream.bits(7) _critical = stream.bit() length = stream.byte() retval[metadataType] = stream.value(length) return retval
def parse_queueHandle(stream: BitStreamReader): # pylint: disable=invalid-name """Parse queueHandle from raw bitstream""" # According to the docs queueHandle should be an uint8_t value # just like the other similar messages. But for unknown reason zipgateway # sends this like an ipv6 address (at least version 7.11.01) print("Node failing", stream.remaining(advance=False)) if stream.bytesLeft() == 16: stream.advance(8 * 15) return stream.byte()
def deserialize(cls, stream: BitStreamReader): """Deserialize header extension from stream""" retval = {} extLength = stream.byte() - 1 reader = BitStreamReader(stream.value(extLength)) while reader.bytesLeft() > 0: option = ZIPPacketOption() option.parseAttributes(reader) retval[option.optionType] = option.optionData return retval
def deserialize(cls, stream: BitStreamReader): """Deserialize ZIP Maintenance Report""" retval = {} while stream.bytesLeft(): imeType = IMEType(stream.byte()) length = stream.byte() imeVal = stream.value(length) typeCls = IME_MAPPING.get(imeType, IMEUnknownValue) retval[imeType] = typeCls.load(BitStreamReader(imeVal)) return retval
def parse_commandClass(stream: BitStreamReader): # pylint: disable=invalid-name """Parse attribute commandClass""" retval = [] length = stream.byte() i = 0 while i < length: commandClass = stream.byte() # TODO: Handle command classes with 2 bytes command = stream.byte() retval.append([commandClass, command]) i += 2 return retval
def test_dsk_t_invalid_data(): dsk = dsk_t() dsk.__setstate__("12345-67890") assert dsk._dsk == b"" with pytest.raises(EOFError): dsk.deserialize( BitStreamReader(b"\x0f~Mp\x22\xf1\xd9\xb4\xa9\xa8\x13")) with pytest.raises(ValueError): dsk_t().__setstate__(b"12345-67890") with pytest.raises(ValueError): dsk_t.deserializeN( BitStreamReader(b"\x0f~Mp\x22\xf1\xd9\xb4\xa9\xa8\x13"), 8)
def deserialize(stream: BitStreamReader): """Deserialize a bitstream into a Message object""" if stream.bytesLeft() < 2: return UnknownMessage(0x0000) cmdClass = stream.byte() cmd = stream.byte() hid = cmdClass << 8 | (cmd & 0xFF) MsgCls = ZWaveMessage.get(hid, None) # pylint: disable=invalid-name if MsgCls: msg = MsgCls() msg.parseAttributes(stream) else: msg = UnknownMessage(hid) return msg
def test_dsk_t(): DSK = "32333-28706-61913-46249-43027-54794-27762-42208" rawDSK = b"~Mp\x22\xf1\xd9\xb4\xa9\xa8\x13\xd6\nlr\xa4\xe0" dsk = dsk_t() dsk.__setstate__(DSK) assert dsk._dsk == rawDSK assert dsk.__getstate__() == DSK assert repr(dsk) == DSK writer = BitStreamWriter() dsk.serialize(writer) assert writer == rawDSK reader = BitStreamReader(rawDSK) assert dsk_t.deserialize(reader) == rawDSK reader = BitStreamReader(rawDSK) assert dsk_t.deserializeN(reader, 0) == b""
def parse_optionData(self, stream: BitStreamReader): # pylint: disable=invalid-name """Parse attribute optionData""" clsType = ZIPPacketOptionData length = stream.byte() data = stream.value(length) if self.optionType == ZIPPacketOptionType.MAINTENANCE_REPORT: clsType = ZIPPacketOptionMaintenanceReport elif self.optionType == ZIPPacketOptionType.ENCAPSULATION_FORMAT_INFORMATION: clsType = ZIPPacketOptionEncapsulationFormatInfo elif self.optionType == ZIPPacketOptionType.EXPECTED_DELAY: clsType = ZIPPacketOptionExpectedDelay cls = clsType() if hasattr(cls, "parseAttributes"): cls.parseAttributes(BitStreamReader(data)) elif hasattr(cls, "__setstate__"): data = clsType.deserialize(BitStreamReader(data)) cls.__setstate__(data) else: value = clsType.deserialize(BitStreamReader(data)) return clsType(value) return cls
def deserialize(cls, stream: BitStreamReader): """Deserialize types from stream""" supported = cls() value = int.from_bytes(stream.remaining(), byteorder="big", signed=False) i = 1 while value > 0: if value & 1 == 1: supported.add(SensorType(i)) value >>= 1 i += 1 return supported
def parseAttributes(self, stream: BitStreamReader): """Populate the attributes from a raw bitstream.""" for attr in self.attributes: if stream.bytesLeft() == 0: # No more data, cannot decode rest of the attributes break attrName, attrType = attr[0], attr[1] deserializer = getattr(self, "parse_{}".format(attrName), None) if deserializer: value = deserializer(stream) else: value = attrType.deserialize(stream) # This can be optimized to reduce the second loop in __setattr__ setattr(self, attrName, value)
def deserialize(cls, stream: BitStreamReader): """Deserialize nodes from association report.""" data = stream.remaining() nodes = [] while data: node = data[0] data = data[1:] if node == MULTI_CHANNEL_ASSOCIATION_SET_MARKER_V2: break nodes.append((node, None)) while data: node = data[0] endpoint = data[1] nodes.append((node, endpoint)) data = data[2:] return nodes
def test_uint5_t(streamReader: BitStreamReader): assert uint5_t.deserialize(streamReader) == 0 streamReader.advance(3) assert uint5_t.deserialize(streamReader) == 0 streamReader.advance(3) assert uint5_t.deserialize(streamReader) == 0x19 streamReader.advance(3) assert uint5_t.deserialize(streamReader) == 0x08 streamWriter = BitStreamWriter() uint5_t(20).serialize(streamWriter) assert streamWriter == b"\xa0"
def test_IPv6_t(): # pylint: disable=line-too-long pkt = b"X\x01\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\xa8\x00\xee\xea\xec\xfa\xf9" stream = BitStreamReader(pkt) assert stream.byte() == 88 assert stream.byte() == 1 assert stream.bits(5) == 0 assert stream.bit() == 0 assert stream.bits(2) == 0 assert stream.byte() == 6 ipv6 = IPv6.deserialize(stream) assert ipv6 == ipaddress.ip_address("::ffff:c0a8:ee") streamWriter = BitStreamWriter() ipv6.serialize(streamWriter) assert ( streamWriter == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\xa8\x00\xee")
def streamReader(): return BitStreamReader(b"\x02\x01\xCB\x40")
def test_str_t(): stream = BitStreamReader(b"\x0BHello World") assert str_t.deserialize(stream) == "Hello World"
def test_HomeID(): homeID = HomeID.deserialize(BitStreamReader(b"\xea\xec\xfa\xf9")) assert str(homeID) == "EAECFAF9"
def test_float_t_values(raw, expected): reader = BitStreamReader(raw) value = float_t.deserialize(reader) assert value == expected
def test_zip_packet_ima(header, includedReport): data = Zip.HeaderExtension.deserialize(BitStreamReader(header)) hdr = Zip.HeaderExtension() hdr.__setstate__(data) assert hdr.get(includedReport)
def parse_command(stream: BitStreamReader): # pylint: disable=invalid-name """Parse the length prefixed command""" length = stream.byte() return Message.decode(stream.value(length))
def test_nodes_deserialize(): reader = BitStreamReader(bytes([1, 0, 2, 0])) nodes = Association.Nodes.deserialize(reader) assert nodes == [(1, None), (2, 0)]
def parse_commandClass(self, stream: BitStreamReader): # pylint: disable=invalid-name """Parse the length prefixed command""" length = self.nodeInfoLength - 7 if length > stream.bytesLeft(): return list(stream.remaining()) return list(stream.value(length))
def parse_value(self, stream: BitStreamReader): # pylint: disable=invalid-name """Decode the value from the report""" return int.from_bytes(stream.value(self.size), "big", signed=False)
def test_BitStreamReader_eof(streamReader: BitStreamReader): streamReader.remaining() assert streamReader.bytesLeft() == 0 with pytest.raises(EOFError): streamReader.byte()
def test_attributes_parseAttributes(): pkt = b"\x01\x02" attributable = AnotherAttributable() attributable.parseAttributes(BitStreamReader(pkt)) assert attributable.foo == 1 assert attributable.bar == 2
def test_BitStreamReader_remaining(streamReader: BitStreamReader): assert streamReader.remaining(advance=False) == b"\x02\x01\xcb@" assert streamReader.value(1) == b"\x02" assert streamReader.remaining() == b"\x01\xcb@"
def decode(cls, pkt: bytearray): """Decode a raw bytearray into a Message object""" return cls.deserialize(BitStreamReader(pkt))