1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file test_stream_flags.c
4 /// \brief Tests Stream Header and Stream Footer coders
5 //
6 // Authors: Jia Tan
7 // Lasse Collin
8 //
9 // This file has been put into the public domain.
10 // You can do whatever you want with this file.
11 //
12 ///////////////////////////////////////////////////////////////////////////////
13
14 #include "tests.h"
15
16
17 // Size of the Stream Flags field
18 // (taken from src/liblzma/common/stream_flags_common.h)
19 #define XZ_STREAM_FLAGS_SIZE 2
20
21 #ifdef HAVE_ENCODERS
22 // Header and footer magic bytes for .xz file format
23 // (taken from src/liblzma/common/stream_flags_common.c)
24 static const uint8_t xz_header_magic[6]
25 = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
26 static const uint8_t xz_footer_magic[2] = { 0x59, 0x5A };
27 #endif
28
29
30 #ifdef HAVE_ENCODERS
31 static void
32 stream_header_encode_helper(lzma_check check)
33 {
34 lzma_stream_flags flags = {
35 .version = 0,
36 .check = check,
37 };
38
39 uint8_t header[LZMA_STREAM_HEADER_SIZE];
40
41 // Encode Stream Header
42 assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
43
44 // Stream Header must start with Header Magic Bytes
45 const uint32_t magic_size = sizeof(xz_header_magic);
46 assert_array_eq(header, xz_header_magic, magic_size);
47
48 // Next must come Stream Flags
49 const uint8_t *encoded_stream_flags = header + magic_size;
50
51 // First byte is always null-byte.
52 // Second byte must have the Check ID in the lowest four bits
53 // and the highest four bits zero.
54 const uint8_t expected_stream_flags[] = { 0, check };
55 assert_array_eq(encoded_stream_flags, expected_stream_flags,
56 XZ_STREAM_FLAGS_SIZE);
57
58 // Last part is the CRC32 of the Stream Flags
59 const uint8_t *crc_ptr = encoded_stream_flags + XZ_STREAM_FLAGS_SIZE;
60 const uint32_t expected_crc = lzma_crc32(expected_stream_flags,
61 XZ_STREAM_FLAGS_SIZE, 0);
62 assert_uint_eq(read32le(crc_ptr), expected_crc);
63 }
64 #endif
65
66
67 static void
68 test_lzma_stream_header_encode(void)
69 {
70 #ifndef HAVE_ENCODERS
71 assert_skip("Encoder support disabled");
72 #else
73 for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
74 stream_header_encode_helper(i);
75
76 lzma_stream_flags flags = {
77 .version = 0,
78 .check = LZMA_CHECK_CRC32
79 };
80
81 uint8_t header[LZMA_STREAM_HEADER_SIZE];
82
83 // Should fail if version > 0
84 flags.version = 1;
85 assert_lzma_ret(lzma_stream_header_encode(&flags, header),
86 LZMA_OPTIONS_ERROR);
87 flags.version = 0;
88
89 // Should fail if Check ID is invalid
90 flags.check = INVALID_LZMA_CHECK_ID;
91 assert_lzma_ret(lzma_stream_header_encode(&flags, header),
92 LZMA_PROG_ERROR);
93 flags.check = LZMA_CHECK_CRC32;
94
95 // Should pass even if Backward Size is invalid
96 // because Stream Header doesn't have that field.
97 flags.backward_size = LZMA_VLI_MAX + 1;
98 assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
99 #endif
100 }
101
102
103 #if defined(HAVE_ENCODERS)
104 static void
105 stream_footer_encode_helper(lzma_check check)
106 {
107 lzma_stream_flags flags = {
108 .version = 0,
109 .check = check,
110 .backward_size = LZMA_BACKWARD_SIZE_MIN,
111 };
112
113 uint8_t footer[LZMA_STREAM_HEADER_SIZE];
114
115 // Encode Stream Footer
116 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
117
118 // Stream Footer must start with CRC32
119 const uint32_t crc = read32le(footer);
120 const uint32_t expected_crc = lzma_crc32(footer + sizeof(uint32_t),
121 LZMA_STREAM_HEADER_SIZE - (sizeof(uint32_t) +
122 sizeof(xz_footer_magic)), 0);
123 assert_uint_eq(crc, expected_crc);
124
125 // Next the Backward Size
126 const uint32_t backwards_size = read32le(footer + sizeof(uint32_t));
127 const uint32_t expected_backwards_size = flags.backward_size / 4 - 1;
128 assert_uint_eq(backwards_size, expected_backwards_size);
129
130 // Next the Stream Flags
131 const uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
132
133 // First byte must be null
134 assert_uint_eq(stream_flags[0], 0);
135
136 // Second byte must have the Check ID in the lowest four bits
137 // and the highest four bits zero.
138 assert_uint_eq(stream_flags[1], check);
139
140 // And ends with Footer Magic Bytes
141 const uint8_t *expected_footer_magic = stream_flags +
142 XZ_STREAM_FLAGS_SIZE;
143 assert_array_eq(expected_footer_magic, xz_footer_magic,
144 sizeof(xz_footer_magic));
145 }
146 #endif
147
148
149 static void
150 test_lzma_stream_footer_encode(void)
151 {
152 #ifndef HAVE_ENCODERS
153 assert_skip("Encoder support disabled");
154 #else
155 for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
156 stream_footer_encode_helper(i);
157
158 lzma_stream_flags flags = {
159 .version = 0,
160 .backward_size = LZMA_BACKWARD_SIZE_MIN,
161 .check = LZMA_CHECK_CRC32
162 };
163
164 uint8_t footer[LZMA_STREAM_HEADER_SIZE];
165
166 // Should fail if version > 0
167 flags.version = 1;
168 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
169 LZMA_OPTIONS_ERROR);
170 flags.version = 0;
171
172 // Should fail if Check ID is invalid
173 flags.check = INVALID_LZMA_CHECK_ID;
174 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
175 LZMA_PROG_ERROR);
176
177 // Should fail if Backward Size is invalid
178 flags.backward_size -= 1;
179 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
180 LZMA_PROG_ERROR);
181 flags.backward_size += 2;
182 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
183 LZMA_PROG_ERROR);
184 flags.backward_size = LZMA_BACKWARD_SIZE_MAX + 4;
185 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
186 LZMA_PROG_ERROR);
187 #endif
188 }
189
190
191 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
192 static void
193 stream_header_decode_helper(lzma_check check)
194 {
195 lzma_stream_flags flags = {
196 .version = 0,
197 .check = check
198 };
199
200 uint8_t header[LZMA_STREAM_HEADER_SIZE];
201
202 assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
203
204 lzma_stream_flags dest_flags;
205 assert_lzma_ret(lzma_stream_header_decode(&dest_flags, header),
206 LZMA_OK);
207
208 // Version should be 0
209 assert_uint_eq(dest_flags.version, 0);
210
211 // Backward Size should be LZMA_VLI_UNKNOWN
212 assert_uint_eq(dest_flags.backward_size, LZMA_VLI_UNKNOWN);
213
214 // Check ID must equal the argument given to this function.
215 assert_uint_eq(dest_flags.check, check);
216 }
217 #endif
218
219
220 static void
221 test_lzma_stream_header_decode(void)
222 {
223 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
224 assert_skip("Encoder or decoder support disabled");
225 #else
226 for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
227 stream_header_decode_helper(i);
228
229 lzma_stream_flags flags = {
230 .version = 0,
231 .check = LZMA_CHECK_CRC32
232 };
233
234 uint8_t header[LZMA_STREAM_HEADER_SIZE];
235 lzma_stream_flags dest;
236
237 // First encode known flags to header buffer
238 assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
239
240 // Should fail if magic bytes do not match
241 header[0] ^= 1;
242 assert_lzma_ret(lzma_stream_header_decode(&dest, header),
243 LZMA_FORMAT_ERROR);
244 header[0] ^= 1;
245
246 // Should fail if a reserved bit is set
247 uint8_t *stream_flags = header + sizeof(xz_header_magic);
248 stream_flags[0] = 1;
249
250 // Need to adjust CRC32 after making a change since the CRC32
251 // is verified before decoding the Stream Flags field.
252 uint8_t *crc32_ptr = header + sizeof(xz_header_magic)
253 + XZ_STREAM_FLAGS_SIZE;
254 const uint32_t crc_orig = read32le(crc32_ptr);
255 uint32_t new_crc32 = lzma_crc32(
256 stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
257 write32le(crc32_ptr, new_crc32);
258 assert_lzma_ret(lzma_stream_header_decode(&dest, header),
259 LZMA_OPTIONS_ERROR);
260 stream_flags[0] = 0;
261 write32le(crc32_ptr, crc_orig);
262
263 // Should fail if upper bits of check ID are set
264 stream_flags[1] |= 0xF0;
265 new_crc32 = lzma_crc32(stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
266 write32le(crc32_ptr, new_crc32);
267 assert_lzma_ret(lzma_stream_header_decode(&dest, header),
268 LZMA_OPTIONS_ERROR);
269 stream_flags[1] = flags.check;
270 write32le(crc32_ptr, crc_orig);
271
272 // Should fail if CRC32 does not match.
273 // First, alter a byte in the Stream Flags.
274 stream_flags[0] = 1;
275 assert_lzma_ret(lzma_stream_header_decode(&dest, header),
276 LZMA_DATA_ERROR);
277 stream_flags[0] = 0;
278
279 // Next, change the CRC32.
280 *crc32_ptr ^= 1;
281 assert_lzma_ret(lzma_stream_header_decode(&dest, header),
282 LZMA_DATA_ERROR);
283 #endif
284 }
285
286
287 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
288 static void
289 stream_footer_decode_helper(lzma_check check)
290 {
291 lzma_stream_flags flags = {
292 .version = 0,
293 .backward_size = LZMA_BACKWARD_SIZE_MIN,
294 .check = check,
295 };
296
297 uint8_t footer[LZMA_STREAM_HEADER_SIZE];
298 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
299
300 lzma_stream_flags dest_flags;
301 assert_lzma_ret(lzma_stream_footer_decode(&dest_flags, footer),
302 LZMA_OK);
303
304 // Version should be 0.
305 assert_uint_eq(dest_flags.version, 0);
306
307 // Backward Size should equal the value from the flags.
308 assert_uint_eq(dest_flags.backward_size, flags.backward_size);
309
310 // Check ID must equal argument given to this function.
311 assert_uint_eq(dest_flags.check, check);
312 }
313 #endif
314
315
316 static void
317 test_lzma_stream_footer_decode(void)
318 {
319 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
320 assert_skip("Encoder or decoder support disabled");
321 #else
322 for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
323 stream_footer_decode_helper(i);
324
325 lzma_stream_flags flags = {
326 .version = 0,
327 .check = LZMA_CHECK_CRC32,
328 .backward_size = LZMA_BACKWARD_SIZE_MIN
329 };
330
331 uint8_t footer[LZMA_STREAM_HEADER_SIZE];
332 lzma_stream_flags dest;
333
334 // First encode known flags to the footer buffer
335 assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
336
337 // Should fail if magic bytes do not match
338 footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
339 assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
340 LZMA_FORMAT_ERROR);
341 footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
342
343 // Should fail if a reserved bit is set.
344 // In the Stream Footer, the Stream Flags follow the CRC32 (4 bytes)
345 // and the Backward Size (4 bytes)
346 uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
347 stream_flags[0] = 1;
348
349 // Need to adjust the CRC32 so it will not fail that check instead
350 uint8_t *crc32_ptr = footer;
351 const uint32_t crc_orig = read32le(crc32_ptr);
352 uint8_t *backward_size = footer + sizeof(uint32_t);
353 uint32_t new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
354 XZ_STREAM_FLAGS_SIZE, 0);
355 write32le(crc32_ptr, new_crc32);
356 assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
357 LZMA_OPTIONS_ERROR);
358 stream_flags[0] = 0;
359 write32le(crc32_ptr, crc_orig);
360
361 // Should fail if upper bits of check ID are set
362 stream_flags[1] |= 0xF0;
363 new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
364 XZ_STREAM_FLAGS_SIZE, 0);
365 write32le(crc32_ptr, new_crc32);
366 assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
367 LZMA_OPTIONS_ERROR);
368 stream_flags[1] = flags.check;
369 write32le(crc32_ptr, crc_orig);
370
371 // Should fail if CRC32 does not match.
372 // First, alter a byte in the Stream Flags.
373 stream_flags[0] = 1;
374 assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
375 LZMA_DATA_ERROR);
376 stream_flags[0] = 0;
377
378 // Next, change the CRC32
379 *crc32_ptr ^= 1;
380 assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
381 LZMA_DATA_ERROR);
382 #endif
383 }
384
385
386 static void
387 test_lzma_stream_flags_compare(void)
388 {
389 lzma_stream_flags first = {
390 .version = 0,
391 .backward_size = LZMA_BACKWARD_SIZE_MIN,
392 .check = LZMA_CHECK_CRC32,
393 };
394
395 lzma_stream_flags second = first;
396
397 // First test should pass
398 assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
399
400 // Altering either version should cause an error
401 first.version = 1;
402 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
403 LZMA_OPTIONS_ERROR);
404 second.version = 1;
405 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
406 LZMA_OPTIONS_ERROR);
407 first.version = 0;
408 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
409 LZMA_OPTIONS_ERROR);
410 second.version = 0;
411
412 // Check types must be under the maximum
413 first.check = INVALID_LZMA_CHECK_ID;
414 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
415 LZMA_PROG_ERROR);
416 second.check = INVALID_LZMA_CHECK_ID;
417 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
418 LZMA_PROG_ERROR);
419 first.check = LZMA_CHECK_CRC32;
420 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
421 LZMA_PROG_ERROR);
422 second.check = LZMA_CHECK_CRC32;
423
424 // Check types must be equal
425 for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++) {
426 first.check = i;
427 if (i == second.check)
428 assert_lzma_ret(lzma_stream_flags_compare(&first,
429 &second), LZMA_OK);
430 else
431 assert_lzma_ret(lzma_stream_flags_compare(&first,
432 &second), LZMA_DATA_ERROR);
433 }
434 first.check = LZMA_CHECK_CRC32;
435
436 // Backward Size comparison is skipped if either are LZMA_VLI_UNKNOWN
437 first.backward_size = LZMA_VLI_UNKNOWN;
438 assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
439 second.backward_size = LZMA_VLI_MAX + 1;
440 assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
441 second.backward_size = LZMA_BACKWARD_SIZE_MIN;
442
443 // Backward Sizes need to be valid
444 first.backward_size = LZMA_VLI_MAX + 4;
445 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
446 LZMA_PROG_ERROR);
447 second.backward_size = LZMA_VLI_MAX + 4;
448 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
449 LZMA_PROG_ERROR);
450 first.backward_size = LZMA_BACKWARD_SIZE_MIN;
451 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
452 LZMA_PROG_ERROR);
453 second.backward_size = LZMA_BACKWARD_SIZE_MIN;
454
455 // Backward Sizes must be equal
456 second.backward_size = first.backward_size + 4;
457 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
458 LZMA_DATA_ERROR);
459
460 // Should fail if Backward Sizes are > LZMA_BACKWARD_SIZE_MAX
461 // even though they are equal
462 first.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
463 second.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
464 assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
465 LZMA_PROG_ERROR);
466 }
467
468
469 extern int
470 main(int argc, char **argv)
471 {
472 tuktest_start(argc, argv);
473 tuktest_run(test_lzma_stream_header_encode);
474 tuktest_run(test_lzma_stream_footer_encode);
475 tuktest_run(test_lzma_stream_header_decode);
476 tuktest_run(test_lzma_stream_footer_decode);
477 tuktest_run(test_lzma_stream_flags_compare);
478 return tuktest_end();
479 }