1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file block_header_decoder.c 4207753Smm/// \brief Decodes Block Header from .xz files 5207753Smm// 6207753Smm// Author: Lasse Collin 7207753Smm// 8207753Smm// This file has been put into the public domain. 9207753Smm// You can do whatever you want with this file. 10207753Smm// 11207753Smm/////////////////////////////////////////////////////////////////////////////// 12207753Smm 13207753Smm#include "common.h" 14207753Smm#include "check.h" 15207753Smm 16207753Smm 17207753Smmstatic void 18207753Smmfree_properties(lzma_block *block, lzma_allocator *allocator) 19207753Smm{ 20207753Smm // Free allocated filter options. The last array member is not 21207753Smm // touched after the initialization in the beginning of 22207753Smm // lzma_block_header_decode(), so we don't need to touch that here. 23207753Smm for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i) { 24207753Smm lzma_free(block->filters[i].options, allocator); 25207753Smm block->filters[i].id = LZMA_VLI_UNKNOWN; 26207753Smm block->filters[i].options = NULL; 27207753Smm } 28207753Smm 29207753Smm return; 30207753Smm} 31207753Smm 32207753Smm 33207753Smmextern LZMA_API(lzma_ret) 34207753Smmlzma_block_header_decode(lzma_block *block, 35207753Smm lzma_allocator *allocator, const uint8_t *in) 36207753Smm{ 37207753Smm // NOTE: We consider the header to be corrupt not only when the 38207753Smm // CRC32 doesn't match, but also when variable-length integers 39207753Smm // are invalid or over 63 bits, or if the header is too small 40207753Smm // to contain the claimed information. 41207753Smm 42207753Smm // Initialize the filter options array. This way the caller can 43207753Smm // safely free() the options even if an error occurs in this function. 44207753Smm for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) { 45207753Smm block->filters[i].id = LZMA_VLI_UNKNOWN; 46207753Smm block->filters[i].options = NULL; 47207753Smm } 48207753Smm 49207753Smm // Always zero for now. 50207753Smm block->version = 0; 51207753Smm 52207753Smm // Validate Block Header Size and Check type. The caller must have 53207753Smm // already set these, so it is a programming error if this test fails. 54207753Smm if (lzma_block_header_size_decode(in[0]) != block->header_size 55207753Smm || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX) 56207753Smm return LZMA_PROG_ERROR; 57207753Smm 58207753Smm // Exclude the CRC32 field. 59207753Smm const size_t in_size = block->header_size - 4; 60207753Smm 61207753Smm // Verify CRC32 62207753Smm if (lzma_crc32(in, in_size, 0) != unaligned_read32le(in + in_size)) 63207753Smm return LZMA_DATA_ERROR; 64207753Smm 65207753Smm // Check for unsupported flags. 66207753Smm if (in[1] & 0x3C) 67207753Smm return LZMA_OPTIONS_ERROR; 68207753Smm 69207753Smm // Start after the Block Header Size and Block Flags fields. 70207753Smm size_t in_pos = 2; 71207753Smm 72207753Smm // Compressed Size 73207753Smm if (in[1] & 0x40) { 74207753Smm return_if_error(lzma_vli_decode(&block->compressed_size, 75207753Smm NULL, in, &in_pos, in_size)); 76207753Smm 77207753Smm // Validate Compressed Size. This checks that it isn't zero 78207753Smm // and that the total size of the Block is a valid VLI. 79207753Smm if (lzma_block_unpadded_size(block) == 0) 80207753Smm return LZMA_DATA_ERROR; 81207753Smm } else { 82207753Smm block->compressed_size = LZMA_VLI_UNKNOWN; 83207753Smm } 84207753Smm 85207753Smm // Uncompressed Size 86207753Smm if (in[1] & 0x80) 87207753Smm return_if_error(lzma_vli_decode(&block->uncompressed_size, 88207753Smm NULL, in, &in_pos, in_size)); 89207753Smm else 90207753Smm block->uncompressed_size = LZMA_VLI_UNKNOWN; 91207753Smm 92207753Smm // Filter Flags 93207753Smm const size_t filter_count = (in[1] & 3) + 1; 94207753Smm for (size_t i = 0; i < filter_count; ++i) { 95207753Smm const lzma_ret ret = lzma_filter_flags_decode( 96207753Smm &block->filters[i], allocator, 97207753Smm in, &in_pos, in_size); 98207753Smm if (ret != LZMA_OK) { 99207753Smm free_properties(block, allocator); 100207753Smm return ret; 101207753Smm } 102207753Smm } 103207753Smm 104207753Smm // Padding 105207753Smm while (in_pos < in_size) { 106207753Smm if (in[in_pos++] != 0x00) { 107207753Smm free_properties(block, allocator); 108207753Smm 109207753Smm // Possibly some new field present so use 110207753Smm // LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR. 111207753Smm return LZMA_OPTIONS_ERROR; 112207753Smm } 113207753Smm } 114207753Smm 115207753Smm return LZMA_OK; 116207753Smm} 117