2 * Licensed under a two-clause BSD-style license.
3 * See LICENSE for details.
6 #include "git-compat-util.h"
7 #include "line_buffer.h"
13 * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
15 * svndiff0 ::= 'SVN\0' window*
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;
22 #define VLI_CONTINUE 0x80
23 #define VLI_DIGIT_MASK 0x7f
24 #define VLI_BITS_PER_DIGIT 7
26 static int error_short_read(struct line_buffer
*input
)
28 if (buffer_ferror(input
))
29 return error("error reading delta: %s", strerror(errno
));
30 return error("invalid delta: unexpected end of file");
33 static int read_magic(struct line_buffer
*in
, off_t
*len
)
35 static const char magic
[] = {'S', 'V', 'N', '\0'};
36 struct strbuf sb
= STRBUF_INIT
;
38 if (*len
< sizeof(magic
) ||
39 buffer_read_binary(in
, &sb
, sizeof(magic
)) != sizeof(magic
)) {
45 if (memcmp(sb
.buf
, magic
, sizeof(magic
))) {
47 return error("invalid delta: unrecognized file type");
50 *len
-= sizeof(magic
);
55 static int read_int(struct line_buffer
*in
, uintmax_t *result
, off_t
*len
)
59 for (sz
= *len
; sz
; sz
--) {
60 const int ch
= buffer_read_char(in
);
64 rv
<<= VLI_BITS_PER_DIGIT
;
65 rv
+= (ch
& VLI_DIGIT_MASK
);
66 if (ch
& VLI_CONTINUE
)
73 return error_short_read(in
);
76 static int read_offset(struct line_buffer
*in
, off_t
*result
, off_t
*len
)
79 if (read_int(in
, &val
, len
))
81 if (val
> maximum_signed_value_of_type(off_t
))
82 return error("unrepresentable offset in delta: %"PRIuMAX
"", val
);
87 static int read_length(struct line_buffer
*in
, size_t *result
, off_t
*len
)
90 if (read_int(in
, &val
, len
))
93 return error("unrepresentable length in delta: %"PRIuMAX
"", val
);
98 static int apply_one_window(struct line_buffer
*delta
, off_t
*delta_len
)
101 size_t instructions_len
;
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
))
110 if (instructions_len
)
111 return error("What do you think I am? A delta applier?");
113 return error("No support for inline data yet");
117 int svndiff0_apply(struct line_buffer
*delta
, off_t delta_len
,
118 struct sliding_view
*preimage
, FILE *postimage
)
120 assert(delta
&& preimage
&& postimage
);
122 if (read_magic(delta
, &delta_len
))
124 while (delta_len
) { /* For each window: */
128 if (read_offset(delta
, &pre_off
, &delta_len
) ||
129 read_length(delta
, &pre_len
, &delta_len
) ||
130 apply_one_window(delta
, &delta_len
))