blob: fac85dbd832117f3bc1981a384bbdbccbc91492b [file] [log] [blame]
Chris Liechti3e02f702015-12-16 23:06:04 +01001#! python
2#
3# This is a codec to create and decode hexdumps with spaces between characters. used by miniterm.
4#
5# This file is part of pySerial. https://github.com/pyserial/pyserial
6# (C) 2011 Chris Liechti <cliechti@gmx.net>
7#
8# SPDX-License-Identifier: BSD-3-Clause
Chris Liechtic0c660a2015-08-25 00:55:51 +02009"""\
10Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
11"""
12
13import codecs
14import serial
15
16HEXDIGITS = '0123456789ABCDEF'
17
18### Codec APIs
19
Chris Liechti033f17c2015-08-30 21:28:04 +020020
Chris Liechtic0c660a2015-08-25 00:55:51 +020021def hex_encode(input, errors='strict'):
22 return (serial.to_bytes([int(h, 16) for h in input.split()]), len(input))
23
Chris Liechti033f17c2015-08-30 21:28:04 +020024
Chris Liechtic0c660a2015-08-25 00:55:51 +020025def hex_decode(input, errors='strict'):
26 return (''.join('{:02X} '.format(b) for b in input), len(input))
27
Chris Liechti033f17c2015-08-30 21:28:04 +020028
Chris Liechtic0c660a2015-08-25 00:55:51 +020029class Codec(codecs.Codec):
30 def encode(self, input, errors='strict'):
31 return serial.to_bytes([int(h, 16) for h in input.split()])
Chris Liechti033f17c2015-08-30 21:28:04 +020032
Chris Liechtic0c660a2015-08-25 00:55:51 +020033 def decode(self, input, errors='strict'):
34 return ''.join('{:02X} '.format(b) for b in input)
35
Chris Liechti033f17c2015-08-30 21:28:04 +020036
Chris Liechtic0c660a2015-08-25 00:55:51 +020037class IncrementalEncoder(codecs.IncrementalEncoder):
38
39 def __init__(self, errors='strict'):
40 self.errors = errors
41 self.state = 0
42
43 def reset(self):
44 self.state = 0
45
46 def getstate(self):
47 return self.state
48
49 def setstate(self, state):
50 self.state = state
51
52 def encode(self, input, final=False):
53 state = self.state
54 encoded = []
55 for c in input.upper():
56 if c in HEXDIGITS:
57 z = HEXDIGITS.index(c)
58 if state:
59 encoded.append(z + (state & 0xf0))
60 state = 0
61 else:
62 state = 0x100 + (z << 4)
63 elif c == ' ': # allow spaces to separate values
64 if state and self.errors == 'strict':
65 raise UnicodeError('odd number of hex digits')
66 state = 0
67 else:
68 if self.errors == 'strict':
69 raise UnicodeError('non-hex digit found: %r' % c)
70 self.state = state
71 return serial.to_bytes(encoded)
72
Chris Liechti033f17c2015-08-30 21:28:04 +020073
Chris Liechtic0c660a2015-08-25 00:55:51 +020074class IncrementalDecoder(codecs.IncrementalDecoder):
75 def decode(self, input, final=False):
76 return ''.join('{:02X} '.format(b) for b in input)
77
Chris Liechti033f17c2015-08-30 21:28:04 +020078
Chris Liechtic0c660a2015-08-25 00:55:51 +020079class StreamWriter(Codec, codecs.StreamWriter):
80 pass
81
Chris Liechti033f17c2015-08-30 21:28:04 +020082
Chris Liechtic0c660a2015-08-25 00:55:51 +020083class StreamReader(Codec, codecs.StreamReader):
84 pass
85
Chris Liechtic0c660a2015-08-25 00:55:51 +020086
Chris Liechti033f17c2015-08-30 21:28:04 +020087### encodings module API
Chris Liechtic0c660a2015-08-25 00:55:51 +020088def getregentry():
89 return codecs.CodecInfo(
90 name='hexlify',
91 encode=hex_encode,
92 decode=hex_decode,
93 incrementalencoder=IncrementalEncoder,
94 incrementaldecoder=IncrementalDecoder,
95 streamwriter=StreamWriter,
96 streamreader=StreamReader,
97 _is_text_encoding=True,
98 )