1///////////////////////////////////////////////////////////////////////////////
2//
3/// \file       test_block_header.c
4/// \brief      Tests Block Header coders
5//
6//  Author:     Lasse Collin
7//
8//  This file has been put into the public domain.
9//  You can do whatever you want with this file.
10//
11///////////////////////////////////////////////////////////////////////////////
12
13#include "tests.h"
14
15
16static uint8_t buf[LZMA_BLOCK_HEADER_SIZE_MAX];
17static lzma_block known_options;
18static lzma_block decoded_options;
19
20static lzma_options_lzma opt_lzma;
21
22static lzma_filter filters_none[1] = {
23	{
24		.id = LZMA_VLI_UNKNOWN,
25	},
26};
27
28
29static lzma_filter filters_one[2] = {
30	{
31		.id = LZMA_FILTER_LZMA2,
32		.options = &opt_lzma,
33	}, {
34		.id = LZMA_VLI_UNKNOWN,
35	}
36};
37
38
39static lzma_filter filters_four[5] = {
40	{
41		.id = LZMA_FILTER_X86,
42		.options = NULL,
43	}, {
44		.id = LZMA_FILTER_X86,
45		.options = NULL,
46	}, {
47		.id = LZMA_FILTER_X86,
48		.options = NULL,
49	}, {
50		.id = LZMA_FILTER_LZMA2,
51		.options = &opt_lzma,
52	}, {
53		.id = LZMA_VLI_UNKNOWN,
54	}
55};
56
57
58static lzma_filter filters_five[6] = {
59	{
60		.id = LZMA_FILTER_X86,
61		.options = NULL,
62	}, {
63		.id = LZMA_FILTER_X86,
64		.options = NULL,
65	}, {
66		.id = LZMA_FILTER_X86,
67		.options = NULL,
68	}, {
69		.id = LZMA_FILTER_X86,
70		.options = NULL,
71	}, {
72		.id = LZMA_FILTER_LZMA2,
73		.options = &opt_lzma,
74	}, {
75		.id = LZMA_VLI_UNKNOWN,
76	}
77};
78
79
80static void
81code(void)
82{
83	expect(lzma_block_header_encode(&known_options, buf) == LZMA_OK);
84
85	lzma_filter filters[LZMA_FILTERS_MAX + 1];
86	memcrap(filters, sizeof(filters));
87	memcrap(&decoded_options, sizeof(decoded_options));
88
89	decoded_options.header_size = known_options.header_size;
90	decoded_options.check = known_options.check;
91	decoded_options.filters = filters;
92	expect(lzma_block_header_decode(&decoded_options, NULL, buf)
93			== LZMA_OK);
94
95	expect(known_options.compressed_size
96			== decoded_options.compressed_size);
97	expect(known_options.uncompressed_size
98			== decoded_options.uncompressed_size);
99
100	for (size_t i = 0; known_options.filters[i].id
101			!= LZMA_VLI_UNKNOWN; ++i)
102		expect(known_options.filters[i].id == filters[i].id);
103
104	for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i)
105		free(decoded_options.filters[i].options);
106}
107
108
109static void
110test1(void)
111{
112	known_options = (lzma_block){
113		.check = LZMA_CHECK_NONE,
114		.compressed_size = LZMA_VLI_UNKNOWN,
115		.uncompressed_size = LZMA_VLI_UNKNOWN,
116		.filters = NULL,
117	};
118
119	expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
120
121	known_options.filters = filters_none;
122	expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
123
124	known_options.filters = filters_five;
125	expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
126
127	known_options.filters = filters_one;
128	expect(lzma_block_header_size(&known_options) == LZMA_OK);
129
130	known_options.check = 999; // Some invalid value, which gets ignored.
131	expect(lzma_block_header_size(&known_options) == LZMA_OK);
132
133	known_options.compressed_size = 5;
134	expect(lzma_block_header_size(&known_options) == LZMA_OK);
135
136	known_options.compressed_size = 0; // Cannot be zero.
137	expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
138
139	// LZMA_VLI_MAX is too big to keep the total size of the Block
140	// a valid VLI, but lzma_block_header_size() is not meant
141	// to validate it. (lzma_block_header_encode() must validate it.)
142	known_options.compressed_size = LZMA_VLI_MAX;
143	expect(lzma_block_header_size(&known_options) == LZMA_OK);
144
145	known_options.compressed_size = LZMA_VLI_UNKNOWN;
146	known_options.uncompressed_size = 0;
147	expect(lzma_block_header_size(&known_options) == LZMA_OK);
148
149	known_options.uncompressed_size = LZMA_VLI_MAX + 1;
150	expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
151}
152
153
154static void
155test2(void)
156{
157	known_options = (lzma_block){
158		.check = LZMA_CHECK_CRC32,
159		.compressed_size = LZMA_VLI_UNKNOWN,
160		.uncompressed_size = LZMA_VLI_UNKNOWN,
161		.filters = filters_four,
162	};
163
164	expect(lzma_block_header_size(&known_options) == LZMA_OK);
165	code();
166
167	known_options.compressed_size = 123456;
168	known_options.uncompressed_size = 234567;
169	expect(lzma_block_header_size(&known_options) == LZMA_OK);
170	code();
171
172	// We can make the sizes smaller while keeping the header size
173	// the same.
174	known_options.compressed_size = 12;
175	known_options.uncompressed_size = 23;
176	code();
177}
178
179
180static void
181test3(void)
182{
183	known_options = (lzma_block){
184		.check = LZMA_CHECK_CRC32,
185		.compressed_size = LZMA_VLI_UNKNOWN,
186		.uncompressed_size = LZMA_VLI_UNKNOWN,
187		.filters = filters_one,
188	};
189
190	expect(lzma_block_header_size(&known_options) == LZMA_OK);
191	known_options.header_size += 4;
192	expect(lzma_block_header_encode(&known_options, buf) == LZMA_OK);
193
194	lzma_filter filters[LZMA_FILTERS_MAX + 1];
195	decoded_options.header_size = known_options.header_size;
196	decoded_options.check = known_options.check;
197	decoded_options.filters = filters;
198
199	// Wrong size
200	++buf[0];
201	expect(lzma_block_header_decode(&decoded_options, NULL, buf)
202			== LZMA_PROG_ERROR);
203	--buf[0];
204
205	// Wrong CRC32
206	buf[known_options.header_size - 1] ^= 1;
207	expect(lzma_block_header_decode(&decoded_options, NULL, buf)
208			== LZMA_DATA_ERROR);
209	buf[known_options.header_size - 1] ^= 1;
210
211	// Unsupported filter
212	// NOTE: This may need updating when new IDs become supported.
213	buf[2] ^= 0x1F;
214	unaligned_write32le(buf + known_options.header_size - 4,
215			lzma_crc32(buf, known_options.header_size - 4, 0));
216	expect(lzma_block_header_decode(&decoded_options, NULL, buf)
217			== LZMA_OPTIONS_ERROR);
218	buf[2] ^= 0x1F;
219
220	// Non-nul Padding
221	buf[known_options.header_size - 4 - 1] ^= 1;
222	unaligned_write32le(buf + known_options.header_size - 4,
223			lzma_crc32(buf, known_options.header_size - 4, 0));
224	expect(lzma_block_header_decode(&decoded_options, NULL, buf)
225			== LZMA_OPTIONS_ERROR);
226	buf[known_options.header_size - 4 - 1] ^= 1;
227}
228
229
230int
231main(void)
232{
233	succeed(lzma_lzma_preset(&opt_lzma, 1));
234
235	test1();
236	test2();
237	test3();
238
239	return 0;
240}
241