##// END OF EJS Templates
Fix missing uint64_t definition in parsers.c under Windows
Dhruva Krishnamurthy -
r7122:3cf699e8 default
parent child Browse files
Show More
@@ -1,415 +1,416 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 19 return c - 'a' + 10;
20 20 if (c >= 'A' && c <= 'F')
21 21 return c - 'A' + 10;
22 22
23 23 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
24 24 return 0;
25 25 }
26 26
27 27 /*
28 28 * Turn a hex-encoded string into binary.
29 29 */
30 30 static PyObject *unhexlify(const char *str, int len)
31 31 {
32 32 PyObject *ret;
33 33 const char *c;
34 34 char *d;
35 35
36 36 ret = PyString_FromStringAndSize(NULL, len / 2);
37 37 if (!ret)
38 38 return NULL;
39 39
40 40 d = PyString_AS_STRING(ret);
41 41 for (c = str; c < str + len;) {
42 42 int hi = hexdigit(*c++);
43 43 int lo = hexdigit(*c++);
44 44 *d++ = (hi << 4) | lo;
45 45 }
46 46
47 47 return ret;
48 48 }
49 49
50 50 /*
51 51 * This code assumes that a manifest is stitched together with newline
52 52 * ('\n') characters.
53 53 */
54 54 static PyObject *parse_manifest(PyObject *self, PyObject *args)
55 55 {
56 56 PyObject *mfdict, *fdict;
57 57 char *str, *cur, *start, *zero;
58 58 int len;
59 59
60 60 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
61 61 &PyDict_Type, &mfdict,
62 62 &PyDict_Type, &fdict,
63 63 &str, &len))
64 64 goto quit;
65 65
66 66 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
67 67 PyObject *file = NULL, *node = NULL;
68 68 PyObject *flags = NULL;
69 69 int nlen;
70 70
71 71 if (!*cur) {
72 72 zero = cur;
73 73 continue;
74 74 }
75 75 else if (*cur != '\n')
76 76 continue;
77 77
78 78 if (!zero) {
79 79 PyErr_SetString(PyExc_ValueError,
80 80 "manifest entry has no separator");
81 81 goto quit;
82 82 }
83 83
84 84 file = PyString_FromStringAndSize(start, zero - start);
85 85 if (!file)
86 86 goto bail;
87 87
88 88 nlen = cur - zero - 1;
89 89
90 90 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
91 91 if (!node)
92 92 goto bail;
93 93
94 94 if (nlen > 40) {
95 95 PyObject *flags;
96 96
97 97 flags = PyString_FromStringAndSize(zero + 41,
98 98 nlen - 40);
99 99 if (!flags)
100 100 goto bail;
101 101
102 102 if (PyDict_SetItem(fdict, file, flags) == -1)
103 103 goto bail;
104 104 }
105 105
106 106 if (PyDict_SetItem(mfdict, file, node) == -1)
107 107 goto bail;
108 108
109 109 start = cur + 1;
110 110 zero = NULL;
111 111
112 112 Py_XDECREF(flags);
113 113 Py_XDECREF(node);
114 114 Py_XDECREF(file);
115 115 continue;
116 116 bail:
117 117 Py_XDECREF(flags);
118 118 Py_XDECREF(node);
119 119 Py_XDECREF(file);
120 120 goto quit;
121 121 }
122 122
123 123 if (len > 0 && *(cur - 1) != '\n') {
124 124 PyErr_SetString(PyExc_ValueError,
125 125 "manifest contains trailing garbage");
126 126 goto quit;
127 127 }
128 128
129 129 Py_INCREF(Py_None);
130 130 return Py_None;
131 131 quit:
132 132 return NULL;
133 133 }
134 134
135 135 #ifdef _WIN32
136 136 # ifdef _MSC_VER
137 137 /* msvc 6.0 has problems */
138 138 # define inline __inline
139 139 typedef unsigned long uint32_t;
140 typedef unsigned __int64 uint64_t;
140 141 # else
141 142 # include <stdint.h>
142 143 # endif
143 144 static uint32_t ntohl(uint32_t x)
144 145 {
145 146 return ((x & 0x000000ffUL) << 24) |
146 147 ((x & 0x0000ff00UL) << 8) |
147 148 ((x & 0x00ff0000UL) >> 8) |
148 149 ((x & 0xff000000UL) >> 24);
149 150 }
150 151 #else
151 152 /* not windows */
152 153 # include <sys/types.h>
153 154 # if defined __BEOS__ && !defined __HAIKU__
154 155 # include <ByteOrder.h>
155 156 # else
156 157 # include <arpa/inet.h>
157 158 # endif
158 159 # include <inttypes.h>
159 160 #endif
160 161
161 162 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
162 163 {
163 164 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
164 165 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
165 166 char *str, *cur, *end, *cpos;
166 167 int state, mode, size, mtime, flen;
167 168 int len;
168 169 char decode[16]; /* for alignment */
169 170
170 171 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
171 172 &PyDict_Type, &dmap,
172 173 &PyDict_Type, &cmap,
173 174 &str, &len))
174 175 goto quit;
175 176
176 177 /* read parents */
177 178 if (len < 40)
178 179 goto quit;
179 180
180 181 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
181 182 if (!parents)
182 183 goto quit;
183 184
184 185 /* read filenames */
185 186 cur = str + 40;
186 187 end = str + len;
187 188
188 189 while (cur < end - 17) {
189 190 /* unpack header */
190 191 state = *cur;
191 192 memcpy(decode, cur + 1, 16);
192 193 mode = ntohl(*(uint32_t *)(decode));
193 194 size = ntohl(*(uint32_t *)(decode + 4));
194 195 mtime = ntohl(*(uint32_t *)(decode + 8));
195 196 flen = ntohl(*(uint32_t *)(decode + 12));
196 197 cur += 17;
197 198 if (cur + flen > end)
198 199 goto quit;
199 200
200 201 entry = Py_BuildValue("ciii", state, mode, size, mtime);
201 202 PyObject_GC_UnTrack(entry); /* don't waste time with this */
202 203 if (!entry)
203 204 goto quit;
204 205
205 206 cpos = memchr(cur, 0, flen);
206 207 if (cpos) {
207 208 fname = PyString_FromStringAndSize(cur, cpos - cur);
208 209 cname = PyString_FromStringAndSize(cpos + 1,
209 210 flen - (cpos - cur) - 1);
210 211 if (!fname || !cname ||
211 212 PyDict_SetItem(cmap, fname, cname) == -1 ||
212 213 PyDict_SetItem(dmap, fname, entry) == -1)
213 214 goto quit;
214 215 Py_DECREF(cname);
215 216 } else {
216 217 fname = PyString_FromStringAndSize(cur, flen);
217 218 if (!fname ||
218 219 PyDict_SetItem(dmap, fname, entry) == -1)
219 220 goto quit;
220 221 }
221 222 cur += flen;
222 223 Py_DECREF(fname);
223 224 Py_DECREF(entry);
224 225 fname = cname = entry = NULL;
225 226 }
226 227
227 228 ret = parents;
228 229 Py_INCREF(ret);
229 230 quit:
230 231 Py_XDECREF(fname);
231 232 Py_XDECREF(cname);
232 233 Py_XDECREF(entry);
233 234 Py_XDECREF(parents);
234 235 return ret;
235 236 }
236 237
237 238
238 239 static inline uint64_t ntohll(uint64_t x)
239 240 {
240 241 return (((uint64_t)ntohl((uint32_t)x)) << 32) |
241 242 (uint64_t)ntohl((uint32_t)(x >> 32));
242 243 }
243 244
244 245 const char nullid[20];
245 246 const int nullrev = -1;
246 247
247 248 /* RevlogNG format (all in big endian, data may be inlined):
248 249 * 6 bytes: offset
249 250 * 2 bytes: flags
250 251 * 4 bytes: compressed length
251 252 * 4 bytes: uncompressed length
252 253 * 4 bytes: base revision
253 254 * 4 bytes: link revision
254 255 * 4 bytes: parent 1 revision
255 256 * 4 bytes: parent 2 revision
256 257 * 32 bytes: nodeid (only 20 bytes used)
257 258 */
258 259 static int _parse_index_ng (const char *data, int size, int inlined,
259 260 PyObject *index, PyObject *nodemap)
260 261 {
261 262 PyObject *entry = NULL, *node_id = NULL, *n_obj = NULL;
262 263 PyObject *nullrev_obj = NULL, *nullid_obj = NULL;
263 264 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
264 265 uint64_t offset_flags;
265 266 int n = 0;
266 267 const char *end = data + size;
267 268
268 269 while (data < end) {
269 270 offset_flags = ntohll(*((uint64_t *) data));
270 271 if (n == 0) /* mask out version number for the first entry */
271 272 offset_flags &= 0xFFFF;
272 273
273 274 comp_len = ntohl(*((uint32_t *) (data + 8)));
274 275 uncomp_len = ntohl(*((uint32_t *) (data + 12)));
275 276 base_rev = ntohl(*((uint32_t *) (data + 16)));
276 277 link_rev = ntohl(*((uint32_t *) (data + 20)));
277 278 parent_1 = ntohl(*((uint32_t *) (data + 24)));
278 279 parent_2 = ntohl(*((uint32_t *) (data + 28)));
279 280 node_id = PyString_FromStringAndSize(data + 32, 20);
280 281 n_obj = PyInt_FromLong(n);
281 282 if (!node_id || !n_obj ||
282 283 PyDict_SetItem(nodemap, node_id, n_obj) != 0)
283 284 goto quit;
284 285 Py_DECREF(n_obj);
285 286
286 287 entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len,
287 288 uncomp_len, base_rev, link_rev,
288 289 parent_1, parent_2, node_id);
289 290 PyObject_GC_UnTrack(entry); /* don't waste time with this */
290 291 if (!entry)
291 292 goto quit;
292 293
293 294 /* append to or set value in the index list */
294 295 if (inlined) {
295 296 if (PyList_Append(index, entry) != 0)
296 297 goto quit;
297 298 Py_DECREF(entry);
298 299 } else {
299 300 PyList_SET_ITEM(index, n, entry); /* steals reference */
300 301 }
301 302
302 303 data += 64 + (inlined ? comp_len : 0);
303 304 n++;
304 305 }
305 306 if (data > end) {
306 307 if (!PyErr_Occurred())
307 308 PyErr_SetString(PyExc_ValueError, "corrupt index file");
308 309 goto quit;
309 310 }
310 311
311 312 /* create the nullid/nullrev entry in the nodemap and the
312 313 * magic nullid entry in the index at [-1] */
313 314 nullid_obj = PyString_FromStringAndSize(nullid, 20);
314 315 nullrev_obj = PyInt_FromLong(nullrev);
315 316 if (!nodemap || !nullid_obj || !nullrev_obj ||
316 317 PyDict_SetItem(nodemap, nullid_obj, nullrev_obj) != 0)
317 318 goto quit;
318 319 Py_DECREF(nullrev_obj);
319 320
320 321 entry = Py_BuildValue("iiiiiiiN", 0, 0, 0, -1, -1, -1, -1, nullid_obj);
321 322 PyObject_GC_UnTrack(entry); /* don't waste time with this */
322 323 if (!entry)
323 324 goto quit;
324 325 if (inlined) {
325 326 if (PyList_Append(index, entry) != 0)
326 327 goto quit;
327 328 Py_DECREF(entry);
328 329 } else {
329 330 PyList_SET_ITEM(index, n, entry); /* steals reference */
330 331 }
331 332
332 333 return 1;
333 334
334 335 quit:
335 336 Py_XDECREF(n_obj);
336 337 Py_XDECREF(node_id);
337 338 Py_XDECREF(entry);
338 339 Py_XDECREF(nullrev_obj);
339 340 Py_XDECREF(nullid_obj);
340 341 return 0;
341 342 }
342 343
343 344
344 345
345 346 /* This function parses a index file and returns a Python tuple of the
346 347 * following format: (index, nodemap, cache)
347 348 *
348 349 * index: a list of tuples containing the RevlogNG records
349 350 * nodemap: a dict mapping node ids to indices in the index list
350 351 * cache: if data is inlined, a tuple (index_file_content, 0) else None
351 352 */
352 353 static PyObject *parse_index(PyObject *self, PyObject *args)
353 354 {
354 355 const char *data;
355 356 int size, inlined;
356 357 PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL;
357 358 PyObject *data_obj = NULL, *inlined_obj;
358 359
359 360 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
360 361 return NULL;
361 362 inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
362 363
363 364 /* If no data is inlined, we know the size of the index list in
364 365 * advance: size divided by size of one one revlog record (64 bytes)
365 366 * plus one for the nullid */
366 367 index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1);
367 368 if (!index)
368 369 goto quit;
369 370
370 371 nodemap = PyDict_New();
371 372
372 373 /* set up the cache return value */
373 374 if (inlined) {
374 375 /* Note that the reference to data_obj is only borrowed */
375 376 data_obj = PyTuple_GET_ITEM(args, 0);
376 377 cache = Py_BuildValue("iO", 0, data_obj);
377 378 if (!cache)
378 379 goto quit;
379 380 } else {
380 381 cache = Py_None;
381 382 Py_INCREF(Py_None);
382 383 }
383 384
384 385 /* actually populate the index and the nodemap with data */
385 386 if (!_parse_index_ng (data, size, inlined, index, nodemap))
386 387 goto quit;
387 388
388 389 rval = Py_BuildValue("NNN", index, nodemap, cache);
389 390 if (!rval)
390 391 goto quit;
391 392 return rval;
392 393
393 394 quit:
394 395 Py_XDECREF(index);
395 396 Py_XDECREF(nodemap);
396 397 Py_XDECREF(cache);
397 398 Py_XDECREF(rval);
398 399 Py_XDECREF(data_obj);
399 400 return NULL;
400 401 }
401 402
402 403
403 404 static char parsers_doc[] = "Efficient content parsing.";
404 405
405 406 static PyMethodDef methods[] = {
406 407 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
407 408 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
408 409 {"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"},
409 410 {NULL, NULL}
410 411 };
411 412
412 413 PyMODINIT_FUNC initparsers(void)
413 414 {
414 415 Py_InitModule3("parsers", methods, parsers_doc);
415 416 }
General Comments 0
You need to be logged in to leave comments. Login now