1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file stream_encoder_single.c
4 /// \brief Encodes Single-Block .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 ///////////////////////////////////////////////////////////////////////////////
20 #include "stream_common.h"
21 #include "block_encoder.h"
25 /// Uncompressed Size, Backward Size, and Footer Magic Bytes are
26 /// part of Block in the file format specification, but it is simpler
27 /// to implement them as part of Stream.
35 lzma_next_coder block_encoder;
37 /// Block encoder options
38 lzma_options_block block_options;
40 /// Stream Flags; we need to have these in this struct so that we
41 /// can encode Stream Footer.
42 lzma_stream_flags stream_flags;
44 /// Stream Header + Block Header, or Stream Footer
52 stream_encode(lzma_coder *coder, lzma_allocator *allocator,
53 const uint8_t *restrict in, size_t *restrict in_pos,
54 size_t in_size, uint8_t *restrict out, size_t *out_pos,
55 size_t out_size, lzma_action action)
57 // NOTE: We don't check if the amount of input is in the proper limits,
58 // because the Block encoder will do it for us.
60 while (*out_pos < out_size)
61 switch (coder->sequence) {
63 bufcpy(coder->header, &coder->header_pos, coder->header_size,
64 out, out_pos, out_size);
66 if (coder->header_pos == coder->header_size) {
67 coder->header_pos = 0;
68 coder->sequence = SEQ_DATA;
74 const lzma_ret ret = coder->block_encoder.code(
75 coder->block_encoder.coder, allocator,
77 out, out_pos, out_size, action);
78 if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
81 assert(*in_pos == in_size);
83 assert(coder->header_size >= LZMA_STREAM_TAIL_SIZE);
84 coder->header_size = LZMA_STREAM_TAIL_SIZE;
86 return_if_error(lzma_stream_tail_encode(
87 coder->header, &coder->stream_flags));
89 coder->sequence = SEQ_FOOTER;
94 bufcpy(coder->header, &coder->header_pos, coder->header_size,
95 out, out_pos, out_size);
97 return coder->header_pos == coder->header_size
98 ? LZMA_STREAM_END : LZMA_OK;
101 return LZMA_PROG_ERROR;
109 stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
111 lzma_next_coder_end(&coder->block_encoder, allocator);
112 lzma_free(coder->header, allocator);
113 lzma_free(coder, allocator);
119 stream_encoder_init(lzma_next_coder *next,
120 lzma_allocator *allocator, const lzma_options_stream *options)
123 return LZMA_PROG_ERROR;
125 if (next->coder == NULL) {
126 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
127 if (next->coder == NULL)
128 return LZMA_MEM_ERROR;
130 next->code = &stream_encode;
131 next->end = &stream_encoder_end;
132 next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
134 // Free the previous buffer, if any.
135 lzma_free(next->coder->header, allocator);
138 // At this point, next->coder->header points to nothing useful.
139 next->coder->header = NULL;
141 // Basic initializations
142 next->coder->sequence = SEQ_HEADERS;
143 next->coder->header_pos = 0;
145 // Initialize next->coder->stream_flags.
146 next->coder->stream_flags = (lzma_stream_flags){
147 .check = options->check,
148 .has_crc32 = options->has_crc32,
152 // Initialize next->coder->block_options.
153 next->coder->block_options = (lzma_options_block){
154 .check = options->check,
155 .has_crc32 = options->has_crc32,
156 .has_eopm = options->uncompressed_size
157 == LZMA_VLI_VALUE_UNKNOWN,
158 .is_metadata = false,
159 .has_uncompressed_size_in_footer = options->uncompressed_size
160 == LZMA_VLI_VALUE_UNKNOWN,
161 .has_backward_size = true,
162 .handle_padding = false,
163 .compressed_size = LZMA_VLI_VALUE_UNKNOWN,
164 .uncompressed_size = options->uncompressed_size,
165 .compressed_reserve = 0,
166 .uncompressed_reserve = 0,
167 .total_size = LZMA_VLI_VALUE_UNKNOWN,
168 .total_limit = LZMA_VLI_VALUE_UNKNOWN,
169 .uncompressed_limit = LZMA_VLI_VALUE_UNKNOWN,
170 .padding = LZMA_BLOCK_HEADER_PADDING_AUTO,
171 .alignment = options->alignment + LZMA_STREAM_HEADER_SIZE,
173 memcpy(next->coder->block_options.filters, options->filters,
174 sizeof(options->filters));
176 return_if_error(lzma_block_header_size(&next->coder->block_options));
178 // Encode Stream Flags and Block Header into next->coder->header.
179 next->coder->header_size = (size_t)(LZMA_STREAM_HEADER_SIZE)
180 + next->coder->block_options.header_size;
181 next->coder->header = lzma_alloc(next->coder->header_size, allocator);
182 if (next->coder->header == NULL)
183 return LZMA_MEM_ERROR;
185 return_if_error(lzma_stream_header_encode(next->coder->header,
186 &next->coder->stream_flags));
188 return_if_error(lzma_block_header_encode(
189 next->coder->header + LZMA_STREAM_HEADER_SIZE,
190 &next->coder->block_options));
192 // Initialize the Block encoder.
193 return lzma_block_encoder_init(&next->coder->block_encoder, allocator,
194 &next->coder->block_options);
200 lzma_stream_encoder_single_init(lzma_next_coder *next,
201 lzma_allocator *allocator, const lzma_options_stream *options)
203 lzma_next_coder_init(stream_encoder_init, allocator, options);
208 extern LZMA_API lzma_ret
209 lzma_stream_encoder_single(
210 lzma_stream *strm, const lzma_options_stream *options)
212 lzma_next_strm_init(strm, stream_encoder_init, options);
214 strm->internal->supported_actions[LZMA_RUN] = true;
215 strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
216 strm->internal->supported_actions[LZMA_FINISH] = true;