blob: 5b35e8eeaa0a7003c1443cc1cd68e7a807b3f876 [file] [log] [blame]
Chris Liechtic0c660a2015-08-25 00:55:51 +02001"""\
2Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
3"""
4
5import codecs
6import serial
7
8HEXDIGITS = '0123456789ABCDEF'
9
10### Codec APIs
11
Chris Liechti033f17c2015-08-30 21:28:04 +020012
Chris Liechtic0c660a2015-08-25 00:55:51 +020013def hex_encode(input, errors='strict'):
14 return (serial.to_bytes([int(h, 16) for h in input.split()]), len(input))
15
Chris Liechti033f17c2015-08-30 21:28:04 +020016
Chris Liechtic0c660a2015-08-25 00:55:51 +020017def hex_decode(input, errors='strict'):
18 return (''.join('{:02X} '.format(b) for b in input), len(input))
19
Chris Liechti033f17c2015-08-30 21:28:04 +020020
Chris Liechtic0c660a2015-08-25 00:55:51 +020021class Codec(codecs.Codec):
22 def encode(self, input, errors='strict'):
23 return serial.to_bytes([int(h, 16) for h in input.split()])
Chris Liechti033f17c2015-08-30 21:28:04 +020024
Chris Liechtic0c660a2015-08-25 00:55:51 +020025 def decode(self, input, errors='strict'):
26 return ''.join('{:02X} '.format(b) for b in input)
27
Chris Liechti033f17c2015-08-30 21:28:04 +020028
Chris Liechtic0c660a2015-08-25 00:55:51 +020029class IncrementalEncoder(codecs.IncrementalEncoder):
30
31 def __init__(self, errors='strict'):
32 self.errors = errors
33 self.state = 0
34
35 def reset(self):
36 self.state = 0
37
38 def getstate(self):
39 return self.state
40
41 def setstate(self, state):
42 self.state = state
43
44 def encode(self, input, final=False):
45 state = self.state
46 encoded = []
47 for c in input.upper():
48 if c in HEXDIGITS:
49 z = HEXDIGITS.index(c)
50 if state:
51 encoded.append(z + (state & 0xf0))
52 state = 0
53 else:
54 state = 0x100 + (z << 4)
55 elif c == ' ': # allow spaces to separate values
56 if state and self.errors == 'strict':
57 raise UnicodeError('odd number of hex digits')
58 state = 0
59 else:
60 if self.errors == 'strict':
61 raise UnicodeError('non-hex digit found: %r' % c)
62 self.state = state
63 return serial.to_bytes(encoded)
64
Chris Liechti033f17c2015-08-30 21:28:04 +020065
Chris Liechtic0c660a2015-08-25 00:55:51 +020066class IncrementalDecoder(codecs.IncrementalDecoder):
67 def decode(self, input, final=False):
68 return ''.join('{:02X} '.format(b) for b in input)
69
Chris Liechti033f17c2015-08-30 21:28:04 +020070
Chris Liechtic0c660a2015-08-25 00:55:51 +020071class StreamWriter(Codec, codecs.StreamWriter):
72 pass
73
Chris Liechti033f17c2015-08-30 21:28:04 +020074
Chris Liechtic0c660a2015-08-25 00:55:51 +020075class StreamReader(Codec, codecs.StreamReader):
76 pass
77
Chris Liechtic0c660a2015-08-25 00:55:51 +020078
Chris Liechti033f17c2015-08-30 21:28:04 +020079### encodings module API
Chris Liechtic0c660a2015-08-25 00:55:51 +020080def getregentry():
81 return codecs.CodecInfo(
82 name='hexlify',
83 encode=hex_encode,
84 decode=hex_decode,
85 incrementalencoder=IncrementalEncoder,
86 incrementaldecoder=IncrementalDecoder,
87 streamwriter=StreamWriter,
88 streamreader=StreamReader,
89 _is_text_encoding=True,
90 )