1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file metadata_encoder.c
4 /// \brief Encodes metadata to be stored into Metadata Blocks
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 ///////////////////////////////////////////////////////////////////////////////
20 #include "metadata_encoder.h"
21 #include "block_encoder.h"
27 SEQ_HEADER_METADATA_SIZE,
29 SEQ_UNCOMPRESSED_SIZE,
32 SEQ_INDEX_UNCOMPRESSED,
39 /// Position in variable-length integers
42 /// Local copy of the Metadata structure. Note that we keep
43 /// a copy only of the main structure, not Index or Extra Records.
44 lzma_metadata metadata;
46 /// Number of Records in Index
49 /// Index Record currently being processed
50 const lzma_index *index_current;
52 /// Block encoder for the encoded Metadata
53 lzma_next_coder block_encoder;
55 /// True once everything except compression has been done.
58 /// buffer[buffer_pos] is the first byte that needs to be compressed.
61 /// buffer[buffer_size] is the next position where a byte will be
62 /// written by process().
65 /// Temporary buffer to which encoded Metadata is written before
67 uint8_t buffer[LZMA_BUFFER_SIZE];
71 #define write_vli(num) \
73 const lzma_ret ret = lzma_vli_encode(num, &coder->pos, 1, \
74 coder->buffer, &coder->buffer_size, \
76 if (ret != LZMA_STREAM_END) \
83 process(lzma_coder *coder)
85 while (coder->buffer_size < LZMA_BUFFER_SIZE)
86 switch (coder->sequence) {
88 coder->buffer[coder->buffer_size] = 0;
90 if (coder->metadata.header_metadata_size != 0)
91 coder->buffer[coder->buffer_size] |= 0x01;
93 if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
94 coder->buffer[coder->buffer_size] |= 0x02;
96 if (coder->metadata.uncompressed_size
97 != LZMA_VLI_VALUE_UNKNOWN)
98 coder->buffer[coder->buffer_size] |= 0x04;
100 if (coder->index_count > 0)
101 coder->buffer[coder->buffer_size] |= 0x08;
103 if (coder->metadata.extra != NULL)
104 coder->buffer[coder->buffer_size] |= 0x80;
106 ++coder->buffer_size;
107 coder->sequence = SEQ_HEADER_METADATA_SIZE;
110 case SEQ_HEADER_METADATA_SIZE:
111 if (coder->metadata.header_metadata_size != 0)
112 write_vli(coder->metadata.header_metadata_size);
114 coder->sequence = SEQ_TOTAL_SIZE;
118 if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
119 write_vli(coder->metadata.total_size);
121 coder->sequence = SEQ_UNCOMPRESSED_SIZE;
124 case SEQ_UNCOMPRESSED_SIZE:
125 if (coder->metadata.uncompressed_size
126 != LZMA_VLI_VALUE_UNKNOWN)
127 write_vli(coder->metadata.uncompressed_size);
129 coder->sequence = SEQ_INDEX_COUNT;
132 case SEQ_INDEX_COUNT:
133 if (coder->index_count == 0) {
134 if (coder->metadata.extra == NULL) {
135 coder->sequence = SEQ_END;
136 return LZMA_STREAM_END;
139 coder->sequence = SEQ_EXTRA_ID;
143 write_vli(coder->index_count);
144 coder->sequence = SEQ_INDEX_TOTAL;
147 case SEQ_INDEX_TOTAL:
148 write_vli(coder->index_current->total_size);
150 coder->index_current = coder->index_current->next;
151 if (coder->index_current == NULL) {
152 coder->index_current = coder->metadata.index;
153 coder->sequence = SEQ_INDEX_UNCOMPRESSED;
158 case SEQ_INDEX_UNCOMPRESSED:
159 write_vli(coder->index_current->uncompressed_size);
161 coder->index_current = coder->index_current->next;
162 if (coder->index_current != NULL)
165 if (coder->metadata.extra != NULL) {
166 coder->sequence = SEQ_EXTRA_ID;
170 coder->sequence = SEQ_END;
171 return LZMA_STREAM_END;
174 const lzma_ret ret = lzma_vli_encode(
175 coder->metadata.extra->id, &coder->pos, 1,
176 coder->buffer, &coder->buffer_size,
182 case LZMA_STREAM_END:
185 // Handle the special ID 0.
186 if (coder->metadata.extra->id == 0) {
187 coder->metadata.extra
188 = coder->metadata.extra->next;
189 if (coder->metadata.extra == NULL) {
190 coder->sequence = SEQ_END;
191 return LZMA_STREAM_END;
194 coder->sequence = SEQ_EXTRA_ID;
197 coder->sequence = SEQ_EXTRA_SIZE;
210 if (coder->metadata.extra->size >= (lzma_vli)(SIZE_MAX))
211 return LZMA_HEADER_ERROR;
213 write_vli(coder->metadata.extra->size);
214 coder->sequence = SEQ_EXTRA_DATA;
218 bufcpy(coder->metadata.extra->data, &coder->pos,
219 coder->metadata.extra->size,
220 coder->buffer, &coder->buffer_size,
223 if ((size_t)(coder->metadata.extra->size) == coder->pos) {
224 coder->metadata.extra = coder->metadata.extra->next;
225 if (coder->metadata.extra == NULL) {
226 coder->sequence = SEQ_END;
227 return LZMA_STREAM_END;
231 coder->sequence = SEQ_EXTRA_ID;
237 // Everything is encoded. Let the compression code finish
239 return LZMA_STREAM_END;
247 metadata_encode(lzma_coder *coder, lzma_allocator *allocator,
248 const uint8_t *restrict in lzma_attribute((unused)),
249 size_t *restrict in_pos lzma_attribute((unused)),
250 size_t in_size lzma_attribute((unused)), uint8_t *restrict out,
251 size_t *restrict out_pos, size_t out_size,
252 lzma_action action lzma_attribute((unused)))
254 while (!coder->end_was_reached) {
255 // Flush coder->buffer if it isn't empty.
256 if (coder->buffer_size > 0) {
257 const lzma_ret ret = coder->block_encoder.code(
258 coder->block_encoder.coder, allocator,
259 coder->buffer, &coder->buffer_pos,
261 out, out_pos, out_size, LZMA_RUN);
262 if (coder->buffer_pos < coder->buffer_size
266 coder->buffer_pos = 0;
267 coder->buffer_size = 0;
270 const lzma_ret ret = process(coder);
276 case LZMA_STREAM_END:
277 coder->end_was_reached = true;
286 return coder->block_encoder.code(coder->block_encoder.coder, allocator,
287 coder->buffer, &coder->buffer_pos, coder->buffer_size,
288 out, out_pos, out_size, LZMA_FINISH);
293 metadata_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
295 lzma_next_coder_end(&coder->block_encoder, allocator);
296 lzma_free(coder, allocator);
302 metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
303 lzma_options_block *options, const lzma_metadata *metadata)
305 if (options == NULL || metadata == NULL)
306 return LZMA_PROG_ERROR;
308 if (next->coder == NULL) {
309 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
310 if (next->coder == NULL)
311 return LZMA_MEM_ERROR;
313 next->code = &metadata_encode;
314 next->end = &metadata_encoder_end;
315 next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
318 next->coder->sequence = SEQ_FLAGS;
319 next->coder->pos = 0;
320 next->coder->metadata = *metadata;
321 next->coder->index_count = 0;
322 next->coder->index_current = metadata->index;
323 next->coder->end_was_reached = false;
324 next->coder->buffer_pos = 0;
325 next->coder->buffer_size = 0;
327 // Count and validate the Index Records.
329 const lzma_index *i = metadata->index;
331 if (i->total_size > LZMA_VLI_VALUE_MAX
332 || i->uncompressed_size
333 > LZMA_VLI_VALUE_MAX)
334 return LZMA_PROG_ERROR;
336 ++next->coder->index_count;
341 // Initialize the Block encoder.
342 return lzma_block_encoder_init(
343 &next->coder->block_encoder, allocator, options);
348 lzma_metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
349 lzma_options_block *options, const lzma_metadata *metadata)
351 lzma_next_coder_init(metadata_encoder_init, next, allocator,
356 extern LZMA_API lzma_ret
357 lzma_metadata_encoder(lzma_stream *strm, lzma_options_block *options,
358 const lzma_metadata *metadata)
360 lzma_next_strm_init(strm, metadata_encoder_init, options, metadata);
362 strm->internal->supported_actions[LZMA_FINISH] = true;
368 extern LZMA_API lzma_vli
369 lzma_metadata_size(const lzma_metadata *metadata)
371 lzma_vli size = 1; // Metadata Flags
373 // Validate header_metadata_size, total_size, and uncompressed_size.
374 if (metadata->header_metadata_size > LZMA_VLI_VALUE_MAX
375 || !lzma_vli_is_valid(metadata->total_size)
376 || metadata->total_size == 0
377 || !lzma_vli_is_valid(metadata->uncompressed_size))
380 // Add the sizes of these three fields.
381 if (metadata->header_metadata_size != 0)
382 size += lzma_vli_size(metadata->header_metadata_size);
384 if (metadata->total_size != LZMA_VLI_VALUE_UNKNOWN)
385 size += lzma_vli_size(metadata->total_size);
387 if (metadata->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
388 size += lzma_vli_size(metadata->uncompressed_size);
391 if (metadata->index != NULL) {
392 const lzma_index *i = metadata->index;
396 const size_t x = lzma_vli_size(i->total_size);
397 const size_t y = lzma_vli_size(i->uncompressed_size);
398 if (x == 0 || y == 0)
407 const size_t tmp = lzma_vli_size(count);
416 const lzma_extra *e = metadata->extra;
418 // Validate the numbers.
419 if (e->id > LZMA_VLI_VALUE_MAX
420 || e->size >= (lzma_vli)(SIZE_MAX))
424 size += lzma_vli_size(e->id);
426 size += lzma_vli_size(e->size);