Mercurial > hg-stable
comparison mercurial/mpatch.c @ 29706:6b3a8d034b69
mpatch: provide things that will be exported later with a prefixed name
For cffi a bunch of mpatch functions need to be visible through a .h file.
This change renames them so it won't create potential c namespace conflicts.
author | Maciej Fijalkowski <fijall@gmail.com> |
---|---|
date | Mon, 18 Jul 2016 16:25:14 +0200 |
parents | e9a0bcc9314d |
children | b9b9f9a92481 |
comparison
equal
deleted
inserted
replaced
29705:e9a0bcc9314d | 29706:6b3a8d034b69 |
---|---|
30 #include "compat.h" | 30 #include "compat.h" |
31 | 31 |
32 static char mpatch_doc[] = "Efficient binary patching."; | 32 static char mpatch_doc[] = "Efficient binary patching."; |
33 static PyObject *mpatch_Error; | 33 static PyObject *mpatch_Error; |
34 | 34 |
35 struct frag { | 35 struct mpatch_frag { |
36 int start, end, len; | 36 int start, end, len; |
37 const char *data; | 37 const char *data; |
38 }; | 38 }; |
39 | 39 |
40 struct flist { | 40 struct mpatch_flist { |
41 struct frag *base, *head, *tail; | 41 struct mpatch_frag *base, *head, *tail; |
42 }; | 42 }; |
43 | 43 |
44 static struct flist *lalloc(ssize_t size) | 44 static struct mpatch_flist *lalloc(ssize_t size) |
45 { | 45 { |
46 struct 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; |
50 | 50 |
51 a = (struct flist *)malloc(sizeof(struct flist)); | 51 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist)); |
52 if (a) { | 52 if (a) { |
53 a->base = (struct frag *)malloc(sizeof(struct frag) * size); | 53 a->base = (struct mpatch_frag *)malloc(sizeof(struct mpatch_frag) * size); |
54 if (a->base) { | 54 if (a->base) { |
55 a->head = a->tail = a->base; | 55 a->head = a->tail = a->base; |
56 return a; | 56 return a; |
57 } | 57 } |
58 free(a); | 58 free(a); |
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 lfree(struct flist *a) | 66 static 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 } |
72 } | 72 } |
73 | 73 |
74 static ssize_t lsize(struct flist *a) | 74 static ssize_t lsize(struct mpatch_flist *a) |
75 { | 75 { |
76 return a->tail - a->head; | 76 return a->tail - a->head; |
77 } | 77 } |
78 | 78 |
79 /* move hunks in source that are less cut to dest, compensating | 79 /* move hunks in source that are less cut to dest, compensating |
80 for changes in offset. the last hunk may be split if necessary. | 80 for changes in offset. the last hunk may be split if necessary. |
81 */ | 81 */ |
82 static int gather(struct flist *dest, struct flist *src, int cut, int offset) | 82 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut, |
83 { | 83 int offset) |
84 struct frag *d = dest->tail, *s = src->head; | 84 { |
85 struct mpatch_frag *d = dest->tail, *s = src->head; | |
85 int postend, c, l; | 86 int postend, c, l; |
86 | 87 |
87 while (s != src->tail) { | 88 while (s != src->tail) { |
88 if (s->start + offset >= cut) | 89 if (s->start + offset >= cut) |
89 break; /* we've gone far enough */ | 90 break; /* we've gone far enough */ |
122 src->head = s; | 123 src->head = s; |
123 return offset; | 124 return offset; |
124 } | 125 } |
125 | 126 |
126 /* like gather, but with no output list */ | 127 /* like gather, but with no output list */ |
127 static int discard(struct flist *src, int cut, int offset) | 128 static int discard(struct mpatch_flist *src, int cut, int offset) |
128 { | 129 { |
129 struct frag *s = src->head; | 130 struct mpatch_frag *s = src->head; |
130 int postend, c, l; | 131 int postend, c, l; |
131 | 132 |
132 while (s != src->tail) { | 133 while (s != src->tail) { |
133 if (s->start + offset >= cut) | 134 if (s->start + offset >= cut) |
134 break; | 135 break; |
159 return offset; | 160 return offset; |
160 } | 161 } |
161 | 162 |
162 /* combine hunk lists a and b, while adjusting b for offset changes in a/ | 163 /* combine hunk lists a and b, while adjusting b for offset changes in a/ |
163 this deletes a and b and returns the resultant list. */ | 164 this deletes a and b and returns the resultant list. */ |
164 static struct flist *combine(struct flist *a, struct flist *b) | 165 static struct mpatch_flist *combine(struct mpatch_flist *a, |
165 { | 166 struct mpatch_flist *b) |
166 struct flist *c = NULL; | 167 { |
167 struct frag *bh, *ct; | 168 struct mpatch_flist *c = NULL; |
169 struct mpatch_frag *bh, *ct; | |
168 int offset = 0, post; | 170 int offset = 0, post; |
169 | 171 |
170 if (a && b) | 172 if (a && b) |
171 c = lalloc((lsize(a) + lsize(b)) * 2); | 173 c = lalloc((lsize(a) + lsize(b)) * 2); |
172 | 174 |
188 c->tail++; | 190 c->tail++; |
189 offset = post; | 191 offset = post; |
190 } | 192 } |
191 | 193 |
192 /* hold on to tail from a */ | 194 /* hold on to tail from a */ |
193 memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a)); | 195 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a)); |
194 c->tail += lsize(a); | 196 c->tail += lsize(a); |
195 } | 197 } |
196 | 198 |
197 lfree(a); | 199 mpatch_lfree(a); |
198 lfree(b); | 200 mpatch_lfree(b); |
199 return c; | 201 return c; |
200 } | 202 } |
201 | 203 |
202 /* decode a binary patch into a hunk list */ | 204 /* decode a binary patch into a hunk list */ |
203 static struct flist *decode(const char *bin, ssize_t len) | 205 static struct mpatch_flist *mpatch_decode(const char *bin, ssize_t len) |
204 { | 206 { |
205 struct flist *l; | 207 struct mpatch_flist *l; |
206 struct frag *lt; | 208 struct mpatch_frag *lt; |
207 int pos = 0; | 209 int pos = 0; |
208 | 210 |
209 /* assume worst case size, we won't have many of these lists */ | 211 /* assume worst case size, we won't have many of these lists */ |
210 l = lalloc(len / 12 + 1); | 212 l = lalloc(len / 12 + 1); |
211 if (!l) | 213 if (!l) |
225 } | 227 } |
226 | 228 |
227 if (pos != len) { | 229 if (pos != len) { |
228 if (!PyErr_Occurred()) | 230 if (!PyErr_Occurred()) |
229 PyErr_SetString(mpatch_Error, "patch cannot be decoded"); | 231 PyErr_SetString(mpatch_Error, "patch cannot be decoded"); |
230 lfree(l); | 232 mpatch_lfree(l); |
231 return NULL; | 233 return NULL; |
232 } | 234 } |
233 | 235 |
234 l->tail = lt; | 236 l->tail = lt; |
235 return l; | 237 return l; |
236 } | 238 } |
237 | 239 |
238 /* calculate the size of resultant text */ | 240 /* calculate the size of resultant text */ |
239 static ssize_t calcsize(ssize_t len, struct flist *l) | 241 static ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l) |
240 { | 242 { |
241 ssize_t outlen = 0, last = 0; | 243 ssize_t outlen = 0, last = 0; |
242 struct frag *f = l->head; | 244 struct mpatch_frag *f = l->head; |
243 | 245 |
244 while (f != l->tail) { | 246 while (f != l->tail) { |
245 if (f->start < last || f->end > len) { | 247 if (f->start < last || f->end > len) { |
246 if (!PyErr_Occurred()) | 248 if (!PyErr_Occurred()) |
247 PyErr_SetString(mpatch_Error, | 249 PyErr_SetString(mpatch_Error, |
256 | 258 |
257 outlen += len - last; | 259 outlen += len - last; |
258 return outlen; | 260 return outlen; |
259 } | 261 } |
260 | 262 |
261 static int apply(char *buf, const char *orig, ssize_t len, struct flist *l) | 263 static int mpatch_apply(char *buf, const char *orig, ssize_t len, |
262 { | 264 struct mpatch_flist *l) |
263 struct frag *f = l->head; | 265 { |
266 struct mpatch_frag *f = l->head; | |
264 int last = 0; | 267 int last = 0; |
265 char *p = buf; | 268 char *p = buf; |
266 | 269 |
267 while (f != l->tail) { | 270 while (f != l->tail) { |
268 if (f->start < last || f->end > len) { | 271 if (f->start < last || f->end > len) { |
281 memcpy(p, orig + last, len - last); | 284 memcpy(p, orig + last, len - last); |
282 return 1; | 285 return 1; |
283 } | 286 } |
284 | 287 |
285 /* recursively generate a patch of all bins between start and end */ | 288 /* recursively generate a patch of all bins between start and end */ |
286 static struct flist *fold(PyObject *bins, ssize_t start, ssize_t end) | 289 static struct mpatch_flist *mpatch_fold(PyObject *bins, ssize_t start, |
290 ssize_t end) | |
287 { | 291 { |
288 ssize_t len, blen; | 292 ssize_t len, blen; |
289 const char *buffer; | 293 const char *buffer; |
290 | 294 |
291 if (start + 1 == end) { | 295 if (start + 1 == end) { |
293 PyObject *tmp = PyList_GetItem(bins, start); | 297 PyObject *tmp = PyList_GetItem(bins, start); |
294 if (!tmp) | 298 if (!tmp) |
295 return NULL; | 299 return NULL; |
296 if (PyObject_AsCharBuffer(tmp, &buffer, &blen)) | 300 if (PyObject_AsCharBuffer(tmp, &buffer, &blen)) |
297 return NULL; | 301 return NULL; |
298 return decode(buffer, blen); | 302 return mpatch_decode(buffer, blen); |
299 } | 303 } |
300 | 304 |
301 /* divide and conquer, memory management is elsewhere */ | 305 /* divide and conquer, memory management is elsewhere */ |
302 len = (end - start) / 2; | 306 len = (end - start) / 2; |
303 return combine(fold(bins, start, start + len), | 307 return combine(mpatch_fold(bins, start, start + len), |
304 fold(bins, start + len, end)); | 308 mpatch_fold(bins, start + len, end)); |
305 } | 309 } |
306 | 310 |
307 static PyObject * | 311 static PyObject * |
308 patches(PyObject *self, PyObject *args) | 312 patches(PyObject *self, PyObject *args) |
309 { | 313 { |
310 PyObject *text, *bins, *result; | 314 PyObject *text, *bins, *result; |
311 struct flist *patch; | 315 struct mpatch_flist *patch; |
312 const char *in; | 316 const char *in; |
313 char *out; | 317 char *out; |
314 Py_ssize_t len, outlen, inlen; | 318 Py_ssize_t len, outlen, inlen; |
315 | 319 |
316 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) | 320 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) |
324 } | 328 } |
325 | 329 |
326 if (PyObject_AsCharBuffer(text, &in, &inlen)) | 330 if (PyObject_AsCharBuffer(text, &in, &inlen)) |
327 return NULL; | 331 return NULL; |
328 | 332 |
329 patch = fold(bins, 0, len); | 333 patch = mpatch_fold(bins, 0, len); |
330 if (!patch) | 334 if (!patch) |
331 return NULL; | 335 return NULL; |
332 | 336 |
333 outlen = calcsize(inlen, patch); | 337 outlen = mpatch_calcsize(inlen, patch); |
334 if (outlen < 0) { | 338 if (outlen < 0) { |
335 result = NULL; | 339 result = NULL; |
336 goto cleanup; | 340 goto cleanup; |
337 } | 341 } |
338 result = PyBytes_FromStringAndSize(NULL, outlen); | 342 result = PyBytes_FromStringAndSize(NULL, outlen); |
339 if (!result) { | 343 if (!result) { |
340 result = NULL; | 344 result = NULL; |
341 goto cleanup; | 345 goto cleanup; |
342 } | 346 } |
343 out = PyBytes_AsString(result); | 347 out = PyBytes_AsString(result); |
344 if (!apply(out, in, inlen, patch)) { | 348 if (!mpatch_apply(out, in, inlen, patch)) { |
345 Py_DECREF(result); | 349 Py_DECREF(result); |
346 result = NULL; | 350 result = NULL; |
347 } | 351 } |
348 cleanup: | 352 cleanup: |
349 lfree(patch); | 353 mpatch_lfree(patch); |
350 return result; | 354 return result; |
351 } | 355 } |
352 | 356 |
353 /* calculate size of a patched file directly */ | 357 /* calculate size of a patched file directly */ |
354 static PyObject * | 358 static PyObject * |