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