changeset 29693 | b9b9f9a92481 |
parent 29692 | 6b3a8d034b69 |
child 29694 | 55dd12204b8e |
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 |