1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file block_header_encoder.c
4 /// \brief Encodes Block Header for .lzma files
6 // Copyright (C) 2007 Lasse Collin
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 ///////////////////////////////////////////////////////////////////////////////
24 extern LZMA_API lzma_ret
25 lzma_block_header_size(lzma_options_block *options)
27 // Block Flags take two bytes.
31 if (!lzma_vli_is_valid(options->compressed_size)) {
32 return LZMA_PROG_ERROR;
34 } else if (options->compressed_reserve != 0) {
35 // Make sure that the known Compressed Size fits into the
36 // reserved space. Note that lzma_vli_size() will return zero
37 // if options->compressed_size is LZMA_VLI_VALUE_UNKNOWN, so
38 // we don't need to handle that special case separately.
39 if (options->compressed_reserve > LZMA_VLI_BYTES_MAX
40 || lzma_vli_size(options->compressed_size)
41 > (size_t)(options->compressed_reserve))
42 return LZMA_PROG_ERROR;
44 size += options->compressed_reserve;
46 } else if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
47 // Compressed Size is known. We have already checked
48 // that is is a valid VLI, and since it isn't
49 // LZMA_VLI_VALUE_UNKNOWN, we can be sure that
50 // lzma_vli_size() will succeed.
51 size += lzma_vli_size(options->compressed_size);
55 if (!lzma_vli_is_valid(options->uncompressed_size)) {
56 return LZMA_PROG_ERROR;
58 } else if (options->uncompressed_reserve != 0) {
59 if (options->uncompressed_reserve > LZMA_VLI_BYTES_MAX
60 || lzma_vli_size(options->uncompressed_size)
61 > (size_t)(options->uncompressed_reserve))
62 return LZMA_PROG_ERROR;
64 size += options->uncompressed_reserve;
66 } else if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
67 size += lzma_vli_size(options->uncompressed_size);
70 // List of Filter Flags
71 for (size_t i = 0; options->filters[i].id != LZMA_VLI_VALUE_UNKNOWN;
73 // Don't allow too many filters.
75 return LZMA_PROG_ERROR;
78 const lzma_ret ret = lzma_filter_flags_size(&tmp,
79 options->filters + i);
87 if (options->has_crc32)
92 if (options->padding == LZMA_BLOCK_HEADER_PADDING_AUTO) {
93 const uint32_t preferred = lzma_alignment_output(
95 const uint32_t unaligned = size + options->alignment;
96 padding = (int32_t)(unaligned % preferred);
98 padding = preferred - padding;
99 } else if (options->padding >= LZMA_BLOCK_HEADER_PADDING_MIN
100 && options->padding <= LZMA_BLOCK_HEADER_PADDING_MAX) {
101 padding = options->padding;
103 return LZMA_PROG_ERROR;
106 // All success. Copy the calculated values to the options structure.
107 options->padding = padding;
108 options->header_size = size + (size_t)(padding);
114 extern LZMA_API lzma_ret
115 lzma_block_header_encode(uint8_t *out, const lzma_options_block *options)
117 // We write the Block Flags later.
118 if (options->header_size < 2)
119 return LZMA_PROG_ERROR;
121 const size_t out_size = options->header_size;
125 if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
126 || options->compressed_reserve != 0) {
127 const lzma_vli size = options->compressed_size
128 != LZMA_VLI_VALUE_UNKNOWN
129 ? options->compressed_size : 0;
132 size, &vli_pos, options->compressed_reserve,
133 out, &out_pos, out_size) != LZMA_STREAM_END)
134 return LZMA_PROG_ERROR;
139 if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
140 || options->uncompressed_reserve != 0) {
141 const lzma_vli size = options->uncompressed_size
142 != LZMA_VLI_VALUE_UNKNOWN
143 ? options->uncompressed_size : 0;
146 size, &vli_pos, options->uncompressed_reserve,
147 out, &out_pos, out_size) != LZMA_STREAM_END)
148 return LZMA_PROG_ERROR;
154 for (filter_count = 0; options->filters[filter_count].id
155 != LZMA_VLI_VALUE_UNKNOWN; ++filter_count) {
156 // There can be at maximum of seven filters.
157 if (filter_count == 7)
158 return LZMA_PROG_ERROR;
160 const lzma_ret ret = lzma_filter_flags_encode(out, &out_pos,
161 out_size, options->filters + filter_count);
162 // FIXME: Don't return LZMA_BUF_ERROR.
168 out[0] = filter_count;
170 if (options->has_eopm)
172 else if (options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
173 return LZMA_PROG_ERROR;
175 if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
176 || options->compressed_reserve != 0)
179 if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
180 || options->uncompressed_reserve != 0)
183 if (options->is_metadata)
187 if (options->padding < LZMA_BLOCK_HEADER_PADDING_MIN
188 || options->padding > LZMA_BLOCK_HEADER_PADDING_MAX)
189 return LZMA_PROG_ERROR;
191 out[1] = (uint8_t)(options->padding);
194 if (options->has_crc32) {
195 if (out_size - out_pos < 4)
196 return LZMA_PROG_ERROR;
198 const uint32_t crc = lzma_crc32(out, out_pos, 0);
199 for (size_t i = 0; i < 4; ++i)
200 out[out_pos++] = crc >> (i * 8);
203 // Padding - the amount of available space must now match with
204 // the size of the Padding field.
205 if (out_size - out_pos != (size_t)(options->padding))
206 return LZMA_PROG_ERROR;
208 memzero(out + out_pos, (size_t)(options->padding));