# uu.py # Copyright 1994 by Lance Ellinghouse # Cathedral City, California Republic, United States of America. # All Rights Reserved # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, # provided that the above copyright notice appear in all copies and that # both that copyright notice and this permission notice appear in # supporting documentation, and that the name of Lance Ellinghouse # not be used in advertising or publicity pertaining to distribution # of the software without specific, written prior permission. # LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND # FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE CENTRUM BE LIABLE # FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # This file implements the UUencode and UUdecode functions. # encode(filename, mode, in_file, out_file) # decode(filename, mode, in_file) # decode(in_file, out_file) # decode(in_file) # encode a single char to always be printable def _ENC(ch): if type(ch) == type(''): a = ch[:1] # only 1 char if len(a) == 0: raise ValueError, 'need to pass in at least 1 char' a = ord(a) elif type(ch) == type(0): a = ch else: raise TypeError, 'must pass in an integer or single character' return chr((a & 077) + ord(' ')) # input 3 chars, output 4 encoded chars def _outenc(str): if len(str) > 3: raise ValueError, 'can only accept strings of 3 chars' p0, p1, p2 = 0, 0, 0 if len(str) > 2: p2 = ord(str[2]) if len(str) > 1: p1 = ord(str[1]) if len(str) > 0: p0 = ord(str[0]) c1 = p0 >> 2 c2 = (p0 << 4) & 060 | (p1 >> 4) & 017 c3 = (p1 << 2) & 074 | (p2 >> 6) & 03 c4 = p2 & 077 rtn = _ENC(c1) rtn = rtn + _ENC(c2) rtn = rtn + _ENC(c3) rtn = rtn + _ENC(c4) return rtn # pass in 45 bytes max, returns 62 bytes encoded def _encode(str): if len(str) > 45: raise ValueError, 'cannot handle more than 45 chars at once' length = len(str) rtn = _ENC(length) i = 0 while i < length: rtn = rtn + _outenc(str[i:(i+3)]) i = i + 3 rtn = rtn + '\n' return rtn # encode a fileobject and write out to a file object def encode(filename, mode, in_file, out_file): out_file.write('begin %o %s\n' % ((mode&0777),filename)) str = in_file.read(45) while len(str) > 0: out_file.write(_encode(str)) str = in_file.read(45) out_file.write(' \nend\n') return None # def decode a single char from printable to possibly non-printable def _DEC(ch): if type(ch) != type('') or len(ch) != 1: raise ValueError, 'need to pass in a single char' a = ord(ch[0:1]) return (a - ord(' ')) # input 4 chars encoded, output 3 chars unencoded def _outdec(str): if len(str) > 4: raise ValueError, 'can only accept strings of 4 chars' p0, p1, p2, p3 = 0, 0, 0, 0 if len(str) > 3: p3 = _DEC(str[3]) if len(str) > 2: p2 = _DEC(str[2]) if len(str) > 1: p1 = _DEC(str[1]) if len(str) > 0: p0 = _DEC(str[0]) c1 = p0 << 2 | (p1 & 060) >> 4 c2 = (p1 & 017) << 4 | (p2 & 074) >> 2 c3 = (p2 & 03) << 6 | (p3 & 077) rtn = chr(c1) rtn = rtn + chr(c2) rtn = rtn + chr(c3) return rtn # pass in 62 bytes and return 45 bytes unencoded def _decode(str): if len(str) > 62: raise ValueError, 'cannot handle more than 62 chars at once' length = _DEC(str[0]) i = 1 rtn = '' while len(rtn) < length: rtn = rtn + _outdec(str[i:(i+4)]) i = i + 4 return rtn[0:length] # decode(filename, mode, in_file) # decode(in_file, out_file) # decode(in_file) def decode(*args): ok = 1 _setup = None out_file = None if len(args) == 3: filename, mode, in_file = args if type(filename) != type(''): ok = 0 if type(mode) != type(0): ok = 0 try: _ = getattr(in_file,'readline') except AttributeError: ok = 0 def _setup(out_file,args): filename, mode, in_file = args # open file as specified and assign out_file for later use out_file = open(filename,'w',mode) _out_file_orig = 0 _ = in_file.readline() return (out_file,_out_file_orig) elif len(args) == 2: in_file, out_file = args try: _ = getattr(in_file,'readline') _ = getattr(out_file,'write') except AttributeError: ok = 0 def _setup(out_file, args): in_file, out_file = args # Toss the 'begin mode filename' part.. not needed _ = in_file.readline() _out_file_orig = 1 return (out_file,_out_file_orig) elif len(args) == 1: in_file = args[0] try: _ = getattr(in_file,'readline') except AttributeError: ok = 0 def _setup(out_file, args): import strop in_file = args[0] # open file as specified in uu file and # assign out_file for later use i = in_file.readline() i = strop.strip(i) if 'begin' != i[:5]: raise IOError, 'input file not in UUencoded format' [dummy, mode, filename] = strop.split(i) mode = strop.atoi(mode, 8) out_file = open(filename,'w',mode) _out_file_orig = 0 return (out_file,_out_file_orig) if ok != 1: raise SyntaxError, 'must be (filename, mode, in_file) or (in_file,out_file) or (in_file)' out_file, _out_file_orig = _setup(out_file, args) str = in_file.readline() while len(str) > 0 and str != ' \n' and str != 'end\n': out_file.write(_decode(str)) str = in_file.readline() if _out_file_orig == 0: out_file.close() del out_file return None def test(): import sys if sys.argv[1:2] == ['-d']: if sys.argv[2:]: decode(open(sys.argv[2]), sys.stdout) else: decode(sys.stdin, sys.stdout) elif sys.argv[1:2] == ['-e']: if sys.argv[2:]: file = sys.argv[2] fp = open(file) else: file = '-' fp = sys.stdin encode(file, 0644, fp, sys.stdout) else: print 'usage: uu -d [file]; (to decode)' print 'or: uu -e [file]; (to encode)' sys.exit(2) if __name__ == '__main__': test()