From f1945466e8895453f2f19900b375f9f7cce99ee3 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 14 Jun 1995 23:43:44 +0000 Subject: two mime encoding schemes --- Lib/base64.py | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Lib/quopri.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100755 Lib/base64.py create mode 100755 Lib/quopri.py diff --git a/Lib/base64.py b/Lib/base64.py new file mode 100755 index 0000000..2f9bdc1 --- /dev/null +++ b/Lib/base64.py @@ -0,0 +1,125 @@ +# Conversions to/from base64 transport encoding as per RFC-MIME (Dec 1991 +# version). + +# Parameters set by RFX-XXXX. +MAXLINESIZE = 76 # Excluding the CRLF +INVAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +PAD = '=' + +# Check that I typed that string correctly... +if len(INVAR) <> 64: raise RuntimeError, 'wrong INVAR string!?!?' + +# Compute the inverse table, for decode(). +inverse = {} +for i in range(64): inverse[INVAR[i]] = i +del i +inverse[PAD] = 0 + +# Encode a file. +def encode(input, output): + line = '' + BUFSIZE = 8192 + leftover = '' + while 1: + s = input.read(BUFSIZE) + if not s: break + s = leftover + s + i = 0 + while i+3 <= len(s): + quad = makequad(s[i:i+3]) + i = i+3 + if len(line) + 4 > MAXLINESIZE: + output.write(line + '\n') + line = '' + line = line + quad + leftover = s[i:] + if leftover: + quad = makeshortquad(leftover) + if len(line) + 4 > MAXLINESIZE: + output.write(line + '\n') + line = '' + line = line + quad + if line: + output.write(line + '\n') + +def makequad(s): # Return the quad for a 3 character string + x = ord(s[0])*0x10000 + ord(s[1])*0x100 + ord(s[2]) + x, c4 = divmod(x, 64) + x, c3 = divmod(x, 64) + c1, c2 = divmod(x, 64) + return INVAR[c1] + INVAR[c2] +INVAR[c3] + INVAR[c4] + +def makeshortquad(s): # Return the quad value for a 1 or 2 character string + n = len(s) + while len(s) < 3: + s = s + '\0' + quad = makequad(s) + if n == 2: + quad = quad[:3] + PAD + elif n == 1: + quad = quad[:2] + 2*PAD + return quad + +# Decode a file. +def decode(input, output): + BUFSIZE = 8192 + bits, n, bytes, prev = 0, 0, '', '' + while 1: + line = input.readline() + if not line: break + for c in line: + if inverse.has_key(c): + bits = bits*64 + inverse[c] + n = n+6 + if n == 24: + triplet = decodequad(bits) + if c == PAD: + if prev == PAD: + triplet = triplet[:1] + else: + triplet = triplet[:2] + bits, n = 0, 0 + bytes = bytes + triplet + if len(bytes) > BUFSIZE: + output.write(bytes[:BUFSIZE]) + bytes = bytes[BUFSIZE:] + prev = c + if bytes: + output.write(bytes) + +def decodequad(bits): # Turn 24 bits into 3 characters + bits, c3 = divmod(bits, 256) + c1, c2 = divmod(bits, 256) + return chr(c1) + chr(c2) + chr(c3) + +def encodestring(s): + import StringIO + f = StringIO.StringIO(s) + g = StringIO.StringIO() + encode(f, g) + return g.getvalue() + +def decodestring(s): + import StringIO + f = StringIO.StringIO(s) + g = StringIO.StringIO() + decode(f, g) + return g.getvalue() + +# Small test program, reads stdin, writes stdout. +# no arg: encode, any arg: decode. +def test(): + import sys + if sys.argv[1:]: + decode(sys.stdin, sys.stdout) + else: + encode(sys.stdin, sys.stdout) + +def test1(): + s0 = "Aladdin:open sesame" + s1 = encodestring(s0) + s2 = decodestring(s1) + print s0, `s1`, s2 + +if __name__ == '__main__': + test() diff --git a/Lib/quopri.py b/Lib/quopri.py new file mode 100755 index 0000000..4c39228 --- /dev/null +++ b/Lib/quopri.py @@ -0,0 +1,101 @@ +# Conversions to/from quoted-printable transport encoding as per RFC-XXXX +# (Dec 1991 version). + +ESCAPE = '=' +MAXLINESIZE = 76 +HEX = '0123456789ABCDEF' + +def needsquoting(c, quotetabs): + if c == '\t': + return not quotetabs + return c == ESCAPE or not(' ' <= c <= '~') + +def quote(c): + if c == ESCAPE: + return ESCAPE * 2 + else: + i = ord(c) + return ESCAPE + HEX[i/16] + HEX[i%16] + +def encode(input, output, quotetabs): + while 1: + line = input.readline() + if not line: break + new = '' + last = line[-1:] + if last == '\n': line = line[:-1] + else: last = '' + prev = '' + for c in line: + if needsquoting(c, quotetabs): + c = quote(c) + if len(new) + len(c) >= MAXLINESIZE: + output.write(new + ESCAPE + '\n') + new = '' + new = new + c + prev = c + if prev in (' ', '\t'): + output.write(new + ESCAPE + '\n\n') + else: + output.write(new + '\n') + +def decode(input, output): + new = '' + while 1: + line = input.readline() + if not line: break + i, n = 0, len(line) + if n > 0 and line[n-1] == '\n': + partial = 0; n = n-1 + # Strip trailing whitespace + while n > 0 and line[n-1] in (' ', '\t'): + n = n-1 + else: + partial = 1 + while i < n: + c = line[i] + if c <> ESCAPE: + new = new + c; i = i+1 + elif i+1 == n and not partial: + partial = 1; break + elif i+1 < n and line[i+1] == ESCAPE: + new = new + ESCAPE; i = i+2 + elif i+2 < n and ishex(line[i+1]) and ishex(line[i+2]): + new = new + chr(unhex(line[i+1:i+3])); i = i+3 + else: # Bad escape sequence -- leave it in + new = new + c; i = i+1 + if not partial: + output.write(new + '\n') + new = '' + if new: + output.write(new) + +def ishex(c): + return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F' + +def unhex(s): + bits = 0 + for c in s: + if '0' <= c <= '9': + i = ord('0') + elif 'a' <= c <= 'f': + i = ord('a')-10 + elif 'A' <= c <= 'F': + i = ord('A')-10 + else: + break + bits = bits*16 + (ord(c) - i) + return bits + +def test(): + import sys + if sys.argv[1:]: + if sys.argv[1] == '-t': # Quote tabs + encode(sys.stdin, sys.stdout, 1) + else: + decode(sys.stdin, sys.stdout) + else: + encode(sys.stdin, sys.stdout, 0) + +if __name__ == '__main__': + main() -- cgit v0.12