##// END OF EJS Templates
base85: add version to help detect breaking binary changes
Jun Wu -
r32356:7948adb5 default
parent child Browse files
Show More
@@ -1,182 +1,189
1 1 /*
2 2 base85 codec
3 3
4 4 Copyright 2006 Brendan Cully <brendan@kublai.com>
5 5
6 6 This software may be used and distributed according to the terms of
7 7 the GNU General Public License, incorporated herein by reference.
8 8
9 9 Largely based on git's implementation
10 10 */
11 11
12 12 #define PY_SSIZE_T_CLEAN
13 13 #include <Python.h>
14 14
15 15 #include "util.h"
16 16
17 17 static const char b85chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
18 18 "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
19 19 static char b85dec[256];
20 20
21 21 static void b85prep(void)
22 22 {
23 23 unsigned i;
24 24
25 25 memset(b85dec, 0, sizeof(b85dec));
26 26 for (i = 0; i < sizeof(b85chars); i++)
27 27 b85dec[(int)(b85chars[i])] = i + 1;
28 28 }
29 29
30 30 static PyObject *b85encode(PyObject *self, PyObject *args)
31 31 {
32 32 const unsigned char *text;
33 33 PyObject *out;
34 34 char *dst;
35 35 Py_ssize_t len, olen, i;
36 36 unsigned int acc, val, ch;
37 37 int pad = 0;
38 38
39 39 if (!PyArg_ParseTuple(args, "s#|i", &text, &len, &pad))
40 40 return NULL;
41 41
42 42 if (pad)
43 43 olen = ((len + 3) / 4 * 5) - 3;
44 44 else {
45 45 olen = len % 4;
46 46 if (olen)
47 47 olen++;
48 48 olen += len / 4 * 5;
49 49 }
50 50 if (!(out = PyBytes_FromStringAndSize(NULL, olen + 3)))
51 51 return NULL;
52 52
53 53 dst = PyBytes_AsString(out);
54 54
55 55 while (len) {
56 56 acc = 0;
57 57 for (i = 24; i >= 0; i -= 8) {
58 58 ch = *text++;
59 59 acc |= ch << i;
60 60 if (--len == 0)
61 61 break;
62 62 }
63 63 for (i = 4; i >= 0; i--) {
64 64 val = acc % 85;
65 65 acc /= 85;
66 66 dst[i] = b85chars[val];
67 67 }
68 68 dst += 5;
69 69 }
70 70
71 71 if (!pad)
72 72 _PyBytes_Resize(&out, olen);
73 73
74 74 return out;
75 75 }
76 76
77 77 static PyObject *b85decode(PyObject *self, PyObject *args)
78 78 {
79 79 PyObject *out;
80 80 const char *text;
81 81 char *dst;
82 82 Py_ssize_t len, i, j, olen, cap;
83 83 int c;
84 84 unsigned int acc;
85 85
86 86 if (!PyArg_ParseTuple(args, "s#", &text, &len))
87 87 return NULL;
88 88
89 89 olen = len / 5 * 4;
90 90 i = len % 5;
91 91 if (i)
92 92 olen += i - 1;
93 93 if (!(out = PyBytes_FromStringAndSize(NULL, olen)))
94 94 return NULL;
95 95
96 96 dst = PyBytes_AsString(out);
97 97
98 98 i = 0;
99 99 while (i < len)
100 100 {
101 101 acc = 0;
102 102 cap = len - i - 1;
103 103 if (cap > 4)
104 104 cap = 4;
105 105 for (j = 0; j < cap; i++, j++)
106 106 {
107 107 c = b85dec[(int)*text++] - 1;
108 108 if (c < 0)
109 109 return PyErr_Format(
110 110 PyExc_ValueError,
111 111 "bad base85 character at position %d",
112 112 (int)i);
113 113 acc = acc * 85 + c;
114 114 }
115 115 if (i++ < len)
116 116 {
117 117 c = b85dec[(int)*text++] - 1;
118 118 if (c < 0)
119 119 return PyErr_Format(
120 120 PyExc_ValueError,
121 121 "bad base85 character at position %d",
122 122 (int)i);
123 123 /* overflow detection: 0xffffffff == "|NsC0",
124 124 * "|NsC" == 0x03030303 */
125 125 if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c)
126 126 return PyErr_Format(
127 127 PyExc_ValueError,
128 128 "bad base85 sequence at position %d",
129 129 (int)i);
130 130 acc += c;
131 131 }
132 132
133 133 cap = olen < 4 ? olen : 4;
134 134 olen -= cap;
135 135 for (j = 0; j < 4 - cap; j++)
136 136 acc *= 85;
137 137 if (cap && cap < 4)
138 138 acc += 0xffffff >> (cap - 1) * 8;
139 139 for (j = 0; j < cap; j++)
140 140 {
141 141 acc = (acc << 8) | (acc >> 24);
142 142 *dst++ = acc;
143 143 }
144 144 }
145 145
146 146 return out;
147 147 }
148 148
149 149 static char base85_doc[] = "Base85 Data Encoding";
150 150
151 151 static PyMethodDef methods[] = {
152 152 {"b85encode", b85encode, METH_VARARGS,
153 153 "Encode text in base85.\n\n"
154 154 "If the second parameter is true, pad the result to a multiple of "
155 155 "five characters.\n"},
156 156 {"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"},
157 157 {NULL, NULL}
158 158 };
159 159
160 static const int version = 1;
161
160 162 #ifdef IS_PY3K
161 163 static struct PyModuleDef base85_module = {
162 164 PyModuleDef_HEAD_INIT,
163 165 "base85",
164 166 base85_doc,
165 167 -1,
166 168 methods
167 169 };
168 170
169 171 PyMODINIT_FUNC PyInit_base85(void)
170 172 {
173 PyObject *m;
171 174 b85prep();
172 175
173 return PyModule_Create(&base85_module);
176 m = PyModule_Create(&base85_module);
177 PyModule_AddIntConstant(m, "version", version);
178 return m;
174 179 }
175 180 #else
176 181 PyMODINIT_FUNC initbase85(void)
177 182 {
178 Py_InitModule3("base85", methods, base85_doc);
183 PyObject *m;
184 m = Py_InitModule3("base85", methods, base85_doc);
179 185
180 186 b85prep();
187 PyModule_AddIntConstant(m, "version", version);
181 188 }
182 189 #endif
General Comments 0
You need to be logged in to leave comments. Login now