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