]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/stream_encoder_single.c
Small LZMA_SYNC_FLUSH fixes to Block and Single-Stream encoders.
[icculus/xz.git] / src / liblzma / common / stream_encoder_single.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       stream_encoder_single.c
4 /// \brief      Encodes Single-Block .lzma files
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
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.
12 //
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.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "stream_common.h"
21 #include "block_encoder.h"
22
23
24 struct lzma_coder_s {
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.
28         enum {
29                 SEQ_HEADERS,
30                 SEQ_DATA,
31                 SEQ_FOOTER,
32         } sequence;
33
34         /// Block encoder
35         lzma_next_coder block_encoder;
36
37         /// Block encoder options
38         lzma_options_block block_options;
39
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;
43
44         /// Stream Header + Block Header, or Stream Footer
45         uint8_t *header;
46         size_t header_pos;
47         size_t header_size;
48 };
49
50
51 static lzma_ret
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)
56 {
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.
59
60         while (*out_pos < out_size)
61         switch (coder->sequence) {
62         case SEQ_HEADERS:
63                 bufcpy(coder->header, &coder->header_pos, coder->header_size,
64                                 out, out_pos, out_size);
65
66                 if (coder->header_pos == coder->header_size) {
67                         coder->header_pos = 0;
68                         coder->sequence = SEQ_DATA;
69                 }
70
71                 break;
72
73         case SEQ_DATA: {
74                 const lzma_ret ret = coder->block_encoder.code(
75                                 coder->block_encoder.coder, allocator,
76                                 in, in_pos, in_size,
77                                 out, out_pos, out_size, action);
78                 if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
79                         return ret;
80
81                 assert(*in_pos == in_size);
82
83                 assert(coder->header_size >= LZMA_STREAM_TAIL_SIZE);
84                 coder->header_size = LZMA_STREAM_TAIL_SIZE;
85
86                 return_if_error(lzma_stream_tail_encode(
87                                 coder->header, &coder->stream_flags));
88
89                 coder->sequence = SEQ_FOOTER;
90                 break;
91         }
92
93         case SEQ_FOOTER:
94                 bufcpy(coder->header, &coder->header_pos, coder->header_size,
95                                 out, out_pos, out_size);
96
97                 return coder->header_pos == coder->header_size
98                                 ? LZMA_STREAM_END : LZMA_OK;
99
100         default:
101                 return LZMA_PROG_ERROR;
102         }
103
104         return LZMA_OK;
105 }
106
107
108 static void
109 stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
110 {
111         lzma_next_coder_end(&coder->block_encoder, allocator);
112         lzma_free(coder->header, allocator);
113         lzma_free(coder, allocator);
114         return;
115 }
116
117
118 static lzma_ret
119 stream_encoder_init(lzma_next_coder *next,
120                 lzma_allocator *allocator, const lzma_options_stream *options)
121 {
122         if (options == NULL)
123                 return LZMA_PROG_ERROR;
124
125         if (next->coder == NULL) {
126                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
127                 if (next->coder == NULL)
128                         return LZMA_MEM_ERROR;
129
130                 next->code = &stream_encode;
131                 next->end = &stream_encoder_end;
132                 next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
133         } else {
134                 // Free the previous buffer, if any.
135                 lzma_free(next->coder->header, allocator);
136         }
137
138         // At this point, next->coder->header points to nothing useful.
139         next->coder->header = NULL;
140
141         // Basic initializations
142         next->coder->sequence = SEQ_HEADERS;
143         next->coder->header_pos = 0;
144
145         // Initialize next->coder->stream_flags.
146         next->coder->stream_flags = (lzma_stream_flags){
147                 .check = options->check,
148                 .has_crc32 = options->has_crc32,
149                 .is_multi = false,
150         };
151
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,
172         };
173         memcpy(next->coder->block_options.filters, options->filters,
174                                 sizeof(options->filters));
175
176         return_if_error(lzma_block_header_size(&next->coder->block_options));
177
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;
184
185         return_if_error(lzma_stream_header_encode(next->coder->header,
186                         &next->coder->stream_flags));
187
188         return_if_error(lzma_block_header_encode(
189                         next->coder->header + LZMA_STREAM_HEADER_SIZE,
190                         &next->coder->block_options));
191
192         // Initialize the Block encoder.
193         return lzma_block_encoder_init(&next->coder->block_encoder, allocator,
194                         &next->coder->block_options);
195 }
196
197
198 /*
199 extern lzma_ret
200 lzma_stream_encoder_single_init(lzma_next_coder *next,
201                 lzma_allocator *allocator, const lzma_options_stream *options)
202 {
203         lzma_next_coder_init(stream_encoder_init, allocator, options);
204 }
205 */
206
207
208 extern LZMA_API lzma_ret
209 lzma_stream_encoder_single(
210                 lzma_stream *strm, const lzma_options_stream *options)
211 {
212         lzma_next_strm_init(strm, stream_encoder_init, options);
213
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;
217
218         return LZMA_OK;
219 }