1/*
2 * Copyright (C) 2005 Junio C Hamano
3 * The delta-parsing part is almost straight copy of patch-delta.c
4 * which is (C) 2005 Nicolas Pitre <nico@cam.org>.
5 */
6#include "cache.h"
7#include "delta.h"
8#include "count-delta.h"
9#include <stdlib.h>
10#include <string.h>
11#include <limits.h>
12
13struct span {
14 struct span *next;
15 unsigned long ofs;
16 unsigned long end;
17};
18
19static void touch_range(struct span **span,
20 unsigned long ofs, unsigned long end)
21{
22 struct span *e = *span;
23 struct span *p = NULL;
24
25 while (e && e->ofs <= ofs) {
26 again:
27 if (ofs < e->end) {
28 while (e->end < end) {
29 if (e->next) {
30 e->end = e->next->ofs;
31 e = e->next;
32 }
33 else {
34 e->end = end;
35 return;
36 }
37 }
38 return;
39 }
40 p = e;
41 e = e->next;
42 }
43 if (e && e->ofs <= end) {
44 e->ofs = ofs;
45 goto again;
46 }
47 else {
48 e = xmalloc(sizeof(*e));
49 e->ofs = ofs;
50 e->end = end;
51 if (p) {
52 e->next = p->next;
53 p->next = e;
54 }
55 else {
56 e->next = *span;
57 *span = e;
58 }
59 }
60}
61
62static unsigned long count_range(struct span *s)
63{
64 struct span *t;
65 unsigned long sz = 0;
66 while (s) {
67 t = s;
68 sz += s->end - s->ofs;
69 s = s->next;
70 free(t);
71 }
72 return sz;
73}
74
75/*
76 * NOTE. We do not _interpret_ delta fully. As an approximation, we
77 * just count the number of bytes that are copied from the source, and
78 * the number of literal data bytes that are inserted.
79 *
80 * Number of bytes that are _not_ copied from the source is deletion,
81 * and number of inserted literal bytes are addition, so sum of them
82 * is the extent of damage.
83 */
84int count_delta(void *delta_buf, unsigned long delta_size,
85 unsigned long *src_copied, unsigned long *literal_added)
86{
87 unsigned long added_literal;
88 const unsigned char *data, *top;
89 unsigned char cmd;
90 unsigned long src_size, dst_size, out;
91 struct span *span = NULL;
92
93 if (delta_size < DELTA_SIZE_MIN)
94 return -1;
95
96 data = delta_buf;
97 top = delta_buf + delta_size;
98
99 src_size = get_delta_hdr_size(&data);
100 dst_size = get_delta_hdr_size(&data);
101
102 added_literal = out = 0;
103 while (data < top) {
104 cmd = *data++;
105 if (cmd & 0x80) {
106 unsigned long cp_off = 0, cp_size = 0;
107 if (cmd & 0x01) cp_off = *data++;
108 if (cmd & 0x02) cp_off |= (*data++ << 8);
109 if (cmd & 0x04) cp_off |= (*data++ << 16);
110 if (cmd & 0x08) cp_off |= (*data++ << 24);
111 if (cmd & 0x10) cp_size = *data++;
112 if (cmd & 0x20) cp_size |= (*data++ << 8);
113 if (cmd & 0x40) cp_size |= (*data++ << 16);
114 if (cp_size == 0) cp_size = 0x10000;
115
116 touch_range(&span, cp_off, cp_off+cp_size);
117 out += cp_size;
118 } else {
119 /* write literal into dst */
120 added_literal += cmd;
121 out += cmd;
122 data += cmd;
123 }
124 }
125
126 *src_copied = count_range(span);
127
128 /* sanity check */
129 if (data != top || out != dst_size)
130 return -1;
131
132 /* delete size is what was _not_ copied from source.
133 * edit size is that and literal additions.
134 */
135 *literal_added = added_literal;
136 return 0;
137}