mercurial/mpatch.c
changeset 29693 b9b9f9a92481
parent 29692 6b3a8d034b69
child 29694 55dd12204b8e
equal deleted inserted replaced
29692:6b3a8d034b69 29693:b9b9f9a92481
    39 
    39 
    40 struct mpatch_flist {
    40 struct mpatch_flist {
    41 	struct mpatch_frag *base, *head, *tail;
    41 	struct mpatch_frag *base, *head, *tail;
    42 };
    42 };
    43 
    43 
    44 static struct mpatch_flist *lalloc(ssize_t size)
    44 struct mpatch_flist *lalloc(ssize_t size)
    45 {
    45 {
    46 	struct mpatch_flist *a = NULL;
    46 	struct mpatch_flist *a = NULL;
    47 
    47 
    48 	if (size < 1)
    48 	if (size < 1)
    49 		size = 1;
    49 		size = 1;
    61 	if (!PyErr_Occurred())
    61 	if (!PyErr_Occurred())
    62 		PyErr_NoMemory();
    62 		PyErr_NoMemory();
    63 	return NULL;
    63 	return NULL;
    64 }
    64 }
    65 
    65 
    66 static void mpatch_lfree(struct mpatch_flist *a)
    66 void mpatch_lfree(struct mpatch_flist *a)
    67 {
    67 {
    68 	if (a) {
    68 	if (a) {
    69 		free(a->base);
    69 		free(a->base);
    70 		free(a);
    70 		free(a);
    71 	}
    71 	}
   200 	mpatch_lfree(b);
   200 	mpatch_lfree(b);
   201 	return c;
   201 	return c;
   202 }
   202 }
   203 
   203 
   204 /* decode a binary patch into a hunk list */
   204 /* decode a binary patch into a hunk list */
   205 static struct mpatch_flist *mpatch_decode(const char *bin, ssize_t len)
   205 struct mpatch_flist *mpatch_decode(const char *bin, ssize_t len)
   206 {
   206 {
   207 	struct mpatch_flist *l;
   207 	struct mpatch_flist *l;
   208 	struct mpatch_frag *lt;
   208 	struct mpatch_frag *lt;
   209 	int pos = 0;
   209 	int pos = 0;
   210 
   210 
   236 	l->tail = lt;
   236 	l->tail = lt;
   237 	return l;
   237 	return l;
   238 }
   238 }
   239 
   239 
   240 /* calculate the size of resultant text */
   240 /* calculate the size of resultant text */
   241 static ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
   241 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
   242 {
   242 {
   243 	ssize_t outlen = 0, last = 0;
   243 	ssize_t outlen = 0, last = 0;
   244 	struct mpatch_frag *f = l->head;
   244 	struct mpatch_frag *f = l->head;
   245 
   245 
   246 	while (f != l->tail) {
   246 	while (f != l->tail) {
   258 
   258 
   259 	outlen += len - last;
   259 	outlen += len - last;
   260 	return outlen;
   260 	return outlen;
   261 }
   261 }
   262 
   262 
   263 static int mpatch_apply(char *buf, const char *orig, ssize_t len,
   263 int mpatch_apply(char *buf, const char *orig, ssize_t len,
   264 	struct mpatch_flist *l)
   264 	struct mpatch_flist *l)
   265 {
   265 {
   266 	struct mpatch_frag *f = l->head;
   266 	struct mpatch_frag *f = l->head;
   267 	int last = 0;
   267 	int last = 0;
   268 	char *p = buf;
   268 	char *p = buf;
   284 	memcpy(p, orig + last, len - last);
   284 	memcpy(p, orig + last, len - last);
   285 	return 1;
   285 	return 1;
   286 }
   286 }
   287 
   287 
   288 /* recursively generate a patch of all bins between start and end */
   288 /* recursively generate a patch of all bins between start and end */
   289 static struct mpatch_flist *mpatch_fold(PyObject *bins, ssize_t start,
   289 struct mpatch_flist *mpatch_fold(PyObject *bins, ssize_t start,
   290 	ssize_t end)
   290 	ssize_t end)
   291 {
   291 {
   292 	ssize_t len, blen;
   292 	ssize_t len, blen;
   293 	const char *buffer;
   293 	const char *buffer;
   294 
   294 
   306 	len = (end - start) / 2;
   306 	len = (end - start) / 2;
   307 	return combine(mpatch_fold(bins, start, start + len),
   307 	return combine(mpatch_fold(bins, start, start + len),
   308 		       mpatch_fold(bins, start + len, end));
   308 		       mpatch_fold(bins, start + len, end));
   309 }
   309 }
   310 
   310 
   311 static PyObject *
       
   312 patches(PyObject *self, PyObject *args)
       
   313 {
       
   314 	PyObject *text, *bins, *result;
       
   315 	struct mpatch_flist *patch;
       
   316 	const char *in;
       
   317 	char *out;
       
   318 	Py_ssize_t len, outlen, inlen;
       
   319 
       
   320 	if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
       
   321 		return NULL;
       
   322 
       
   323 	len = PyList_Size(bins);
       
   324 	if (!len) {
       
   325 		/* nothing to do */
       
   326 		Py_INCREF(text);
       
   327 		return text;
       
   328 	}
       
   329 
       
   330 	if (PyObject_AsCharBuffer(text, &in, &inlen))
       
   331 		return NULL;
       
   332 
       
   333 	patch = mpatch_fold(bins, 0, len);
       
   334 	if (!patch)
       
   335 		return NULL;
       
   336 
       
   337 	outlen = mpatch_calcsize(inlen, patch);
       
   338 	if (outlen < 0) {
       
   339 		result = NULL;
       
   340 		goto cleanup;
       
   341 	}
       
   342 	result = PyBytes_FromStringAndSize(NULL, outlen);
       
   343 	if (!result) {
       
   344 		result = NULL;
       
   345 		goto cleanup;
       
   346 	}
       
   347 	out = PyBytes_AsString(result);
       
   348 	if (!mpatch_apply(out, in, inlen, patch)) {
       
   349 		Py_DECREF(result);
       
   350 		result = NULL;
       
   351 	}
       
   352 cleanup:
       
   353 	mpatch_lfree(patch);
       
   354 	return result;
       
   355 }
       
   356 
       
   357 /* calculate size of a patched file directly */
       
   358 static PyObject *
       
   359 patchedsize(PyObject *self, PyObject *args)
       
   360 {
       
   361 	long orig, start, end, len, outlen = 0, last = 0, pos = 0;
       
   362 	Py_ssize_t patchlen;
       
   363 	char *bin;
       
   364 
       
   365 	if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
       
   366 		return NULL;
       
   367 
       
   368 	while (pos >= 0 && pos < patchlen) {
       
   369 		start = getbe32(bin + pos);
       
   370 		end = getbe32(bin + pos + 4);
       
   371 		len = getbe32(bin + pos + 8);
       
   372 		if (start > end)
       
   373 			break; /* sanity check */
       
   374 		pos += 12 + len;
       
   375 		outlen += start - last;
       
   376 		last = end;
       
   377 		outlen += len;
       
   378 	}
       
   379 
       
   380 	if (pos != patchlen) {
       
   381 		if (!PyErr_Occurred())
       
   382 			PyErr_SetString(mpatch_Error, "patch cannot be decoded");
       
   383 		return NULL;
       
   384 	}
       
   385 
       
   386 	outlen += orig - last;
       
   387 	return Py_BuildValue("l", outlen);
       
   388 }
       
   389 
       
   390 static PyMethodDef methods[] = {
       
   391 	{"patches", patches, METH_VARARGS, "apply a series of patches\n"},
       
   392 	{"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
       
   393 	{NULL, NULL}
       
   394 };
       
   395 
       
   396 #ifdef IS_PY3K
       
   397 static struct PyModuleDef mpatch_module = {
       
   398 	PyModuleDef_HEAD_INIT,
       
   399 	"mpatch",
       
   400 	mpatch_doc,
       
   401 	-1,
       
   402 	methods
       
   403 };
       
   404 
       
   405 PyMODINIT_FUNC PyInit_mpatch(void)
       
   406 {
       
   407 	PyObject *m;
       
   408 
       
   409 	m = PyModule_Create(&mpatch_module);
       
   410 	if (m == NULL)
       
   411 		return NULL;
       
   412 
       
   413 	mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
       
   414 					  NULL, NULL);
       
   415 	Py_INCREF(mpatch_Error);
       
   416 	PyModule_AddObject(m, "mpatchError", mpatch_Error);
       
   417 
       
   418 	return m;
       
   419 }
       
   420 #else
       
   421 PyMODINIT_FUNC
       
   422 initmpatch(void)
       
   423 {
       
   424 	Py_InitModule3("mpatch", methods, mpatch_doc);
       
   425 	mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
       
   426 					  NULL, NULL);
       
   427 }
       
   428 #endif