block_header_decoder.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. /// \file block_header_decoder.c
  4. /// \brief Decodes Block Header from .xz files
  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. #include "common.h"
  13. #include "check.h"
  14. static void
  15. free_properties(lzma_block *block, const lzma_allocator *allocator)
  16. {
  17. // Free allocated filter options. The last array member is not
  18. // touched after the initialization in the beginning of
  19. // lzma_block_header_decode(), so we don't need to touch that here.
  20. for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i) {
  21. lzma_free(block->filters[i].options, allocator);
  22. block->filters[i].id = LZMA_VLI_UNKNOWN;
  23. block->filters[i].options = NULL;
  24. }
  25. return;
  26. }
  27. extern LZMA_API(lzma_ret)
  28. lzma_block_header_decode(lzma_block *block,
  29. const lzma_allocator *allocator, const uint8_t *in)
  30. {
  31. // NOTE: We consider the header to be corrupt not only when the
  32. // CRC32 doesn't match, but also when variable-length integers
  33. // are invalid or over 63 bits, or if the header is too small
  34. // to contain the claimed information.
  35. // Initialize the filter options array. This way the caller can
  36. // safely free() the options even if an error occurs in this function.
  37. for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) {
  38. block->filters[i].id = LZMA_VLI_UNKNOWN;
  39. block->filters[i].options = NULL;
  40. }
  41. // Versions 0 and 1 are supported. If a newer version was specified,
  42. // we need to downgrade it.
  43. if (block->version > 1)
  44. block->version = 1;
  45. // This isn't a Block Header option, but since the decompressor will
  46. // read it if version >= 1, it's better to initialize it here than
  47. // to expect the caller to do it since in almost all cases this
  48. // should be false.
  49. block->ignore_check = false;
  50. // Validate Block Header Size and Check type. The caller must have
  51. // already set these, so it is a programming error if this test fails.
  52. if (lzma_block_header_size_decode(in[0]) != block->header_size
  53. || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
  54. return LZMA_PROG_ERROR;
  55. // Exclude the CRC32 field.
  56. const size_t in_size = block->header_size - 4;
  57. // Verify CRC32
  58. if (lzma_crc32(in, in_size, 0) != unaligned_read32le(in + in_size))
  59. return LZMA_DATA_ERROR;
  60. // Check for unsupported flags.
  61. if (in[1] & 0x3C)
  62. return LZMA_OPTIONS_ERROR;
  63. // Start after the Block Header Size and Block Flags fields.
  64. size_t in_pos = 2;
  65. // Compressed Size
  66. if (in[1] & 0x40) {
  67. return_if_error(lzma_vli_decode(&block->compressed_size,
  68. NULL, in, &in_pos, in_size));
  69. // Validate Compressed Size. This checks that it isn't zero
  70. // and that the total size of the Block is a valid VLI.
  71. if (lzma_block_unpadded_size(block) == 0)
  72. return LZMA_DATA_ERROR;
  73. } else {
  74. block->compressed_size = LZMA_VLI_UNKNOWN;
  75. }
  76. // Uncompressed Size
  77. if (in[1] & 0x80)
  78. return_if_error(lzma_vli_decode(&block->uncompressed_size,
  79. NULL, in, &in_pos, in_size));
  80. else
  81. block->uncompressed_size = LZMA_VLI_UNKNOWN;
  82. // Filter Flags
  83. const size_t filter_count = (in[1] & 3) + 1;
  84. for (size_t i = 0; i < filter_count; ++i) {
  85. const lzma_ret ret = lzma_filter_flags_decode(
  86. &block->filters[i], allocator,
  87. in, &in_pos, in_size);
  88. if (ret != LZMA_OK) {
  89. free_properties(block, allocator);
  90. return ret;
  91. }
  92. }
  93. // Padding
  94. while (in_pos < in_size) {
  95. if (in[in_pos++] != 0x00) {
  96. free_properties(block, allocator);
  97. // Possibly some new field present so use
  98. // LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR.
  99. return LZMA_OPTIONS_ERROR;
  100. }
  101. }
  102. return LZMA_OK;
  103. }