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