Merge branch 'np/delta' into next
[git/gitweb.git] / count-delta.c
blob3ee3a0ccf1b92f3f8838ca2e728bde9f60d1b8e8
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>
13 struct span {
14 struct span *next;
15 unsigned long ofs;
16 unsigned long end;
19 static void touch_range(struct span **span,
20 unsigned long ofs, unsigned long end)
22 struct span *e = *span;
23 struct span *p = NULL;
25 while (e && e->ofs <= ofs) {
26 again:
27 if (ofs < e->end) {
28 while (e->end < end) {
29 if (e->next && e->next->ofs <= end) {
30 e->end = e->next->ofs;
31 e = e->next;
33 else {
34 e->end = end;
35 return;
38 return;
40 p = e;
41 e = e->next;
43 if (e && e->ofs <= end) {
44 e->ofs = ofs;
45 goto again;
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;
55 else {
56 e->next = *span;
57 *span = e;
62 static unsigned long count_range(struct span *s)
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);
72 return sz;
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.
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.
84 int count_delta(void *delta_buf, unsigned long delta_size,
85 unsigned long *src_copied, unsigned long *literal_added)
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;
93 if (delta_size < DELTA_SIZE_MIN)
94 return -1;
96 data = delta_buf;
97 top = delta_buf + delta_size;
99 src_size = get_delta_hdr_size(&data);
100 dst_size = get_delta_hdr_size(&data);
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;
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;
126 *src_copied = count_range(span);
128 /* sanity check */
129 if (data != top || out != dst_size)
130 return -1;
132 /* delete size is what was _not_ copied from source.
133 * edit size is that and literal additions.
135 *literal_added = added_literal;
136 return 0;