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