Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/base85.c @ 3287:e93c926e069e
Handle odd-sized base85 input and output
author | Brendan Cully <brendan@kublai.com> |
---|---|
date | Sat, 07 Oct 2006 16:21:33 -0700 |
parents | 1f2c3983a6c5 |
children | a5209a1e53d8 |
comparison
equal
deleted
inserted
replaced
3279:1f2c3983a6c5 | 3287:e93c926e069e |
---|---|
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 { |