Show More
@@ -20,26 +20,15 b'' | |||||
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."; |
|
|||
33 | static PyObject *mpatch_Error; |
|
|||
34 |
|
29 | |||
35 | struct mpatch_frag { |
|
30 | char *mpatch_errors[] = {NULL, "invalid patch", "patch cannot be decoded", | |
36 | int start, end, len; |
|
31 | "no memory"}; | |
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 | { | |
@@ -56,10 +45,7 b' struct mpatch_flist *lalloc(ssize_t size' | |||||
56 | return a; |
|
45 | return a; | |
57 | } |
|
46 | } | |
58 | free(a); |
|
47 | free(a); | |
59 | a = NULL; |
|
|||
60 | } |
|
48 | } | |
61 | if (!PyErr_Occurred()) |
|
|||
62 | PyErr_NoMemory(); |
|
|||
63 | return NULL; |
|
49 | return NULL; | |
64 | } |
|
50 | } | |
65 |
|
51 | |||
@@ -202,7 +188,7 b' static struct mpatch_flist *combine(stru' | |||||
202 | } |
|
188 | } | |
203 |
|
189 | |||
204 | /* decode a binary patch into a hunk list */ |
|
190 | /* decode a binary patch into a hunk list */ | |
205 |
|
|
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; | |
@@ -211,7 +197,7 b' struct mpatch_flist *mpatch_decode(const' | |||||
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 | |||
@@ -227,14 +213,13 b' struct mpatch_flist *mpatch_decode(const' | |||||
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 |
|
|
221 | *res = l; | |
|
222 | return 0; | |||
238 | } |
|
223 | } | |
239 |
|
224 | |||
240 | /* calculate the size of resultant text */ |
|
225 | /* calculate the size of resultant text */ | |
@@ -245,10 +230,7 b' ssize_t mpatch_calcsize(ssize_t len, str' | |||||
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; | |
@@ -269,10 +251,7 b' int mpatch_apply(char *buf, const char *' | |||||
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; | |
@@ -282,29 +261,24 b' int mpatch_apply(char *buf, const char *' | |||||
282 | f++; |
|
261 | f++; | |
283 | } |
|
262 | } | |
284 | memcpy(p, orig + last, len - last); |
|
263 | memcpy(p, orig + last, len - last); | |
285 |
return |
|
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( |
|
268 | struct mpatch_flist *mpatch_fold(void *bins, | |
290 | ssize_t end) |
|
269 | struct mpatch_flist* (*get_next_item)(void*, ssize_t), | |
|
270 | ssize_t start, ssize_t end) | |||
291 | { |
|
271 | { | |
292 |
ssize_t len |
|
272 | ssize_t len; | |
293 | const char *buffer; |
|
|||
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 |
|
|
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 |
@@ -1,6 +1,12 b'' | |||||
1 | #ifndef _HG_MPATCH_H_ |
|
1 | #ifndef _HG_MPATCH_H_ | |
2 | #define _HG_MPATCH_H_ |
|
2 | #define _HG_MPATCH_H_ | |
3 |
|
3 | |||
|
4 | extern char *mpatch_errors[]; | |||
|
5 | ||||
|
6 | #define MPATCH_ERR_NO_MEM -3 | |||
|
7 | #define MPATCH_ERR_CANNOT_BE_DECODED -2 | |||
|
8 | #define MPATCH_ERR_INVALID_PATCH -1 | |||
|
9 | ||||
4 | struct mpatch_frag { |
|
10 | struct mpatch_frag { | |
5 | int start, end, len; |
|
11 | int start, end, len; | |
6 | const char *data; |
|
12 | const char *data; | |
@@ -15,6 +21,8 b' ssize_t mpatch_calcsize(ssize_t len, str' | |||||
15 | void mpatch_lfree(struct mpatch_flist *a); |
|
21 | void mpatch_lfree(struct mpatch_flist *a); | |
16 | int mpatch_apply(char *buf, const char *orig, ssize_t len, |
|
22 | int mpatch_apply(char *buf, const char *orig, ssize_t len, | |
17 | struct mpatch_flist *l); |
|
23 | struct mpatch_flist *l); | |
18 |
struct mpatch_flist *mpatch_fold(void *bins, |
|
24 | struct mpatch_flist *mpatch_fold(void *bins, | |
|
25 | struct mpatch_flist* (*get_next_item)(void*, ssize_t), | |||
|
26 | ssize_t start, ssize_t end); | |||
19 |
|
27 | |||
20 | #endif |
|
28 | #endif |
@@ -33,12 +33,33 b'' | |||||
33 | static char mpatch_doc[] = "Efficient binary patching."; |
|
33 | static char mpatch_doc[] = "Efficient binary patching."; | |
34 | static PyObject *mpatch_Error; |
|
34 | static PyObject *mpatch_Error; | |
35 |
|
35 | |||
|
36 | struct mpatch_flist *cpygetitem(void *bins, ssize_t pos) | |||
|
37 | { | |||
|
38 | const char *buffer; | |||
|
39 | struct mpatch_flist *res; | |||
|
40 | ssize_t blen; | |||
|
41 | int r; | |||
|
42 | ||||
|
43 | PyObject *tmp = PyList_GetItem((PyObject*)bins, pos); | |||
|
44 | if (!tmp) | |||
|
45 | return NULL; | |||
|
46 | if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen)) | |||
|
47 | return NULL; | |||
|
48 | if ((r = mpatch_decode(buffer, blen, &res)) < 0) { | |||
|
49 | if (!PyErr_Occurred()) | |||
|
50 | PyErr_SetString(mpatch_Error, mpatch_errors[-r]); | |||
|
51 | return NULL; | |||
|
52 | } | |||
|
53 | return res; | |||
|
54 | } | |||
|
55 | ||||
36 | static PyObject * |
|
56 | static PyObject * | |
37 | patches(PyObject *self, PyObject *args) |
|
57 | patches(PyObject *self, PyObject *args) | |
38 | { |
|
58 | { | |
39 | PyObject *text, *bins, *result; |
|
59 | PyObject *text, *bins, *result; | |
40 | struct mpatch_flist *patch; |
|
60 | struct mpatch_flist *patch; | |
41 | const char *in; |
|
61 | const char *in; | |
|
62 | int r; | |||
42 | char *out; |
|
63 | char *out; | |
43 | Py_ssize_t len, outlen, inlen; |
|
64 | Py_ssize_t len, outlen, inlen; | |
44 |
|
65 | |||
@@ -55,12 +76,16 b' patches(PyObject *self, PyObject *args)' | |||||
55 | if (PyObject_AsCharBuffer(text, &in, &inlen)) |
|
76 | if (PyObject_AsCharBuffer(text, &in, &inlen)) | |
56 | return NULL; |
|
77 | return NULL; | |
57 |
|
78 | |||
58 | patch = mpatch_fold(bins, 0, len); |
|
79 | patch = mpatch_fold(bins, cpygetitem, 0, len); | |
59 | if (!patch) |
|
80 | if (!patch) { /* error already set or memory error */ | |
|
81 | if (!PyErr_Occurred()) | |||
|
82 | PyErr_NoMemory(); | |||
60 | return NULL; |
|
83 | return NULL; | |
|
84 | } | |||
61 |
|
85 | |||
62 | outlen = mpatch_calcsize(inlen, patch); |
|
86 | outlen = mpatch_calcsize(inlen, patch); | |
63 | if (outlen < 0) { |
|
87 | if (outlen < 0) { | |
|
88 | r = (int)outlen; | |||
64 | result = NULL; |
|
89 | result = NULL; | |
65 | goto cleanup; |
|
90 | goto cleanup; | |
66 | } |
|
91 | } | |
@@ -70,12 +95,14 b' patches(PyObject *self, PyObject *args)' | |||||
70 | goto cleanup; |
|
95 | goto cleanup; | |
71 | } |
|
96 | } | |
72 | out = PyBytes_AsString(result); |
|
97 | out = PyBytes_AsString(result); | |
73 |
if ( |
|
98 | if ((r = mpatch_apply(out, in, inlen, patch)) < 0) { | |
74 | Py_DECREF(result); |
|
99 | Py_DECREF(result); | |
75 | result = NULL; |
|
100 | result = NULL; | |
76 | } |
|
101 | } | |
77 | cleanup: |
|
102 | cleanup: | |
78 | mpatch_lfree(patch); |
|
103 | mpatch_lfree(patch); | |
|
104 | if (!result && !PyErr_Occurred()) | |||
|
105 | PyErr_SetString(mpatch_Error, mpatch_errors[-r]); | |||
79 | return result; |
|
106 | return result; | |
80 | } |
|
107 | } | |
81 |
|
108 |
General Comments 0
You need to be logged in to leave comments.
Login now