comparison mercurial/mpatch.c @ 29694:55dd12204b8e

mpatch: remove dependency on Python.h in mpatch.c Now all the CPython-related stuff are referenced only from mpatch_module.c with mpatch.c being freely usable from a future cffi module
author Maciej Fijalkowski <fijall@gmail.com>
date Fri, 22 Jul 2016 17:28:05 +0200
parents b9b9f9a92481
children 21ac534d7d30
comparison
equal deleted inserted replaced
29693:b9b9f9a92481 29694:55dd12204b8e
18 18
19 This software may be used and distributed according to the terms 19 This software may be used and distributed according to the terms
20 of the GNU General Public License, incorporated herein by reference. 20 of the GNU General Public License, incorporated herein by reference.
21 */ 21 */
22 22
23 #define PY_SSIZE_T_CLEAN
24 #include <Python.h>
25 #include <stdlib.h> 23 #include <stdlib.h>
26 #include <string.h> 24 #include <string.h>
27 25
28 #include "util.h"
29 #include "bitmanipulation.h" 26 #include "bitmanipulation.h"
30 #include "compat.h" 27 #include "compat.h"
31 28 #include "mpatch.h"
32 static char mpatch_doc[] = "Efficient binary patching."; 29
33 static PyObject *mpatch_Error; 30 char *mpatch_errors[] = {NULL, "invalid patch", "patch cannot be decoded",
34 31 "no memory"};
35 struct mpatch_frag {
36 int start, end, len;
37 const char *data;
38 };
39
40 struct mpatch_flist {
41 struct mpatch_frag *base, *head, *tail;
42 };
43 32
44 struct mpatch_flist *lalloc(ssize_t size) 33 struct mpatch_flist *lalloc(ssize_t size)
45 { 34 {
46 struct mpatch_flist *a = NULL; 35 struct mpatch_flist *a = NULL;
47 36
54 if (a->base) { 43 if (a->base) {
55 a->head = a->tail = a->base; 44 a->head = a->tail = a->base;
56 return a; 45 return a;
57 } 46 }
58 free(a); 47 free(a);
59 a = NULL; 48 }
60 }
61 if (!PyErr_Occurred())
62 PyErr_NoMemory();
63 return NULL; 49 return NULL;
64 } 50 }
65 51
66 void mpatch_lfree(struct mpatch_flist *a) 52 void mpatch_lfree(struct mpatch_flist *a)
67 { 53 {
200 mpatch_lfree(b); 186 mpatch_lfree(b);
201 return c; 187 return c;
202 } 188 }
203 189
204 /* decode a binary patch into a hunk list */ 190 /* decode a binary patch into a hunk list */
205 struct mpatch_flist *mpatch_decode(const char *bin, ssize_t len) 191 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
206 { 192 {
207 struct mpatch_flist *l; 193 struct mpatch_flist *l;
208 struct mpatch_frag *lt; 194 struct mpatch_frag *lt;
209 int pos = 0; 195 int pos = 0;
210 196
211 /* assume worst case size, we won't have many of these lists */ 197 /* assume worst case size, we won't have many of these lists */
212 l = lalloc(len / 12 + 1); 198 l = lalloc(len / 12 + 1);
213 if (!l) 199 if (!l)
214 return NULL; 200 return MPATCH_ERR_NO_MEM;
215 201
216 lt = l->tail; 202 lt = l->tail;
217 203
218 while (pos >= 0 && pos < len) { 204 while (pos >= 0 && pos < len) {
219 lt->start = getbe32(bin + pos); 205 lt->start = getbe32(bin + pos);
225 break; /* sanity check */ 211 break; /* sanity check */
226 lt++; 212 lt++;
227 } 213 }
228 214
229 if (pos != len) { 215 if (pos != len) {
230 if (!PyErr_Occurred())
231 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
232 mpatch_lfree(l); 216 mpatch_lfree(l);
233 return NULL; 217 return MPATCH_ERR_CANNOT_BE_DECODED;
234 } 218 }
235 219
236 l->tail = lt; 220 l->tail = lt;
237 return l; 221 *res = l;
222 return 0;
238 } 223 }
239 224
240 /* calculate the size of resultant text */ 225 /* calculate the size of resultant text */
241 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l) 226 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
242 { 227 {
243 ssize_t outlen = 0, last = 0; 228 ssize_t outlen = 0, last = 0;
244 struct mpatch_frag *f = l->head; 229 struct mpatch_frag *f = l->head;
245 230
246 while (f != l->tail) { 231 while (f != l->tail) {
247 if (f->start < last || f->end > len) { 232 if (f->start < last || f->end > len) {
248 if (!PyErr_Occurred()) 233 return MPATCH_ERR_INVALID_PATCH;
249 PyErr_SetString(mpatch_Error,
250 "invalid patch");
251 return -1;
252 } 234 }
253 outlen += f->start - last; 235 outlen += f->start - last;
254 last = f->end; 236 last = f->end;
255 outlen += f->len; 237 outlen += f->len;
256 f++; 238 f++;
267 int last = 0; 249 int last = 0;
268 char *p = buf; 250 char *p = buf;
269 251
270 while (f != l->tail) { 252 while (f != l->tail) {
271 if (f->start < last || f->end > len) { 253 if (f->start < last || f->end > len) {
272 if (!PyErr_Occurred()) 254 return MPATCH_ERR_INVALID_PATCH;
273 PyErr_SetString(mpatch_Error,
274 "invalid patch");
275 return 0;
276 } 255 }
277 memcpy(p, orig + last, f->start - last); 256 memcpy(p, orig + last, f->start - last);
278 p += f->start - last; 257 p += f->start - last;
279 memcpy(p, f->data, f->len); 258 memcpy(p, f->data, f->len);
280 last = f->end; 259 last = f->end;
281 p += f->len; 260 p += f->len;
282 f++; 261 f++;
283 } 262 }
284 memcpy(p, orig + last, len - last); 263 memcpy(p, orig + last, len - last);
285 return 1; 264 return 0;
286 } 265 }
287 266
288 /* recursively generate a patch of all bins between start and end */ 267 /* recursively generate a patch of all bins between start and end */
289 struct mpatch_flist *mpatch_fold(PyObject *bins, ssize_t start, 268 struct mpatch_flist *mpatch_fold(void *bins,
290 ssize_t end) 269 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
291 { 270 ssize_t start, ssize_t end)
292 ssize_t len, blen; 271 {
293 const char *buffer; 272 ssize_t len;
294 273
295 if (start + 1 == end) { 274 if (start + 1 == end) {
296 /* trivial case, output a decoded list */ 275 /* trivial case, output a decoded list */
297 PyObject *tmp = PyList_GetItem(bins, start); 276 return get_next_item(bins, start);
298 if (!tmp)
299 return NULL;
300 if (PyObject_AsCharBuffer(tmp, &buffer, &blen))
301 return NULL;
302 return mpatch_decode(buffer, blen);
303 } 277 }
304 278
305 /* divide and conquer, memory management is elsewhere */ 279 /* divide and conquer, memory management is elsewhere */
306 len = (end - start) / 2; 280 len = (end - start) / 2;
307 return combine(mpatch_fold(bins, start, start + len), 281 return combine(mpatch_fold(bins, get_next_item, start, start + len),
308 mpatch_fold(bins, start + len, end)); 282 mpatch_fold(bins, get_next_item, start + len, end));
309 } 283 }
310 284