diff options
Diffstat (limited to 'xdelta3/xdelta3-merge.h')
-rw-r--r-- | xdelta3/xdelta3-merge.h | 284 |
1 files changed, 264 insertions, 20 deletions
diff --git a/xdelta3/xdelta3-merge.h b/xdelta3/xdelta3-merge.h index a7b3329..d917ba5 100644 --- a/xdelta3/xdelta3-merge.h +++ b/xdelta3/xdelta3-merge.h | |||
@@ -28,6 +28,7 @@ xd3_whole_state_init (xd3_stream *stream) | |||
28 | { | 28 | { |
29 | XD3_ASSERT (stream->whole_target.adds == NULL); | 29 | XD3_ASSERT (stream->whole_target.adds == NULL); |
30 | XD3_ASSERT (stream->whole_target.inst == NULL); | 30 | XD3_ASSERT (stream->whole_target.inst == NULL); |
31 | XD3_ASSERT (stream->whole_target.length == 0); | ||
31 | 32 | ||
32 | stream->whole_target.adds_alloc = XD3_ALLOCSIZE; | 33 | stream->whole_target.adds_alloc = XD3_ALLOCSIZE; |
33 | stream->whole_target.inst_alloc = XD3_ALLOCSIZE / sizeof (xd3_winst); | 34 | stream->whole_target.inst_alloc = XD3_ALLOCSIZE / sizeof (xd3_winst); |
@@ -98,6 +99,40 @@ xd3_realloc_buffer (xd3_stream *stream, | |||
98 | return 0; | 99 | return 0; |
99 | } | 100 | } |
100 | 101 | ||
102 | /* allocate one new output instruction */ | ||
103 | static int | ||
104 | xd3_whole_alloc_winst (xd3_stream *stream, | ||
105 | xd3_winst **winstp) | ||
106 | { | ||
107 | int ret; | ||
108 | |||
109 | if ((ret = xd3_realloc_buffer (stream, | ||
110 | stream->whole_target.instlen, | ||
111 | sizeof (xd3_winst), | ||
112 | 1, | ||
113 | & stream->whole_target.inst_alloc, | ||
114 | (void**) & stream->whole_target.inst))) | ||
115 | { | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | *winstp = &stream->whole_target.inst[stream->whole_target.instlen++]; | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int | ||
125 | xd3_whole_alloc_adds (xd3_stream *stream, | ||
126 | usize_t count) | ||
127 | { | ||
128 | return xd3_realloc_buffer (stream, | ||
129 | stream->whole_target.addslen, | ||
130 | 1, | ||
131 | count, | ||
132 | & stream->whole_target.adds_alloc, | ||
133 | (void**) & stream->whole_target.adds); | ||
134 | } | ||
135 | |||
101 | static int | 136 | static int |
102 | xd3_whole_append_inst (xd3_stream *stream, | 137 | xd3_whole_append_inst (xd3_stream *stream, |
103 | xd3_hinst *inst) | 138 | xd3_hinst *inst) |
@@ -105,32 +140,24 @@ xd3_whole_append_inst (xd3_stream *stream, | |||
105 | int ret; | 140 | int ret; |
106 | xd3_winst *winst; | 141 | xd3_winst *winst; |
107 | 142 | ||
108 | if ((ret = xd3_realloc_buffer (stream, | 143 | if ((ret = xd3_whole_alloc_winst (stream, &winst))) |
109 | stream->whole_target.instlen, | ||
110 | sizeof (xd3_winst), | ||
111 | 1, | ||
112 | & stream->whole_target.inst_alloc, | ||
113 | (void**) & stream->whole_target.inst))) | ||
114 | { | 144 | { |
115 | return ret; | 145 | return ret; |
116 | } | 146 | } |
117 | 147 | ||
148 | winst->type = inst->type; | ||
149 | winst->mode = 0; | ||
150 | winst->size = inst->size; | ||
151 | winst->position = stream->whole_target.length; | ||
152 | stream->whole_target.length += inst->size; | ||
153 | |||
118 | if ((inst->type <= XD3_ADD) && | 154 | if ((inst->type <= XD3_ADD) && |
119 | (ret = xd3_realloc_buffer (stream, | 155 | (ret = xd3_whole_alloc_adds (stream, |
120 | stream->whole_target.addslen, | 156 | (inst->type == XD3_RUN ? 1 : inst->size)))) |
121 | 1, | ||
122 | (inst->type == XD3_RUN ? 1 : inst->size), | ||
123 | & stream->whole_target.adds_alloc, | ||
124 | (void**) & stream->whole_target.adds))) | ||
125 | { | 157 | { |
126 | return ret; | 158 | return ret; |
127 | } | 159 | } |
128 | 160 | ||
129 | winst = &stream->whole_target.inst[stream->whole_target.instlen++]; | ||
130 | winst->type = inst->type; | ||
131 | winst->mode = 0; | ||
132 | winst->size = inst->size; | ||
133 | |||
134 | switch (inst->type) | 161 | switch (inst->type) |
135 | { | 162 | { |
136 | case XD3_RUN: | 163 | case XD3_RUN: |
@@ -220,17 +247,234 @@ int xd3_merge_input_output (xd3_stream *stream, | |||
220 | return 0; | 247 | return 0; |
221 | } | 248 | } |
222 | 249 | ||
250 | static int | ||
251 | xd3_merge_run (xd3_stream *stream, | ||
252 | xd3_whole_state *source, | ||
253 | xd3_winst *iinst) | ||
254 | { | ||
255 | int ret; | ||
256 | xd3_winst *oinst; | ||
257 | |||
258 | if ((ret = xd3_whole_alloc_winst (stream, &oinst)) || | ||
259 | (ret = xd3_whole_alloc_adds (stream, 1))) | ||
260 | { | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | oinst->type = iinst->type; | ||
265 | oinst->mode = iinst->mode; | ||
266 | oinst->size = iinst->size; | ||
267 | oinst->addr = stream->whole_target.addslen; | ||
268 | |||
269 | XD3_ASSERT (stream->whole_target.length == iinst->position); | ||
270 | oinst->position = stream->whole_target.length; | ||
271 | stream->whole_target.length += iinst->size; | ||
272 | |||
273 | stream->whole_target.adds[stream->whole_target.addslen++] = | ||
274 | source->adds[iinst->addr]; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int | ||
280 | xd3_merge_add (xd3_stream *stream, | ||
281 | xd3_whole_state *source, | ||
282 | xd3_winst *iinst) | ||
283 | { | ||
284 | int ret; | ||
285 | xd3_winst *oinst; | ||
286 | |||
287 | if ((ret = xd3_whole_alloc_winst (stream, &oinst)) || | ||
288 | (ret = xd3_whole_alloc_adds (stream, iinst->size))) | ||
289 | { | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | oinst->type = iinst->type; | ||
294 | oinst->mode = iinst->mode; | ||
295 | oinst->size = iinst->size; | ||
296 | oinst->addr = stream->whole_target.addslen; | ||
297 | |||
298 | XD3_ASSERT (stream->whole_target.length == iinst->position); | ||
299 | oinst->position = stream->whole_target.length; | ||
300 | stream->whole_target.length += iinst->size; | ||
301 | |||
302 | memcpy(stream->whole_target.adds, | ||
303 | source->adds + iinst->addr, | ||
304 | stream->whole_target.addslen); | ||
305 | |||
306 | stream->whole_target.addslen += iinst->size; | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int | ||
312 | xd3_merge_target_copy (xd3_stream *stream, | ||
313 | xd3_winst *iinst) | ||
314 | { | ||
315 | int ret; | ||
316 | xd3_winst *oinst; | ||
317 | |||
318 | if ((ret = xd3_whole_alloc_winst (stream, &oinst))) | ||
319 | { | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | XD3_ASSERT (stream->whole_target.length == iinst->position); | ||
324 | stream->whole_target.length += iinst->size; | ||
325 | |||
326 | memcpy (oinst, iinst, sizeof (*oinst)); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int | ||
331 | xd3_merge_find_position (xd3_stream *stream, | ||
332 | xd3_whole_state *source, | ||
333 | xoff_t address, | ||
334 | usize_t *inst_num) | ||
335 | { | ||
336 | usize_t low; | ||
337 | usize_t high; | ||
338 | |||
339 | if (address >= source->length) | ||
340 | { | ||
341 | stream->msg = "Invalid copy offset in merge"; | ||
342 | return XD3_INVALID_INPUT; | ||
343 | } | ||
344 | |||
345 | low = 0; | ||
346 | high = source->instlen; | ||
347 | |||
348 | while (low != high) | ||
349 | { | ||
350 | xoff_t mid_lpos; | ||
351 | xoff_t mid_hpos; | ||
352 | usize_t mid = low + (high - low) / 2; | ||
353 | mid_lpos = source->inst[mid].position; | ||
354 | |||
355 | if (address < mid_lpos) | ||
356 | { | ||
357 | high = mid; | ||
358 | continue; | ||
359 | } | ||
360 | |||
361 | mid_hpos = mid_lpos + source->inst[mid].size; | ||
362 | |||
363 | if (address >= mid_hpos) | ||
364 | { | ||
365 | low = mid + 1; | ||
366 | continue; | ||
367 | } | ||
368 | |||
369 | *inst_num = mid; | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | stream->msg = "Internal error in merge"; | ||
374 | return XD3_INTERNAL; | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | xd3_merge_source_copy (xd3_stream *stream, | ||
379 | xd3_whole_state *source, | ||
380 | xd3_winst *iinst_orig) | ||
381 | { | ||
382 | int ret; | ||
383 | xd3_winst iinst; | ||
384 | usize_t sinst_num; | ||
385 | |||
386 | memcpy (& iinst, iinst_orig, sizeof (iinst)); | ||
387 | |||
388 | XD3_ASSERT (iinst.mode == VCD_SOURCE); | ||
389 | |||
390 | if ((ret = xd3_merge_find_position (stream, source, | ||
391 | iinst.addr, &sinst_num))) | ||
392 | { | ||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | while (iinst.size > 0) | ||
397 | { | ||
398 | xd3_winst *sinst; | ||
399 | xd3_winst *minst; | ||
400 | usize_t sinst_offset; | ||
401 | usize_t sinst_left; | ||
402 | usize_t this_take; | ||
403 | |||
404 | XD3_ASSERT (sinst_num < source->instlen); | ||
405 | |||
406 | sinst = &source->inst[sinst_num]; | ||
407 | |||
408 | XD3_ASSERT (sinst->position >= iinst.addr); | ||
409 | |||
410 | sinst_offset = sinst->position - iinst.addr; | ||
411 | |||
412 | XD3_ASSERT (sinst->size > (sinst->position - iinst.addr)); | ||
413 | |||
414 | sinst_left = sinst->size - sinst_offset; | ||
415 | this_take = min (iinst.size, sinst_left); | ||
416 | |||
417 | XD3_ASSERT (this_take > 0); | ||
418 | |||
419 | if ((ret = xd3_whole_alloc_winst (stream, &minst))) | ||
420 | { | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | minst->size = this_take; | ||
425 | minst->mode = VCD_SOURCE; | ||
426 | minst->type = XD3_CPY; | ||
427 | minst->addr = sinst->addr + sinst_offset; | ||
428 | minst->position = iinst.position; | ||
429 | |||
430 | stream->whole_target.length += this_take; | ||
431 | iinst.position += this_take; | ||
432 | iinst.addr += this_take; | ||
433 | iinst.size -= this_take; | ||
434 | sinst_num += 1; | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
223 | /* xd3_merge_inputs() applies *input to *source, returns its result in | 440 | /* xd3_merge_inputs() applies *input to *source, returns its result in |
224 | * stream. In certain cases, input == stream->whole_target. */ | 441 | * stream. */ |
225 | int xd3_merge_inputs (xd3_stream *stream, | 442 | int xd3_merge_inputs (xd3_stream *stream, |
226 | xd3_whole_state *source, | 443 | xd3_whole_state *source, |
227 | xd3_whole_state *input) | 444 | xd3_whole_state *input) |
228 | { | 445 | { |
446 | int ret = 0; | ||
447 | int input_i; | ||
229 | 448 | ||
449 | /* iterate over each instruction. */ | ||
450 | for (input_i = 0; ret == 0 && input_i < input->instlen; ++input_i) | ||
451 | { | ||
452 | xd3_winst *iinst = &input->inst[input_i]; | ||
230 | 453 | ||
231 | xd3_swap_whole_state (&stream->whole_target, input); | 454 | switch (iinst->type) |
455 | { | ||
456 | case XD3_RUN: | ||
457 | ret = xd3_merge_run (stream, source, iinst); | ||
458 | break; | ||
459 | case XD3_ADD: | ||
460 | ret = xd3_merge_add (stream, source, iinst); | ||
461 | break; | ||
462 | default: | ||
463 | /* Note: VCD_TARGET support is completely untested all | ||
464 | * throughout. */ | ||
465 | if (iinst->mode == 0 || iinst->mode == VCD_TARGET) | ||
466 | { | ||
467 | ret = xd3_merge_target_copy (stream, iinst); | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | ret = xd3_merge_source_copy (stream, source, iinst); | ||
472 | } | ||
473 | break; | ||
474 | } | ||
475 | } | ||
232 | 476 | ||
233 | return 0; | 477 | return ret; |
234 | } | 478 | } |
235 | 479 | ||
236 | #endif | 480 | #endif |