Mercurial > hg
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 |