Skip to content

Commit e2c2245

Browse files
committed
Adapt init consume str
1 parent 5a148a0 commit e2c2245

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

custom_components/dmx/client/__init__.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,44 @@ def _append_str(packet: bytearray, text: str, length: int):
448448
packet.extend(map(ord, padded_text))
449449

450450
@staticmethod
451-
def _consume_str(packet: bytearray, index: int, length: int) -> (str, int):
452-
str_bytes = str(packet[index:index + length - 1], "ASCII")
453-
string = str_bytes.split('\0')[0]
454-
return string, index + length
451+
def _consume_str(packet: bytearray, index: int, length: int) -> (Optional[str], int):
452+
decoded_str: Optional[str] = None
453+
raw_string_from_packet = packet[index:index + length]
454+
455+
# assume the data is ascii
456+
try:
457+
# if there is a NUL character in the bytearry, it terminates earlier
458+
nul_terminator = re.compile(b"([^\\x00]+)")
459+
460+
terminated_string = nul_terminator.match(raw_string_from_packet).group(1) \
461+
if nul_terminator.match(raw_string_from_packet) else raw_string_from_packet
462+
463+
# remove every other control character
464+
sanitized_str = re.sub(b"[^\x00-\x7F]",b"", terminated_string)
465+
466+
# decode
467+
decoded_str = sanitized_str.decode('ascii')
468+
469+
except UnicodeDecodeError:
470+
# data not ascii, try to use the decoding shotgun
471+
decoded_str = ArtBase._decode_bytes(raw_string_from_packet)
472+
473+
# check if decoding has failed
474+
if decoded_str is None:
475+
log.error("Unable to convert bytes to string: {raw_hex}".format(raw_hex=bytes(raw_string_from_packet).hex()))
476+
477+
return decoded_str, index + length
478+
479+
@staticmethod
480+
def _decode_bytes(byte_str: bytearray) -> Optional[str]:
481+
for encoding in ArtBase.__ENCODINGS__:
482+
try:
483+
decoded_str = byte_str.decode(encoding)
484+
sanitized_str = str(decoded_str).strip().strip('\x00')
485+
log.debug(f"decoded as {encoding}: {sanitized_str}")
486+
return sanitized_str
487+
except UnicodeDecodeError as e:
488+
log.warning(f"failed ({e.reason}) to decode as {encoding}: {bytes(byte_str).hex()}")
455489

456490
@staticmethod
457491
def peek_opcode(packet: bytearray) -> OpCode | None:

0 commit comments

Comments
 (0)