1 // Copyright 2008 Google Inc.
2 // Author: Lincoln Smith
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <config.h>
17 #include "vcdecoder_test.h"
18 #include <string.h> // strlen
19 #include "checksum.h"
20 #include "codetable.h"
21 #include "testing.h"
22 #include "varint_bigendian.h"
23 #include "vcdiff_defs.h"
24
25 namespace open_vcdiff {
26
27 const char VCDiffDecoderTest::kStandardFileHeader[] = {
28 0xD6, // 'V' | 0x80
29 0xC3, // 'C' | 0x80
30 0xC4, // 'D' | 0x80
31 0x00, // Draft standard version number
32 0x00 // Hdr_Indicator: no custom code table, no compression
33 };
34
35 const char VCDiffDecoderTest::kInterleavedFileHeader[] = {
36 0xD6, // 'V' | 0x80
37 0xC3, // 'C' | 0x80
38 0xC4, // 'D' | 0x80
39 'S', // SDCH version code
40 0x00 // Hdr_Indicator: no custom code table, no compression
41 };
42
43 const char VCDiffDecoderTest::kDictionary[] =
44 "\"Just the place for a Snark!\" the Bellman cried,\n"
45 "As he landed his crew with care;\n"
46 "Supporting each man on the top of the tide\n"
47 "By a finger entwined in his hair.\n";
48
49 const char VCDiffDecoderTest::kExpectedTarget[] =
50 "\"Just the place for a Snark! I have said it twice:\n"
51 "That alone should encourage the crew.\n"
52 "Just the place for a Snark! I have said it thrice:\n"
53 "What I tell you three times is true.\"\n";
54
VCDiffDecoderTest()55 VCDiffDecoderTest::VCDiffDecoderTest() : fuzzer_(0), fuzzed_byte_position_(0) {
56 dictionary_ = kDictionary;
57 expected_target_ = kExpectedTarget;
58 }
59
SetUp()60 void VCDiffDecoderTest::SetUp() {
61 InitializeDeltaFile();
62 }
63
UseStandardFileHeader()64 void VCDiffDecoderTest::UseStandardFileHeader() {
65 delta_file_header_.assign(kStandardFileHeader,
66 sizeof(kStandardFileHeader));
67 }
68
UseInterleavedFileHeader()69 void VCDiffDecoderTest::UseInterleavedFileHeader() {
70 delta_file_header_.assign(kInterleavedFileHeader,
71 sizeof(kInterleavedFileHeader));
72 }
73
InitializeDeltaFile()74 void VCDiffDecoderTest::InitializeDeltaFile() {
75 delta_file_ = delta_file_header_ + delta_window_header_ + delta_window_body_;
76 }
77
GetByteFromStringLength(const char * s,int which_byte)78 char VCDiffDecoderTest::GetByteFromStringLength(const char* s,
79 int which_byte) {
80 char varint_buf[VarintBE<int32_t>::kMaxBytes];
81 VarintBE<int32_t>::Encode(static_cast<int32_t>(strlen(s)), varint_buf);
82 return varint_buf[which_byte];
83 }
84
AddChecksum(VCDChecksum checksum)85 void VCDiffDecoderTest::AddChecksum(VCDChecksum checksum) {
86 int32_t checksum_as_int32 = static_cast<int32_t>(checksum);
87 delta_window_header_[0] |= VCD_CHECKSUM;
88 VarintBE<int32_t>::AppendToString(checksum_as_int32, &delta_window_header_);
89 // Adjust delta window size to include checksum.
90 // This method wouldn't work if adding to the length caused the VarintBE
91 // value to spill over into another byte. Luckily, this test data happens
92 // not to cause such an overflow.
93 delta_window_header_[4] += VarintBE<int32_t>::Length(checksum_as_int32);
94 }
95
ComputeAndAddChecksum()96 void VCDiffDecoderTest::ComputeAndAddChecksum() {
97 AddChecksum(ComputeAdler32(expected_target_.data(),
98 expected_target_.size()));
99 }
100
101 // Write the maximum expressible positive 32-bit VarintBE
102 // (0x7FFFFFFF) at the given offset in the delta window.
WriteMaxVarintAtOffset(int offset,int bytes_to_replace)103 void VCDiffDecoderTest::WriteMaxVarintAtOffset(int offset,
104 int bytes_to_replace) {
105 static const char kMaxVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0x7F };
106 delta_file_.replace(delta_file_header_.size() + offset,
107 bytes_to_replace,
108 kMaxVarint,
109 sizeof(kMaxVarint));
110 }
111
112 // Write a negative 32-bit VarintBE (0x80000000) at the given offset
113 // in the delta window.
WriteNegativeVarintAtOffset(int offset,int bytes_to_replace)114 void VCDiffDecoderTest::WriteNegativeVarintAtOffset(int offset,
115 int bytes_to_replace) {
116 static const char kNegativeVarint[] = { 0x88, 0x80, 0x80, 0x80, 0x00 };
117 delta_file_.replace(delta_file_header_.size() + offset,
118 bytes_to_replace,
119 kNegativeVarint,
120 sizeof(kNegativeVarint));
121 }
122
123 // Write a VarintBE that has too many continuation bytes
124 // at the given offset in the delta window.
WriteInvalidVarintAtOffset(int offset,int bytes_to_replace)125 void VCDiffDecoderTest::WriteInvalidVarintAtOffset(int offset,
126 int bytes_to_replace) {
127 static const char kInvalidVarint[] = { 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F };
128 delta_file_.replace(delta_file_header_.size() + offset,
129 bytes_to_replace,
130 kInvalidVarint,
131 sizeof(kInvalidVarint));
132 }
133
FuzzOneByteInDeltaFile()134 bool VCDiffDecoderTest::FuzzOneByteInDeltaFile() {
135 static const struct Fuzzer {
136 char _and;
137 char _or;
138 char _xor;
139 } fuzzers[] = {
140 { 0xff, 0x80, 0x00 },
141 { 0xff, 0xff, 0x00 },
142 { 0xff, 0x00, 0x80 },
143 { 0xff, 0x00, 0xff },
144 { 0xff, 0x01, 0x00 },
145 { 0x7f, 0x00, 0x00 },
146 };
147
148 for (; fuzzer_ < (sizeof(fuzzers) / sizeof(fuzzers[0])); ++fuzzer_) {
149 for (; fuzzed_byte_position_ < delta_file_.size();
150 ++fuzzed_byte_position_) {
151 char fuzzed_byte = (((delta_file_[fuzzed_byte_position_]
152 & fuzzers[fuzzer_]._and)
153 | fuzzers[fuzzer_]._or)
154 ^ fuzzers[fuzzer_]._xor);
155 if (fuzzed_byte != delta_file_[fuzzed_byte_position_]) {
156 delta_file_[fuzzed_byte_position_] = fuzzed_byte;
157 ++fuzzed_byte_position_;
158 return true;
159 }
160 }
161 fuzzed_byte_position_ = 0;
162 }
163 return false;
164 }
165
166 const char VCDiffStandardDecoderTest::kWindowHeader[] = {
167 VCD_SOURCE, // Win_Indicator: take source from dictionary
168 FirstByteOfStringLength(kDictionary), // Source segment size
169 SecondByteOfStringLength(kDictionary),
170 0x00, // Source segment position: start of dictionary
171 0x79, // Length of the delta encoding
172 FirstByteOfStringLength(kExpectedTarget), // Size of the target window
173 SecondByteOfStringLength(kExpectedTarget),
174 0x00, // Delta_indicator (no compression)
175 0x64, // length of data for ADDs and RUNs
176 0x0C, // length of instructions section
177 0x03 // length of addresses for COPYs
178 };
179
180 const char VCDiffStandardDecoderTest::kWindowBody[] = {
181 // Data for ADDs: 1st section (length 61)
182 ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
183 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
184 'T', 'h', 'a', 't', ' ',
185 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
186 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
187 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
188 // Data for ADDs: 2nd section (length 2)
189 'h', 'r',
190 // Data for ADDs: 3rd section (length 9)
191 'W', 'h', 'a', 't', ' ',
192 'I', ' ', 't', 'e',
193 // Data for RUN: 4th section (length 1)
194 'l',
195 // Data for ADD: 4th section (length 27)
196 ' ', 'y', 'o', 'u', ' ',
197 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
198 't', 'r', 'u', 'e', '.', '\"', '\n',
199 // Instructions and sizes (length 13)
200 0x13, // VCD_COPY mode VCD_SELF, size 0
201 0x1C, // Size of COPY (28)
202 0x01, // VCD_ADD size 0
203 0x3D, // Size of ADD (61)
204 0x23, // VCD_COPY mode VCD_HERE, size 0
205 0x2C, // Size of COPY (44)
206 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5
207 0x0A, // VCD_ADD size 9
208 0x00, // VCD_RUN size 0
209 0x02, // Size of RUN (2)
210 0x01, // VCD_ADD size 0
211 0x1B, // Size of ADD (27)
212 // Addresses for COPYs (length 3)
213 0x00, // Start of dictionary
214 0x58, // HERE mode address for 2nd copy (27+61 back from here_address)
215 0x2D // NEAR(1) mode address for 2nd copy (45 after prior address)
216 };
217
VCDiffStandardDecoderTest()218 VCDiffStandardDecoderTest::VCDiffStandardDecoderTest() {
219 UseStandardFileHeader();
220 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
221 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
222 }
223
224 const char VCDiffInterleavedDecoderTest::kWindowHeader[] = {
225 VCD_SOURCE, // Win_Indicator: take source from dictionary
226 FirstByteOfStringLength(kDictionary), // Source segment size
227 SecondByteOfStringLength(kDictionary),
228 0x00, // Source segment position: start of dictionary
229 0x79, // Length of the delta encoding
230 FirstByteOfStringLength(kExpectedTarget), // Size of the target window
231 SecondByteOfStringLength(kExpectedTarget),
232 0x00, // Delta_indicator (no compression)
233 0x00, // length of data for ADDs and RUNs (unused)
234 0x73, // length of interleaved section
235 0x00 // length of addresses for COPYs (unused)
236 };
237
238 const char VCDiffInterleavedDecoderTest::kWindowBody[] = {
239 0x13, // VCD_COPY mode VCD_SELF, size 0
240 0x1C, // Size of COPY (28)
241 0x00, // Address of COPY: Start of dictionary
242 0x01, // VCD_ADD size 0
243 0x3D, // Size of ADD (61)
244 // Data for ADD (length 61)
245 ' ', 'I', ' ', 'h', 'a', 'v', 'e', ' ', 's', 'a', 'i', 'd', ' ',
246 'i', 't', ' ', 't', 'w', 'i', 'c', 'e', ':', '\n',
247 'T', 'h', 'a', 't', ' ',
248 'a', 'l', 'o', 'n', 'e', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ',
249 'e', 'n', 'c', 'o', 'u', 'r', 'a', 'g', 'e', ' ',
250 't', 'h', 'e', ' ', 'c', 'r', 'e', 'w', '.', '\n',
251 0x23, // VCD_COPY mode VCD_HERE, size 0
252 0x2C, // Size of COPY (44)
253 0x58, // HERE mode address (27+61 back from here_address)
254 0xCB, // VCD_ADD size 2 + VCD_COPY mode NEAR(1), size 5
255 // Data for ADDs: 2nd section (length 2)
256 'h', 'r',
257 0x2D, // NEAR(1) mode address (45 after prior address)
258 0x0A, // VCD_ADD size 9
259 // Data for ADDs: 3rd section (length 9)
260 'W', 'h', 'a', 't', ' ',
261 'I', ' ', 't', 'e',
262 0x00, // VCD_RUN size 0
263 0x02, // Size of RUN (2)
264 // Data for RUN: 4th section (length 1)
265 'l',
266 0x01, // VCD_ADD size 0
267 0x1B, // Size of ADD (27)
268 // Data for ADD: 4th section (length 27)
269 ' ', 'y', 'o', 'u', ' ',
270 't', 'h', 'r', 'e', 'e', ' ', 't', 'i', 'm', 'e', 's', ' ', 'i', 's', ' ',
271 't', 'r', 'u', 'e', '.', '\"', '\n'
272 };
273
VCDiffInterleavedDecoderTest()274 VCDiffInterleavedDecoderTest::VCDiffInterleavedDecoderTest() {
275 UseInterleavedFileHeader();
276 delta_window_header_.assign(kWindowHeader, sizeof(kWindowHeader));
277 delta_window_body_.assign(kWindowBody, sizeof(kWindowBody));
278 }
279
280 } // namespace open_vcdiff
281