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
91 != LZMA_VLI_VALUE_UNKNOWN)
92 coder->buffer[coder->buffer_size] |= 0x01;
94 if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
95 coder->buffer[coder->buffer_size] |= 0x02;
97 if (coder->metadata.uncompressed_size
98 != LZMA_VLI_VALUE_UNKNOWN)
99 coder->buffer[coder->buffer_size] |= 0x04;
101 if (coder->index_count > 0)
102 coder->buffer[coder->buffer_size] |= 0x08;
104 if (coder->metadata.extra != NULL)
105 coder->buffer[coder->buffer_size] |= 0x80;
107 ++coder->buffer_size;
108 coder->sequence = SEQ_HEADER_METADATA_SIZE;
111 case SEQ_HEADER_METADATA_SIZE:
112 if (coder->metadata.header_metadata_size
113 != LZMA_VLI_VALUE_UNKNOWN)
114 write_vli(coder->metadata.header_metadata_size);
116 coder->sequence = SEQ_TOTAL_SIZE;
120 if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
121 write_vli(coder->metadata.total_size);
123 coder->sequence = SEQ_UNCOMPRESSED_SIZE;
126 case SEQ_UNCOMPRESSED_SIZE:
127 if (coder->metadata.uncompressed_size
128 != LZMA_VLI_VALUE_UNKNOWN)
129 write_vli(coder->metadata.uncompressed_size);
131 coder->sequence = SEQ_INDEX_COUNT;
134 case SEQ_INDEX_COUNT:
135 if (coder->index_count == 0) {
136 if (coder->metadata.extra == NULL) {
137 coder->sequence = SEQ_END;
138 return LZMA_STREAM_END;
141 coder->sequence = SEQ_EXTRA_ID;
145 write_vli(coder->index_count);
146 coder->sequence = SEQ_INDEX_TOTAL;
149 case SEQ_INDEX_TOTAL:
150 write_vli(coder->index_current->total_size);
152 coder->index_current = coder->index_current->next;
153 if (coder->index_current == NULL) {
154 coder->index_current = coder->metadata.index;
155 coder->sequence = SEQ_INDEX_UNCOMPRESSED;
160 case SEQ_INDEX_UNCOMPRESSED:
161 write_vli(coder->index_current->uncompressed_size);
163 coder->index_current = coder->index_current->next;
164 if (coder->index_current != NULL)
167 if (coder->metadata.extra != NULL) {
168 coder->sequence = SEQ_EXTRA_ID;
172 coder->sequence = SEQ_END;
173 return LZMA_STREAM_END;
176 const lzma_ret ret = lzma_vli_encode(
177 coder->metadata.extra->id, &coder->pos, 1,
178 coder->buffer, &coder->buffer_size,
184 case LZMA_STREAM_END:
187 // Handle the special ID 0.
188 if (coder->metadata.extra->id == 0) {
189 coder->metadata.extra
190 = coder->metadata.extra->next;
191 if (coder->metadata.extra == NULL) {
192 coder->sequence = SEQ_END;
193 return LZMA_STREAM_END;
196 coder->sequence = SEQ_EXTRA_ID;
199 coder->sequence = SEQ_EXTRA_SIZE;
212 if (coder->metadata.extra->size >= (lzma_vli)(SIZE_MAX))
213 return LZMA_HEADER_ERROR;
215 write_vli(coder->metadata.extra->size);
216 coder->sequence = SEQ_EXTRA_DATA;
220 bufcpy(coder->metadata.extra->data, &coder->pos,
221 coder->metadata.extra->size,
222 coder->buffer, &coder->buffer_size,
225 if ((size_t)(coder->metadata.extra->size) == coder->pos) {
226 coder->metadata.extra = coder->metadata.extra->next;
227 if (coder->metadata.extra == NULL) {
228 coder->sequence = SEQ_END;
229 return LZMA_STREAM_END;
233 coder->sequence = SEQ_EXTRA_ID;
239 // Everything is encoded. Let the compression code finish
241 return LZMA_STREAM_END;
249 metadata_encode(lzma_coder *coder, lzma_allocator *allocator,
250 const uint8_t *restrict in lzma_attribute((unused)),
251 size_t *restrict in_pos lzma_attribute((unused)),
252 size_t in_size lzma_attribute((unused)), uint8_t *restrict out,
253 size_t *restrict out_pos, size_t out_size,
254 lzma_action action lzma_attribute((unused)))
256 while (!coder->end_was_reached) {
257 // Flush coder->buffer if it isn't empty.
258 if (coder->buffer_size > 0) {
259 const lzma_ret ret = coder->block_encoder.code(
260 coder->block_encoder.coder, allocator,
261 coder->buffer, &coder->buffer_pos,
263 out, out_pos, out_size, LZMA_RUN);
264 if (coder->buffer_pos < coder->buffer_size
268 coder->buffer_pos = 0;
269 coder->buffer_size = 0;
272 const lzma_ret ret = process(coder);
278 case LZMA_STREAM_END:
279 coder->end_was_reached = true;
288 return coder->block_encoder.code(coder->block_encoder.coder, allocator,
289 coder->buffer, &coder->buffer_pos, coder->buffer_size,
290 out, out_pos, out_size, LZMA_FINISH);
295 metadata_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
297 lzma_next_coder_end(&coder->block_encoder, allocator);
298 lzma_free(coder, allocator);
304 metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
305 lzma_options_block *options, const lzma_metadata *metadata)
307 if (options == NULL || metadata == NULL)
308 return LZMA_PROG_ERROR;
310 if (next->coder == NULL) {
311 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
312 if (next->coder == NULL)
313 return LZMA_MEM_ERROR;
315 next->code = &metadata_encode;
316 next->end = &metadata_encoder_end;
317 next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
320 next->coder->sequence = SEQ_FLAGS;
321 next->coder->pos = 0;
322 next->coder->metadata = *metadata;
323 next->coder->index_count = 0;
324 next->coder->index_current = metadata->index;
325 next->coder->end_was_reached = false;
326 next->coder->buffer_pos = 0;
327 next->coder->buffer_size = 0;
329 // Count and validate the Index Records.
331 const lzma_index *i = metadata->index;
333 if (i->total_size > LZMA_VLI_VALUE_MAX
334 || i->uncompressed_size
335 > LZMA_VLI_VALUE_MAX)
336 return LZMA_PROG_ERROR;
338 ++next->coder->index_count;
343 // Initialize the Block encoder.
344 return lzma_block_encoder_init(
345 &next->coder->block_encoder, allocator, options);
350 lzma_metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
351 lzma_options_block *options, const lzma_metadata *metadata)
353 lzma_next_coder_init(metadata_encoder_init, next, allocator,
358 extern LZMA_API lzma_ret
359 lzma_metadata_encoder(lzma_stream *strm, lzma_options_block *options,
360 const lzma_metadata *metadata)
362 lzma_next_strm_init(strm, metadata_encoder_init, options, metadata);
364 strm->internal->supported_actions[LZMA_FINISH] = true;
370 extern LZMA_API lzma_vli
371 lzma_metadata_size(const lzma_metadata *metadata)
373 lzma_vli size = 1; // Metadata Flags
375 // Validate header_metadata_size, total_size, and uncompressed_size.
376 if (!lzma_vli_is_valid(metadata->header_metadata_size)
377 || !lzma_vli_is_valid(metadata->total_size)
378 || !lzma_vli_is_valid(metadata->uncompressed_size))
381 // Add the sizes of these three fields.
382 if (metadata->header_metadata_size != LZMA_VLI_VALUE_UNKNOWN)
383 size += lzma_vli_size(metadata->header_metadata_size);
385 if (metadata->total_size != LZMA_VLI_VALUE_UNKNOWN)
386 size += lzma_vli_size(metadata->total_size);
388 if (metadata->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
389 size += lzma_vli_size(metadata->uncompressed_size);
392 if (metadata->index != NULL) {
393 const lzma_index *i = metadata->index;
397 const size_t x = lzma_vli_size(i->total_size);
398 const size_t y = lzma_vli_size(i->uncompressed_size);
399 if (x == 0 || y == 0)
408 const size_t tmp = lzma_vli_size(count);
417 const lzma_extra *e = metadata->extra;
419 // Validate the numbers.
420 if (e->id > LZMA_VLI_VALUE_MAX
421 || e->size >= (lzma_vli)(SIZE_MAX))
425 size += lzma_vli_size(e->id);
427 size += lzma_vli_size(e->size);