##// END OF EJS Templates
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
Vadim Gelfer -
r2468:1ac0574f default
parent child Browse files
Show More
@@ -1,361 +1,362
1 1 /*
2 2 bdiff.c - efficient binary diff extension for Mercurial
3 3
4 4 Copyright 2005 Matt Mackall <mpm@selenic.com>
5 5
6 6 This software may be used and distributed according to the terms of
7 7 the GNU General Public License, incorporated herein by reference.
8 8
9 9 Based roughly on Python difflib
10 10 */
11 11
12 12 #include <Python.h>
13 #include <stdint.h>
13 14 #include <stdlib.h>
14 15 #include <string.h>
15 16
16 17 #ifdef __hpux
17 18 #define inline
18 19 #endif
19 20
20 21 #ifdef __SUNPRO_C
21 22 # define inline
22 23 #endif
23 24
24 25 #ifdef _WIN32
25 26 #ifdef _MSC_VER
26 27 #define inline __inline
27 28 typedef unsigned long uint32_t;
28 29 #else
29 30 #include <stdint.h>
30 31 #endif
31 32 static uint32_t htonl(uint32_t x)
32 33 {
33 34 return ((x & 0x000000ffUL) << 24) |
34 35 ((x & 0x0000ff00UL) << 8) |
35 36 ((x & 0x00ff0000UL) >> 8) |
36 37 ((x & 0xff000000UL) >> 24);
37 38 }
38 39 #else
39 40 #include <sys/types.h>
40 41 #include <arpa/inet.h>
41 42 #endif
42 43
43 44 struct line {
44 45 int h, len, n, e;
45 46 const char *l;
46 47 };
47 48
48 49 struct pos {
49 50 int pos, len;
50 51 };
51 52
52 53 struct hunk {
53 54 int a1, a2, b1, b2;
54 55 };
55 56
56 57 struct hunklist {
57 58 struct hunk *base, *head;
58 59 };
59 60
60 61 static inline uint32_t rol32(uint32_t word, unsigned int shift)
61 62 {
62 63 return (word << shift) | (word >> (32 - shift));
63 64 }
64 65
65 66 int splitlines(const char *a, int len, struct line **lr)
66 67 {
67 68 int h, i;
68 69 const char *p, *b = a;
69 70 struct line *l;
70 71
71 72 /* count the lines */
72 73 i = 1; /* extra line for sentinel */
73 74 for (p = a; p < a + len; p++)
74 75 if (*p == '\n' || p == a + len - 1)
75 76 i++;
76 77
77 78 *lr = l = (struct line *)malloc(sizeof(struct line) * i);
78 79 if (!l)
79 80 return -1;
80 81
81 82 /* build the line array and calculate hashes */
82 83 h = 0;
83 84 for (p = a; p < a + len; p++) {
84 85 h = *p + rol32(h, 7); /* a simple hash from GNU diff */
85 86 if (*p == '\n' || p == a + len - 1) {
86 87 l->len = p - b + 1;
87 88 l->h = h * l->len;
88 89 l->l = b;
89 90 l->n = -1;
90 91 l++;
91 92 b = p + 1;
92 93 h = 0;
93 94 }
94 95 }
95 96
96 97 /* set up a sentinel */
97 98 l->h = l->len = 0;
98 99 l->l = a + len;
99 100 return i - 1;
100 101 }
101 102
102 103 int inline cmp(struct line *a, struct line *b)
103 104 {
104 105 return a->h != b->h || a->len != b->len || memcmp(a->l, b->l, a->len);
105 106 }
106 107
107 108 static int equatelines(struct line *a, int an, struct line *b, int bn)
108 109 {
109 110 int i, j, buckets = 1, t;
110 111 struct pos *h;
111 112
112 113 /* build a hash table of the next highest power of 2 */
113 114 while (buckets < bn + 1)
114 115 buckets *= 2;
115 116
116 117 h = (struct pos *)malloc(buckets * sizeof(struct pos));
117 118 buckets = buckets - 1;
118 119 if (!h)
119 120 return 0;
120 121
121 122 /* clear the hash table */
122 123 for (i = 0; i <= buckets; i++) {
123 124 h[i].pos = -1;
124 125 h[i].len = 0;
125 126 }
126 127
127 128 /* add lines to the hash table chains */
128 129 for (i = bn - 1; i >= 0; i--) {
129 130 /* find the equivalence class */
130 131 for (j = b[i].h & buckets; h[j].pos != -1;
131 132 j = (j + 1) & buckets)
132 133 if (!cmp(b + i, b + h[j].pos))
133 134 break;
134 135
135 136 /* add to the head of the equivalence class */
136 137 b[i].n = h[j].pos;
137 138 b[i].e = j;
138 139 h[j].pos = i;
139 140 h[j].len++; /* keep track of popularity */
140 141 }
141 142
142 143 /* compute popularity threshold */
143 144 t = (bn >= 200) ? bn / 100 : bn + 1;
144 145
145 146 /* match items in a to their equivalence class in b */
146 147 for (i = 0; i < an; i++) {
147 148 /* find the equivalence class */
148 149 for (j = a[i].h & buckets; h[j].pos != -1;
149 150 j = (j + 1) & buckets)
150 151 if (!cmp(a + i, b + h[j].pos))
151 152 break;
152 153
153 154 a[i].e = j; /* use equivalence class for quick compare */
154 155 if (h[j].len <= t)
155 156 a[i].n = h[j].pos; /* point to head of match list */
156 157 else
157 158 a[i].n = -1; /* too popular */
158 159 }
159 160
160 161 /* discard hash tables */
161 162 free(h);
162 163 return 1;
163 164 }
164 165
165 166 static int longest_match(struct line *a, struct line *b, struct pos *pos,
166 167 int a1, int a2, int b1, int b2, int *omi, int *omj)
167 168 {
168 169 int mi = a1, mj = b1, mk = 0, mb = 0, i, j, k;
169 170
170 171 for (i = a1; i < a2; i++) {
171 172 /* skip things before the current block */
172 173 for (j = a[i].n; j != -1 && j < b1; j = b[j].n)
173 174 ;
174 175
175 176 /* loop through all lines match a[i] in b */
176 177 for (; j != -1 && j < b2; j = b[j].n) {
177 178 /* does this extend an earlier match? */
178 179 if (i > a1 && j > b1 && pos[j - 1].pos == i - 1)
179 180 k = pos[j - 1].len + 1;
180 181 else
181 182 k = 1;
182 183 pos[j].pos = i;
183 184 pos[j].len = k;
184 185
185 186 /* best match so far? */
186 187 if (k > mk) {
187 188 mi = i;
188 189 mj = j;
189 190 mk = k;
190 191 }
191 192 }
192 193 }
193 194
194 195 if (mk) {
195 196 mi = mi - mk + 1;
196 197 mj = mj - mk + 1;
197 198 }
198 199
199 200 /* expand match to include neighboring popular lines */
200 201 while (mi - mb > a1 && mj - mb > b1 &&
201 202 a[mi - mb - 1].e == b[mj - mb - 1].e)
202 203 mb++;
203 204 while (mi + mk < a2 && mj + mk < b2 &&
204 205 a[mi + mk].e == b[mj + mk].e)
205 206 mk++;
206 207
207 208 *omi = mi - mb;
208 209 *omj = mj - mb;
209 210 return mk + mb;
210 211 }
211 212
212 213 static void recurse(struct line *a, struct line *b, struct pos *pos,
213 214 int a1, int a2, int b1, int b2, struct hunklist *l)
214 215 {
215 216 int i, j, k;
216 217
217 218 /* find the longest match in this chunk */
218 219 k = longest_match(a, b, pos, a1, a2, b1, b2, &i, &j);
219 220 if (!k)
220 221 return;
221 222
222 223 /* and recurse on the remaining chunks on either side */
223 224 recurse(a, b, pos, a1, i, b1, j, l);
224 225 l->head->a1 = i;
225 226 l->head->a2 = i + k;
226 227 l->head->b1 = j;
227 228 l->head->b2 = j + k;
228 229 l->head++;
229 230 recurse(a, b, pos, i + k, a2, j + k, b2, l);
230 231 }
231 232
232 233 static struct hunklist diff(struct line *a, int an, struct line *b, int bn)
233 234 {
234 235 struct hunklist l;
235 236 struct pos *pos;
236 237 int t;
237 238
238 239 /* allocate and fill arrays */
239 240 t = equatelines(a, an, b, bn);
240 241 pos = (struct pos *)calloc(bn, sizeof(struct pos));
241 242 /* we can't have more matches than lines in the shorter file */
242 243 l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) *
243 244 ((an<bn ? an:bn) + 1));
244 245
245 246 if (pos && l.base && t) {
246 247 /* generate the matching block list */
247 248 recurse(a, b, pos, 0, an, 0, bn, &l);
248 249 l.head->a1 = an;
249 250 l.head->b1 = bn;
250 251 l.head++;
251 252 }
252 253
253 254 free(pos);
254 255 return l;
255 256 }
256 257
257 258 static PyObject *blocks(PyObject *self, PyObject *args)
258 259 {
259 260 PyObject *sa, *sb, *rl = NULL, *m;
260 261 struct line *a, *b;
261 262 struct hunklist l = {NULL, NULL};
262 263 struct hunk *h;
263 264 int an, bn, pos = 0;
264 265
265 266 if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb))
266 267 return NULL;
267 268
268 269 an = splitlines(PyString_AsString(sa), PyString_Size(sa), &a);
269 270 bn = splitlines(PyString_AsString(sb), PyString_Size(sb), &b);
270 271 if (!a || !b)
271 272 goto nomem;
272 273
273 274 l = diff(a, an, b, bn);
274 275 rl = PyList_New(l.head - l.base);
275 276 if (!l.head || !rl)
276 277 goto nomem;
277 278
278 279 for (h = l.base; h != l.head; h++) {
279 280 m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2);
280 281 PyList_SetItem(rl, pos, m);
281 282 pos++;
282 283 }
283 284
284 285 nomem:
285 286 free(a);
286 287 free(b);
287 288 free(l.base);
288 289 return rl ? rl : PyErr_NoMemory();
289 290 }
290 291
291 292 static PyObject *bdiff(PyObject *self, PyObject *args)
292 293 {
293 294 PyObject *sa, *sb, *result = NULL;
294 295 struct line *al, *bl;
295 296 struct hunklist l = {NULL, NULL};
296 297 struct hunk *h;
297 298 char encode[12], *rb;
298 299 int an, bn, len = 0, la = 0, lb = 0;
299 300
300 301 if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb))
301 302 return NULL;
302 303
303 304 an = splitlines(PyString_AsString(sa), PyString_Size(sa), &al);
304 305 bn = splitlines(PyString_AsString(sb), PyString_Size(sb), &bl);
305 306 if (!al || !bl)
306 307 goto nomem;
307 308
308 309 l = diff(al, an, bl, bn);
309 310 if (!l.head)
310 311 goto nomem;
311 312
312 313 /* calculate length of output */
313 314 for (h = l.base; h != l.head; h++) {
314 315 if (h->a1 != la || h->b1 != lb)
315 316 len += 12 + bl[h->b1].l - bl[lb].l;
316 317 la = h->a2;
317 318 lb = h->b2;
318 319 }
319 320
320 321 result = PyString_FromStringAndSize(NULL, len);
321 322 if (!result)
322 323 goto nomem;
323 324
324 325 /* build binary patch */
325 326 rb = PyString_AsString(result);
326 327 la = lb = 0;
327 328
328 329 for (h = l.base; h != l.head; h++) {
329 330 if (h->a1 != la || h->b1 != lb) {
330 331 len = bl[h->b1].l - bl[lb].l;
331 332 *(uint32_t *)(encode) = htonl(al[la].l - al->l);
332 333 *(uint32_t *)(encode + 4) = htonl(al[h->a1].l - al->l);
333 334 *(uint32_t *)(encode + 8) = htonl(len);
334 335 memcpy(rb, encode, 12);
335 336 memcpy(rb + 12, bl[lb].l, len);
336 337 rb += 12 + len;
337 338 }
338 339 la = h->a2;
339 340 lb = h->b2;
340 341 }
341 342
342 343 nomem:
343 344 free(al);
344 345 free(bl);
345 346 free(l.base);
346 347 return result ? result : PyErr_NoMemory();
347 348 }
348 349
349 350 static char mdiff_doc[] = "Efficient binary diff.";
350 351
351 352 static PyMethodDef methods[] = {
352 353 {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"},
353 354 {"blocks", blocks, METH_VARARGS, "find a list of matching lines\n"},
354 355 {NULL, NULL}
355 356 };
356 357
357 358 PyMODINIT_FUNC initbdiff(void)
358 359 {
359 360 Py_InitModule3("bdiff", methods, mdiff_doc);
360 361 }
361 362
@@ -1,404 +1,408
1 1 /*
2 2 mpatch.c - efficient binary patching for Mercurial
3 3
4 4 This implements a patch algorithm that's O(m + nlog n) where m is the
5 5 size of the output and n is the number of patches.
6 6
7 7 Given a list of binary patches, it unpacks each into a hunk list,
8 8 then combines the hunk lists with a treewise recursion to form a
9 9 single hunk list. This hunk list is then applied to the original
10 10 text.
11 11
12 12 The text (or binary) fragments are copied directly from their source
13 13 Python objects into a preallocated output string to avoid the
14 14 allocation of intermediate Python objects. Working memory is about 2x
15 15 the total number of hunks.
16 16
17 17 Copyright 2005 Matt Mackall <mpm@selenic.com>
18 18
19 19 This software may be used and distributed according to the terms
20 20 of the GNU General Public License, incorporated herein by reference.
21 21 */
22 22
23 23 #include <Python.h>
24 24 #include <stdlib.h>
25 25 #include <string.h>
26
26 27 #ifdef _WIN32
27 28 #ifdef _MSC_VER
29 /* msvc 6.0 has problems */
28 30 #define inline __inline
29 31 typedef unsigned long uint32_t;
30 32 #else
31 33 #include <stdint.h>
32 34 #endif
33 35 static uint32_t ntohl(uint32_t x)
34 36 {
35 37 return ((x & 0x000000ffUL) << 24) |
36 38 ((x & 0x0000ff00UL) << 8) |
37 39 ((x & 0x00ff0000UL) >> 8) |
38 40 ((x & 0xff000000UL) >> 24);
39 41 }
40 42 #else
43 /* not windows */
41 44 #include <sys/types.h>
42 45 #include <arpa/inet.h>
46 # include <stdint.h>
43 47 #endif
44 48
45 49 static char mpatch_doc[] = "Efficient binary patching.";
46 50 static PyObject *mpatch_Error;
47 51
48 52 struct frag {
49 53 int start, end, len;
50 54 char *data;
51 55 };
52 56
53 57 struct flist {
54 58 struct frag *base, *head, *tail;
55 59 };
56 60
57 61 static struct flist *lalloc(int size)
58 62 {
59 63 struct flist *a = NULL;
60 64
61 65 a = (struct flist *)malloc(sizeof(struct flist));
62 66 if (a) {
63 67 a->base = (struct frag *)malloc(sizeof(struct frag) * size);
64 68 if (a->base) {
65 69 a->head = a->tail = a->base;
66 70 return a;
67 71 }
68 72 free(a);
69 73 a = NULL;
70 74 }
71 75 if (!PyErr_Occurred())
72 76 PyErr_NoMemory();
73 77 return NULL;
74 78 }
75 79
76 80 static void lfree(struct flist *a)
77 81 {
78 82 if (a) {
79 83 free(a->base);
80 84 free(a);
81 85 }
82 86 }
83 87
84 88 static int lsize(struct flist *a)
85 89 {
86 90 return a->tail - a->head;
87 91 }
88 92
89 93 /* move hunks in source that are less cut to dest, compensating
90 94 for changes in offset. the last hunk may be split if necessary.
91 95 */
92 96 static int gather(struct flist *dest, struct flist *src, int cut, int offset)
93 97 {
94 98 struct frag *d = dest->tail, *s = src->head;
95 99 int postend, c, l;
96 100
97 101 while (s != src->tail) {
98 102 if (s->start + offset >= cut)
99 103 break; /* we've gone far enough */
100 104
101 105 postend = offset + s->start + s->len;
102 106 if (postend <= cut) {
103 107 /* save this hunk */
104 108 offset += s->start + s->len - s->end;
105 109 *d++ = *s++;
106 110 }
107 111 else {
108 112 /* break up this hunk */
109 113 c = cut - offset;
110 114 if (s->end < c)
111 115 c = s->end;
112 116 l = cut - offset - s->start;
113 117 if (s->len < l)
114 118 l = s->len;
115 119
116 120 offset += s->start + l - c;
117 121
118 122 d->start = s->start;
119 123 d->end = c;
120 124 d->len = l;
121 125 d->data = s->data;
122 126 d++;
123 127 s->start = c;
124 128 s->len = s->len - l;
125 129 s->data = s->data + l;
126 130
127 131 break;
128 132 }
129 133 }
130 134
131 135 dest->tail = d;
132 136 src->head = s;
133 137 return offset;
134 138 }
135 139
136 140 /* like gather, but with no output list */
137 141 static int discard(struct flist *src, int cut, int offset)
138 142 {
139 143 struct frag *s = src->head;
140 144 int postend, c, l;
141 145
142 146 while (s != src->tail) {
143 147 if (s->start + offset >= cut)
144 148 break;
145 149
146 150 postend = offset + s->start + s->len;
147 151 if (postend <= cut) {
148 152 offset += s->start + s->len - s->end;
149 153 s++;
150 154 }
151 155 else {
152 156 c = cut - offset;
153 157 if (s->end < c)
154 158 c = s->end;
155 159 l = cut - offset - s->start;
156 160 if (s->len < l)
157 161 l = s->len;
158 162
159 163 offset += s->start + l - c;
160 164 s->start = c;
161 165 s->len = s->len - l;
162 166 s->data = s->data + l;
163 167
164 168 break;
165 169 }
166 170 }
167 171
168 172 src->head = s;
169 173 return offset;
170 174 }
171 175
172 176 /* combine hunk lists a and b, while adjusting b for offset changes in a/
173 177 this deletes a and b and returns the resultant list. */
174 178 static struct flist *combine(struct flist *a, struct flist *b)
175 179 {
176 180 struct flist *c = NULL;
177 181 struct frag *bh, *ct;
178 182 int offset = 0, post;
179 183
180 184 if (a && b)
181 185 c = lalloc((lsize(a) + lsize(b)) * 2);
182 186
183 187 if (c) {
184 188
185 189 for (bh = b->head; bh != b->tail; bh++) {
186 190 /* save old hunks */
187 191 offset = gather(c, a, bh->start, offset);
188 192
189 193 /* discard replaced hunks */
190 194 post = discard(a, bh->end, offset);
191 195
192 196 /* insert new hunk */
193 197 ct = c->tail;
194 198 ct->start = bh->start - offset;
195 199 ct->end = bh->end - post;
196 200 ct->len = bh->len;
197 201 ct->data = bh->data;
198 202 c->tail++;
199 203 offset = post;
200 204 }
201 205
202 206 /* hold on to tail from a */
203 207 memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a));
204 208 c->tail += lsize(a);
205 209 }
206 210
207 211 lfree(a);
208 212 lfree(b);
209 213 return c;
210 214 }
211 215
212 216 /* decode a binary patch into a hunk list */
213 217 static struct flist *decode(char *bin, int len)
214 218 {
215 219 struct flist *l;
216 220 struct frag *lt;
217 221 char *end = bin + len;
218 222 char decode[12]; /* for dealing with alignment issues */
219 223
220 224 /* assume worst case size, we won't have many of these lists */
221 225 l = lalloc(len / 12);
222 226 if (!l)
223 227 return NULL;
224 228
225 229 lt = l->tail;
226 230
227 231 while (bin < end) {
228 232 memcpy(decode, bin, 12);
229 233 lt->start = ntohl(*(uint32_t *)decode);
230 234 lt->end = ntohl(*(uint32_t *)(decode + 4));
231 235 lt->len = ntohl(*(uint32_t *)(decode + 8));
232 236 lt->data = bin + 12;
233 237 bin += 12 + lt->len;
234 238 lt++;
235 239 }
236 240
237 241 if (bin != end) {
238 242 if (!PyErr_Occurred())
239 243 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
240 244 lfree(l);
241 245 return NULL;
242 246 }
243 247
244 248 l->tail = lt;
245 249 return l;
246 250 }
247 251
248 252 /* calculate the size of resultant text */
249 253 static int calcsize(int len, struct flist *l)
250 254 {
251 255 int outlen = 0, last = 0;
252 256 struct frag *f = l->head;
253 257
254 258 while (f != l->tail) {
255 259 if (f->start < last || f->end > len) {
256 260 if (!PyErr_Occurred())
257 261 PyErr_SetString(mpatch_Error,
258 262 "invalid patch");
259 263 return -1;
260 264 }
261 265 outlen += f->start - last;
262 266 last = f->end;
263 267 outlen += f->len;
264 268 f++;
265 269 }
266 270
267 271 outlen += len - last;
268 272 return outlen;
269 273 }
270 274
271 275 static int apply(char *buf, char *orig, int len, struct flist *l)
272 276 {
273 277 struct frag *f = l->head;
274 278 int last = 0;
275 279 char *p = buf;
276 280
277 281 while (f != l->tail) {
278 282 if (f->start < last || f->end > len) {
279 283 if (!PyErr_Occurred())
280 284 PyErr_SetString(mpatch_Error,
281 285 "invalid patch");
282 286 return 0;
283 287 }
284 288 memcpy(p, orig + last, f->start - last);
285 289 p += f->start - last;
286 290 memcpy(p, f->data, f->len);
287 291 last = f->end;
288 292 p += f->len;
289 293 f++;
290 294 }
291 295 memcpy(p, orig + last, len - last);
292 296 return 1;
293 297 }
294 298
295 299 /* recursively generate a patch of all bins between start and end */
296 300 static struct flist *fold(PyObject *bins, int start, int end)
297 301 {
298 302 int len;
299 303
300 304 if (start + 1 == end) {
301 305 /* trivial case, output a decoded list */
302 306 PyObject *tmp = PyList_GetItem(bins, start);
303 307 if (!tmp)
304 308 return NULL;
305 309 return decode(PyString_AsString(tmp), PyString_Size(tmp));
306 310 }
307 311
308 312 /* divide and conquer, memory management is elsewhere */
309 313 len = (end - start) / 2;
310 314 return combine(fold(bins, start, start + len),
311 315 fold(bins, start + len, end));
312 316 }
313 317
314 318 static PyObject *
315 319 patches(PyObject *self, PyObject *args)
316 320 {
317 321 PyObject *text, *bins, *result;
318 322 struct flist *patch;
319 323 char *in, *out;
320 324 int len, outlen;
321 325
322 326 if (!PyArg_ParseTuple(args, "SO:mpatch", &text, &bins))
323 327 return NULL;
324 328
325 329 len = PyList_Size(bins);
326 330 if (!len) {
327 331 /* nothing to do */
328 332 Py_INCREF(text);
329 333 return text;
330 334 }
331 335
332 336 patch = fold(bins, 0, len);
333 337 if (!patch)
334 338 return NULL;
335 339
336 340 outlen = calcsize(PyString_Size(text), patch);
337 341 if (outlen < 0) {
338 342 result = NULL;
339 343 goto cleanup;
340 344 }
341 345 result = PyString_FromStringAndSize(NULL, outlen);
342 346 if (!result) {
343 347 result = NULL;
344 348 goto cleanup;
345 349 }
346 350 in = PyString_AsString(text);
347 351 out = PyString_AsString(result);
348 352 if (!apply(out, in, PyString_Size(text), patch)) {
349 353 Py_DECREF(result);
350 354 result = NULL;
351 355 }
352 356 cleanup:
353 357 lfree(patch);
354 358 return result;
355 359 }
356 360
357 361 /* calculate size of a patched file directly */
358 362 static PyObject *
359 363 patchedsize(PyObject *self, PyObject *args)
360 364 {
361 365 long orig, start, end, len, outlen = 0, last = 0;
362 366 int patchlen;
363 367 char *bin, *binend;
364 368 char decode[12]; /* for dealing with alignment issues */
365 369
366 370 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
367 371 return NULL;
368 372
369 373 binend = bin + patchlen;
370 374
371 375 while (bin < binend) {
372 376 memcpy(decode, bin, 12);
373 377 start = ntohl(*(uint32_t *)decode);
374 378 end = ntohl(*(uint32_t *)(decode + 4));
375 379 len = ntohl(*(uint32_t *)(decode + 8));
376 380 bin += 12 + len;
377 381 outlen += start - last;
378 382 last = end;
379 383 outlen += len;
380 384 }
381 385
382 386 if (bin != binend) {
383 387 if (!PyErr_Occurred())
384 388 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
385 389 return NULL;
386 390 }
387 391
388 392 outlen += orig - last;
389 393 return Py_BuildValue("l", outlen);
390 394 }
391 395
392 396 static PyMethodDef methods[] = {
393 397 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
394 398 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
395 399 {NULL, NULL}
396 400 };
397 401
398 402 PyMODINIT_FUNC
399 403 initmpatch(void)
400 404 {
401 405 Py_InitModule3("mpatch", methods, mpatch_doc);
402 406 mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL);
403 407 }
404 408
General Comments 0
You need to be logged in to leave comments. Login now