comparison mercurial/mpatch.c @ 5444:a0952e4e52eb

mpatch: allow buffer objects for input
author Matt Mackall <mpm@selenic.com>
date Thu, 11 Oct 2007 00:46:45 -0500
parents 4759da3e4dc8
children cd1a6e7216c5 b0e5f44fdeb3
comparison
equal deleted inserted replaced
5443:58496354773f 5444:a0952e4e52eb
53 static char mpatch_doc[] = "Efficient binary patching."; 53 static char mpatch_doc[] = "Efficient binary patching.";
54 static PyObject *mpatch_Error; 54 static PyObject *mpatch_Error;
55 55
56 struct frag { 56 struct frag {
57 int start, end, len; 57 int start, end, len;
58 char *data; 58 const char *data;
59 }; 59 };
60 60
61 struct flist { 61 struct flist {
62 struct frag *base, *head, *tail; 62 struct frag *base, *head, *tail;
63 }; 63 };
219 lfree(b); 219 lfree(b);
220 return c; 220 return c;
221 } 221 }
222 222
223 /* decode a binary patch into a hunk list */ 223 /* decode a binary patch into a hunk list */
224 static struct flist *decode(char *bin, int len) 224 static struct flist *decode(const char *bin, int len)
225 { 225 {
226 struct flist *l; 226 struct flist *l;
227 struct frag *lt; 227 struct frag *lt;
228 char *data = bin + 12, *end = bin + len; 228 const char *data = bin + 12, *end = bin + len;
229 char decode[12]; /* for dealing with alignment issues */ 229 char decode[12]; /* for dealing with alignment issues */
230 230
231 /* assume worst case size, we won't have many of these lists */ 231 /* assume worst case size, we won't have many of these lists */
232 l = lalloc(len / 12); 232 l = lalloc(len / 12);
233 if (!l) 233 if (!l)
282 282
283 outlen += len - last; 283 outlen += len - last;
284 return outlen; 284 return outlen;
285 } 285 }
286 286
287 static int apply(char *buf, char *orig, int len, struct flist *l) 287 static int apply(char *buf, const char *orig, int len, struct flist *l)
288 { 288 {
289 struct frag *f = l->head; 289 struct frag *f = l->head;
290 int last = 0; 290 int last = 0;
291 char *p = buf; 291 char *p = buf;
292 292
310 310
311 /* recursively generate a patch of all bins between start and end */ 311 /* recursively generate a patch of all bins between start and end */
312 static struct flist *fold(PyObject *bins, int start, int end) 312 static struct flist *fold(PyObject *bins, int start, int end)
313 { 313 {
314 int len; 314 int len;
315 ssize_t blen;
316 const char *buffer;
315 317
316 if (start + 1 == end) { 318 if (start + 1 == end) {
317 /* trivial case, output a decoded list */ 319 /* trivial case, output a decoded list */
318 PyObject *tmp = PyList_GetItem(bins, start); 320 PyObject *tmp = PyList_GetItem(bins, start);
319 if (!tmp) 321 if (!tmp)
320 return NULL; 322 return NULL;
321 return decode(PyString_AsString(tmp), PyString_Size(tmp)); 323 if (PyObject_AsCharBuffer(tmp, &buffer, &blen))
324 return NULL;
325 return decode(buffer, blen);
322 } 326 }
323 327
324 /* divide and conquer, memory management is elsewhere */ 328 /* divide and conquer, memory management is elsewhere */
325 len = (end - start) / 2; 329 len = (end - start) / 2;
326 return combine(fold(bins, start, start + len), 330 return combine(fold(bins, start, start + len),
330 static PyObject * 334 static PyObject *
331 patches(PyObject *self, PyObject *args) 335 patches(PyObject *self, PyObject *args)
332 { 336 {
333 PyObject *text, *bins, *result; 337 PyObject *text, *bins, *result;
334 struct flist *patch; 338 struct flist *patch;
335 char *in, *out; 339 const char *in;
340 char *out;
336 int len, outlen; 341 int len, outlen;
337 342 ssize_t inlen;
338 if (!PyArg_ParseTuple(args, "SO:mpatch", &text, &bins)) 343
344 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
339 return NULL; 345 return NULL;
340 346
341 len = PyList_Size(bins); 347 len = PyList_Size(bins);
342 if (!len) { 348 if (!len) {
343 /* nothing to do */ 349 /* nothing to do */
344 Py_INCREF(text); 350 Py_INCREF(text);
345 return text; 351 return text;
346 } 352 }
347 353
354 if (PyObject_AsCharBuffer(text, &in, &inlen))
355 return NULL;
356
348 patch = fold(bins, 0, len); 357 patch = fold(bins, 0, len);
349 if (!patch) 358 if (!patch)
350 return NULL; 359 return NULL;
351 360
352 outlen = calcsize(PyString_Size(text), patch); 361 outlen = calcsize(inlen, patch);
353 if (outlen < 0) { 362 if (outlen < 0) {
354 result = NULL; 363 result = NULL;
355 goto cleanup; 364 goto cleanup;
356 } 365 }
357 result = PyString_FromStringAndSize(NULL, outlen); 366 result = PyString_FromStringAndSize(NULL, outlen);
358 if (!result) { 367 if (!result) {
359 result = NULL; 368 result = NULL;
360 goto cleanup; 369 goto cleanup;
361 } 370 }
362 in = PyString_AsString(text);
363 out = PyString_AsString(result); 371 out = PyString_AsString(result);
364 if (!apply(out, in, PyString_Size(text), patch)) { 372 if (!apply(out, in, inlen, patch)) {
365 Py_DECREF(result); 373 Py_DECREF(result);
366 result = NULL; 374 result = NULL;
367 } 375 }
368 cleanup: 376 cleanup:
369 lfree(patch); 377 lfree(patch);