31 const unsigned char *text; |
31 const unsigned char *text; |
32 PyObject *out; |
32 PyObject *out; |
33 char *dst; |
33 char *dst; |
34 int len, olen, i; |
34 int len, olen, i; |
35 unsigned int acc, val, ch; |
35 unsigned int acc, val, ch; |
|
36 int pad = 0; |
36 |
37 |
37 if (!PyArg_ParseTuple(args, "s#", &text, &len)) |
38 if (!PyArg_ParseTuple(args, "s#|i", &text, &len, &pad)) |
38 return NULL; |
39 return NULL; |
39 |
40 |
40 olen = (len + 3) / 4 * 5; |
41 if (pad) |
41 if (!(out = PyString_FromStringAndSize(NULL, olen))) |
42 olen = ((len + 3) / 4 * 5) - 3; |
|
43 else { |
|
44 olen = len % 4; |
|
45 if (olen) |
|
46 olen++; |
|
47 olen += len / 4 * 5; |
|
48 } |
|
49 if (!(out = PyString_FromStringAndSize(NULL, olen + 3))) |
42 return NULL; |
50 return NULL; |
43 |
51 |
44 dst = PyString_AS_STRING(out); |
52 dst = PyString_AS_STRING(out); |
45 |
53 |
46 while (len) |
54 while (len) { |
47 { |
|
48 acc = 0; |
55 acc = 0; |
49 for (i = 24; i >= 0; i -= 8) { |
56 for (i = 24; i >= 0; i -= 8) { |
50 ch = *text++; |
57 ch = *text++; |
51 acc |= ch << i; |
58 acc |= ch << i; |
52 if (--len == 0) |
59 if (--len == 0) |
58 dst[i] = b85chars[val]; |
65 dst[i] = b85chars[val]; |
59 } |
66 } |
60 dst += 5; |
67 dst += 5; |
61 } |
68 } |
62 |
69 |
|
70 if (!pad) |
|
71 _PyString_Resize(&out, olen); |
|
72 |
63 return out; |
73 return out; |
64 } |
74 } |
65 |
75 |
66 static PyObject * |
76 static PyObject * |
67 b85decode(PyObject *self, PyObject *args) |
77 b85decode(PyObject *self, PyObject *args) |
68 { |
78 { |
69 PyObject *out; |
79 PyObject *out; |
70 const char *text; |
80 const char *text; |
71 char *dst; |
81 char *dst; |
72 int len, i, j, olen, c; |
82 int len, i, j, olen, c, cap; |
73 unsigned int acc; |
83 unsigned int acc; |
74 |
84 |
75 if (!PyArg_ParseTuple(args, "s#", &text, &len)) |
85 if (!PyArg_ParseTuple(args, "s#", &text, &len)) |
76 return NULL; |
86 return NULL; |
77 |
87 |
78 olen = (len + 4) / 5 * 4; |
88 olen = len / 5 * 4; |
|
89 i = len % 5; |
|
90 if (i) |
|
91 olen += i - 1; |
79 if (!(out = PyString_FromStringAndSize(NULL, olen))) |
92 if (!(out = PyString_FromStringAndSize(NULL, olen))) |
80 return NULL; |
93 return NULL; |
81 |
94 |
82 dst = PyString_AS_STRING(out); |
95 dst = PyString_AS_STRING(out); |
83 |
96 |
84 for (i = 1; len; i++) |
97 i = 0; |
|
98 while (i < len) |
85 { |
99 { |
86 acc = 0; |
100 acc = 0; |
87 for (j = 0; j < 4 && --len; j++) |
101 cap = len - i - 1; |
|
102 if (cap > 4) |
|
103 cap = 4; |
|
104 for (j = 0; j < cap; i++, j++) |
88 { |
105 { |
89 c = b85dec[(int)*text++] - 1; |
106 c = b85dec[(int)*text++] - 1; |
90 if (c < 0) |
107 if (c < 0) |
91 return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); |
108 return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); |
92 acc = acc * 85 + c; |
109 acc = acc * 85 + c; |
93 } |
110 } |
94 if (len--) |
111 if (i++ < len) |
95 { |
112 { |
96 c = b85dec[(int)*text++] - 1; |
113 c = b85dec[(int)*text++] - 1; |
97 if (c < 0) |
114 if (c < 0) |
98 return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); |
115 return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); |
|
116 /* overflow detection: 0xffffffff == "|NsC0", |
|
117 * "|NsC" == 0x03030303 */ |
|
118 if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c) |
|
119 return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i); |
|
120 acc += c; |
99 } |
121 } |
100 else |
|
101 c = 0; |
|
102 /* overflow detection: 0xffffffff == "|NsC0", |
|
103 * "|NsC" == 0x03030303 */ |
|
104 if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c) |
|
105 return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i); |
|
106 |
|
107 acc += c; |
|
108 |
122 |
109 for (j = 0; j < 4; j++) |
123 cap = olen < 4 ? olen : 4; |
|
124 olen -= cap; |
|
125 for (j = 0; j < 4 - cap; j++) |
|
126 acc *= 85; |
|
127 if (cap && cap < 4) |
|
128 acc += 0xffffff >> (cap - 1) * 8; |
|
129 for (j = 0; j < cap; j++) |
110 { |
130 { |
111 acc = (acc << 8) | (acc >> 24); |
131 acc = (acc << 8) | (acc >> 24); |
112 *dst++ = (char)acc; |
132 *dst++ = acc; |
113 } |
133 } |
114 } |
134 } |
115 |
135 |
116 return out; |
136 return out; |
117 } |
137 } |
118 |
138 |
119 static char base85_doc[] = "Base85 Data Encoding"; |
139 static char base85_doc[] = "Base85 Data Encoding"; |
120 |
140 |
121 static PyMethodDef methods[] = { |
141 static PyMethodDef methods[] = { |
122 {"b85encode", b85encode, METH_VARARGS, "encode text in base85\n"}, |
142 {"b85encode", b85encode, METH_VARARGS, |
123 {"b85decode", b85decode, METH_VARARGS, "decode base85 text\n"}, |
143 "Encode text in base85.\n\n" |
|
144 "If the second parameter is true, pad the result to a multiple of " |
|
145 "five characters.\n"}, |
|
146 {"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"}, |
124 {NULL, NULL} |
147 {NULL, NULL} |
125 }; |
148 }; |
126 |
149 |
127 PyMODINIT_FUNC initbase85(void) |
150 PyMODINIT_FUNC initbase85(void) |
128 { |
151 { |