Home | History | Annotate | Download | only in Lib
      1 #! /usr/bin/env python

      2 
      3 # Copyright 1994 by Lance Ellinghouse

      4 # Cathedral City, California Republic, United States of America.

      5 #                        All Rights Reserved

      6 # Permission to use, copy, modify, and distribute this software and its

      7 # documentation for any purpose and without fee is hereby granted,

      8 # provided that the above copyright notice appear in all copies and that

      9 # both that copyright notice and this permission notice appear in

     10 # supporting documentation, and that the name of Lance Ellinghouse

     11 # not be used in advertising or publicity pertaining to distribution

     12 # of the software without specific, written prior permission.

     13 # LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO

     14 # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND

     15 # FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE CENTRUM BE LIABLE

     16 # FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

     17 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

     18 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT

     19 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

     20 #

     21 # Modified by Jack Jansen, CWI, July 1995:

     22 # - Use binascii module to do the actual line-by-line conversion

     23 #   between ascii and binary. This results in a 1000-fold speedup. The C

     24 #   version is still 5 times faster, though.

     25 # - Arguments more compliant with python standard

     26 
     27 """Implementation of the UUencode and UUdecode functions.
     28 
     29 encode(in_file, out_file [,name, mode])
     30 decode(in_file [, out_file, mode])
     31 """
     32 
     33 import binascii
     34 import os
     35 import sys
     36 
     37 __all__ = ["Error", "encode", "decode"]
     38 
     39 class Error(Exception):
     40     pass
     41 
     42 def encode(in_file, out_file, name=None, mode=None):
     43     """Uuencode file"""
     44     #

     45     # If in_file is a pathname open it and change defaults

     46     #

     47     opened_files = []
     48     try:
     49         if in_file == '-':
     50             in_file = sys.stdin
     51         elif isinstance(in_file, basestring):
     52             if name is None:
     53                 name = os.path.basename(in_file)
     54             if mode is None:
     55                 try:
     56                     mode = os.stat(in_file).st_mode
     57                 except AttributeError:
     58                     pass
     59             in_file = open(in_file, 'rb')
     60             opened_files.append(in_file)
     61         #

     62         # Open out_file if it is a pathname

     63         #

     64         if out_file == '-':
     65             out_file = sys.stdout
     66         elif isinstance(out_file, basestring):
     67             out_file = open(out_file, 'wb')
     68             opened_files.append(out_file)
     69         #

     70         # Set defaults for name and mode

     71         #

     72         if name is None:
     73             name = '-'
     74         if mode is None:
     75             mode = 0666
     76         #

     77         # Write the data

     78         #

     79         out_file.write('begin %o %s\n' % ((mode&0777),name))
     80         data = in_file.read(45)
     81         while len(data) > 0:
     82             out_file.write(binascii.b2a_uu(data))
     83             data = in_file.read(45)
     84         out_file.write(' \nend\n')
     85     finally:
     86         for f in opened_files:
     87             f.close()
     88 
     89 
     90 def decode(in_file, out_file=None, mode=None, quiet=0):
     91     """Decode uuencoded file"""
     92     #

     93     # Open the input file, if needed.

     94     #

     95     opened_files = []
     96     if in_file == '-':
     97         in_file = sys.stdin
     98     elif isinstance(in_file, basestring):
     99         in_file = open(in_file)
    100         opened_files.append(in_file)
    101     try:
    102         #

    103         # Read until a begin is encountered or we've exhausted the file

    104         #

    105         while True:
    106             hdr = in_file.readline()
    107             if not hdr:
    108                 raise Error('No valid begin line found in input file')
    109             if not hdr.startswith('begin'):
    110                 continue
    111             hdrfields = hdr.split(' ', 2)
    112             if len(hdrfields) == 3 and hdrfields[0] == 'begin':
    113                 try:
    114                     int(hdrfields[1], 8)
    115                     break
    116                 except ValueError:
    117                     pass
    118         if out_file is None:
    119             out_file = hdrfields[2].rstrip()
    120             if os.path.exists(out_file):
    121                 raise Error('Cannot overwrite existing file: %s' % out_file)
    122         if mode is None:
    123             mode = int(hdrfields[1], 8)
    124         #

    125         # Open the output file

    126         #

    127         if out_file == '-':
    128             out_file = sys.stdout
    129         elif isinstance(out_file, basestring):
    130             fp = open(out_file, 'wb')
    131             try:
    132                 os.path.chmod(out_file, mode)
    133             except AttributeError:
    134                 pass
    135             out_file = fp
    136             opened_files.append(out_file)
    137         #

    138         # Main decoding loop

    139         #

    140         s = in_file.readline()
    141         while s and s.strip() != 'end':
    142             try:
    143                 data = binascii.a2b_uu(s)
    144             except binascii.Error, v:
    145                 # Workaround for broken uuencoders by /Fredrik Lundh

    146                 nbytes = (((ord(s[0])-32) & 63) * 4 + 5) // 3
    147                 data = binascii.a2b_uu(s[:nbytes])
    148                 if not quiet:
    149                     sys.stderr.write("Warning: %s\n" % v)
    150             out_file.write(data)
    151             s = in_file.readline()
    152         if not s:
    153             raise Error('Truncated input file')
    154     finally:
    155         for f in opened_files:
    156             f.close()
    157 
    158 def test():
    159     """uuencode/uudecode main program"""
    160 
    161     import optparse
    162     parser = optparse.OptionParser(usage='usage: %prog [-d] [-t] [input [output]]')
    163     parser.add_option('-d', '--decode', dest='decode', help='Decode (instead of encode)?', default=False, action='store_true')
    164     parser.add_option('-t', '--text', dest='text', help='data is text, encoded format unix-compatible text?', default=False, action='store_true')
    165 
    166     (options, args) = parser.parse_args()
    167     if len(args) > 2:
    168         parser.error('incorrect number of arguments')
    169         sys.exit(1)
    170 
    171     input = sys.stdin
    172     output = sys.stdout
    173     if len(args) > 0:
    174         input = args[0]
    175     if len(args) > 1:
    176         output = args[1]
    177 
    178     if options.decode:
    179         if options.text:
    180             if isinstance(output, basestring):
    181                 output = open(output, 'w')
    182             else:
    183                 print sys.argv[0], ': cannot do -t to stdout'
    184                 sys.exit(1)
    185         decode(input, output)
    186     else:
    187         if options.text:
    188             if isinstance(input, basestring):
    189                 input = open(input, 'r')
    190             else:
    191                 print sys.argv[0], ': cannot do -t from stdin'
    192                 sys.exit(1)
    193         encode(input, output)
    194 
    195 if __name__ == '__main__':
    196     test()
    197