1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# 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
def test():
import sys, getopt
try:
opts, args = getopt.getopt(sys.argv[1:], 'deut')
except getopt.error, msg:
sys.stdout = sys.stderr
print msg
print """usage: basd64 [-d] [-e] [-u] [-t] [file|-]
-d, -u: decode
-e: encode (default)
-t: decode string 'Aladdin:open sesame'"""
sys.exit(2)
func = encode
for o, a in opts:
if o == '-e': func = encode
if o == '-d': func = decode
if o == '-u': func = decode
if o == '-t': test1(); return
if args and args[0] != '-':
func(open(args[0]), sys.stdout)
else:
func(sys.stdin, sys.stdout)
def test1():
s0 = "Aladdin:open sesame"
s1 = encodestring(s0)
s2 = decodestring(s1)
print s0, `s1`, s2
if __name__ == '__main__':
test()
|