]>
Commit | Line | Data |
---|---|---|
ddcc8c5b JN |
1 | /* |
2 | * Licensed under a two-clause BSD-style license. | |
3 | * See LICENSE for details. | |
4 | */ | |
5 | ||
6 | #include "git-compat-util.h" | |
7 | #include "line_buffer.h" | |
8 | #include "svndiff.h" | |
9 | ||
10 | /* | |
11 | * svndiff0 applier | |
12 | * | |
13 | * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff. | |
14 | * | |
15 | * svndiff0 ::= 'SVN\0' window* | |
25271211 JN |
16 | * window ::= int int int int int instructions inline_data; |
17 | * int ::= highdigit* lowdigit; | |
18 | * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value; | |
19 | * lowdigit ::= # 7 bit value; | |
ddcc8c5b JN |
20 | */ |
21 | ||
25271211 JN |
22 | #define VLI_CONTINUE 0x80 |
23 | #define VLI_DIGIT_MASK 0x7f | |
24 | #define VLI_BITS_PER_DIGIT 7 | |
25 | ||
ddcc8c5b JN |
26 | static int error_short_read(struct line_buffer *input) |
27 | { | |
28 | if (buffer_ferror(input)) | |
29 | return error("error reading delta: %s", strerror(errno)); | |
30 | return error("invalid delta: unexpected end of file"); | |
31 | } | |
32 | ||
33 | static int read_magic(struct line_buffer *in, off_t *len) | |
34 | { | |
35 | static const char magic[] = {'S', 'V', 'N', '\0'}; | |
36 | struct strbuf sb = STRBUF_INIT; | |
37 | ||
38 | if (*len < sizeof(magic) || | |
25271211 JN |
39 | buffer_read_binary(in, &sb, sizeof(magic)) != sizeof(magic)) { |
40 | error_short_read(in); | |
41 | strbuf_release(&sb); | |
42 | return -1; | |
43 | } | |
ddcc8c5b | 44 | |
25271211 JN |
45 | if (memcmp(sb.buf, magic, sizeof(magic))) { |
46 | strbuf_release(&sb); | |
ddcc8c5b | 47 | return error("invalid delta: unrecognized file type"); |
25271211 | 48 | } |
ddcc8c5b JN |
49 | |
50 | *len -= sizeof(magic); | |
51 | strbuf_release(&sb); | |
52 | return 0; | |
53 | } | |
54 | ||
25271211 JN |
55 | static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len) |
56 | { | |
57 | uintmax_t rv = 0; | |
58 | off_t sz; | |
59 | for (sz = *len; sz; sz--) { | |
60 | const int ch = buffer_read_char(in); | |
61 | if (ch == EOF) | |
62 | break; | |
63 | ||
64 | rv <<= VLI_BITS_PER_DIGIT; | |
65 | rv += (ch & VLI_DIGIT_MASK); | |
66 | if (ch & VLI_CONTINUE) | |
67 | continue; | |
68 | ||
69 | *result = rv; | |
70 | *len = sz - 1; | |
71 | return 0; | |
72 | } | |
73 | return error_short_read(in); | |
74 | } | |
75 | ||
76 | static int read_offset(struct line_buffer *in, off_t *result, off_t *len) | |
77 | { | |
78 | uintmax_t val; | |
79 | if (read_int(in, &val, len)) | |
80 | return -1; | |
81 | if (val > maximum_signed_value_of_type(off_t)) | |
82 | return error("unrepresentable offset in delta: %"PRIuMAX"", val); | |
83 | *result = val; | |
84 | return 0; | |
85 | } | |
86 | ||
87 | static int read_length(struct line_buffer *in, size_t *result, off_t *len) | |
88 | { | |
89 | uintmax_t val; | |
90 | if (read_int(in, &val, len)) | |
91 | return -1; | |
92 | if (val > SIZE_MAX) | |
93 | return error("unrepresentable length in delta: %"PRIuMAX"", val); | |
94 | *result = val; | |
95 | return 0; | |
96 | } | |
97 | ||
98 | static int apply_one_window(struct line_buffer *delta, off_t *delta_len) | |
99 | { | |
100 | size_t out_len; | |
101 | size_t instructions_len; | |
102 | size_t data_len; | |
103 | assert(delta_len); | |
104 | ||
105 | /* "source view" offset and length already handled; */ | |
106 | if (read_length(delta, &out_len, delta_len) || | |
107 | read_length(delta, &instructions_len, delta_len) || | |
108 | read_length(delta, &data_len, delta_len)) | |
109 | return -1; | |
110 | if (instructions_len) | |
111 | return error("What do you think I am? A delta applier?"); | |
112 | if (data_len) | |
113 | return error("No support for inline data yet"); | |
114 | return 0; | |
115 | } | |
116 | ||
ddcc8c5b JN |
117 | int svndiff0_apply(struct line_buffer *delta, off_t delta_len, |
118 | struct sliding_view *preimage, FILE *postimage) | |
119 | { | |
120 | assert(delta && preimage && postimage); | |
121 | ||
122 | if (read_magic(delta, &delta_len)) | |
123 | return -1; | |
25271211 JN |
124 | while (delta_len) { /* For each window: */ |
125 | off_t pre_off; | |
126 | size_t pre_len; | |
127 | ||
128 | if (read_offset(delta, &pre_off, &delta_len) || | |
129 | read_length(delta, &pre_len, &delta_len) || | |
130 | apply_one_window(delta, &delta_len)) | |
131 | return -1; | |
132 | } | |
ddcc8c5b JN |
133 | return 0; |
134 | } |