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