1 1.1 christos // SPDX-License-Identifier: 0BSD 2 1.1 christos 3 1.1 christos /////////////////////////////////////////////////////////////////////////////// 4 1.1 christos // 5 1.1 christos /// \file test_microlzma.c 6 1.1 christos /// \brief Tests MicroLZMA encoding and decoding 7 1.1 christos // 8 1.1 christos // Author: Jia Tan 9 1.1 christos // 10 1.1 christos /////////////////////////////////////////////////////////////////////////////// 11 1.1 christos 12 1.1 christos #include "tests.h" 13 1.1 christos 14 1.1 christos #define BUFFER_SIZE 1024 15 1.1 christos 16 1.1 christos 17 1.1 christos #ifdef HAVE_ENCODER_LZMA1 18 1.1 christos 19 1.1 christos // MicroLZMA encoded "Hello\nWorld\n" output size in bytes. 20 1.1 christos #define ENCODED_OUTPUT_SIZE 17 21 1.1 christos 22 1.1 christos // Byte array of "Hello\nWorld\n". This is used for various encoder tests. 23 1.1 christos static const uint8_t hello_world[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 24 1.1 christos 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; 25 1.1 christos 26 1.1 christos // This is the CRC32 value of the MicroLZMA encoding of "Hello\nWorld\n". 27 1.1 christos // The settings used were based on LZMA_PRESET_DEFAULT as of liblzma 5.6.0. 28 1.1 christos // This assumes MicroLZMA is correct in liblzma 5.6.0, which is safe 29 1.1 christos // considering the encoded "Hello\nWorld\n" can successfully be decoded at 30 1.1 christos // this time. This is to test for regressions that cause MicroLZMA output 31 1.1 christos // to change. 32 1.1 christos static const uint32_t hello_world_encoded_crc = 0x3CDE40A8; 33 1.1 christos 34 1.1 christos 35 1.1 christos // Function implementation borrowed from lzma_decoder.c. It is needed to 36 1.1 christos // ensure the first byte of a MicroLZMA stream is set correctly with the 37 1.1 christos // negation of the LZMA properties. 38 1.1 christos static bool 39 1.1 christos lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte) 40 1.1 christos { 41 1.1 christos if (byte > (4 * 5 + 4) * 9 + 8) 42 1.1 christos return true; 43 1.1 christos 44 1.1 christos // See the file format specification to understand this. 45 1.1 christos options->pb = byte / (9 * 5); 46 1.1 christos byte -= options->pb * 9 * 5; 47 1.1 christos options->lp = byte / 9; 48 1.1 christos options->lc = byte - options->lp * 9; 49 1.1 christos 50 1.1 christos return options->lc + options->lp > LZMA_LCLP_MAX; 51 1.1 christos } 52 1.1 christos 53 1.1 christos 54 1.1 christos /////////////////// 55 1.1 christos // Encoder tests // 56 1.1 christos /////////////////// 57 1.1 christos 58 1.1 christos // This tests a few of the basic options. These options are not unique to 59 1.1 christos // MicroLZMA in any way, its mostly ensuring that the options are actually 60 1.1 christos // being checked before initializing the decoder internals. 61 1.1 christos static void 62 1.1 christos test_encode_options(void) 63 1.1 christos { 64 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 65 1.1 christos lzma_options_lzma opt_lzma; 66 1.1 christos 67 1.1 christos // Initialize with default options. 68 1.1 christos assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT)); 69 1.1 christos 70 1.1 christos // NULL stream 71 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(NULL, &opt_lzma), 72 1.1 christos LZMA_PROG_ERROR); 73 1.1 christos 74 1.1 christos // lc/lp/pb = 5/0/2 (lc invalid) 75 1.1 christos opt_lzma.lc = 5; 76 1.1 christos opt_lzma.lp = 0; 77 1.1 christos opt_lzma.pb = 2; 78 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 79 1.1 christos LZMA_OPTIONS_ERROR); 80 1.1 christos 81 1.1 christos // lc/lp/pb = 0/5/2 (lp invalid) 82 1.1 christos opt_lzma.lc = 0; 83 1.1 christos opt_lzma.lp = 5; 84 1.1 christos opt_lzma.pb = 2; 85 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 86 1.1 christos LZMA_OPTIONS_ERROR); 87 1.1 christos 88 1.1 christos // lc/lp/pb = 3/2/2 (lc + lp invalid) 89 1.1 christos opt_lzma.lc = 3; 90 1.1 christos opt_lzma.lp = 2; 91 1.1 christos opt_lzma.pb = 2; 92 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 93 1.1 christos LZMA_OPTIONS_ERROR); 94 1.1 christos 95 1.1 christos // lc/lp/pb = 3/0/5 (pb invalid) 96 1.1 christos opt_lzma.lc = 3; 97 1.1 christos opt_lzma.lp = 0; 98 1.1 christos opt_lzma.pb = 5; 99 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 100 1.1 christos LZMA_OPTIONS_ERROR); 101 1.1 christos 102 1.1 christos // Zero out lp, pb, lc options to not interfere with later tests. 103 1.1 christos opt_lzma.lp = 0; 104 1.1 christos opt_lzma.pb = 0; 105 1.1 christos opt_lzma.lc = 0; 106 1.1 christos 107 1.1 christos // Set invalid dictionary size. 108 1.1 christos opt_lzma.dict_size = LZMA_DICT_SIZE_MIN - 1; 109 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 110 1.1 christos LZMA_OPTIONS_ERROR); 111 1.1 christos 112 1.1 christos // Maximum dictionary size for the encoder, as described in lzma12.h 113 1.1 christos // is 1.5 GiB. 114 1.1 christos opt_lzma.dict_size = (UINT32_C(1) << 30) + (UINT32_C(1) << 29) + 1; 115 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 116 1.1 christos LZMA_OPTIONS_ERROR); 117 1.1 christos 118 1.1 christos lzma_end(&strm); 119 1.1 christos } 120 1.1 christos 121 1.1 christos 122 1.1 christos static void 123 1.1 christos test_encode_basic(void) 124 1.1 christos { 125 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 126 1.1 christos lzma_options_lzma opt_lzma; 127 1.1 christos 128 1.1 christos // The lzma_lzma_preset return value is inverse of what it perhaps 129 1.1 christos // should be, that is, it returns false on success. 130 1.1 christos assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT)); 131 1.1 christos 132 1.1 christos // Initialize the encoder using the default options. 133 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK); 134 1.1 christos 135 1.1 christos uint8_t output[BUFFER_SIZE]; 136 1.1 christos 137 1.1 christos strm.next_in = hello_world; 138 1.1 christos strm.avail_in = sizeof(hello_world); 139 1.1 christos strm.next_out = output; 140 1.1 christos strm.avail_out = sizeof(output); 141 1.1 christos 142 1.1 christos // Everything must be encoded in one lzma_code() call. 143 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END); 144 1.1 christos 145 1.1 christos // Check that the entire input was consumed. 146 1.1 christos assert_uint_eq(strm.total_in, sizeof(hello_world)); 147 1.1 christos 148 1.1 christos // Check that the first byte in the output stream is not 0x00. 149 1.1 christos // In a regular raw LZMA stream the first byte is always 0x00. 150 1.1 christos // In MicroLZMA the first byte replaced by the bitwise-negation 151 1.1 christos // of the LZMA properties. 152 1.1 christos assert_uint(output[0], !=, 0x00); 153 1.1 christos 154 1.1 christos const uint8_t props = ~output[0]; 155 1.1 christos 156 1.1 christos lzma_options_lzma test_options; 157 1.1 christos assert_false(lzma_lzma_lclppb_decode(&test_options, props)); 158 1.1 christos 159 1.1 christos assert_uint_eq(opt_lzma.lc, test_options.lc); 160 1.1 christos assert_uint_eq(opt_lzma.lp, test_options.lp); 161 1.1 christos assert_uint_eq(opt_lzma.pb, test_options.pb); 162 1.1 christos 163 1.1 christos // Compute the check over the output data. This is compared to 164 1.1 christos // the expected check value. 165 1.1 christos const uint32_t check_val = lzma_crc32(output, strm.total_out, 0); 166 1.1 christos 167 1.1 christos assert_uint_eq(check_val, hello_world_encoded_crc); 168 1.1 christos 169 1.1 christos lzma_end(&strm); 170 1.1 christos } 171 1.1 christos 172 1.1 christos 173 1.1 christos // This tests the behavior when strm.avail_out is so small it cannot hold 174 1.1 christos // the header plus 1 encoded byte (< 6). 175 1.1 christos static void 176 1.1 christos test_encode_small_out(void) 177 1.1 christos { 178 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 179 1.1 christos lzma_options_lzma opt_lzma; 180 1.1 christos 181 1.1 christos assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT)); 182 1.1 christos 183 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK); 184 1.1 christos 185 1.1 christos uint8_t output[BUFFER_SIZE]; 186 1.1 christos 187 1.1 christos strm.next_in = hello_world; 188 1.1 christos strm.avail_in = sizeof(hello_world); 189 1.1 christos strm.next_out = output; 190 1.1 christos strm.avail_out = 5; 191 1.1 christos 192 1.1 christos // LZMA_PROG_ERROR is expected when strm.avail_out < 6 193 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_PROG_ERROR); 194 1.1 christos 195 1.1 christos // The encoder must be reset because coders cannot be used again 196 1.1 christos // after returning LZMA_PROG_ERROR. 197 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK); 198 1.1 christos 199 1.1 christos // Reset strm.avail_out to be > 6, but not enough to hold all of the 200 1.1 christos // compressed data. 201 1.1 christos strm.avail_out = ENCODED_OUTPUT_SIZE - 1; 202 1.1 christos 203 1.1 christos // Encoding should not return an error now. 204 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END); 205 1.1 christos assert_uint(strm.total_in, <, sizeof(hello_world)); 206 1.1 christos 207 1.1 christos lzma_end(&strm); 208 1.1 christos } 209 1.1 christos 210 1.1 christos 211 1.1 christos // LZMA_FINISH is the only supported action. All others must 212 1.1 christos // return LZMA_PROG_ERROR. 213 1.1 christos static void 214 1.1 christos test_encode_actions(void) 215 1.1 christos { 216 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 217 1.1 christos lzma_options_lzma opt_lzma; 218 1.1 christos 219 1.1 christos assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT)); 220 1.1 christos 221 1.1 christos const lzma_action actions[] = { 222 1.1 christos LZMA_RUN, 223 1.1 christos LZMA_SYNC_FLUSH, 224 1.1 christos LZMA_FULL_FLUSH, 225 1.1 christos LZMA_FULL_BARRIER, 226 1.1 christos }; 227 1.1 christos 228 1.1 christos for (size_t i = 0; i < ARRAY_SIZE(actions); ++i) { 229 1.1 christos assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), 230 1.1 christos LZMA_OK); 231 1.1 christos 232 1.1 christos uint8_t output[BUFFER_SIZE]; 233 1.1 christos 234 1.1 christos strm.next_in = hello_world; 235 1.1 christos strm.avail_in = sizeof(hello_world); 236 1.1 christos strm.next_out = output; 237 1.1 christos strm.avail_out = sizeof(output); 238 1.1 christos 239 1.1 christos assert_lzma_ret(lzma_code(&strm, actions[i]), 240 1.1 christos LZMA_PROG_ERROR); 241 1.1 christos } 242 1.1 christos 243 1.1 christos lzma_end(&strm); 244 1.1 christos } 245 1.1 christos #endif // HAVE_ENCODER_LZMA1 246 1.1 christos 247 1.1 christos 248 1.1 christos /////////////////// 249 1.1 christos // Decoder tests // 250 1.1 christos /////////////////// 251 1.1 christos 252 1.1 christos #if defined(HAVE_DECODER_LZMA1) && defined(HAVE_ENCODER_LZMA1) 253 1.1 christos 254 1.1 christos // Byte array of "Goodbye World!". This is used for various decoder tests. 255 1.1 christos static const uint8_t goodbye_world[] = { 0x47, 0x6F, 0x6F, 0x64, 0x62, 256 1.1 christos 0x79, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 }; 257 1.1 christos 258 1.1 christos static uint8_t *goodbye_world_encoded = NULL; 259 1.1 christos static size_t goodbye_world_encoded_size = 0; 260 1.1 christos 261 1.1 christos 262 1.1 christos // Helper function to encode data and return the compressed size. 263 1.1 christos static size_t 264 1.1 christos basic_microlzma_encode(const uint8_t *input, size_t in_size, 265 1.1 christos uint8_t **compressed) 266 1.1 christos { 267 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 268 1.1 christos lzma_options_lzma opt_lzma; 269 1.1 christos 270 1.1 christos // Lazy way to set the output size since the input should never 271 1.1 christos // inflate by much in these simple test cases. This is tested to 272 1.1 christos // be large enough after encoding to fit the entire input, so if 273 1.1 christos // this assumption does not hold then this will fail. 274 1.1 christos const size_t out_size = in_size << 1; 275 1.1 christos 276 1.1 christos *compressed = tuktest_malloc(out_size); 277 1.1 christos 278 1.1 christos // Always encode with the default options for simplicity. 279 1.1 christos if (lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT)) 280 1.1 christos goto decoder_setup_error; 281 1.1 christos 282 1.1 christos if (lzma_microlzma_encoder(&strm, &opt_lzma) != LZMA_OK) 283 1.1 christos goto decoder_setup_error; 284 1.1 christos 285 1.1 christos strm.next_in = input; 286 1.1 christos strm.avail_in = in_size; 287 1.1 christos strm.next_out = *compressed; 288 1.1 christos strm.avail_out = out_size; 289 1.1 christos 290 1.1 christos if (lzma_code(&strm, LZMA_FINISH) != LZMA_STREAM_END) 291 1.1 christos goto decoder_setup_error; 292 1.1 christos 293 1.1 christos // Check that the entire input was consumed and that it fit into 294 1.1 christos // the output buffer. 295 1.1 christos if (strm.total_in != in_size) 296 1.1 christos goto decoder_setup_error; 297 1.1 christos 298 1.1 christos lzma_end(&strm); 299 1.1 christos 300 1.1 christos // lzma_end() doesn't touch other members of lzma_stream than 301 1.1 christos // lzma_stream.internal so using strm.total_out here is fine. 302 1.1 christos return strm.total_out; 303 1.1 christos 304 1.1 christos decoder_setup_error: 305 1.1 christos tuktest_error("Failed to initialize decoder tests"); 306 1.1 christos return 0; 307 1.1 christos } 308 1.1 christos 309 1.1 christos 310 1.1 christos static void 311 1.1 christos test_decode_options(void) 312 1.1 christos { 313 1.1 christos // NULL stream 314 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(NULL, BUFFER_SIZE, 315 1.1 christos sizeof(hello_world), true, 316 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_PROG_ERROR); 317 1.1 christos 318 1.1 christos // Uncompressed size larger than max 319 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 320 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, BUFFER_SIZE, 321 1.1 christos LZMA_VLI_MAX + 1, true, LZMA_DICT_SIZE_DEFAULT), 322 1.1 christos LZMA_OPTIONS_ERROR); 323 1.1 christos } 324 1.1 christos 325 1.1 christos 326 1.1 christos // Test that decoding succeeds when uncomp_size is correct regardless of 327 1.1 christos // the value of uncomp_size_is_exact. 328 1.1 christos static void 329 1.1 christos test_decode_uncomp_size_is_exact(void) 330 1.1 christos { 331 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 332 1.1 christos 333 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 334 1.1 christos goodbye_world_encoded_size, 335 1.1 christos sizeof(goodbye_world), true, 336 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 337 1.1 christos 338 1.1 christos uint8_t output[BUFFER_SIZE]; 339 1.1 christos 340 1.1 christos strm.next_in = goodbye_world_encoded; 341 1.1 christos strm.avail_in = goodbye_world_encoded_size; 342 1.1 christos strm.next_out = output; 343 1.1 christos strm.avail_out = sizeof(output); 344 1.1 christos 345 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END); 346 1.1 christos assert_uint_eq(strm.total_in, goodbye_world_encoded_size); 347 1.1 christos 348 1.1 christos assert_uint_eq(strm.total_out, sizeof(goodbye_world)); 349 1.1 christos assert_array_eq(goodbye_world, output, sizeof(goodbye_world)); 350 1.1 christos 351 1.1 christos // Reset decoder with uncomp_size_is_exact set to false and 352 1.1 christos // uncomp_size set to correct value. Also test using the 353 1.1 christos // uncompressed size as the dictionary size. 354 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 355 1.1 christos goodbye_world_encoded_size, 356 1.1 christos sizeof(goodbye_world), false, 357 1.1 christos sizeof(goodbye_world)), LZMA_OK); 358 1.1 christos 359 1.1 christos strm.next_in = goodbye_world_encoded; 360 1.1 christos strm.avail_in = goodbye_world_encoded_size; 361 1.1 christos strm.next_out = output; 362 1.1 christos strm.avail_out = sizeof(output); 363 1.1 christos 364 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END); 365 1.1 christos assert_uint_eq(strm.total_in, goodbye_world_encoded_size); 366 1.1 christos 367 1.1 christos assert_uint_eq(strm.total_out, sizeof(goodbye_world)); 368 1.1 christos assert_array_eq(goodbye_world, output, sizeof(goodbye_world)); 369 1.1 christos 370 1.1 christos lzma_end(&strm); 371 1.1 christos } 372 1.1 christos 373 1.1 christos 374 1.1 christos // This tests decoding when MicroLZMA decoder is called with 375 1.1 christos // an incorrect uncompressed size. 376 1.1 christos static void 377 1.1 christos test_decode_uncomp_size_wrong(void) 378 1.1 christos { 379 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 380 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 381 1.1 christos goodbye_world_encoded_size, 382 1.1 christos sizeof(goodbye_world) + 1, false, 383 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 384 1.1 christos 385 1.1 christos uint8_t output[BUFFER_SIZE]; 386 1.1 christos 387 1.1 christos strm.next_in = goodbye_world_encoded; 388 1.1 christos strm.avail_in = goodbye_world_encoded_size; 389 1.1 christos strm.next_out = output; 390 1.1 christos strm.avail_out = sizeof(output); 391 1.1 christos 392 1.1 christos // LZMA_OK should be returned because the input size given was 393 1.1 christos // larger than the actual encoded size. The decoder is expecting 394 1.1 christos // more input to possibly fill the uncompressed size that was set. 395 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK); 396 1.1 christos 397 1.1 christos assert_uint_eq(strm.total_out, sizeof(goodbye_world)); 398 1.1 christos 399 1.1 christos assert_array_eq(goodbye_world, output, sizeof(goodbye_world)); 400 1.1 christos 401 1.1 christos // Next, test with uncomp_size_is_exact set. 402 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 403 1.1 christos goodbye_world_encoded_size, 404 1.1 christos sizeof(goodbye_world) + 1, true, 405 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 406 1.1 christos 407 1.1 christos strm.next_in = goodbye_world_encoded; 408 1.1 christos strm.avail_in = goodbye_world_encoded_size; 409 1.1 christos strm.next_out = output; 410 1.1 christos strm.avail_out = sizeof(output); 411 1.1 christos 412 1.1 christos // No error detected, even though all input was consumed and there 413 1.1 christos // is more room in the output buffer. 414 1.1 christos // 415 1.1 christos // FIXME? LZMA_FINISH tells that no more input is coming and 416 1.1 christos // the MicroLZMA decoder knows the exact compressed size from 417 1.1 christos // the initialization as well. So should it return LZMA_DATA_ERROR 418 1.1 christos // on the first call instead of relying on the generic lzma_code() 419 1.1 christos // logic to eventually get LZMA_BUF_ERROR? 420 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK); 421 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK); 422 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_BUF_ERROR); 423 1.1 christos 424 1.1 christos assert_uint_eq(strm.total_out, sizeof(goodbye_world)); 425 1.1 christos assert_array_eq(goodbye_world, output, sizeof(goodbye_world)); 426 1.1 christos 427 1.1 christos // Reset stream with uncomp_size smaller than the real 428 1.1 christos // uncompressed size. 429 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 430 1.1 christos goodbye_world_encoded_size, 431 1.1 christos ARRAY_SIZE(hello_world) - 1, true, 432 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 433 1.1 christos 434 1.1 christos strm.next_in = goodbye_world_encoded; 435 1.1 christos strm.avail_in = goodbye_world_encoded_size; 436 1.1 christos strm.next_out = output; 437 1.1 christos strm.avail_out = sizeof(output); 438 1.1 christos 439 1.1 christos // This case actually results in an error since it decodes the full 440 1.1 christos // uncompressed size but the range coder is not in the proper state 441 1.1 christos // for the stream to end. 442 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_DATA_ERROR); 443 1.1 christos 444 1.1 christos lzma_end(&strm); 445 1.1 christos } 446 1.1 christos 447 1.1 christos 448 1.1 christos static void 449 1.1 christos test_decode_comp_size_wrong(void) 450 1.1 christos { 451 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 452 1.1 christos 453 1.1 christos // goodbye_world_encoded_size + 1 is safe because extra space was 454 1.1 christos // allocated for goodbye_world_encoded. The extra space isn't 455 1.1 christos // initialized but it shouldn't be read either, thus Valgrind 456 1.1 christos // has to remain happy with this code. 457 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 458 1.1 christos goodbye_world_encoded_size + 1, 459 1.1 christos sizeof(goodbye_world), true, 460 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 461 1.1 christos 462 1.1 christos uint8_t output[BUFFER_SIZE]; 463 1.1 christos 464 1.1 christos strm.next_in = goodbye_world_encoded; 465 1.1 christos strm.avail_in = goodbye_world_encoded_size; 466 1.1 christos strm.next_out = output; 467 1.1 christos strm.avail_out = sizeof(output); 468 1.1 christos 469 1.1 christos // When uncomp_size_is_exact is set, the compressed size must be 470 1.1 christos // correct or else LZMA_DATA_ERROR is returned. 471 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR); 472 1.1 christos 473 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 474 1.1 christos goodbye_world_encoded_size + 1, 475 1.1 christos sizeof(goodbye_world), false, 476 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 477 1.1 christos 478 1.1 christos strm.next_in = goodbye_world_encoded; 479 1.1 christos strm.avail_in = goodbye_world_encoded_size; 480 1.1 christos strm.next_out = output; 481 1.1 christos strm.avail_out = sizeof(output); 482 1.1 christos 483 1.1 christos // When uncomp_size_is_exact is not set, the decoder does not 484 1.1 christos // detect when the compressed size is wrong as long as all of the 485 1.1 christos // expected output has been decoded. This is because the decoder 486 1.1 christos // assumes that the real uncompressed size might be bigger than 487 1.1 christos // the specified value and in that case more input might be needed 488 1.1 christos // as well. 489 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END); 490 1.1 christos 491 1.1 christos lzma_end(&strm); 492 1.1 christos } 493 1.1 christos 494 1.1 christos 495 1.1 christos static void 496 1.1 christos test_decode_bad_lzma_properties(void) 497 1.1 christos { 498 1.1 christos // Alter first byte to encode invalid LZMA properties. 499 1.1 christos uint8_t *compressed = tuktest_malloc(goodbye_world_encoded_size); 500 1.1 christos memcpy(compressed, goodbye_world_encoded, goodbye_world_encoded_size); 501 1.1 christos 502 1.1 christos // lc=3, lp=2, pb=2 503 1.1 christos compressed[0] = (uint8_t)~0x6FU; 504 1.1 christos 505 1.1 christos lzma_stream strm = LZMA_STREAM_INIT; 506 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 507 1.1 christos goodbye_world_encoded_size, 508 1.1 christos sizeof(goodbye_world), false, 509 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 510 1.1 christos 511 1.1 christos uint8_t output[BUFFER_SIZE]; 512 1.1 christos 513 1.1 christos strm.next_in = compressed; 514 1.1 christos strm.avail_in = goodbye_world_encoded_size; 515 1.1 christos strm.next_out = output; 516 1.1 christos strm.avail_out = sizeof(output); 517 1.1 christos 518 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_OPTIONS_ERROR); 519 1.1 christos 520 1.1 christos // Use valid, but incorrect LZMA properties. 521 1.1 christos // lc=3, lp=1, pb=2 522 1.1 christos compressed[0] = (uint8_t)~0x66; 523 1.1 christos 524 1.1 christos assert_lzma_ret(lzma_microlzma_decoder(&strm, 525 1.1 christos goodbye_world_encoded_size, 526 1.1 christos ARRAY_SIZE(goodbye_world), true, 527 1.1 christos LZMA_DICT_SIZE_DEFAULT), LZMA_OK); 528 1.1 christos 529 1.1 christos strm.next_in = compressed; 530 1.1 christos strm.avail_in = goodbye_world_encoded_size; 531 1.1 christos strm.next_out = output; 532 1.1 christos strm.avail_out = sizeof(output); 533 1.1 christos 534 1.1 christos assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_DATA_ERROR); 535 1.1 christos 536 1.1 christos lzma_end(&strm); 537 1.1 christos } 538 1.1 christos #endif 539 1.1 christos 540 1.1 christos 541 1.1 christos extern int 542 1.1 christos main(int argc, char **argv) 543 1.1 christos { 544 1.1 christos tuktest_start(argc, argv); 545 1.1 christos 546 1.1 christos #ifndef HAVE_ENCODER_LZMA1 547 1.1 christos tuktest_early_skip("LZMA1 encoder disabled"); 548 1.1 christos #else 549 1.1 christos tuktest_run(test_encode_options); 550 1.1 christos tuktest_run(test_encode_basic); 551 1.1 christos tuktest_run(test_encode_small_out); 552 1.1 christos tuktest_run(test_encode_actions); 553 1.1 christos 554 1.1 christos // MicroLZMA decoder tests require the basic encoder functionality. 555 1.1 christos # ifdef HAVE_DECODER_LZMA1 556 1.1 christos goodbye_world_encoded_size = basic_microlzma_encode(goodbye_world, 557 1.1 christos sizeof(goodbye_world), &goodbye_world_encoded); 558 1.1 christos 559 1.1 christos tuktest_run(test_decode_options); 560 1.1 christos tuktest_run(test_decode_uncomp_size_is_exact); 561 1.1 christos tuktest_run(test_decode_uncomp_size_wrong); 562 1.1 christos tuktest_run(test_decode_comp_size_wrong); 563 1.1 christos tuktest_run(test_decode_bad_lzma_properties); 564 1.1 christos # endif 565 1.1 christos 566 1.1 christos return tuktest_end(); 567 1.1 christos #endif 568 1.1 christos } 569