Show More
@@ -234,11 +234,178 b' quit:' | |||
|
234 | 234 | return ret; |
|
235 | 235 | } |
|
236 | 236 | |
|
237 | ||
|
238 | static inline uint64_t ntohll(uint64_t x) | |
|
239 | { | |
|
240 | return (((uint64_t)ntohl((uint32_t)x)) << 32) | | |
|
241 | (uint64_t)ntohl((uint32_t)(x >> 32)); | |
|
242 | } | |
|
243 | ||
|
244 | const char nullid[20]; | |
|
245 | const int nullrev = -1; | |
|
246 | ||
|
247 | /* RevlogNG format (all in big endian, data may be inlined): | |
|
248 | * 6 bytes: offset | |
|
249 | * 2 bytes: flags | |
|
250 | * 4 bytes: compressed length | |
|
251 | * 4 bytes: uncompressed length | |
|
252 | * 4 bytes: base revision | |
|
253 | * 4 bytes: link revision | |
|
254 | * 4 bytes: parent 1 revision | |
|
255 | * 4 bytes: parent 2 revision | |
|
256 | * 32 bytes: nodeid (only 20 bytes used) | |
|
257 | */ | |
|
258 | static int _parse_index_ng (const char *data, int size, int inlined, | |
|
259 | PyObject *index, PyObject *nodemap) | |
|
260 | { | |
|
261 | PyObject *entry = NULL, *node_id = NULL, *n_obj = NULL; | |
|
262 | PyObject *nullrev_obj = NULL, *nullid_obj = NULL; | |
|
263 | int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2; | |
|
264 | uint64_t offset_flags; | |
|
265 | int n = 0; | |
|
266 | const char *end = data + size; | |
|
267 | ||
|
268 | while (data < end) { | |
|
269 | offset_flags = ntohll(*((uint64_t *) data)); | |
|
270 | if (n == 0) /* mask out version number for the first entry */ | |
|
271 | offset_flags &= 0xFFFF; | |
|
272 | ||
|
273 | comp_len = ntohl(*((uint32_t *) (data + 8))); | |
|
274 | uncomp_len = ntohl(*((uint32_t *) (data + 12))); | |
|
275 | base_rev = ntohl(*((uint32_t *) (data + 16))); | |
|
276 | link_rev = ntohl(*((uint32_t *) (data + 20))); | |
|
277 | parent_1 = ntohl(*((uint32_t *) (data + 24))); | |
|
278 | parent_2 = ntohl(*((uint32_t *) (data + 28))); | |
|
279 | node_id = PyString_FromStringAndSize(data + 32, 20); | |
|
280 | n_obj = PyInt_FromLong(n); | |
|
281 | if (!node_id || !n_obj || | |
|
282 | PyDict_SetItem(nodemap, node_id, n_obj) != 0) | |
|
283 | goto quit; | |
|
284 | Py_DECREF(n_obj); | |
|
285 | ||
|
286 | entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len, | |
|
287 | uncomp_len, base_rev, link_rev, | |
|
288 | parent_1, parent_2, node_id); | |
|
289 | PyObject_GC_UnTrack(entry); /* don't waste time with this */ | |
|
290 | if (!entry) | |
|
291 | goto quit; | |
|
292 | ||
|
293 | /* append to or set value in the index list */ | |
|
294 | if (inlined) { | |
|
295 | if (PyList_Append(index, entry) != 0) | |
|
296 | goto quit; | |
|
297 | Py_DECREF(entry); | |
|
298 | } else { | |
|
299 | PyList_SET_ITEM(index, n, entry); /* steals reference */ | |
|
300 | } | |
|
301 | ||
|
302 | data += 64 + (inlined ? comp_len : 0); | |
|
303 | n++; | |
|
304 | } | |
|
305 | if (data > end) { | |
|
306 | if (!PyErr_Occurred()) | |
|
307 | PyErr_SetString(PyExc_ValueError, "corrupt index file"); | |
|
308 | goto quit; | |
|
309 | } | |
|
310 | ||
|
311 | /* create the nullid/nullrev entry in the nodemap and the | |
|
312 | * magic nullid entry in the index at [-1] */ | |
|
313 | nullid_obj = PyString_FromStringAndSize(nullid, 20); | |
|
314 | nullrev_obj = PyInt_FromLong(nullrev); | |
|
315 | if (!nodemap || !nullid_obj || !nullrev_obj || | |
|
316 | PyDict_SetItem(nodemap, nullid_obj, nullrev_obj) != 0) | |
|
317 | goto quit; | |
|
318 | Py_DECREF(nullrev_obj); | |
|
319 | ||
|
320 | entry = Py_BuildValue("iiiiiiiN", 0, 0, 0, -1, -1, -1, -1, nullid_obj); | |
|
321 | PyObject_GC_UnTrack(entry); /* don't waste time with this */ | |
|
322 | if (!entry) | |
|
323 | goto quit; | |
|
324 | if (inlined) { | |
|
325 | if (PyList_Append(index, entry) != 0) | |
|
326 | goto quit; | |
|
327 | Py_DECREF(entry); | |
|
328 | } else { | |
|
329 | PyList_SET_ITEM(index, n, entry); /* steals reference */ | |
|
330 | } | |
|
331 | ||
|
332 | return 1; | |
|
333 | ||
|
334 | quit: | |
|
335 | Py_XDECREF(n_obj); | |
|
336 | Py_XDECREF(node_id); | |
|
337 | Py_XDECREF(entry); | |
|
338 | Py_XDECREF(nullrev_obj); | |
|
339 | Py_XDECREF(nullid_obj); | |
|
340 | return 0; | |
|
341 | } | |
|
342 | ||
|
343 | ||
|
344 | ||
|
345 | /* This function parses a index file and returns a Python tuple of the | |
|
346 | * following format: (index, nodemap, cache) | |
|
347 | * | |
|
348 | * index: a list of tuples containing the RevlogNG records | |
|
349 | * nodemap: a dict mapping node ids to indices in the index list | |
|
350 | * cache: if data is inlined, a tuple (index_file_content, 0) else None | |
|
351 | */ | |
|
352 | static PyObject *parse_index(PyObject *self, PyObject *args) | |
|
353 | { | |
|
354 | const char *data; | |
|
355 | int size, inlined; | |
|
356 | PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL; | |
|
357 | PyObject *data_obj = NULL, *inlined_obj; | |
|
358 | ||
|
359 | if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj)) | |
|
360 | return NULL; | |
|
361 | inlined = inlined_obj && PyObject_IsTrue(inlined_obj); | |
|
362 | ||
|
363 | /* If no data is inlined, we know the size of the index list in | |
|
364 | * advance: size divided by size of one one revlog record (64 bytes) | |
|
365 | * plus one for the nullid */ | |
|
366 | index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1); | |
|
367 | if (!index) | |
|
368 | goto quit; | |
|
369 | ||
|
370 | nodemap = PyDict_New(); | |
|
371 | ||
|
372 | /* set up the cache return value */ | |
|
373 | if (inlined) { | |
|
374 | /* Note that the reference to data_obj is only borrowed */ | |
|
375 | data_obj = PyTuple_GET_ITEM(args, 0); | |
|
376 | cache = Py_BuildValue("iO", 0, data_obj); | |
|
377 | if (!cache) | |
|
378 | goto quit; | |
|
379 | } else { | |
|
380 | cache = Py_None; | |
|
381 | Py_INCREF(Py_None); | |
|
382 | } | |
|
383 | ||
|
384 | /* actually populate the index and the nodemap with data */ | |
|
385 | if (!_parse_index_ng (data, size, inlined, index, nodemap)) | |
|
386 | goto quit; | |
|
387 | ||
|
388 | rval = Py_BuildValue("NNN", index, nodemap, cache); | |
|
389 | if (!rval) | |
|
390 | goto quit; | |
|
391 | return rval; | |
|
392 | ||
|
393 | quit: | |
|
394 | Py_XDECREF(index); | |
|
395 | Py_XDECREF(nodemap); | |
|
396 | Py_XDECREF(cache); | |
|
397 | Py_XDECREF(rval); | |
|
398 | Py_XDECREF(data_obj); | |
|
399 | return NULL; | |
|
400 | } | |
|
401 | ||
|
402 | ||
|
237 | 403 | static char parsers_doc[] = "Efficient content parsing."; |
|
238 | 404 | |
|
239 | 405 | static PyMethodDef methods[] = { |
|
240 | 406 | {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"}, |
|
241 | 407 | {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"}, |
|
408 | {"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"}, | |
|
242 | 409 | {NULL, NULL} |
|
243 | 410 | }; |
|
244 | 411 |
General Comments 0
You need to be logged in to leave comments.
Login now