Mercurial > hg
comparison mercurial/pure/base85.py @ 7701:4bdead043d8d
Pure python base85 fallback
Encoding takes about 100x longer than native on a large binary.
author | Brendan Cully <brendan@kublai.com> |
---|---|
date | Tue, 30 Dec 2008 18:58:58 -0800 |
parents | |
children | 2505e9f84153 |
comparison
equal
deleted
inserted
replaced
7700:f410c552fa15 | 7701:4bdead043d8d |
---|---|
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 |