1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file block_header_encoder.c
/// \brief Encodes Block Header for .xz files
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "check.h"
extern LZMA_API(lzma_ret)
lzma_block_header_size(lzma_block *block)
{
if (block->version > 1)
return LZMA_OPTIONS_ERROR;
// Block Header Size + Block Flags + CRC32.
uint32_t size = 1 + 1 + 4;
// Compressed Size
if (block->compressed_size != LZMA_VLI_UNKNOWN) {
const uint32_t add = lzma_vli_size(block->compressed_size);
if (add == 0 || block->compressed_size == 0)
return LZMA_PROG_ERROR;
size += add;
}
// Uncompressed Size
if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
const uint32_t add = lzma_vli_size(block->uncompressed_size);
if (add == 0)
return LZMA_PROG_ERROR;
size += add;
}
// List of Filter Flags
if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
return LZMA_PROG_ERROR;
for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
// Don't allow too many filters.
if (i == LZMA_FILTERS_MAX)
return LZMA_PROG_ERROR;
uint32_t add;
return_if_error(lzma_filter_flags_size(&add,
block->filters + i));
size += add;
}
// Pad to a multiple of four bytes.
block->header_size = (size + 3) & ~UINT32_C(3);
// NOTE: We don't verify that the encoded size of the Block stays
// within limits. This is because it is possible that we are called
// with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
// space for Block Header, and later called again with lower,
// real values.
return LZMA_OK;
}
extern LZMA_API(lzma_ret)
lzma_block_header_encode(const lzma_block *block, uint8_t *out)
{
// Validate everything but filters.
if (lzma_block_unpadded_size(block) == 0
|| !lzma_vli_is_valid(block->uncompressed_size))
return LZMA_PROG_ERROR;
// Indicate the size of the buffer _excluding_ the CRC32 field.
const size_t out_size = block->header_size - 4;
// Store the Block Header Size.
out[0] = out_size / 4;
// We write Block Flags in pieces.
out[1] = 0x00;
size_t out_pos = 2;
// Compressed Size
if (block->compressed_size != LZMA_VLI_UNKNOWN) {
return_if_error(lzma_vli_encode(block->compressed_size, NULL,
out, &out_pos, out_size));
out[1] |= 0x40;
}
// Uncompressed Size
if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
out, &out_pos, out_size));
out[1] |= 0x80;
}
// Filter Flags
if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
return LZMA_PROG_ERROR;
size_t filter_count = 0;
do {
// There can be a maximum of four filters.
if (filter_count == LZMA_FILTERS_MAX)
return LZMA_PROG_ERROR;
return_if_error(lzma_filter_flags_encode(
block->filters + filter_count,
out, &out_pos, out_size));
} while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
out[1] |= filter_count - 1;
// Padding
memzero(out + out_pos, out_size - out_pos);
// CRC32
write32le(out + out_size, lzma_crc32(out, out_size, 0));
return LZMA_OK;
}
|