##// END OF EJS Templates
mpatch: re-wrap wide line with clang-format...
Augie Fackler -
r34634:347c0f42 default
parent child Browse files
Show More
@@ -1,280 +1,281 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 static struct mpatch_flist *lalloc(ssize_t size)
30 static struct mpatch_flist *lalloc(ssize_t size)
31 {
31 {
32 struct mpatch_flist *a = NULL;
32 struct mpatch_flist *a = NULL;
33
33
34 if (size < 1)
34 if (size < 1)
35 size = 1;
35 size = 1;
36
36
37 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
37 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
38 if (a) {
38 if (a) {
39 a->base = (struct mpatch_frag *)malloc(sizeof(struct mpatch_frag) * size);
39 a->base = (struct mpatch_frag *)malloc(
40 sizeof(struct mpatch_frag) * size);
40 if (a->base) {
41 if (a->base) {
41 a->head = a->tail = a->base;
42 a->head = a->tail = a->base;
42 return a;
43 return a;
43 }
44 }
44 free(a);
45 free(a);
45 }
46 }
46 return NULL;
47 return NULL;
47 }
48 }
48
49
49 void mpatch_lfree(struct mpatch_flist *a)
50 void mpatch_lfree(struct mpatch_flist *a)
50 {
51 {
51 if (a) {
52 if (a) {
52 free(a->base);
53 free(a->base);
53 free(a);
54 free(a);
54 }
55 }
55 }
56 }
56
57
57 static ssize_t lsize(struct mpatch_flist *a)
58 static ssize_t lsize(struct mpatch_flist *a)
58 {
59 {
59 return a->tail - a->head;
60 return a->tail - a->head;
60 }
61 }
61
62
62 /* move hunks in source that are less cut to dest, compensating
63 /* move hunks in source that are less cut to dest, compensating
63 for changes in offset. the last hunk may be split if necessary.
64 for changes in offset. the last hunk may be split if necessary.
64 */
65 */
65 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
66 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
66 int offset)
67 int offset)
67 {
68 {
68 struct mpatch_frag *d = dest->tail, *s = src->head;
69 struct mpatch_frag *d = dest->tail, *s = src->head;
69 int postend, c, l;
70 int postend, c, l;
70
71
71 while (s != src->tail) {
72 while (s != src->tail) {
72 if (s->start + offset >= cut)
73 if (s->start + offset >= cut)
73 break; /* we've gone far enough */
74 break; /* we've gone far enough */
74
75
75 postend = offset + s->start + s->len;
76 postend = offset + s->start + s->len;
76 if (postend <= cut) {
77 if (postend <= cut) {
77 /* save this hunk */
78 /* save this hunk */
78 offset += s->start + s->len - s->end;
79 offset += s->start + s->len - s->end;
79 *d++ = *s++;
80 *d++ = *s++;
80 }
81 }
81 else {
82 else {
82 /* break up this hunk */
83 /* break up this hunk */
83 c = cut - offset;
84 c = cut - offset;
84 if (s->end < c)
85 if (s->end < c)
85 c = s->end;
86 c = s->end;
86 l = cut - offset - s->start;
87 l = cut - offset - s->start;
87 if (s->len < l)
88 if (s->len < l)
88 l = s->len;
89 l = s->len;
89
90
90 offset += s->start + l - c;
91 offset += s->start + l - c;
91
92
92 d->start = s->start;
93 d->start = s->start;
93 d->end = c;
94 d->end = c;
94 d->len = l;
95 d->len = l;
95 d->data = s->data;
96 d->data = s->data;
96 d++;
97 d++;
97 s->start = c;
98 s->start = c;
98 s->len = s->len - l;
99 s->len = s->len - l;
99 s->data = s->data + l;
100 s->data = s->data + l;
100
101
101 break;
102 break;
102 }
103 }
103 }
104 }
104
105
105 dest->tail = d;
106 dest->tail = d;
106 src->head = s;
107 src->head = s;
107 return offset;
108 return offset;
108 }
109 }
109
110
110 /* like gather, but with no output list */
111 /* like gather, but with no output list */
111 static int discard(struct mpatch_flist *src, int cut, int offset)
112 static int discard(struct mpatch_flist *src, int cut, int offset)
112 {
113 {
113 struct mpatch_frag *s = src->head;
114 struct mpatch_frag *s = src->head;
114 int postend, c, l;
115 int postend, c, l;
115
116
116 while (s != src->tail) {
117 while (s != src->tail) {
117 if (s->start + offset >= cut)
118 if (s->start + offset >= cut)
118 break;
119 break;
119
120
120 postend = offset + s->start + s->len;
121 postend = offset + s->start + s->len;
121 if (postend <= cut) {
122 if (postend <= cut) {
122 offset += s->start + s->len - s->end;
123 offset += s->start + s->len - s->end;
123 s++;
124 s++;
124 }
125 }
125 else {
126 else {
126 c = cut - offset;
127 c = cut - offset;
127 if (s->end < c)
128 if (s->end < c)
128 c = s->end;
129 c = s->end;
129 l = cut - offset - s->start;
130 l = cut - offset - s->start;
130 if (s->len < l)
131 if (s->len < l)
131 l = s->len;
132 l = s->len;
132
133
133 offset += s->start + l - c;
134 offset += s->start + l - c;
134 s->start = c;
135 s->start = c;
135 s->len = s->len - l;
136 s->len = s->len - l;
136 s->data = s->data + l;
137 s->data = s->data + l;
137
138
138 break;
139 break;
139 }
140 }
140 }
141 }
141
142
142 src->head = s;
143 src->head = s;
143 return offset;
144 return offset;
144 }
145 }
145
146
146 /* combine hunk lists a and b, while adjusting b for offset changes in a/
147 /* combine hunk lists a and b, while adjusting b for offset changes in a/
147 this deletes a and b and returns the resultant list. */
148 this deletes a and b and returns the resultant list. */
148 static struct mpatch_flist *combine(struct mpatch_flist *a,
149 static struct mpatch_flist *combine(struct mpatch_flist *a,
149 struct mpatch_flist *b)
150 struct mpatch_flist *b)
150 {
151 {
151 struct mpatch_flist *c = NULL;
152 struct mpatch_flist *c = NULL;
152 struct mpatch_frag *bh, *ct;
153 struct mpatch_frag *bh, *ct;
153 int offset = 0, post;
154 int offset = 0, post;
154
155
155 if (a && b)
156 if (a && b)
156 c = lalloc((lsize(a) + lsize(b)) * 2);
157 c = lalloc((lsize(a) + lsize(b)) * 2);
157
158
158 if (c) {
159 if (c) {
159
160
160 for (bh = b->head; bh != b->tail; bh++) {
161 for (bh = b->head; bh != b->tail; bh++) {
161 /* save old hunks */
162 /* save old hunks */
162 offset = gather(c, a, bh->start, offset);
163 offset = gather(c, a, bh->start, offset);
163
164
164 /* discard replaced hunks */
165 /* discard replaced hunks */
165 post = discard(a, bh->end, offset);
166 post = discard(a, bh->end, offset);
166
167
167 /* insert new hunk */
168 /* insert new hunk */
168 ct = c->tail;
169 ct = c->tail;
169 ct->start = bh->start - offset;
170 ct->start = bh->start - offset;
170 ct->end = bh->end - post;
171 ct->end = bh->end - post;
171 ct->len = bh->len;
172 ct->len = bh->len;
172 ct->data = bh->data;
173 ct->data = bh->data;
173 c->tail++;
174 c->tail++;
174 offset = post;
175 offset = post;
175 }
176 }
176
177
177 /* hold on to tail from a */
178 /* hold on to tail from a */
178 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
179 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
179 c->tail += lsize(a);
180 c->tail += lsize(a);
180 }
181 }
181
182
182 mpatch_lfree(a);
183 mpatch_lfree(a);
183 mpatch_lfree(b);
184 mpatch_lfree(b);
184 return c;
185 return c;
185 }
186 }
186
187
187 /* decode a binary patch into a hunk list */
188 /* decode a binary patch into a hunk list */
188 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
189 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
189 {
190 {
190 struct mpatch_flist *l;
191 struct mpatch_flist *l;
191 struct mpatch_frag *lt;
192 struct mpatch_frag *lt;
192 int pos = 0;
193 int pos = 0;
193
194
194 /* assume worst case size, we won't have many of these lists */
195 /* assume worst case size, we won't have many of these lists */
195 l = lalloc(len / 12 + 1);
196 l = lalloc(len / 12 + 1);
196 if (!l)
197 if (!l)
197 return MPATCH_ERR_NO_MEM;
198 return MPATCH_ERR_NO_MEM;
198
199
199 lt = l->tail;
200 lt = l->tail;
200
201
201 while (pos >= 0 && pos < len) {
202 while (pos >= 0 && pos < len) {
202 lt->start = getbe32(bin + pos);
203 lt->start = getbe32(bin + pos);
203 lt->end = getbe32(bin + pos + 4);
204 lt->end = getbe32(bin + pos + 4);
204 lt->len = getbe32(bin + pos + 8);
205 lt->len = getbe32(bin + pos + 8);
205 lt->data = bin + pos + 12;
206 lt->data = bin + pos + 12;
206 pos += 12 + lt->len;
207 pos += 12 + lt->len;
207 if (lt->start > lt->end || lt->len < 0)
208 if (lt->start > lt->end || lt->len < 0)
208 break; /* sanity check */
209 break; /* sanity check */
209 lt++;
210 lt++;
210 }
211 }
211
212
212 if (pos != len) {
213 if (pos != len) {
213 mpatch_lfree(l);
214 mpatch_lfree(l);
214 return MPATCH_ERR_CANNOT_BE_DECODED;
215 return MPATCH_ERR_CANNOT_BE_DECODED;
215 }
216 }
216
217
217 l->tail = lt;
218 l->tail = lt;
218 *res = l;
219 *res = l;
219 return 0;
220 return 0;
220 }
221 }
221
222
222 /* calculate the size of resultant text */
223 /* calculate the size of resultant text */
223 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
224 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
224 {
225 {
225 ssize_t outlen = 0, last = 0;
226 ssize_t outlen = 0, last = 0;
226 struct mpatch_frag *f = l->head;
227 struct mpatch_frag *f = l->head;
227
228
228 while (f != l->tail) {
229 while (f != l->tail) {
229 if (f->start < last || f->end > len) {
230 if (f->start < last || f->end > len) {
230 return MPATCH_ERR_INVALID_PATCH;
231 return MPATCH_ERR_INVALID_PATCH;
231 }
232 }
232 outlen += f->start - last;
233 outlen += f->start - last;
233 last = f->end;
234 last = f->end;
234 outlen += f->len;
235 outlen += f->len;
235 f++;
236 f++;
236 }
237 }
237
238
238 outlen += len - last;
239 outlen += len - last;
239 return outlen;
240 return outlen;
240 }
241 }
241
242
242 int mpatch_apply(char *buf, const char *orig, ssize_t len,
243 int mpatch_apply(char *buf, const char *orig, ssize_t len,
243 struct mpatch_flist *l)
244 struct mpatch_flist *l)
244 {
245 {
245 struct mpatch_frag *f = l->head;
246 struct mpatch_frag *f = l->head;
246 int last = 0;
247 int last = 0;
247 char *p = buf;
248 char *p = buf;
248
249
249 while (f != l->tail) {
250 while (f != l->tail) {
250 if (f->start < last || f->end > len) {
251 if (f->start < last || f->end > len) {
251 return MPATCH_ERR_INVALID_PATCH;
252 return MPATCH_ERR_INVALID_PATCH;
252 }
253 }
253 memcpy(p, orig + last, f->start - last);
254 memcpy(p, orig + last, f->start - last);
254 p += f->start - last;
255 p += f->start - last;
255 memcpy(p, f->data, f->len);
256 memcpy(p, f->data, f->len);
256 last = f->end;
257 last = f->end;
257 p += f->len;
258 p += f->len;
258 f++;
259 f++;
259 }
260 }
260 memcpy(p, orig + last, len - last);
261 memcpy(p, orig + last, len - last);
261 return 0;
262 return 0;
262 }
263 }
263
264
264 /* recursively generate a patch of all bins between start and end */
265 /* recursively generate a patch of all bins between start and end */
265 struct mpatch_flist *mpatch_fold(void *bins,
266 struct mpatch_flist *mpatch_fold(void *bins,
266 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
267 struct mpatch_flist* (*get_next_item)(void*, ssize_t),
267 ssize_t start, ssize_t end)
268 ssize_t start, ssize_t end)
268 {
269 {
269 ssize_t len;
270 ssize_t len;
270
271
271 if (start + 1 == end) {
272 if (start + 1 == end) {
272 /* trivial case, output a decoded list */
273 /* trivial case, output a decoded list */
273 return get_next_item(bins, start);
274 return get_next_item(bins, start);
274 }
275 }
275
276
276 /* divide and conquer, memory management is elsewhere */
277 /* divide and conquer, memory management is elsewhere */
277 len = (end - start) / 2;
278 len = (end - start) / 2;
278 return combine(mpatch_fold(bins, get_next_item, start, start + len),
279 return combine(mpatch_fold(bins, get_next_item, start, start + len),
279 mpatch_fold(bins, get_next_item, start + len, end));
280 mpatch_fold(bins, get_next_item, start + len, end));
280 }
281 }
General Comments 0
You need to be logged in to leave comments. Login now