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