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