1""" Python 'uu_codec' Codec - UU content transfer encoding
2
3    Unlike most of the other codecs which target Unicode, this codec
4    will return Python string objects for both encode and decode.
5
6    Written by Marc-Andre Lemburg (mal@lemburg.com). Some details were
7    adapted from uu.py which was written by Lance Ellinghouse and
8    modified by Jack Jansen and Fredrik Lundh.
9
10"""
11import codecs, binascii
12
13### Codec APIs
14
15def uu_encode(input,errors='strict',filename='<data>',mode=0666):
16
17    """ Encodes the object input and returns a tuple (output
18        object, length consumed).
19
20        errors defines the error handling to apply. It defaults to
21        'strict' handling which is the only currently supported
22        error handling for this codec.
23
24    """
25    assert errors == 'strict'
26    from cStringIO import StringIO
27    from binascii import b2a_uu
28    # using str() because of cStringIO's Unicode undesired Unicode behavior.
29    infile = StringIO(str(input))
30    outfile = StringIO()
31    read = infile.read
32    write = outfile.write
33
34    # Encode
35    write('begin %o %s\n' % (mode & 0777, filename))
36    chunk = read(45)
37    while chunk:
38        write(b2a_uu(chunk))
39        chunk = read(45)
40    write(' \nend\n')
41
42    return (outfile.getvalue(), len(input))
43
44def uu_decode(input,errors='strict'):
45
46    """ Decodes the object input and returns a tuple (output
47        object, length consumed).
48
49        input must be an object which provides the bf_getreadbuf
50        buffer slot. Python strings, buffer objects and memory
51        mapped files are examples of objects providing this slot.
52
53        errors defines the error handling to apply. It defaults to
54        'strict' handling which is the only currently supported
55        error handling for this codec.
56
57        Note: filename and file mode information in the input data is
58        ignored.
59
60    """
61    assert errors == 'strict'
62    from cStringIO import StringIO
63    from binascii import a2b_uu
64    infile = StringIO(str(input))
65    outfile = StringIO()
66    readline = infile.readline
67    write = outfile.write
68
69    # Find start of encoded data
70    while 1:
71        s = readline()
72        if not s:
73            raise ValueError, 'Missing "begin" line in input data'
74        if s[:5] == 'begin':
75            break
76
77    # Decode
78    while 1:
79        s = readline()
80        if not s or \
81           s == 'end\n':
82            break
83        try:
84            data = a2b_uu(s)
85        except binascii.Error, v:
86            # Workaround for broken uuencoders by /Fredrik Lundh
87            nbytes = (((ord(s[0])-32) & 63) * 4 + 5) / 3
88            data = a2b_uu(s[:nbytes])
89            #sys.stderr.write("Warning: %s\n" % str(v))
90        write(data)
91    if not s:
92        raise ValueError, 'Truncated input data'
93
94    return (outfile.getvalue(), len(input))
95
96class Codec(codecs.Codec):
97
98    def encode(self,input,errors='strict'):
99        return uu_encode(input,errors)
100
101    def decode(self,input,errors='strict'):
102        return uu_decode(input,errors)
103
104class IncrementalEncoder(codecs.IncrementalEncoder):
105    def encode(self, input, final=False):
106        return uu_encode(input, self.errors)[0]
107
108class IncrementalDecoder(codecs.IncrementalDecoder):
109    def decode(self, input, final=False):
110        return uu_decode(input, self.errors)[0]
111
112class StreamWriter(Codec,codecs.StreamWriter):
113    pass
114
115class StreamReader(Codec,codecs.StreamReader):
116    pass
117
118### encodings module API
119
120def getregentry():
121    return codecs.CodecInfo(
122        name='uu',
123        encode=uu_encode,
124        decode=uu_decode,
125        incrementalencoder=IncrementalEncoder,
126        incrementaldecoder=IncrementalDecoder,
127        streamreader=StreamReader,
128        streamwriter=StreamWriter,
129    )
130