Mercurial > hg
annotate mercurial/mpatch.c @ 12709:4147a292c508
filectx: use ctx.size comparisons to speed up ctx.cmp
Comparing sizes is cheaper than comparing file contents, as it does not
involve reading the file on disk or from the filelog.
It is however not always possible: some extensions, or encode filters,
change data when extracting it to the working directory.
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Tue, 27 Jul 2010 23:07:30 +0900 |
parents | 2ac98313b26c |
children | 613b8bd2284e |
rev | line source |
---|---|
72 | 1 /* |
2 mpatch.c - efficient binary patching for Mercurial | |
3 | |
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. | |
6 | |
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 | |
9 single hunk list. This hunk list is then applied to the original | |
10 text. | |
11 | |
12 The text (or binary) fragments are copied directly from their source | |
13 Python objects into a preallocated output string to avoid the | |
14 allocation of intermediate Python objects. Working memory is about 2x | |
15 the total number of hunks. | |
16 | |
2859 | 17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
72 | 18 |
19 This software may be used and distributed according to the terms | |
20 of the GNU General Public License, incorporated herein by reference. | |
21 */ | |
22 | |
23 #include <Python.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
2468
1ac0574f1768
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2083
diff
changeset
|
26 |
11360
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
27 #include "util.h" |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
28 |
5459
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
29 /* Definitions to get compatibility with python 2.4 and earlier which |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
30 does not have Py_ssize_t. See also PEP 353. |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
31 Note: msvc (8 or earlier) does not have ssize_t, so we use Py_ssize_t. |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
32 */ |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
33 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
34 typedef int Py_ssize_t; |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
35 #define PY_SSIZE_T_MAX INT_MAX |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
36 #define PY_SSIZE_T_MIN INT_MIN |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
37 #endif |
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
38 |
410
7c678976df3e
Make mpatch.c compilable under the other `OS'
mpm@selenic.com
parents:
384
diff
changeset
|
39 #ifdef _WIN32 |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
40 #ifdef _MSC_VER |
2468
1ac0574f1768
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2083
diff
changeset
|
41 /* msvc 6.0 has problems */ |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
42 #define inline __inline |
551 | 43 typedef unsigned long uint32_t; |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
44 #else |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
45 #include <stdint.h> |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
46 #endif |
411
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
47 static uint32_t ntohl(uint32_t x) |
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
48 { |
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
49 return ((x & 0x000000ffUL) << 24) | |
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
50 ((x & 0x0000ff00UL) << 8) | |
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
51 ((x & 0x00ff0000UL) >> 8) | |
9e9f7ab43ce2
Add 'other OS' bits to bdiff.c / style cleanups
mpm@selenic.com
parents:
410
diff
changeset
|
52 ((x & 0xff000000UL) >> 24); |
410
7c678976df3e
Make mpatch.c compilable under the other `OS'
mpm@selenic.com
parents:
384
diff
changeset
|
53 } |
7c678976df3e
Make mpatch.c compilable under the other `OS'
mpm@selenic.com
parents:
384
diff
changeset
|
54 #else |
2468
1ac0574f1768
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2083
diff
changeset
|
55 /* not windows */ |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
56 #include <sys/types.h> |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
57 #if defined __BEOS__ && !defined __HAIKU__ |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
58 #include <ByteOrder.h> |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
59 #else |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
60 #include <arpa/inet.h> |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
61 #endif |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
7036
diff
changeset
|
62 #include <inttypes.h> |
410
7c678976df3e
Make mpatch.c compilable under the other `OS'
mpm@selenic.com
parents:
384
diff
changeset
|
63 #endif |
72 | 64 |
65 static char mpatch_doc[] = "Efficient binary patching."; | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
66 static PyObject *mpatch_Error; |
72 | 67 |
68 struct frag { | |
69 int start, end, len; | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
70 const char *data; |
72 | 71 }; |
72 | |
73 struct flist { | |
74 struct frag *base, *head, *tail; | |
75 }; | |
76 | |
77 static struct flist *lalloc(int size) | |
78 { | |
128 | 79 struct flist *a = NULL; |
72 | 80 |
3138
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
81 if (size < 1) |
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
82 size = 1; |
cc856c4d91ca
mpatch: Fix for malloc corner case on AIX
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
83 |
1978
10606ee61107
do proper typecasting on malloc() and calloc() calls
TK Soh <teekaysoh@yahoo.com>
parents:
1746
diff
changeset
|
84 a = (struct flist *)malloc(sizeof(struct flist)); |
128 | 85 if (a) { |
1978
10606ee61107
do proper typecasting on malloc() and calloc() calls
TK Soh <teekaysoh@yahoo.com>
parents:
1746
diff
changeset
|
86 a->base = (struct frag *)malloc(sizeof(struct frag) * size); |
2048
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
87 if (a->base) { |
128 | 88 a->head = a->tail = a->base; |
2048
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
89 return a; |
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
90 } |
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
91 free(a); |
8f9660c568b8
Set correct exception for another possible malloc error in mpatch.c
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1978
diff
changeset
|
92 a = NULL; |
128 | 93 } |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
94 if (!PyErr_Occurred()) |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
95 PyErr_NoMemory(); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
96 return NULL; |
72 | 97 } |
98 | |
99 static void lfree(struct flist *a) | |
100 { | |
128 | 101 if (a) { |
102 free(a->base); | |
103 free(a); | |
104 } | |
72 | 105 } |
106 | |
107 static int lsize(struct flist *a) | |
108 { | |
109 return a->tail - a->head; | |
110 } | |
111 | |
112 /* move hunks in source that are less cut to dest, compensating | |
113 for changes in offset. the last hunk may be split if necessary. | |
114 */ | |
115 static int gather(struct flist *dest, struct flist *src, int cut, int offset) | |
116 { | |
117 struct frag *d = dest->tail, *s = src->head; | |
118 int postend, c, l; | |
119 | |
120 while (s != src->tail) { | |
121 if (s->start + offset >= cut) | |
82 | 122 break; /* we've gone far enough */ |
72 | 123 |
124 postend = offset + s->start + s->len; | |
125 if (postend <= cut) { | |
126 /* save this hunk */ | |
127 offset += s->start + s->len - s->end; | |
128 *d++ = *s++; | |
129 } | |
130 else { | |
131 /* break up this hunk */ | |
132 c = cut - offset; | |
133 if (s->end < c) | |
134 c = s->end; | |
135 l = cut - offset - s->start; | |
136 if (s->len < l) | |
137 l = s->len; | |
138 | |
139 offset += s->start + l - c; | |
140 | |
141 d->start = s->start; | |
142 d->end = c; | |
143 d->len = l; | |
144 d->data = s->data; | |
145 d++; | |
146 s->start = c; | |
147 s->len = s->len - l; | |
148 s->data = s->data + l; | |
149 | |
82 | 150 break; |
72 | 151 } |
152 } | |
153 | |
154 dest->tail = d; | |
155 src->head = s; | |
156 return offset; | |
157 } | |
158 | |
159 /* like gather, but with no output list */ | |
160 static int discard(struct flist *src, int cut, int offset) | |
161 { | |
162 struct frag *s = src->head; | |
163 int postend, c, l; | |
164 | |
165 while (s != src->tail) { | |
166 if (s->start + offset >= cut) | |
82 | 167 break; |
72 | 168 |
169 postend = offset + s->start + s->len; | |
170 if (postend <= cut) { | |
171 offset += s->start + s->len - s->end; | |
172 s++; | |
173 } | |
174 else { | |
175 c = cut - offset; | |
176 if (s->end < c) | |
177 c = s->end; | |
178 l = cut - offset - s->start; | |
179 if (s->len < l) | |
180 l = s->len; | |
181 | |
182 offset += s->start + l - c; | |
183 s->start = c; | |
184 s->len = s->len - l; | |
185 s->data = s->data + l; | |
186 | |
82 | 187 break; |
72 | 188 } |
189 } | |
190 | |
191 src->head = s; | |
192 return offset; | |
193 } | |
194 | |
195 /* combine hunk lists a and b, while adjusting b for offset changes in a/ | |
196 this deletes a and b and returns the resultant list. */ | |
197 static struct flist *combine(struct flist *a, struct flist *b) | |
198 { | |
128 | 199 struct flist *c = NULL; |
200 struct frag *bh, *ct; | |
72 | 201 int offset = 0, post; |
202 | |
128 | 203 if (a && b) |
204 c = lalloc((lsize(a) + lsize(b)) * 2); | |
205 | |
206 if (c) { | |
72 | 207 |
128 | 208 for (bh = b->head; bh != b->tail; bh++) { |
209 /* save old hunks */ | |
210 offset = gather(c, a, bh->start, offset); | |
72 | 211 |
128 | 212 /* discard replaced hunks */ |
213 post = discard(a, bh->end, offset); | |
72 | 214 |
128 | 215 /* insert new hunk */ |
216 ct = c->tail; | |
217 ct->start = bh->start - offset; | |
218 ct->end = bh->end - post; | |
219 ct->len = bh->len; | |
220 ct->data = bh->data; | |
221 c->tail++; | |
222 offset = post; | |
223 } | |
224 | |
225 /* hold on to tail from a */ | |
226 memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a)); | |
227 c->tail += lsize(a); | |
72 | 228 } |
229 | |
230 lfree(a); | |
231 lfree(b); | |
232 return c; | |
233 } | |
234 | |
235 /* decode a binary patch into a hunk list */ | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
236 static struct flist *decode(const char *bin, int len) |
72 | 237 { |
238 struct flist *l; | |
239 struct frag *lt; | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
240 const char *data = bin + 12, *end = bin + len; |
384
a29decbf7475
mpatch: attempt to handle unpack alignment issues on Solaris
mpm@selenic.com
parents:
282
diff
changeset
|
241 char decode[12]; /* for dealing with alignment issues */ |
72 | 242 |
243 /* assume worst case size, we won't have many of these lists */ | |
244 l = lalloc(len / 12); | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
245 if (!l) |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
246 return NULL; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
247 |
72 | 248 lt = l->tail; |
249 | |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
250 while (data <= end) { |
384
a29decbf7475
mpatch: attempt to handle unpack alignment issues on Solaris
mpm@selenic.com
parents:
282
diff
changeset
|
251 memcpy(decode, bin, 12); |
a29decbf7475
mpatch: attempt to handle unpack alignment issues on Solaris
mpm@selenic.com
parents:
282
diff
changeset
|
252 lt->start = ntohl(*(uint32_t *)decode); |
a29decbf7475
mpatch: attempt to handle unpack alignment issues on Solaris
mpm@selenic.com
parents:
282
diff
changeset
|
253 lt->end = ntohl(*(uint32_t *)(decode + 4)); |
a29decbf7475
mpatch: attempt to handle unpack alignment issues on Solaris
mpm@selenic.com
parents:
282
diff
changeset
|
254 lt->len = ntohl(*(uint32_t *)(decode + 8)); |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
255 if (lt->start > lt->end) |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
256 break; /* sanity check */ |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
257 bin = data + lt->len; |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
258 if (bin < data) |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
259 break; /* big data + big (bogus) len can wrap around */ |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
260 lt->data = data; |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
261 data = bin + 12; |
72 | 262 lt++; |
263 } | |
264 | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
265 if (bin != end) { |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
266 if (!PyErr_Occurred()) |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
267 PyErr_SetString(mpatch_Error, "patch cannot be decoded"); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
268 lfree(l); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
269 return NULL; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
270 } |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
271 |
72 | 272 l->tail = lt; |
273 return l; | |
274 } | |
275 | |
276 /* calculate the size of resultant text */ | |
277 static int calcsize(int len, struct flist *l) | |
278 { | |
279 int outlen = 0, last = 0; | |
280 struct frag *f = l->head; | |
281 | |
282 while (f != l->tail) { | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
283 if (f->start < last || f->end > len) { |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
284 if (!PyErr_Occurred()) |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
285 PyErr_SetString(mpatch_Error, |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
286 "invalid patch"); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
287 return -1; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
288 } |
72 | 289 outlen += f->start - last; |
290 last = f->end; | |
291 outlen += f->len; | |
292 f++; | |
293 } | |
294 | |
295 outlen += len - last; | |
296 return outlen; | |
297 } | |
298 | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
299 static int apply(char *buf, const char *orig, int len, struct flist *l) |
72 | 300 { |
301 struct frag *f = l->head; | |
302 int last = 0; | |
303 char *p = buf; | |
304 | |
305 while (f != l->tail) { | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
306 if (f->start < last || f->end > len) { |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
307 if (!PyErr_Occurred()) |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
308 PyErr_SetString(mpatch_Error, |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
309 "invalid patch"); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
310 return 0; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
311 } |
72 | 312 memcpy(p, orig + last, f->start - last); |
313 p += f->start - last; | |
314 memcpy(p, f->data, f->len); | |
315 last = f->end; | |
316 p += f->len; | |
317 f++; | |
318 } | |
319 memcpy(p, orig + last, len - last); | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
320 return 1; |
72 | 321 } |
322 | |
323 /* recursively generate a patch of all bins between start and end */ | |
324 static struct flist *fold(PyObject *bins, int start, int end) | |
325 { | |
326 int len; | |
5459
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
327 Py_ssize_t blen; |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
328 const char *buffer; |
72 | 329 |
330 if (start + 1 == end) { | |
331 /* trivial case, output a decoded list */ | |
332 PyObject *tmp = PyList_GetItem(bins, start); | |
128 | 333 if (!tmp) |
334 return NULL; | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
335 if (PyObject_AsCharBuffer(tmp, &buffer, &blen)) |
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
336 return NULL; |
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
337 return decode(buffer, blen); |
72 | 338 } |
339 | |
340 /* divide and conquer, memory management is elsewhere */ | |
341 len = (end - start) / 2; | |
342 return combine(fold(bins, start, start + len), | |
343 fold(bins, start + len, end)); | |
344 } | |
345 | |
346 static PyObject * | |
347 patches(PyObject *self, PyObject *args) | |
348 { | |
349 PyObject *text, *bins, *result; | |
350 struct flist *patch; | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
351 const char *in; |
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
352 char *out; |
72 | 353 int len, outlen; |
5459
b0e5f44fdeb3
mpatch: Define Py_ssize_t for old pythons and use it instead of ssize_t.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
5444
diff
changeset
|
354 Py_ssize_t inlen; |
72 | 355 |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
356 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) |
72 | 357 return NULL; |
358 | |
359 len = PyList_Size(bins); | |
360 if (!len) { | |
361 /* nothing to do */ | |
362 Py_INCREF(text); | |
363 return text; | |
364 } | |
365 | |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
366 if (PyObject_AsCharBuffer(text, &in, &inlen)) |
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
367 return NULL; |
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
368 |
72 | 369 patch = fold(bins, 0, len); |
128 | 370 if (!patch) |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
371 return NULL; |
128 | 372 |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
373 outlen = calcsize(inlen, patch); |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
374 if (outlen < 0) { |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
375 result = NULL; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
376 goto cleanup; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
377 } |
11360
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
378 result = PyBytes_FromStringAndSize(NULL, outlen); |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
379 if (!result) { |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
380 result = NULL; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
381 goto cleanup; |
128 | 382 } |
11360
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
383 out = PyBytes_AsString(result); |
5444
a0952e4e52eb
mpatch: allow buffer objects for input
Matt Mackall <mpm@selenic.com>
parents:
4377
diff
changeset
|
384 if (!apply(out, in, inlen, patch)) { |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
385 Py_DECREF(result); |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
386 result = NULL; |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
387 } |
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
388 cleanup: |
72 | 389 lfree(patch); |
390 return result; | |
391 } | |
392 | |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
393 /* calculate size of a patched file directly */ |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
394 static PyObject * |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
395 patchedsize(PyObject *self, PyObject *args) |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
396 { |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
397 long orig, start, end, len, outlen = 0, last = 0; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
398 int patchlen; |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
399 char *bin, *binend, *data; |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
400 char decode[12]; /* for dealing with alignment issues */ |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
401 |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
402 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen)) |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
403 return NULL; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
404 |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
405 binend = bin + patchlen; |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
406 data = bin + 12; |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
407 |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
408 while (data <= binend) { |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
409 memcpy(decode, bin, 12); |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
410 start = ntohl(*(uint32_t *)decode); |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
411 end = ntohl(*(uint32_t *)(decode + 4)); |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
412 len = ntohl(*(uint32_t *)(decode + 8)); |
4358
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
413 if (start > end) |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
414 break; /* sanity check */ |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
415 bin = data + len; |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
416 if (bin < data) |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
417 break; /* big data + big (bogus) len can wrap around */ |
11dc22eb8e8d
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3138
diff
changeset
|
418 data = bin + 12; |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
419 outlen += start - last; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
420 last = end; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
421 outlen += len; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
422 } |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
423 |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
424 if (bin != binend) { |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
425 if (!PyErr_Occurred()) |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
426 PyErr_SetString(mpatch_Error, "patch cannot be decoded"); |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
427 return NULL; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
428 } |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
429 |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
430 outlen += orig - last; |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
431 return Py_BuildValue("l", outlen); |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
432 } |
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
433 |
72 | 434 static PyMethodDef methods[] = { |
435 {"patches", patches, METH_VARARGS, "apply a series of patches\n"}, | |
2078
441ea218414e
Fill in the uncompressed size during revlog.addgroup
mason@suse.com
parents:
1978
diff
changeset
|
436 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"}, |
72 | 437 {NULL, NULL} |
438 }; | |
439 | |
11360
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
440 #ifdef IS_PY3K |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
441 static struct PyModuleDef mpatch_module = { |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
442 PyModuleDef_HEAD_INIT, |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
443 "mpatch", |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
444 mpatch_doc, |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
445 -1, |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
446 methods |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
447 }; |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
448 |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
449 PyMODINIT_FUNC PyInit_mpatch(void) |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
450 { |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
451 PyObject *m; |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
452 |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
453 m = PyModule_Create(&mpatch_module); |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
454 if (m == NULL) |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
455 return NULL; |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
456 |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
457 mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL); |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
458 Py_INCREF(mpatch_Error); |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
459 PyModule_AddObject(m, "mpatchError", mpatch_Error); |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
460 |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
461 return m; |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
462 } |
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
463 #else |
72 | 464 PyMODINIT_FUNC |
465 initmpatch(void) | |
466 { | |
467 Py_InitModule3("mpatch", methods, mpatch_doc); | |
1722
681c5c211b92
catch errors and throw exception with invalid binary patch data
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
597
diff
changeset
|
468 mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL); |
72 | 469 } |
11360
2ac98313b26c
mpatch.c: Added preliminary support for py3k.
Renato Cunha <renatoc@gmail.com>
parents:
10282
diff
changeset
|
470 #endif |