mercurial/parsers.c
changeset 13254 5ef5eb1f3515
parent 11361 3de3d670d2b6
child 13263 c45b5faa6213
equal deleted inserted replaced
13253:61c9bc3da402 13254:5ef5eb1f3515
   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 = {