##// END OF EJS Templates
mpatch: raise MemoryError instead of mpatchError if lalloc() failed...
Yuya Nishihara -
r29749:155f0cc3 default
parent child Browse files
Show More
@@ -1,283 +1,280 b''
1 /*
1 /*
2 mpatch.c - efficient binary patching for Mercurial
2 mpatch.c - efficient binary patching for Mercurial
3
3
4 This implements a patch algorithm that's O(m + nlog n) where m is the
4 This implements a patch algorithm that's O(m + nlog n) where m is the
5 size of the output and n is the number of patches.
5 size of the output and n is the number of patches.
6
6
7 Given a list of binary patches, it unpacks each into a hunk list,
7 Given a list of binary patches, it unpacks each into a hunk list,
8 then combines the hunk lists with a treewise recursion to form a
8 then combines the hunk lists with a treewise recursion to form a
9 single hunk list. This hunk list is then applied to the original
9 single hunk list. This hunk list is then applied to the original
10 text.
10 text.
11
11
12 The text (or binary) fragments are copied directly from their source
12 The text (or binary) fragments are copied directly from their source
13 Python objects into a preallocated output string to avoid the
13 Python objects into a preallocated output string to avoid the
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
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 #include <stdlib.h>
23 #include <stdlib.h>
24 #include <string.h>
24 #include <string.h>
25
25
26 #include "bitmanipulation.h"
26 #include "bitmanipulation.h"
27 #include "compat.h"
27 #include "compat.h"
28 #include "mpatch.h"
28 #include "mpatch.h"
29
29
30 char *mpatch_errors[] = {NULL, "invalid patch", "patch cannot be decoded",
31 "no memory"};
32
33 static struct mpatch_flist *lalloc(ssize_t size)
30 static struct mpatch_flist *lalloc(ssize_t size)
34 {
31 {
35 struct mpatch_flist *a = NULL;
32 struct mpatch_flist *a = NULL;
36
33
37 if (size < 1)
34 if (size < 1)
38 size = 1;
35 size = 1;
39
36
40 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
37 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
41 if (a) {
38 if (a) {
42 a->base = (struct mpatch_frag *)malloc(sizeof(struct mpatch_frag) * size);
39 a->base = (struct mpatch_frag *)malloc(sizeof(struct mpatch_frag) * size);
43 if (a->base) {
40 if (a->base) {
44 a->head = a->tail = a->base;
41 a->head = a->tail = a->base;
45 return a;
42 return a;
46 }
43 }
47 free(a);
44 free(a);
48 }
45 }
49 return NULL;
46 return NULL;
50 }
47 }
51
48
52 void mpatch_lfree(struct mpatch_flist *a)
49 void mpatch_lfree(struct mpatch_flist *a)
53 {
50 {
54 if (a) {
51 if (a) {
55 free(a->base);
52 free(a->base);
56 free(a);
53 free(a);
57 }
54 }
58 }
55 }
59
56
60 static ssize_t lsize(struct mpatch_flist *a)
57 static ssize_t lsize(struct mpatch_flist *a)
61 {
58 {
62 return a->tail - a->head;
59 return a->tail - a->head;
63 }
60 }
64
61
65 /* move hunks in source that are less cut to dest, compensating
62 /* move hunks in source that are less cut to dest, compensating
66 for changes in offset. the last hunk may be split if necessary.
63 for changes in offset. the last hunk may be split if necessary.
67 */
64 */
68 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
65 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
69 int offset)
66 int offset)
70 {
67 {
71 struct mpatch_frag *d = dest->tail, *s = src->head;
68 struct mpatch_frag *d = dest->tail, *s = src->head;
72 int postend, c, l;
69 int postend, c, l;
73
70
74 while (s != src->tail) {
71 while (s != src->tail) {
75 if (s->start + offset >= cut)
72 if (s->start + offset >= cut)
76 break; /* we've gone far enough */
73 break; /* we've gone far enough */
77
74
78 postend = offset + s->start + s->len;
75 postend = offset + s->start + s->len;
79 if (postend <= cut) {
76 if (postend <= cut) {
80 /* save this hunk */
77 /* save this hunk */
81 offset += s->start + s->len - s->end;
78 offset += s->start + s->len - s->end;
82 *d++ = *s++;
79 *d++ = *s++;
83 }
80 }
84 else {
81 else {
85 /* break up this hunk */
82 /* break up this hunk */
86 c = cut - offset;
83 c = cut - offset;
87 if (s->end < c)
84 if (s->end < c)
88 c = s->end;
85 c = s->end;
89 l = cut - offset - s->start;
86 l = cut - offset - s->start;
90 if (s->len < l)
87 if (s->len < l)
91 l = s->len;
88 l = s->len;
92
89
93 offset += s->start + l - c;
90 offset += s->start + l - c;
94
91
95 d->start = s->start;
92 d->start = s->start;
96 d->end = c;
93 d->end = c;
97 d->len = l;
94 d->len = l;
98 d->data = s->data;
95 d->data = s->data;
99 d++;
96 d++;
100 s->start = c;
97 s->start = c;
101 s->len = s->len - l;
98 s->len = s->len - l;
102 s->data = s->data + l;
99 s->data = s->data + l;
103
100
104 break;
101 break;
105 }
102 }
106 }
103 }
107
104
108 dest->tail = d;
105 dest->tail = d;
109 src->head = s;
106 src->head = s;
110 return offset;
107 return offset;
111 }
108 }
112
109
113 /* like gather, but with no output list */
110 /* like gather, but with no output list */
114 static int discard(struct mpatch_flist *src, int cut, int offset)
111 static int discard(struct mpatch_flist *src, int cut, int offset)
115 {
112 {
116 struct mpatch_frag *s = src->head;
113 struct mpatch_frag *s = src->head;
117 int postend, c, l;
114 int postend, c, l;
118
115
119 while (s != src->tail) {
116 while (s != src->tail) {
120 if (s->start + offset >= cut)
117 if (s->start + offset >= cut)
121 break;
118 break;
122
119
123 postend = offset + s->start + s->len;
120 postend = offset + s->start + s->len;
124 if (postend <= cut) {
121 if (postend <= cut) {
125 offset += s->start + s->len - s->end;
122 offset += s->start + s->len - s->end;
126 s++;
123 s++;
127 }
124 }
128 else {
125 else {
129 c = cut - offset;
126 c = cut - offset;
130 if (s->end < c)
127 if (s->end < c)
131 c = s->end;
128 c = s->end;
132 l = cut - offset - s->start;
129 l = cut - offset - s->start;
133 if (s->len < l)
130 if (s->len < l)
134 l = s->len;
131 l = s->len;
135
132
136 offset += s->start + l - c;
133 offset += s->start + l - c;
137 s->start = c;
134 s->start = c;
138 s->len = s->len - l;
135 s->len = s->len - l;
139 s->data = s->data + l;
136 s->data = s->data + l;
140
137
141 break;
138 break;
142 }
139 }
143 }
140 }
144
141
145 src->head = s;
142 src->head = s;
146 return offset;
143 return offset;
147 }
144 }
148
145
149 /* combine hunk lists a and b, while adjusting b for offset changes in a/
146 /* combine hunk lists a and b, while adjusting b for offset changes in a/
150 this deletes a and b and returns the resultant list. */
147 this deletes a and b and returns the resultant list. */
151 static struct mpatch_flist *combine(struct mpatch_flist *a,
148 static struct mpatch_flist *combine(struct mpatch_flist *a,
152 struct mpatch_flist *b)
149 struct mpatch_flist *b)
153 {
150 {
154 struct mpatch_flist *c = NULL;
151 struct mpatch_flist *c = NULL;
155 struct mpatch_frag *bh, *ct;
152 struct mpatch_frag *bh, *ct;
156 int offset = 0, post;
153 int offset = 0, post;
157
154
158 if (a && b)
155 if (a && b)
159 c = lalloc((lsize(a) + lsize(b)) * 2);
156 c = lalloc((lsize(a) + lsize(b)) * 2);
160
157
161 if (c) {
158 if (c) {
162
159
163 for (bh = b->head; bh != b->tail; bh++) {
160 for (bh = b->head; bh != b->tail; bh++) {
164 /* save old hunks */
161 /* save old hunks */
165 offset = gather(c, a, bh->start, offset);
162 offset = gather(c, a, bh->start, offset);
166
163
167 /* discard replaced hunks */
164 /* discard replaced hunks */
168 post = discard(a, bh->end, offset);
165 post = discard(a, bh->end, offset);
169
166
170 /* insert new hunk */
167 /* insert new hunk */
171 ct = c->tail;
168 ct = c->tail;
172 ct->start = bh->start - offset;
169 ct->start = bh->start - offset;
173 ct->end = bh->end - post;
170 ct->end = bh->end - post;
174 ct->len = bh->len;
171 ct->len = bh->len;
175 ct->data = bh->data;
172 ct->data = bh->data;
176 c->tail++;
173 c->tail++;
177 offset = post;
174 offset = post;
178 }
175 }
179
176
180 /* hold on to tail from a */
177 /* hold on to tail from a */
181 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
178 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
182 c->tail += lsize(a);
179 c->tail += lsize(a);
183 }
180 }
184
181
185 mpatch_lfree(a);
182 mpatch_lfree(a);
186 mpatch_lfree(b);
183 mpatch_lfree(b);
187 return c;
184 return c;
188 }
185 }
189
186
190 /* decode a binary patch into a hunk list */
187 /* decode a binary patch into a hunk list */
191 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
188 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
192 {
189 {
193 struct mpatch_flist *l;
190 struct mpatch_flist *l;
194 struct mpatch_frag *lt;
191 struct mpatch_frag *lt;
195 int pos = 0;
192 int pos = 0;
196
193
197 /* assume worst case size, we won't have many of these lists */
194 /* assume worst case size, we won't have many of these lists */
198 l = lalloc(len / 12 + 1);
195 l = lalloc(len / 12 + 1);
199 if (!l)
196 if (!l)
200 return MPATCH_ERR_NO_MEM;
197 return MPATCH_ERR_NO_MEM;
201
198
202 lt = l->tail;
199 lt = l->tail;
203
200
204 while (pos >= 0 && pos < len) {
201 while (pos >= 0 && pos < len) {
205 lt->start = getbe32(bin + pos);
202 lt->start = getbe32(bin + pos);
206 lt->end = getbe32(bin + pos + 4);
203 lt->end = getbe32(bin + pos + 4);
207 lt->len = getbe32(bin + pos + 8);
204 lt->len = getbe32(bin + pos + 8);
208 lt->data = bin + pos + 12;
205 lt->data = bin + pos + 12;
209 pos += 12 + lt->len;
206 pos += 12 + lt->len;
210 if (lt->start > lt->end || lt->len < 0)
207 if (lt->start > lt->end || lt->len < 0)
211 break; /* sanity check */
208 break; /* sanity check */
212 lt++;
209 lt++;
213 }
210 }
214
211
215 if (pos != len) {
212 if (pos != len) {
216 mpatch_lfree(l);
213 mpatch_lfree(l);
217 return MPATCH_ERR_CANNOT_BE_DECODED;
214 return MPATCH_ERR_CANNOT_BE_DECODED;
218 }
215 }
219
216
220 l->tail = lt;
217 l->tail = lt;
221 *res = l;
218 *res = l;
222 return 0;
219 return 0;
223 }
220 }
224
221
225 /* calculate the size of resultant text */
222 /* calculate the size of resultant text */
226 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
223 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
227 {
224 {
228 ssize_t outlen = 0, last = 0;
225 ssize_t outlen = 0, last = 0;
229 struct mpatch_frag *f = l->head;
226 struct mpatch_frag *f = l->head;
230
227
231 while (f != l->tail) {
228 while (f != l->tail) {
232 if (f->start < last || f->end > len) {
229 if (f->start < last || f->end > len) {
233 return MPATCH_ERR_INVALID_PATCH;
230 return MPATCH_ERR_INVALID_PATCH;
234 }
231 }
235 outlen += f->start - last;
232 outlen += f->start - last;
236 last = f->end;
233 last = f->end;
237 outlen += f->len;
234 outlen += f->len;
238 f++;
235 f++;
239 }
236 }
240
237
241 outlen += len - last;
238 outlen += len - last;
242 return outlen;
239 return outlen;
243 }
240 }
244
241
245 int mpatch_apply(char *buf, const char *orig, ssize_t len,
242 int mpatch_apply(char *buf, const char *orig, ssize_t len,
246 struct mpatch_flist *l)
243 struct mpatch_flist *l)
247 {
244 {
248 struct mpatch_frag *f = l->head;
245 struct mpatch_frag *f = l->head;
249 int last = 0;
246 int last = 0;
250 char *p = buf;
247 char *p = buf;
251
248
252 while (f != l->tail) {
249 while (f != l->tail) {
253 if (f->start < last || f->end > len) {
250 if (f->start < last || f->end > len) {
254 return MPATCH_ERR_INVALID_PATCH;
251 return MPATCH_ERR_INVALID_PATCH;
255 }
252 }
256 memcpy(p, orig + last, f->start - last);
253 memcpy(p, orig + last, f->start - last);
257 p += f->start - last;
254 p += f->start - last;
258 memcpy(p, f->data, f->len);
255 memcpy(p, f->data, f->len);
259 last = f->end;
256 last = f->end;
260 p += f->len;
257 p += f->len;
261 f++;
258 f++;
262 }
259 }
263 memcpy(p, orig + last, len - last);
260 memcpy(p, orig + last, len - last);
264 return 0;
261 return 0;
265 }
262 }
266
263
267 /* recursively generate a patch of all bins between start and end */
264 /* recursively generate a patch of all bins between start and end */
268 struct mpatch_flist *mpatch_fold(void *bins,
265 struct mpatch_flist *mpatch_fold(void *bins,
269 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
266 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
270 ssize_t start, ssize_t end)
267 ssize_t start, ssize_t end)
271 {
268 {
272 ssize_t len;
269 ssize_t len;
273
270
274 if (start + 1 == end) {
271 if (start + 1 == end) {
275 /* trivial case, output a decoded list */
272 /* trivial case, output a decoded list */
276 return get_next_item(bins, start);
273 return get_next_item(bins, start);
277 }
274 }
278
275
279 /* divide and conquer, memory management is elsewhere */
276 /* divide and conquer, memory management is elsewhere */
280 len = (end - start) / 2;
277 len = (end - start) / 2;
281 return combine(mpatch_fold(bins, get_next_item, start, start + len),
278 return combine(mpatch_fold(bins, get_next_item, start, start + len),
282 mpatch_fold(bins, get_next_item, start + len, end));
279 mpatch_fold(bins, get_next_item, start + len, end));
283 }
280 }
@@ -1,28 +1,26 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
4 #define MPATCH_ERR_NO_MEM -3
7 #define MPATCH_ERR_CANNOT_BE_DECODED -2
5 #define MPATCH_ERR_CANNOT_BE_DECODED -2
8 #define MPATCH_ERR_INVALID_PATCH -1
6 #define MPATCH_ERR_INVALID_PATCH -1
9
7
10 struct mpatch_frag {
8 struct mpatch_frag {
11 int start, end, len;
9 int start, end, len;
12 const char *data;
10 const char *data;
13 };
11 };
14
12
15 struct mpatch_flist {
13 struct mpatch_flist {
16 struct mpatch_frag *base, *head, *tail;
14 struct mpatch_frag *base, *head, *tail;
17 };
15 };
18
16
19 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist** res);
17 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist** res);
20 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l);
18 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l);
21 void mpatch_lfree(struct mpatch_flist *a);
19 void mpatch_lfree(struct mpatch_flist *a);
22 int mpatch_apply(char *buf, const char *orig, ssize_t len,
20 int mpatch_apply(char *buf, const char *orig, ssize_t len,
23 struct mpatch_flist *l);
21 struct mpatch_flist *l);
24 struct mpatch_flist *mpatch_fold(void *bins,
22 struct mpatch_flist *mpatch_fold(void *bins,
25 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
23 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
26 ssize_t start, ssize_t end);
24 ssize_t start, ssize_t end);
27
25
28 #endif
26 #endif
@@ -1,180 +1,195 b''
1 /*
1 /*
2 mpatch.c - efficient binary patching for Mercurial
2 mpatch.c - efficient binary patching for Mercurial
3
3
4 This implements a patch algorithm that's O(m + nlog n) where m is the
4 This implements a patch algorithm that's O(m + nlog n) where m is the
5 size of the output and n is the number of patches.
5 size of the output and n is the number of patches.
6
6
7 Given a list of binary patches, it unpacks each into a hunk list,
7 Given a list of binary patches, it unpacks each into a hunk list,
8 then combines the hunk lists with a treewise recursion to form a
8 then combines the hunk lists with a treewise recursion to form a
9 single hunk list. This hunk list is then applied to the original
9 single hunk list. This hunk list is then applied to the original
10 text.
10 text.
11
11
12 The text (or binary) fragments are copied directly from their source
12 The text (or binary) fragments are copied directly from their source
13 Python objects into a preallocated output string to avoid the
13 Python objects into a preallocated output string to avoid the
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
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
23 #define PY_SSIZE_T_CLEAN
24 #include <Python.h>
24 #include <Python.h>
25 #include <stdlib.h>
25 #include <stdlib.h>
26 #include <string.h>
26 #include <string.h>
27
27
28 #include "util.h"
28 #include "util.h"
29 #include "bitmanipulation.h"
29 #include "bitmanipulation.h"
30 #include "compat.h"
30 #include "compat.h"
31 #include "mpatch.h"
31 #include "mpatch.h"
32
32
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 static void setpyerr(int r)
37 {
38 switch (r) {
39 case MPATCH_ERR_NO_MEM:
40 PyErr_NoMemory();
41 break;
42 case MPATCH_ERR_CANNOT_BE_DECODED:
43 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
44 break;
45 case MPATCH_ERR_INVALID_PATCH:
46 PyErr_SetString(mpatch_Error, "invalid patch");
47 break;
48 }
49 }
50
36 struct mpatch_flist *cpygetitem(void *bins, ssize_t pos)
51 struct mpatch_flist *cpygetitem(void *bins, ssize_t pos)
37 {
52 {
38 const char *buffer;
53 const char *buffer;
39 struct mpatch_flist *res;
54 struct mpatch_flist *res;
40 ssize_t blen;
55 ssize_t blen;
41 int r;
56 int r;
42
57
43 PyObject *tmp = PyList_GetItem((PyObject*)bins, pos);
58 PyObject *tmp = PyList_GetItem((PyObject*)bins, pos);
44 if (!tmp)
59 if (!tmp)
45 return NULL;
60 return NULL;
46 if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen))
61 if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen))
47 return NULL;
62 return NULL;
48 if ((r = mpatch_decode(buffer, blen, &res)) < 0) {
63 if ((r = mpatch_decode(buffer, blen, &res)) < 0) {
49 if (!PyErr_Occurred())
64 if (!PyErr_Occurred())
50 PyErr_SetString(mpatch_Error, mpatch_errors[-r]);
65 setpyerr(r);
51 return NULL;
66 return NULL;
52 }
67 }
53 return res;
68 return res;
54 }
69 }
55
70
56 static PyObject *
71 static PyObject *
57 patches(PyObject *self, PyObject *args)
72 patches(PyObject *self, PyObject *args)
58 {
73 {
59 PyObject *text, *bins, *result;
74 PyObject *text, *bins, *result;
60 struct mpatch_flist *patch;
75 struct mpatch_flist *patch;
61 const char *in;
76 const char *in;
62 int r = 0;
77 int r = 0;
63 char *out;
78 char *out;
64 Py_ssize_t len, outlen, inlen;
79 Py_ssize_t len, outlen, inlen;
65
80
66 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
81 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
67 return NULL;
82 return NULL;
68
83
69 len = PyList_Size(bins);
84 len = PyList_Size(bins);
70 if (!len) {
85 if (!len) {
71 /* nothing to do */
86 /* nothing to do */
72 Py_INCREF(text);
87 Py_INCREF(text);
73 return text;
88 return text;
74 }
89 }
75
90
76 if (PyObject_AsCharBuffer(text, &in, &inlen))
91 if (PyObject_AsCharBuffer(text, &in, &inlen))
77 return NULL;
92 return NULL;
78
93
79 patch = mpatch_fold(bins, cpygetitem, 0, len);
94 patch = mpatch_fold(bins, cpygetitem, 0, len);
80 if (!patch) { /* error already set or memory error */
95 if (!patch) { /* error already set or memory error */
81 if (!PyErr_Occurred())
96 if (!PyErr_Occurred())
82 PyErr_NoMemory();
97 PyErr_NoMemory();
83 return NULL;
98 return NULL;
84 }
99 }
85
100
86 outlen = mpatch_calcsize(inlen, patch);
101 outlen = mpatch_calcsize(inlen, patch);
87 if (outlen < 0) {
102 if (outlen < 0) {
88 r = (int)outlen;
103 r = (int)outlen;
89 result = NULL;
104 result = NULL;
90 goto cleanup;
105 goto cleanup;
91 }
106 }
92 result = PyBytes_FromStringAndSize(NULL, outlen);
107 result = PyBytes_FromStringAndSize(NULL, outlen);
93 if (!result) {
108 if (!result) {
94 result = NULL;
109 result = NULL;
95 goto cleanup;
110 goto cleanup;
96 }
111 }
97 out = PyBytes_AsString(result);
112 out = PyBytes_AsString(result);
98 if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
113 if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
99 Py_DECREF(result);
114 Py_DECREF(result);
100 result = NULL;
115 result = NULL;
101 }
116 }
102 cleanup:
117 cleanup:
103 mpatch_lfree(patch);
118 mpatch_lfree(patch);
104 if (!result && !PyErr_Occurred())
119 if (!result && !PyErr_Occurred())
105 PyErr_SetString(mpatch_Error, mpatch_errors[-r]);
120 setpyerr(r);
106 return result;
121 return result;
107 }
122 }
108
123
109 /* calculate size of a patched file directly */
124 /* calculate size of a patched file directly */
110 static PyObject *
125 static PyObject *
111 patchedsize(PyObject *self, PyObject *args)
126 patchedsize(PyObject *self, PyObject *args)
112 {
127 {
113 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
128 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
114 Py_ssize_t patchlen;
129 Py_ssize_t patchlen;
115 char *bin;
130 char *bin;
116
131
117 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
132 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
118 return NULL;
133 return NULL;
119
134
120 while (pos >= 0 && pos < patchlen) {
135 while (pos >= 0 && pos < patchlen) {
121 start = getbe32(bin + pos);
136 start = getbe32(bin + pos);
122 end = getbe32(bin + pos + 4);
137 end = getbe32(bin + pos + 4);
123 len = getbe32(bin + pos + 8);
138 len = getbe32(bin + pos + 8);
124 if (start > end)
139 if (start > end)
125 break; /* sanity check */
140 break; /* sanity check */
126 pos += 12 + len;
141 pos += 12 + len;
127 outlen += start - last;
142 outlen += start - last;
128 last = end;
143 last = end;
129 outlen += len;
144 outlen += len;
130 }
145 }
131
146
132 if (pos != patchlen) {
147 if (pos != patchlen) {
133 if (!PyErr_Occurred())
148 if (!PyErr_Occurred())
134 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
149 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
135 return NULL;
150 return NULL;
136 }
151 }
137
152
138 outlen += orig - last;
153 outlen += orig - last;
139 return Py_BuildValue("l", outlen);
154 return Py_BuildValue("l", outlen);
140 }
155 }
141
156
142 static PyMethodDef methods[] = {
157 static PyMethodDef methods[] = {
143 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
158 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
144 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
159 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
145 {NULL, NULL}
160 {NULL, NULL}
146 };
161 };
147
162
148 #ifdef IS_PY3K
163 #ifdef IS_PY3K
149 static struct PyModuleDef mpatch_module = {
164 static struct PyModuleDef mpatch_module = {
150 PyModuleDef_HEAD_INIT,
165 PyModuleDef_HEAD_INIT,
151 "mpatch",
166 "mpatch",
152 mpatch_doc,
167 mpatch_doc,
153 -1,
168 -1,
154 methods
169 methods
155 };
170 };
156
171
157 PyMODINIT_FUNC PyInit_mpatch(void)
172 PyMODINIT_FUNC PyInit_mpatch(void)
158 {
173 {
159 PyObject *m;
174 PyObject *m;
160
175
161 m = PyModule_Create(&mpatch_module);
176 m = PyModule_Create(&mpatch_module);
162 if (m == NULL)
177 if (m == NULL)
163 return NULL;
178 return NULL;
164
179
165 mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
180 mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
166 NULL, NULL);
181 NULL, NULL);
167 Py_INCREF(mpatch_Error);
182 Py_INCREF(mpatch_Error);
168 PyModule_AddObject(m, "mpatchError", mpatch_Error);
183 PyModule_AddObject(m, "mpatchError", mpatch_Error);
169
184
170 return m;
185 return m;
171 }
186 }
172 #else
187 #else
173 PyMODINIT_FUNC
188 PyMODINIT_FUNC
174 initmpatch(void)
189 initmpatch(void)
175 {
190 {
176 Py_InitModule3("mpatch", methods, mpatch_doc);
191 Py_InitModule3("mpatch", methods, mpatch_doc);
177 mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
192 mpatch_Error = PyErr_NewException("mercurial.mpatch.mpatchError",
178 NULL, NULL);
193 NULL, NULL);
179 }
194 }
180 #endif
195 #endif
General Comments 0
You need to be logged in to leave comments. Login now