jpayne@69: """Python 'uu_codec' Codec - UU content transfer encoding. jpayne@69: jpayne@69: This codec de/encodes from bytes to bytes. jpayne@69: jpayne@69: Written by Marc-Andre Lemburg (mal@lemburg.com). Some details were jpayne@69: adapted from uu.py which was written by Lance Ellinghouse and jpayne@69: modified by Jack Jansen and Fredrik Lundh. jpayne@69: """ jpayne@69: jpayne@69: import codecs jpayne@69: import binascii jpayne@69: from io import BytesIO jpayne@69: jpayne@69: ### Codec APIs jpayne@69: jpayne@69: def uu_encode(input, errors='strict', filename='', mode=0o666): jpayne@69: assert errors == 'strict' jpayne@69: infile = BytesIO(input) jpayne@69: outfile = BytesIO() jpayne@69: read = infile.read jpayne@69: write = outfile.write jpayne@69: jpayne@69: # Remove newline chars from filename jpayne@69: filename = filename.replace('\n','\\n') jpayne@69: filename = filename.replace('\r','\\r') jpayne@69: jpayne@69: # Encode jpayne@69: write(('begin %o %s\n' % (mode & 0o777, filename)).encode('ascii')) jpayne@69: chunk = read(45) jpayne@69: while chunk: jpayne@69: write(binascii.b2a_uu(chunk)) jpayne@69: chunk = read(45) jpayne@69: write(b' \nend\n') jpayne@69: jpayne@69: return (outfile.getvalue(), len(input)) jpayne@69: jpayne@69: def uu_decode(input, errors='strict'): jpayne@69: assert errors == 'strict' jpayne@69: infile = BytesIO(input) jpayne@69: outfile = BytesIO() jpayne@69: readline = infile.readline jpayne@69: write = outfile.write jpayne@69: jpayne@69: # Find start of encoded data jpayne@69: while 1: jpayne@69: s = readline() jpayne@69: if not s: jpayne@69: raise ValueError('Missing "begin" line in input data') jpayne@69: if s[:5] == b'begin': jpayne@69: break jpayne@69: jpayne@69: # Decode jpayne@69: while True: jpayne@69: s = readline() jpayne@69: if not s or s == b'end\n': jpayne@69: break jpayne@69: try: jpayne@69: data = binascii.a2b_uu(s) jpayne@69: except binascii.Error as v: jpayne@69: # Workaround for broken uuencoders by /Fredrik Lundh jpayne@69: nbytes = (((s[0]-32) & 63) * 4 + 5) // 3 jpayne@69: data = binascii.a2b_uu(s[:nbytes]) jpayne@69: #sys.stderr.write("Warning: %s\n" % str(v)) jpayne@69: write(data) jpayne@69: if not s: jpayne@69: raise ValueError('Truncated input data') jpayne@69: jpayne@69: return (outfile.getvalue(), len(input)) jpayne@69: jpayne@69: class Codec(codecs.Codec): jpayne@69: def encode(self, input, errors='strict'): jpayne@69: return uu_encode(input, errors) jpayne@69: jpayne@69: def decode(self, input, errors='strict'): jpayne@69: return uu_decode(input, errors) jpayne@69: jpayne@69: class IncrementalEncoder(codecs.IncrementalEncoder): jpayne@69: def encode(self, input, final=False): jpayne@69: return uu_encode(input, self.errors)[0] jpayne@69: jpayne@69: class IncrementalDecoder(codecs.IncrementalDecoder): jpayne@69: def decode(self, input, final=False): jpayne@69: return uu_decode(input, self.errors)[0] jpayne@69: jpayne@69: class StreamWriter(Codec, codecs.StreamWriter): jpayne@69: charbuffertype = bytes jpayne@69: jpayne@69: class StreamReader(Codec, codecs.StreamReader): jpayne@69: charbuffertype = bytes jpayne@69: jpayne@69: ### encodings module API jpayne@69: jpayne@69: def getregentry(): jpayne@69: return codecs.CodecInfo( jpayne@69: name='uu', jpayne@69: encode=uu_encode, jpayne@69: decode=uu_decode, jpayne@69: incrementalencoder=IncrementalEncoder, jpayne@69: incrementaldecoder=IncrementalDecoder, jpayne@69: streamreader=StreamReader, jpayne@69: streamwriter=StreamWriter, jpayne@69: _is_text_encoding=False, jpayne@69: )