(root)/
xz-5.4.5/
tests/
test_block_header.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       test_block_header.c
       4  /// \brief      Tests Block Header coders
       5  //
       6  //  Authors:    Lasse Collin
       7  //              Jia Tan
       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  static lzma_options_lzma opt_lzma;
      18  
      19  
      20  // Used in test_lzma_block_header_decode() between tests to ensure
      21  // no artifacts are leftover in the block struct that could influence
      22  // later tests.
      23  #define RESET_BLOCK(block, buf) \
      24  do { \
      25  	lzma_filter *filters_ = (block).filters; \
      26  	lzma_filters_free(filters_, NULL); \
      27  	memzero((buf), sizeof((buf))); \
      28  	memzero(&(block), sizeof(lzma_block)); \
      29  	(block).filters = filters_; \
      30  	(block).check = LZMA_CHECK_CRC32; \
      31  } while (0);
      32  
      33  
      34  #ifdef HAVE_ENCODERS
      35  static lzma_filter filters_none[1] = {
      36  	{
      37  		.id = LZMA_VLI_UNKNOWN,
      38  	},
      39  };
      40  
      41  
      42  static lzma_filter filters_one[2] = {
      43  	{
      44  		.id = LZMA_FILTER_LZMA2,
      45  		.options = &opt_lzma,
      46  	}, {
      47  		.id = LZMA_VLI_UNKNOWN,
      48  	}
      49  };
      50  
      51  
      52  // These filters are only used in test_lzma_block_header_decode()
      53  // which only runs if encoders and decoders are configured.
      54  #ifdef HAVE_DECODERS
      55  static lzma_filter filters_four[5] = {
      56  	{
      57  		.id = LZMA_FILTER_X86,
      58  		.options = NULL,
      59  	}, {
      60  		.id = LZMA_FILTER_X86,
      61  		.options = NULL,
      62  	}, {
      63  		.id = LZMA_FILTER_X86,
      64  		.options = NULL,
      65  	}, {
      66  		.id = LZMA_FILTER_LZMA2,
      67  		.options = &opt_lzma,
      68  	}, {
      69  		.id = LZMA_VLI_UNKNOWN,
      70  	}
      71  };
      72  #endif
      73  
      74  
      75  static lzma_filter filters_five[6] = {
      76  	{
      77  		.id = LZMA_FILTER_X86,
      78  		.options = NULL,
      79  	}, {
      80  		.id = LZMA_FILTER_X86,
      81  		.options = NULL,
      82  	}, {
      83  		.id = LZMA_FILTER_X86,
      84  		.options = NULL,
      85  	}, {
      86  		.id = LZMA_FILTER_X86,
      87  		.options = NULL,
      88  	}, {
      89  		.id = LZMA_FILTER_LZMA2,
      90  		.options = &opt_lzma,
      91  	}, {
      92  		.id = LZMA_VLI_UNKNOWN,
      93  	}
      94  };
      95  #endif
      96  
      97  
      98  static void
      99  test_lzma_block_header_size(void)
     100  {
     101  #ifndef HAVE_ENCODERS
     102  	assert_skip("Encoder support disabled");
     103  #else
     104  	if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86))
     105  		assert_skip("x86 BCJ encoder is disabled");
     106  
     107  	lzma_block block = {
     108  		.version = 0,
     109  		.filters = filters_one,
     110  		.compressed_size = LZMA_VLI_UNKNOWN,
     111  		.uncompressed_size = LZMA_VLI_UNKNOWN,
     112  		.check = LZMA_CHECK_CRC32
     113  	};
     114  
     115  	// Test that all initial options are valid
     116  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     117  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     118  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     119  	assert_uint_eq(block.header_size % 4, 0);
     120  
     121  	// Test invalid version number
     122  	for (uint32_t i = 2; i < 20; i++) {
     123  		block.version = i;
     124  		assert_lzma_ret(lzma_block_header_size(&block),
     125  				LZMA_OPTIONS_ERROR);
     126  	}
     127  
     128  	block.version = 1;
     129  
     130  	// Test invalid compressed size
     131  	block.compressed_size = 0;
     132  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     133  
     134  	block.compressed_size = LZMA_VLI_MAX + 1;
     135  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     136  	block.compressed_size = LZMA_VLI_UNKNOWN;
     137  
     138  	// Test invalid uncompressed size
     139  	block.uncompressed_size = LZMA_VLI_MAX + 1;
     140  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     141  	block.uncompressed_size = LZMA_VLI_MAX;
     142  
     143  	// Test invalid filters
     144  	block.filters = NULL;
     145  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     146  
     147  	block.filters = filters_none;
     148  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     149  
     150  	block.filters = filters_five;
     151  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
     152  
     153  	block.filters = filters_one;
     154  
     155  	// Test setting compressed_size to something valid
     156  	block.compressed_size = 4096;
     157  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     158  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     159  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     160  	assert_uint_eq(block.header_size % 4, 0);
     161  
     162  	// Test setting uncompressed_size to something valid
     163  	block.uncompressed_size = 4096;
     164  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     165  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     166  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     167  	assert_uint_eq(block.header_size % 4, 0);
     168  
     169  	// This should pass, but header_size will be an invalid value
     170  	// because the total block size will not be able to fit in a valid
     171  	// lzma_vli. This way a temporary value can be used to reserve
     172  	// space for the header and later the actual value can be set.
     173  	block.compressed_size = LZMA_VLI_MAX;
     174  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     175  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     176  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     177  	assert_uint_eq(block.header_size % 4, 0);
     178  
     179  	// Use an invalid value for a filter option. This should still pass
     180  	// because the size of the LZMA2 properties is known by liblzma
     181  	// without reading any of the options so it doesn't validate them.
     182  	lzma_options_lzma bad_ops;
     183  	assert_false(lzma_lzma_preset(&bad_ops, 1));
     184  	bad_ops.pb = 0x1000;
     185  
     186  	lzma_filter bad_filters[2] = {
     187  		{
     188  			.id = LZMA_FILTER_LZMA2,
     189  			.options = &bad_ops
     190  		},
     191  		{
     192  			.id = LZMA_VLI_UNKNOWN,
     193  			.options = NULL
     194  		}
     195  	};
     196  
     197  	block.filters = bad_filters;
     198  
     199  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     200  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     201  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     202  	assert_uint_eq(block.header_size % 4, 0);
     203  
     204  	// Use an invalid block option. The check type isn't stored in
     205  	// the Block Header and so _header_size ignores it.
     206  	block.check = INVALID_LZMA_CHECK_ID;
     207  	block.ignore_check = false;
     208  
     209  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     210  	assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
     211  	assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
     212  	assert_uint_eq(block.header_size % 4, 0);
     213  #endif
     214  }
     215  
     216  
     217  static void
     218  test_lzma_block_header_encode(void)
     219  {
     220  #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
     221  	assert_skip("Encoder or decoder support disabled");
     222  #else
     223  
     224  	if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
     225                          || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
     226                  assert_skip("x86 BCJ encoder and/or decoder "
     227                                  "is disabled");
     228  
     229  	lzma_block block = {
     230  		.version = 1,
     231  		.filters = filters_one,
     232  		.compressed_size = LZMA_VLI_UNKNOWN,
     233  		.uncompressed_size = LZMA_VLI_UNKNOWN,
     234  		.check = LZMA_CHECK_CRC32,
     235  	};
     236  
     237  	// Ensure all block options are valid before changes are tested
     238  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     239  
     240  	uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
     241  
     242  	// Test invalid block version
     243  	for (uint32_t i = 2; i < 20; i++) {
     244  		block.version = i;
     245  		assert_lzma_ret(lzma_block_header_encode(&block, out),
     246  				LZMA_PROG_ERROR);
     247  	}
     248  
     249  	block.version = 1;
     250  
     251  	// Test invalid header size (< min, > max, % 4 != 0)
     252  	block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN - 4;
     253  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     254  			LZMA_PROG_ERROR);
     255  	block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN + 2;
     256  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     257  			LZMA_PROG_ERROR);
     258  	block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX + 4;
     259  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     260  			LZMA_PROG_ERROR);
     261  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     262  
     263  	// Test invalid compressed_size
     264  	block.compressed_size = 0;
     265  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     266  			LZMA_PROG_ERROR);
     267  	block.compressed_size = LZMA_VLI_MAX + 1;
     268  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     269  			LZMA_PROG_ERROR);
     270  
     271  	// This test passes test_lzma_block_header_size, but should
     272  	// fail here because there is not enough space to encode the
     273  	// proper block size because the total size is too big to fit
     274  	// in an lzma_vli
     275  	block.compressed_size = LZMA_VLI_MAX;
     276  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     277  			LZMA_PROG_ERROR);
     278  	block.compressed_size = LZMA_VLI_UNKNOWN;
     279  
     280  	// Test invalid uncompressed size
     281  	block.uncompressed_size = LZMA_VLI_MAX + 1;
     282  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     283  			LZMA_PROG_ERROR);
     284  	block.uncompressed_size = LZMA_VLI_UNKNOWN;
     285  
     286  	// Test invalid block check
     287  	block.check = INVALID_LZMA_CHECK_ID;
     288  	block.ignore_check = false;
     289  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     290  			LZMA_PROG_ERROR);
     291  	block.check = LZMA_CHECK_CRC32;
     292  
     293  	// Test invalid filters
     294  	block.filters = NULL;
     295  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     296  			LZMA_PROG_ERROR);
     297  
     298  	block.filters = filters_none;
     299  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     300  			LZMA_PROG_ERROR);
     301  
     302  	block.filters = filters_five;
     303  	block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX - 4;
     304  	assert_lzma_ret(lzma_block_header_encode(&block, out),
     305  			LZMA_PROG_ERROR);
     306  
     307  	// Test valid encoding and verify bytes of block header.
     308  	// More complicated tests for encoding headers are included
     309  	// in test_lzma_block_header_decode.
     310  	block.filters = filters_one;
     311  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     312  	assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
     313  
     314  	// First read block header size from out and verify
     315  	// that it == (encoded size + 1) * 4
     316  	uint32_t header_size = (out[0] + 1U) * 4;
     317  	assert_uint_eq(header_size, block.header_size);
     318  
     319  	// Next read block flags
     320  	uint8_t flags = out[1];
     321  
     322  	// Should have number of filters = 1
     323  	assert_uint_eq((flags & 0x3) + 1, 1);
     324  
     325  	// Bits 2-7 must be empty not set
     326  	assert_uint_eq(flags & (0xFF - 0x3), 0);
     327  
     328  	// Verify filter flags
     329  	// Decode Filter ID
     330  	lzma_vli filter_id = 0;
     331  	size_t pos = 2;
     332  	assert_lzma_ret(lzma_vli_decode(&filter_id, NULL, out,
     333  			&pos, header_size), LZMA_OK);
     334  	assert_uint_eq(filter_id, filters_one[0].id);
     335  
     336  	// Decode Size of Properties
     337  	lzma_vli prop_size = 0;
     338  	assert_lzma_ret(lzma_vli_decode(&prop_size, NULL, out,
     339  			&pos, header_size), LZMA_OK);
     340  
     341  	// LZMA2 has 1 byte prop size
     342  	assert_uint_eq(prop_size, 1);
     343  	uint8_t expected_filter_props = 0;
     344  	assert_lzma_ret(lzma_properties_encode(filters_one,
     345  			&expected_filter_props), LZMA_OK);
     346  	assert_uint_eq(out[pos], expected_filter_props);
     347  	pos++;
     348  
     349  	// Check null-padding
     350  	for (size_t i = pos; i < header_size - 4; i++)
     351  		assert_uint_eq(out[i], 0);
     352  
     353  	// Check CRC32
     354  	assert_uint_eq(read32le(&out[header_size - 4]), lzma_crc32(out,
     355  			header_size - 4, 0));
     356  #endif
     357  }
     358  
     359  
     360  #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
     361  // Helper function to compare two lzma_block structures field by field
     362  static void
     363  compare_blocks(lzma_block *block_expected, lzma_block *block_actual)
     364  {
     365  	assert_uint_eq(block_actual->version, block_expected->version);
     366  	assert_uint_eq(block_actual->compressed_size,
     367  			block_expected->compressed_size);
     368  	assert_uint_eq(block_actual->uncompressed_size,
     369  			block_expected->uncompressed_size);
     370  	assert_uint_eq(block_actual->check, block_expected->check);
     371  	assert_uint_eq(block_actual->header_size, block_expected->header_size);
     372  
     373  	// Compare filter IDs
     374  	assert_true(block_expected->filters && block_actual->filters);
     375  	lzma_filter expected_filter = block_expected->filters[0];
     376  	uint32_t filter_count = 0;
     377  	while (expected_filter.id != LZMA_VLI_UNKNOWN) {
     378  		assert_uint_eq(block_actual->filters[filter_count].id,
     379  				expected_filter.id);
     380  		expected_filter = block_expected->filters[++filter_count];
     381  	}
     382  
     383  	assert_uint_eq(block_actual->filters[filter_count].id,
     384  			LZMA_VLI_UNKNOWN);
     385  }
     386  #endif
     387  
     388  
     389  static void
     390  test_lzma_block_header_decode(void)
     391  {
     392  #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
     393  	assert_skip("Encoder or decoder support disabled");
     394  #else
     395  	if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
     396                          || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
     397                  assert_skip("x86 BCJ encoder and/or decoder "
     398                                  "is disabled");
     399  
     400  	lzma_block block = {
     401  		.filters = filters_one,
     402  		.compressed_size = LZMA_VLI_UNKNOWN,
     403  		.uncompressed_size = LZMA_VLI_UNKNOWN,
     404  		.check = LZMA_CHECK_CRC32,
     405  		.version = 0
     406  	};
     407  
     408  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     409  
     410  	// Encode block header with simple options
     411  	uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
     412  	assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
     413  
     414  	// Decode block header and check that the options match
     415  	lzma_filter decoded_filters[LZMA_FILTERS_MAX + 1];
     416  	lzma_block decoded_block = {
     417  		.version = 0,
     418  		.filters = decoded_filters,
     419  		.check = LZMA_CHECK_CRC32
     420  	};
     421  	decoded_block.header_size = lzma_block_header_size_decode(out[0]);
     422  
     423  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     424  			LZMA_OK);
     425  	compare_blocks(&block, &decoded_block);
     426  
     427  	// Reset output buffer and decoded_block
     428  	RESET_BLOCK(decoded_block, out);
     429  
     430  	// Test with compressed size set
     431  	block.compressed_size = 4096;
     432  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     433  	assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
     434  	decoded_block.header_size = lzma_block_header_size_decode(out[0]);
     435  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     436  			LZMA_OK);
     437  	compare_blocks(&block, &decoded_block);
     438  
     439  	RESET_BLOCK(decoded_block, out);
     440  
     441  	// Test with uncompressed size set
     442  	block.uncompressed_size = 4096;
     443  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     444  	assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
     445  	decoded_block.header_size = lzma_block_header_size_decode(out[0]);
     446  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     447  			LZMA_OK);
     448  	compare_blocks(&block, &decoded_block);
     449  
     450  	RESET_BLOCK(decoded_block, out);
     451  
     452  	// Test with multiple filters
     453  	block.filters = filters_four;
     454  	assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
     455  	assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
     456  	decoded_block.header_size = lzma_block_header_size_decode(out[0]);
     457  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     458  			LZMA_OK);
     459  	compare_blocks(&block, &decoded_block);
     460  
     461  	lzma_filters_free(decoded_filters, NULL);
     462  
     463  	// Test with too high version. The decoder will set it to a version
     464  	// that it supports.
     465  	decoded_block.version = 2;
     466  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     467  			LZMA_OK);
     468  	assert_uint_eq(decoded_block.version, 1);
     469  
     470  	// Free the filters for the last time since all other cases should
     471  	// result in an error.
     472  	lzma_filters_free(decoded_filters, NULL);
     473  
     474  	// Test bad check type
     475  	decoded_block.check = INVALID_LZMA_CHECK_ID;
     476  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     477  			LZMA_PROG_ERROR);
     478  	decoded_block.check = LZMA_CHECK_CRC32;
     479  
     480  	// Test bad check value
     481  	out[decoded_block.header_size - 1] -= 10;
     482  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     483  			LZMA_DATA_ERROR);
     484  	out[decoded_block.header_size - 1] += 10;
     485  
     486  	// Test non-NULL padding
     487  	out[decoded_block.header_size - 5] = 1;
     488  
     489  	// Recompute CRC32
     490  	write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
     491  			decoded_block.header_size - 4, 0));
     492  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     493  			LZMA_OPTIONS_ERROR);
     494  
     495  	// Test unsupported flags
     496  	out[1] = 0xFF;
     497  
     498  	// Recompute CRC32
     499  	write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
     500  			decoded_block.header_size - 4, 0));
     501  	assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
     502  			LZMA_OPTIONS_ERROR);
     503  #endif
     504  }
     505  
     506  
     507  extern int
     508  main(int argc, char **argv)
     509  {
     510  	tuktest_start(argc, argv);
     511  
     512  	if (lzma_lzma_preset(&opt_lzma, 1))
     513  		tuktest_error("lzma_lzma_preset() failed");
     514  
     515  	tuktest_run(test_lzma_block_header_size);
     516  	tuktest_run(test_lzma_block_header_encode);
     517  	tuktest_run(test_lzma_block_header_decode);
     518  
     519  	return tuktest_end();
     520  }