242 } |
242 } |
243 |
243 |
244 const char nullid[20]; |
244 const char nullid[20]; |
245 const int nullrev = -1; |
245 const int nullrev = -1; |
246 |
246 |
247 /* create an index tuple, insert into the nodemap */ |
|
248 static PyObject * _build_idx_entry(PyObject *nodemap, int n, uint64_t offset_flags, |
|
249 int comp_len, int uncomp_len, int base_rev, |
|
250 int link_rev, int parent_1, int parent_2, |
|
251 const char *c_node_id) |
|
252 { |
|
253 int err; |
|
254 PyObject *entry, *node_id, *n_obj; |
|
255 |
|
256 node_id = PyBytes_FromStringAndSize(c_node_id, 20); |
|
257 n_obj = PyInt_FromLong(n); |
|
258 |
|
259 if (!node_id || !n_obj) |
|
260 err = -1; |
|
261 else |
|
262 err = PyDict_SetItem(nodemap, node_id, n_obj); |
|
263 |
|
264 Py_XDECREF(n_obj); |
|
265 if (err) |
|
266 goto error_dealloc; |
|
267 |
|
268 entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len, |
|
269 uncomp_len, base_rev, link_rev, |
|
270 parent_1, parent_2, node_id); |
|
271 if (!entry) |
|
272 goto error_dealloc; |
|
273 PyObject_GC_UnTrack(entry); /* don't waste time with this */ |
|
274 |
|
275 return entry; |
|
276 |
|
277 error_dealloc: |
|
278 Py_XDECREF(node_id); |
|
279 return NULL; |
|
280 } |
|
281 |
|
282 /* RevlogNG format (all in big endian, data may be inlined): |
247 /* RevlogNG format (all in big endian, data may be inlined): |
283 * 6 bytes: offset |
248 * 6 bytes: offset |
284 * 2 bytes: flags |
249 * 2 bytes: flags |
285 * 4 bytes: compressed length |
250 * 4 bytes: compressed length |
286 * 4 bytes: uncompressed length |
251 * 4 bytes: uncompressed length |
288 * 4 bytes: link revision |
253 * 4 bytes: link revision |
289 * 4 bytes: parent 1 revision |
254 * 4 bytes: parent 1 revision |
290 * 4 bytes: parent 2 revision |
255 * 4 bytes: parent 2 revision |
291 * 32 bytes: nodeid (only 20 bytes used) |
256 * 32 bytes: nodeid (only 20 bytes used) |
292 */ |
257 */ |
293 static int _parse_index_ng (const char *data, int size, int inlined, |
258 static int _parse_index_ng(const char *data, int size, int inlined, |
294 PyObject *index, PyObject *nodemap) |
259 PyObject *index) |
295 { |
260 { |
296 PyObject *entry; |
261 PyObject *entry; |
297 int n = 0, err; |
262 int n = 0, err; |
298 uint64_t offset_flags; |
263 uint64_t offset_flags; |
299 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2; |
264 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2; |
319 link_rev = ntohl(*((uint32_t *)(decode + 20))); |
284 link_rev = ntohl(*((uint32_t *)(decode + 20))); |
320 parent_1 = ntohl(*((uint32_t *)(decode + 24))); |
285 parent_1 = ntohl(*((uint32_t *)(decode + 24))); |
321 parent_2 = ntohl(*((uint32_t *)(decode + 28))); |
286 parent_2 = ntohl(*((uint32_t *)(decode + 28))); |
322 c_node_id = decode + 32; |
287 c_node_id = decode + 32; |
323 |
288 |
324 entry = _build_idx_entry(nodemap, n, offset_flags, |
289 entry = Py_BuildValue("Liiiiiis#", offset_flags, comp_len, |
325 comp_len, uncomp_len, base_rev, |
290 uncomp_len, base_rev, link_rev, |
326 link_rev, parent_1, parent_2, |
291 parent_1, parent_2, c_node_id, 20); |
327 c_node_id); |
292 |
328 if (!entry) |
293 if (!entry) |
329 return 0; |
294 return 0; |
|
295 |
|
296 PyObject_GC_UnTrack(entry); /* don't waste time with this */ |
330 |
297 |
331 if (inlined) { |
298 if (inlined) { |
332 err = PyList_Append(index, entry); |
299 err = PyList_Append(index, entry); |
333 Py_DECREF(entry); |
300 Py_DECREF(entry); |
334 if (err) |
301 if (err) |
346 if (!PyErr_Occurred()) |
313 if (!PyErr_Occurred()) |
347 PyErr_SetString(PyExc_ValueError, "corrupt index file"); |
314 PyErr_SetString(PyExc_ValueError, "corrupt index file"); |
348 return 0; |
315 return 0; |
349 } |
316 } |
350 |
317 |
351 /* create the nullid/nullrev entry in the nodemap and the |
318 /* create the magic nullid entry in the index at [-1] */ |
352 * magic nullid entry in the index at [-1] */ |
319 entry = Py_BuildValue("Liiiiiis#", (uint64_t)0, 0, 0, -1, -1, -1, -1, nullid, 20); |
353 entry = _build_idx_entry(nodemap, |
320 |
354 nullrev, 0, 0, 0, -1, -1, -1, -1, nullid); |
|
355 if (!entry) |
321 if (!entry) |
356 return 0; |
322 return 0; |
|
323 |
|
324 PyObject_GC_UnTrack(entry); /* don't waste time with this */ |
|
325 |
357 if (inlined) { |
326 if (inlined) { |
358 err = PyList_Append(index, entry); |
327 err = PyList_Append(index, entry); |
359 Py_DECREF(entry); |
328 Py_DECREF(entry); |
360 if (err) |
329 if (err) |
361 return 0; |
330 return 0; |
364 |
333 |
365 return 1; |
334 return 1; |
366 } |
335 } |
367 |
336 |
368 /* This function parses a index file and returns a Python tuple of the |
337 /* This function parses a index file and returns a Python tuple of the |
369 * following format: (index, nodemap, cache) |
338 * following format: (index, cache) |
370 * |
339 * |
371 * index: a list of tuples containing the RevlogNG records |
340 * index: a list of tuples containing the RevlogNG records |
372 * nodemap: a dict mapping node ids to indices in the index list |
|
373 * cache: if data is inlined, a tuple (index_file_content, 0) else None |
341 * cache: if data is inlined, a tuple (index_file_content, 0) else None |
374 */ |
342 */ |
375 static PyObject *parse_index(PyObject *self, PyObject *args) |
343 static PyObject *parse_index2(PyObject *self, PyObject *args) |
376 { |
344 { |
377 const char *data; |
345 const char *data; |
378 int size, inlined; |
346 int size, inlined; |
379 PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL; |
347 PyObject *rval = NULL, *index = NULL, *cache = NULL; |
380 PyObject *data_obj = NULL, *inlined_obj; |
348 PyObject *data_obj = NULL, *inlined_obj; |
381 |
349 |
382 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj)) |
350 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj)) |
383 return NULL; |
351 return NULL; |
384 inlined = inlined_obj && PyObject_IsTrue(inlined_obj); |
352 inlined = inlined_obj && PyObject_IsTrue(inlined_obj); |
386 /* If no data is inlined, we know the size of the index list in |
354 /* If no data is inlined, we know the size of the index list in |
387 * advance: size divided by size of one one revlog record (64 bytes) |
355 * advance: size divided by size of one one revlog record (64 bytes) |
388 * plus one for the nullid */ |
356 * plus one for the nullid */ |
389 index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1); |
357 index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1); |
390 if (!index) |
358 if (!index) |
391 goto quit; |
|
392 |
|
393 nodemap = PyDict_New(); |
|
394 if (!nodemap) |
|
395 goto quit; |
359 goto quit; |
396 |
360 |
397 /* set up the cache return value */ |
361 /* set up the cache return value */ |
398 if (inlined) { |
362 if (inlined) { |
399 /* Note that the reference to data_obj is only borrowed */ |
363 /* Note that the reference to data_obj is only borrowed */ |
404 } else { |
368 } else { |
405 cache = Py_None; |
369 cache = Py_None; |
406 Py_INCREF(Py_None); |
370 Py_INCREF(Py_None); |
407 } |
371 } |
408 |
372 |
409 /* actually populate the index and the nodemap with data */ |
373 /* actually populate the index with data */ |
410 if (!_parse_index_ng (data, size, inlined, index, nodemap)) |
374 if (!_parse_index_ng(data, size, inlined, index)) |
411 goto quit; |
375 goto quit; |
412 |
376 |
413 rval = Py_BuildValue("NNN", index, nodemap, cache); |
377 rval = Py_BuildValue("NN", index, cache); |
414 if (!rval) |
378 if (!rval) |
415 goto quit; |
379 goto quit; |
416 return rval; |
380 return rval; |
417 |
381 |
418 quit: |
382 quit: |
419 Py_XDECREF(index); |
383 Py_XDECREF(index); |
420 Py_XDECREF(nodemap); |
|
421 Py_XDECREF(cache); |
384 Py_XDECREF(cache); |
422 Py_XDECREF(rval); |
385 Py_XDECREF(rval); |
423 return NULL; |
386 return NULL; |
424 } |
387 } |
425 |
388 |
427 static char parsers_doc[] = "Efficient content parsing."; |
390 static char parsers_doc[] = "Efficient content parsing."; |
428 |
391 |
429 static PyMethodDef methods[] = { |
392 static PyMethodDef methods[] = { |
430 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"}, |
393 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"}, |
431 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"}, |
394 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"}, |
432 {"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"}, |
395 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"}, |
433 {NULL, NULL} |
396 {NULL, NULL} |
434 }; |
397 }; |
435 |
398 |
436 #ifdef IS_PY3K |
399 #ifdef IS_PY3K |
437 static struct PyModuleDef parsers_module = { |
400 static struct PyModuleDef parsers_module = { |