##// END OF EJS Templates
parsers: speed up hex decoding for manifests
Matt Mackall -
r7092:fb3fc276 default
parent child Browse files
Show More
@@ -1,169 +1,146 b''
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
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
10 10 #include <Python.h>
11 11 #include <ctype.h>
12 12 #include <string.h>
13 13
14 14 static int hexdigit(char c)
15 15 {
16 16 if (c >= '0' && c <= '9')
17 17 return c - '0';
18
18 if (c >= 'a' && c <= 'f')
19 return c - 'a' + 10;
19 20 if (c >= 'A' && c <= 'F')
20 21 return c - 'A' + 10;
21 22
22 if (c >= 'a' && c <= 'f')
23 return c - 'a' + 10;
24
25 return -1;
23 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
24 return 0;
26 25 }
27 26
28 27 /*
29 28 * Turn a hex-encoded string into binary.
30 29 */
31 30 static PyObject *unhexlify(const char *str, int len)
32 31 {
33 PyObject *ret = NULL;
32 PyObject *ret;
34 33 const char *c;
35 34 char *d;
36 35
37 if (len % 2) {
38 PyErr_SetString(PyExc_ValueError,
39 "input is not even in length");
40 goto bail;
41 }
42
43 36 ret = PyString_FromStringAndSize(NULL, len / 2);
44 37 if (!ret)
45 goto bail;
38 return NULL;
46 39
47 d = PyString_AsString(ret);
48 if (!d)
49 goto bail;
50
40 d = PyString_AS_STRING(ret);
51 41 for (c = str; c < str + len;) {
52 42 int hi = hexdigit(*c++);
53 43 int lo = hexdigit(*c++);
54
55 if (hi == -1 || lo == -1) {
56 PyErr_SetString(PyExc_ValueError,
57 "input contains non-hex character");
58 goto bail;
59 }
60
61 44 *d++ = (hi << 4) | lo;
62 45 }
63 46
64 goto done;
65
66 bail:
67 Py_XDECREF(ret);
68 ret = NULL;
69 done:
70 47 return ret;
71 48 }
72 49
73 50 /*
74 51 * This code assumes that a manifest is stitched together with newline
75 52 * ('\n') characters.
76 53 */
77 54 static PyObject *parse_manifest(PyObject *self, PyObject *args)
78 55 {
79 56 PyObject *mfdict, *fdict;
80 57 char *str, *cur, *start, *zero;
81 58 int len;
82 59
83 60 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
84 61 &PyDict_Type, &mfdict,
85 62 &PyDict_Type, &fdict,
86 63 &str, &len))
87 64 goto quit;
88 65
89 66 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
90 67 PyObject *file = NULL, *node = NULL;
91 68 PyObject *flags = NULL;
92 69 int nlen;
93 70
94 71 if (!*cur) {
95 72 zero = cur;
96 73 continue;
97 74 }
98 75 else if (*cur != '\n')
99 76 continue;
100 77
101 78 if (!zero) {
102 79 PyErr_SetString(PyExc_ValueError,
103 80 "manifest entry has no separator");
104 81 goto quit;
105 82 }
106 83
107 84 file = PyString_FromStringAndSize(start, zero - start);
108 85 if (!file)
109 86 goto bail;
110 87
111 88 nlen = cur - zero - 1;
112 89
113 90 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
114 91 if (!node)
115 92 goto bail;
116 93
117 94 if (nlen > 40) {
118 95 PyObject *flags;
119 96
120 97 flags = PyString_FromStringAndSize(zero + 41,
121 98 nlen - 40);
122 99 if (!flags)
123 100 goto bail;
124 101
125 102 if (PyDict_SetItem(fdict, file, flags) == -1)
126 103 goto bail;
127 104 }
128 105
129 106 if (PyDict_SetItem(mfdict, file, node) == -1)
130 107 goto bail;
131 108
132 109 start = cur + 1;
133 110 zero = NULL;
134 111
135 112 Py_XDECREF(flags);
136 113 Py_XDECREF(node);
137 114 Py_XDECREF(file);
138 115 continue;
139 116 bail:
140 117 Py_XDECREF(flags);
141 118 Py_XDECREF(node);
142 119 Py_XDECREF(file);
143 120 goto quit;
144 121 }
145 122
146 123 if (len > 0 && *(cur - 1) != '\n') {
147 124 PyErr_SetString(PyExc_ValueError,
148 125 "manifest contains trailing garbage");
149 126 goto quit;
150 127 }
151 128
152 129 Py_INCREF(Py_None);
153 130 return Py_None;
154 131
155 132 quit:
156 133 return NULL;
157 134 }
158 135
159 136 static char parsers_doc[] = "Efficient content parsing.";
160 137
161 138 static PyMethodDef methods[] = {
162 139 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
163 140 {NULL, NULL}
164 141 };
165 142
166 143 PyMODINIT_FUNC initparsers(void)
167 144 {
168 145 Py_InitModule3("parsers", methods, parsers_doc);
169 146 }
General Comments 0
You need to be logged in to leave comments. Login now