blob: 7f0783d1d2a6f38fc4fbd541fdc66e9a2ff7216b [file] [log] [blame]
Guido van Rossum85347411994-09-09 11:10:15 +00001# uu.py
2# Copyright 1994 by Lance Ellinghouse
3# Cathedral City, California Republic, United States of America.
4# All Rights Reserved
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose and without fee is hereby granted,
7# provided that the above copyright notice appear in all copies and that
8# both that copyright notice and this permission notice appear in
9# supporting documentation, and that the name of Lance Ellinghouse
10# not be used in advertising or publicity pertaining to distribution
11# of the software without specific, written prior permission.
12# LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
13# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
14# FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE CENTRUM BE LIABLE
15# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20# This file implements the UUencode and UUdecode functions.
21
22# encode(filename, mode, in_file, out_file)
23# decode(filename, mode, in_file)
24# decode(in_file, out_file)
25# decode(in_file)
26
27# encode a single char to always be printable
28def _ENC(ch):
29 if type(ch) == type(''):
30 a = ch[:1] # only 1 char
31 if len(a) == 0:
32 raise ValueError, 'need to pass in at least 1 char'
33 a = ord(a)
34 elif type(ch) == type(0):
35 a = ch
36 else:
37 raise TypeError, 'must pass in an integer or single character'
38 return chr((a & 077) + ord(' '))
39
40# input 3 chars, output 4 encoded chars
41def _outenc(str):
42 if len(str) > 3:
43 raise ValueError, 'can only accept strings of 3 chars'
44 p0, p1, p2 = 0, 0, 0
45 if len(str) > 2:
46 p2 = ord(str[2])
47 if len(str) > 1:
48 p1 = ord(str[1])
49 if len(str) > 0:
50 p0 = ord(str[0])
51 c1 = p0 >> 2
52 c2 = (p0 << 4) & 060 | (p1 >> 4) & 017
53 c3 = (p1 << 2) & 074 | (p2 >> 6) & 03
54 c4 = p2 & 077
55 rtn = _ENC(c1)
56 rtn = rtn + _ENC(c2)
57 rtn = rtn + _ENC(c3)
58 rtn = rtn + _ENC(c4)
59 return rtn
60
61# pass in 45 bytes max, returns 62 bytes encoded
62def _encode(str):
63 if len(str) > 45:
64 raise ValueError, 'cannot handle more than 45 chars at once'
65 length = len(str)
66 rtn = _ENC(length)
67 i = 0
68 while i < length:
69 rtn = rtn + _outenc(str[i:(i+3)])
70 i = i + 3
71 rtn = rtn + '\n'
72 return rtn
73
74# encode a fileobject and write out to a file object
75def encode(filename, mode, in_file, out_file):
76 out_file.write('begin %o %s\n' % ((mode&0777),filename))
77 str = in_file.read(45)
78 while len(str) > 0:
79 out_file.write(_encode(str))
80 str = in_file.read(45)
81 out_file.write(' \nend\n')
82 return None
83
84# def decode a single char from printable to possibly non-printable
85def _DEC(ch):
86 if type(ch) != type('') or len(ch) != 1:
87 raise ValueError, 'need to pass in a single char'
88 a = ord(ch[0:1])
89 return (a - ord(' '))
90
91# input 4 chars encoded, output 3 chars unencoded
92def _outdec(str):
93 if len(str) > 4:
94 raise ValueError, 'can only accept strings of 4 chars'
95 p0, p1, p2, p3 = 0, 0, 0, 0
96 if len(str) > 3:
97 p3 = _DEC(str[3])
98 if len(str) > 2:
99 p2 = _DEC(str[2])
100 if len(str) > 1:
101 p1 = _DEC(str[1])
102 if len(str) > 0:
103 p0 = _DEC(str[0])
104 c1 = p0 << 2 | (p1 & 060) >> 4
105 c2 = (p1 & 017) << 4 | (p2 & 074) >> 2
106 c3 = (p2 & 03) << 6 | (p3 & 077)
107 rtn = chr(c1)
108 rtn = rtn + chr(c2)
109 rtn = rtn + chr(c3)
110 return rtn
111
112# pass in 62 bytes and return 45 bytes unencoded
113def _decode(str):
114 if len(str) > 62:
115 raise ValueError, 'cannot handle more than 62 chars at once'
116 length = _DEC(str[0])
117 i = 1
118 rtn = ''
119 while len(rtn) < length:
120 rtn = rtn + _outdec(str[i:(i+4)])
121 i = i + 4
122 return rtn[0:length]
123
124# decode(filename, mode, in_file)
125# decode(in_file, out_file)
126# decode(in_file)
127def decode(*args):
128 ok = 1
129 _setup = None
130 out_file = None
131 if len(args) == 3:
132 filename, mode, in_file = args
133 if type(filename) != type(''):
134 ok = 0
135 if type(mode) != type(0):
136 ok = 0
137 try:
138 _ = getattr(in_file,'readline')
139 except AttributeError:
140 ok = 0
141 def _setup(out_file,args):
142 filename, mode, in_file = args
143 # open file as specified and assign out_file for later use
144 out_file = open(filename,'w',mode)
145 _out_file_orig = 0
146 _ = in_file.readline()
147 return (out_file,_out_file_orig)
148 elif len(args) == 2:
149 in_file, out_file = args
150 try:
151 _ = getattr(in_file,'readline')
152 _ = getattr(out_file,'write')
153 except AttributeError:
154 ok = 0
155 def _setup(out_file, args):
156 in_file, out_file = args
157 # Toss the 'begin mode filename' part.. not needed
158 _ = in_file.readline()
159 _out_file_orig = 1
160 return (out_file,_out_file_orig)
161 elif len(args) == 1:
162 in_file = args[0]
163 try:
164 _ = getattr(in_file,'readline')
165 except AttributeError:
166 ok = 0
167 def _setup(out_file, args):
168 import strop
169 in_file = args[0]
170 # open file as specified in uu file and
171 # assign out_file for later use
172 i = in_file.readline()
173 i = strop.strip(i)
174 if 'begin' != i[:5]:
175 raise IOError, 'input file not in UUencoded format'
176 [dummy, mode, filename] = strop.split(i)
177 mode = strop.atoi(mode, 8)
178 out_file = open(filename,'w',mode)
179 _out_file_orig = 0
180 return (out_file,_out_file_orig)
181 if ok != 1:
182 raise SyntaxError, 'must be (filename, mode, in_file) or (in_file,out_file) or (in_file)'
183 out_file, _out_file_orig = _setup(out_file, args)
184 str = in_file.readline()
185 while len(str) > 0 and str != ' \n' and str != 'end\n':
186 out_file.write(_decode(str))
187 str = in_file.readline()
188 if _out_file_orig == 0:
189 out_file.close()
190 del out_file
191 return None
192
193def test():
194 import sys
195 if sys.argv[1:2] == ['-d']:
196 if sys.argv[2:]:
197 decode(open(sys.argv[2]), sys.stdout)
198 else:
199 decode(sys.stdin, sys.stdout)
200 elif sys.argv[1:2] == ['-e']:
201 if sys.argv[2:]:
202 file = sys.argv[2]
203 fp = open(file)
204 else:
205 file = '-'
206 fp = sys.stdin
207 encode(file, 0644, fp, sys.stdout)
208 else:
209 print 'usage: uu -d [file]; (to decode)'
210 print 'or: uu -e [file]; (to encode)'
211 sys.exit(2)
212
213if __name__ == '__main__':
214 test()