dd81e9296591d463a7b06570bc24dc201a836b2e
[git.git] / count-delta.c
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 <stdlib.h>
7 #include <string.h>
8 #include <limits.h>
9 #include "delta.h"
10 #include "count-delta.h"
11
12 static unsigned long get_hdr_size(const unsigned char **datap)
13 {
14         const unsigned char *data = *datap;
15         unsigned long size;
16         unsigned char cmd;
17         int i;
18         size = i = 0;
19         cmd = *data++;
20         while (cmd) {
21                 if (cmd & 1)
22                         size |= *data++ << i;
23                 i += 8;
24                 cmd >>= 1;
25         }
26         *datap = data;
27         return size;
28 }
29
30 /*
31  * NOTE.  We do not _interpret_ delta fully.  As an approximation, we
32  * just count the number of bytes that are copied from the source, and
33  * the number of literal data bytes that are inserted.  Number of
34  * bytes that are _not_ copied from the source is deletion, and number
35  * of inserted literal bytes are addition, so sum of them is what we
36  * return.  xdelta can express an edit that copies data inside of the
37  * destination which originally came from the source.  We do not count
38  * that in the following routine, so we are undercounting the source
39  * material that remains in the final output that way.
40  */
41 unsigned long count_delta(void *delta_buf, unsigned long delta_size)
42 {
43         unsigned long copied_from_source, added_literal;
44         const unsigned char *data, *top;
45         unsigned char cmd;
46         unsigned long src_size, dst_size, out;
47
48         /* the smallest delta size possible is 6 bytes */
49         if (delta_size < 6)
50                 return UINT_MAX;
51
52         data = delta_buf;
53         top = delta_buf + delta_size;
54
55         src_size = get_hdr_size(&data);
56         dst_size = get_hdr_size(&data);
57
58         added_literal = copied_from_source = out = 0;
59         while (data < top) {
60                 cmd = *data++;
61                 if (cmd & 0x80) {
62                         unsigned long cp_off = 0, cp_size = 0;
63                         if (cmd & 0x01) cp_off = *data++;
64                         if (cmd & 0x02) cp_off |= (*data++ << 8);
65                         if (cmd & 0x04) cp_off |= (*data++ << 16);
66                         if (cmd & 0x08) cp_off |= (*data++ << 24);
67                         if (cmd & 0x10) cp_size = *data++;
68                         if (cmd & 0x20) cp_size |= (*data++ << 8);
69                         if (cp_size == 0) cp_size = 0x10000;
70
71                         if (cmd & 0x40)
72                                 /* copy from dst */
73                                 ;
74                         else
75                                 copied_from_source += cp_size;
76                         out += cp_size;
77                 } else {
78                         /* write literal into dst */
79                         added_literal += cmd;
80                         out += cmd;
81                         data += cmd;
82                 }
83         }
84
85         /* sanity check */
86         if (data != top || out != dst_size)
87                 return UINT_MAX;
88
89         /* delete size is what was _not_ copied from source.
90          * edit size is that and literal additions.
91          */
92         return (src_size - copied_from_source) + added_literal;
93 }