7701
|
1 |
# base85.py: pure python base85 codec
|
|
2 |
#
|
|
3 |
# Copyright (C) 2009 Brendan Cully <brendan@kublai.com>
|
|
4 |
#
|
|
5 |
# This software may be used and distributed according to the terms of
|
|
6 |
# the GNU General Public License, incorporated herein by reference.
|
|
7 |
|
|
8 |
import struct
|
|
9 |
|
|
10 |
_b85chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
|
11 |
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
|
|
12 |
_b85dec = {}
|
|
13 |
|
|
14 |
def _mkb85dec():
|
|
15 |
for i in range(len(_b85chars)):
|
|
16 |
_b85dec[_b85chars[i]] = i
|
|
17 |
|
|
18 |
def b85encode(text, pad=False):
|
|
19 |
"""encode text in base85 format"""
|
|
20 |
l = len(text)
|
|
21 |
r = l % 4
|
|
22 |
if r:
|
|
23 |
text += '\0' * (4 - r)
|
|
24 |
longs = len(text) >> 2
|
|
25 |
out = []
|
|
26 |
words = struct.unpack('>%dL' % (longs), text)
|
|
27 |
for word in words:
|
|
28 |
# unrolling improved speed by 33%
|
|
29 |
word, r = divmod(word, 85)
|
|
30 |
e = _b85chars[r]
|
|
31 |
word, r = divmod(word, 85)
|
|
32 |
d = _b85chars[r]
|
|
33 |
word, r = divmod(word, 85)
|
|
34 |
c = _b85chars[r]
|
|
35 |
word, r = divmod(word, 85)
|
|
36 |
b = _b85chars[r]
|
|
37 |
word, r = divmod(word, 85)
|
|
38 |
a = _b85chars[r]
|
|
39 |
|
|
40 |
out += (a, b, c, d, e)
|
|
41 |
|
|
42 |
out = ''.join(out)
|
|
43 |
if pad:
|
|
44 |
return out
|
|
45 |
|
|
46 |
# Trim padding
|
|
47 |
olen = l % 4
|
|
48 |
if olen:
|
|
49 |
olen += 1
|
|
50 |
olen += l / 4 * 5
|
|
51 |
return out[:olen]
|
|
52 |
|
|
53 |
def b85decode(text):
|
|
54 |
"""decode base85-encoded text"""
|
|
55 |
if not _b85dec:
|
|
56 |
_mkb85dec()
|
|
57 |
|
|
58 |
l = len(text)
|
|
59 |
out = []
|
|
60 |
for i in range(0, len(text), 5):
|
|
61 |
chunk = text[i:i+5]
|
|
62 |
acc = 0
|
|
63 |
for j in range(len(chunk)):
|
|
64 |
try:
|
|
65 |
acc = acc * 85 + _b85dec[chunk[j]]
|
|
66 |
except KeyError:
|
|
67 |
raise TypeError('Bad base85 character at byte %d' % (i + j))
|
|
68 |
if acc > 4294967295:
|
|
69 |
raise OverflowError('Base85 overflow in hunk starting at byte %d' % i)
|
|
70 |
out.append(acc)
|
|
71 |
|
|
72 |
# Pad final chunk if necessary
|
|
73 |
cl = l % 5
|
|
74 |
if cl:
|
|
75 |
acc *= 85 ** (5 - cl)
|
|
76 |
if cl > 1:
|
|
77 |
acc += 0xffffff >> (cl - 2) * 8
|
|
78 |
out[-1] = acc
|
|
79 |
|
|
80 |
out = struct.pack('>%dL' % (len(out)), *out)
|
|
81 |
if cl:
|
|
82 |
out = out[:-(5 - cl)]
|
|
83 |
|
|
84 |
return out
|