1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file test_index_hash.c
4 /// \brief Tests src/liblzma/common/index_hash.c API functions
5 ///
6 /// \note No test included for lzma_index_hash_end since it
7 /// would be trivial unless tested for memory leaks
8 /// with something like valgrind
9 //
10 // Author: Jia Tan
11 //
12 // This file has been put into the public domain.
13 // You can do whatever you want with this file.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "tests.h"
18
19 // Needed for UNPADDED_SIZE_MIN and UNPADDED_SIZE_MAX macro definitions
20 // and index_size and vli_ceil4 helper functions
21 #include "common/index.h"
22
23
24 static void
25 test_lzma_index_hash_init(void)
26 {
27 #ifndef HAVE_DECODERS
28 assert_skip("Decoder support disabled");
29 #else
30 // First test with NULL index_hash.
31 // This should create a fresh index_hash.
32 lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
33 assert_true(index_hash != NULL);
34
35 // Next test with non-NULL index_hash.
36 lzma_index_hash *second_hash = lzma_index_hash_init(index_hash, NULL);
37
38 // It should not create a new index_hash pointer.
39 // Instead it must just re-init the first index_hash.
40 assert_true(index_hash == second_hash);
41
42 lzma_index_hash_end(index_hash, NULL);
43 #endif
44 }
45
46
47 static void
48 test_lzma_index_hash_append(void)
49 {
50 #ifndef HAVE_DECODERS
51 assert_skip("Decoder support disabled");
52 #else
53 // Test all invalid parameters
54 assert_lzma_ret(lzma_index_hash_append(NULL, 0, 0),
55 LZMA_PROG_ERROR);
56
57 // Test NULL index_hash
58 assert_lzma_ret(lzma_index_hash_append(NULL, UNPADDED_SIZE_MIN,
59 LZMA_VLI_MAX), LZMA_PROG_ERROR);
60
61 // Test with invalid Unpadded Size
62 lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
63 assert_true(index_hash != NULL);
64 assert_lzma_ret(lzma_index_hash_append(index_hash,
65 UNPADDED_SIZE_MIN - 1, LZMA_VLI_MAX),
66 LZMA_PROG_ERROR);
67
68 // Test with invalid Uncompressed Size
69 assert_lzma_ret(lzma_index_hash_append(index_hash,
70 UNPADDED_SIZE_MIN, LZMA_VLI_MAX + 1),
71 LZMA_PROG_ERROR);
72
73 // First append a Record describing a small Block.
74 // This should succeed.
75 assert_lzma_ret(lzma_index_hash_append(index_hash,
76 UNPADDED_SIZE_MIN, 1), LZMA_OK);
77
78 // Append another small Record.
79 assert_lzma_ret(lzma_index_hash_append(index_hash,
80 UNPADDED_SIZE_MIN, 1), LZMA_OK);
81
82 // Append a Record that would cause the compressed size to grow
83 // too big
84 assert_lzma_ret(lzma_index_hash_append(index_hash,
85 UNPADDED_SIZE_MAX, 1), LZMA_DATA_ERROR);
86
87 lzma_index_hash_end(index_hash, NULL);
88 #endif
89 }
90
91
92 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
93 // Fill an index_hash with unpadded and uncompressed VLIs
94 // by calling lzma_index_hash_append
95 static void
96 fill_index_hash(lzma_index_hash *index_hash, const lzma_vli *unpadded_sizes,
97 const lzma_vli *uncomp_sizes, uint32_t block_count)
98 {
99 for (uint32_t i = 0; i < block_count; ++i)
100 assert_lzma_ret(lzma_index_hash_append(index_hash,
101 unpadded_sizes[i], uncomp_sizes[i]), LZMA_OK);
102 }
103
104
105 // Set the contents of buf to the expected Index based on the
106 // .xz specification. This needs the unpadded and uncompressed VLIs
107 // to correctly create the Index.
108 static void
109 generate_index(uint8_t *buf, const lzma_vli *unpadded_sizes,
110 const lzma_vli *uncomp_sizes, uint32_t block_count,
111 size_t index_max_size)
112 {
113 size_t in_pos = 0;
114 size_t out_pos = 0;
115
116 // First set Index Indicator
117 buf[out_pos++] = INDEX_INDICATOR;
118
119 // Next write out Number of Records
120 assert_lzma_ret(lzma_vli_encode(block_count, &in_pos, buf,
121 &out_pos, index_max_size), LZMA_STREAM_END);
122
123 // Next write out each Record.
124 // A Record consists of Unpadded Size and Uncompressed Size
125 // written next to each other as VLIs.
126 for (uint32_t i = 0; i < block_count; ++i) {
127 in_pos = 0;
128 assert_lzma_ret(lzma_vli_encode(unpadded_sizes[i], &in_pos,
129 buf, &out_pos, index_max_size), LZMA_STREAM_END);
130 in_pos = 0;
131 assert_lzma_ret(lzma_vli_encode(uncomp_sizes[i], &in_pos,
132 buf, &out_pos, index_max_size), LZMA_STREAM_END);
133 }
134
135 // Add Index Padding
136 lzma_vli rounded_out_pos = vli_ceil4(out_pos);
137 memzero(buf + out_pos, rounded_out_pos - out_pos);
138 out_pos = rounded_out_pos;
139
140 // Add the CRC32
141 write32le(buf + out_pos, lzma_crc32(buf, out_pos, 0));
142 out_pos += 4;
143
144 assert_uint_eq(out_pos, index_max_size);
145 }
146 #endif
147
148
149 static void
150 test_lzma_index_hash_decode(void)
151 {
152 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
153 assert_skip("Encoder or decoder support disabled");
154 #else
155 lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
156 assert_true(index_hash != NULL);
157
158 size_t in_pos = 0;
159
160 // Six valid values for the Unpadded Size fields in an Index
161 const lzma_vli unpadded_sizes[6] = {
162 UNPADDED_SIZE_MIN,
163 1000,
164 4000,
165 8000,
166 16000,
167 32000
168 };
169
170 // Six valid values for the Uncompressed Size fields in an Index
171 const lzma_vli uncomp_sizes[6] = {
172 1,
173 500,
174 8000,
175 20,
176 1,
177 500
178 };
179
180 // Add two Records to an index_hash
181 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
182
183 const lzma_vli size_two_records = lzma_index_hash_size(index_hash);
184 assert_uint(size_two_records, >, 0);
185 uint8_t *index_two_records = tuktest_malloc(size_two_records);
186
187 generate_index(index_two_records, unpadded_sizes, uncomp_sizes, 2,
188 size_two_records);
189
190 // First test for basic buffer size error
191 in_pos = size_two_records + 1;
192 assert_lzma_ret(lzma_index_hash_decode(index_hash,
193 index_two_records, &in_pos,
194 size_two_records), LZMA_BUF_ERROR);
195
196 // Next test for invalid Index Indicator
197 in_pos = 0;
198 index_two_records[0] ^= 1;
199 assert_lzma_ret(lzma_index_hash_decode(index_hash,
200 index_two_records, &in_pos,
201 size_two_records), LZMA_DATA_ERROR);
202 index_two_records[0] ^= 1;
203
204 // Next verify the index_hash as expected
205 in_pos = 0;
206 assert_lzma_ret(lzma_index_hash_decode(index_hash,
207 index_two_records, &in_pos,
208 size_two_records), LZMA_STREAM_END);
209
210 // Next test an index_hash with three Records
211 index_hash = lzma_index_hash_init(index_hash, NULL);
212 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 3);
213
214 const lzma_vli size_three_records = lzma_index_hash_size(
215 index_hash);
216 assert_uint(size_three_records, >, 0);
217 uint8_t *index_three_records = tuktest_malloc(size_three_records);
218
219 generate_index(index_three_records, unpadded_sizes, uncomp_sizes,
220 3, size_three_records);
221
222 in_pos = 0;
223 assert_lzma_ret(lzma_index_hash_decode(index_hash,
224 index_three_records, &in_pos,
225 size_three_records), LZMA_STREAM_END);
226
227 // Next test an index_hash with five Records
228 index_hash = lzma_index_hash_init(index_hash, NULL);
229 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
230
231 const lzma_vli size_five_records = lzma_index_hash_size(
232 index_hash);
233 assert_uint(size_five_records, >, 0);
234 uint8_t *index_five_records = tuktest_malloc(size_five_records);
235
236 generate_index(index_five_records, unpadded_sizes, uncomp_sizes, 5,
237 size_five_records);
238
239 // Instead of testing all input at once, give input
240 // one byte at a time
241 in_pos = 0;
242 for (lzma_vli i = 0; i < size_five_records - 1; ++i) {
243 assert_lzma_ret(lzma_index_hash_decode(index_hash,
244 index_five_records, &in_pos, in_pos + 1),
245 LZMA_OK);
246 }
247
248 // Last byte should return LZMA_STREAM_END
249 assert_lzma_ret(lzma_index_hash_decode(index_hash,
250 index_five_records, &in_pos,
251 in_pos + 1), LZMA_STREAM_END);
252
253 // Next test if the index_hash is given an incorrect Unpadded
254 // Size. Should detect and report LZMA_DATA_ERROR
255 index_hash = lzma_index_hash_init(index_hash, NULL);
256 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
257 // The sixth Record will have an invalid Unpadded Size
258 assert_lzma_ret(lzma_index_hash_append(index_hash,
259 unpadded_sizes[5] + 1,
260 uncomp_sizes[5]), LZMA_OK);
261
262 const lzma_vli size_six_records = lzma_index_hash_size(
263 index_hash);
264
265 assert_uint(size_six_records, >, 0);
266 uint8_t *index_six_records = tuktest_malloc(size_six_records);
267
268 generate_index(index_six_records, unpadded_sizes, uncomp_sizes, 6,
269 size_six_records);
270 in_pos = 0;
271 assert_lzma_ret(lzma_index_hash_decode(index_hash,
272 index_six_records, &in_pos,
273 size_six_records), LZMA_DATA_ERROR);
274
275 // Next test if the Index is corrupt (invalid CRC32).
276 // Should detect and report LZMA_DATA_ERROR
277 index_hash = lzma_index_hash_init(index_hash, NULL);
278 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
279
280 index_two_records[size_two_records - 1] ^= 1;
281
282 in_pos = 0;
283 assert_lzma_ret(lzma_index_hash_decode(index_hash,
284 index_two_records, &in_pos,
285 size_two_records), LZMA_DATA_ERROR);
286
287 // Next test with Index and index_hash struct not matching
288 // a Record
289 index_hash = lzma_index_hash_init(index_hash, NULL);
290 fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
291 // Recalculate Index with invalid Unpadded Size
292 const lzma_vli unpadded_sizes_invalid[2] = {
293 unpadded_sizes[0],
294 unpadded_sizes[1] + 1
295 };
296
297 generate_index(index_two_records, unpadded_sizes_invalid,
298 uncomp_sizes, 2, size_two_records);
299
300 in_pos = 0;
301 assert_lzma_ret(lzma_index_hash_decode(index_hash,
302 index_two_records, &in_pos,
303 size_two_records), LZMA_DATA_ERROR);
304
305 lzma_index_hash_end(index_hash, NULL);
306 #endif
307 }
308
309
310 static void
311 test_lzma_index_hash_size(void)
312 {
313 #ifndef HAVE_DECODERS
314 assert_skip("Decoder support disabled");
315 #else
316 lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
317 assert_true(index_hash != NULL);
318
319 // First test empty index_hash
320 // Expected size should be:
321 // Index Indicator - 1 byte
322 // Number of Records - 1 byte
323 // List of Records - 0 bytes
324 // Index Padding - 2 bytes
325 // CRC32 - 4 bytes
326 // Total - 8 bytes
327 assert_uint_eq(lzma_index_hash_size(index_hash), 8);
328
329 // Append a Record describing a small Block to the index_hash
330 assert_lzma_ret(lzma_index_hash_append(index_hash,
331 UNPADDED_SIZE_MIN, 1), LZMA_OK);
332
333 // Expected size should be:
334 // Index Indicator - 1 byte
335 // Number of Records - 1 byte
336 // List of Records - 2 bytes
337 // Index Padding - 0 bytes
338 // CRC32 - 4 bytes
339 // Total - 8 bytes
340 lzma_vli expected_size = 8;
341 assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
342
343 // Append additional small Record
344 assert_lzma_ret(lzma_index_hash_append(index_hash,
345 UNPADDED_SIZE_MIN, 1), LZMA_OK);
346
347 // Expected size should be:
348 // Index Indicator - 1 byte
349 // Number of Records - 1 byte
350 // List of Records - 4 bytes
351 // Index Padding - 2 bytes
352 // CRC32 - 4 bytes
353 // Total - 12 bytes
354 expected_size = 12;
355 assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
356
357 // Append a larger Record to the index_hash (3 bytes for each VLI)
358 const lzma_vli three_byte_vli = 0x10000;
359 assert_lzma_ret(lzma_index_hash_append(index_hash,
360 three_byte_vli, three_byte_vli), LZMA_OK);
361
362 // Expected size should be:
363 // Index Indicator - 1 byte
364 // Number of Records - 1 byte
365 // List of Records - 10 bytes
366 // Index Padding - 0 bytes
367 // CRC32 - 4 bytes
368 // Total - 16 bytes
369 expected_size = 16;
370 assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
371
372 lzma_index_hash_end(index_hash, NULL);
373 #endif
374 }
375
376
377 extern int
378 main(int argc, char **argv)
379 {
380 tuktest_start(argc, argv);
381 tuktest_run(test_lzma_index_hash_init);
382 tuktest_run(test_lzma_index_hash_append);
383 tuktest_run(test_lzma_index_hash_decode);
384 tuktest_run(test_lzma_index_hash_size);
385 return tuktest_end();
386 }