]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/stream_encoder_single.c
Imported to git.
[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                 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                 ret = lzma_stream_tail_encode(
87                                 coder->header, &coder->stream_flags);
88                 if (ret != LZMA_OK)
89                         return ret;
90
91                 coder->sequence = SEQ_FOOTER;
92                 break;
93         }
94
95         case SEQ_FOOTER:
96                 bufcpy(coder->header, &coder->header_pos, coder->header_size,
97                                 out, out_pos, out_size);
98
99                 return coder->header_pos == coder->header_size
100                                 ? LZMA_STREAM_END : LZMA_OK;
101
102         default:
103                 return LZMA_PROG_ERROR;
104         }
105
106         return LZMA_OK;
107 }
108
109
110 static void
111 stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
112 {
113         lzma_next_coder_end(&coder->block_encoder, allocator);
114         lzma_free(coder->header, allocator);
115         lzma_free(coder, allocator);
116         return;
117 }
118
119
120 static lzma_ret
121 stream_encoder_init(lzma_next_coder *next,
122                 lzma_allocator *allocator, const lzma_options_stream *options)
123 {
124         if (options == NULL)
125                 return LZMA_PROG_ERROR;
126
127         if (next->coder == NULL) {
128                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
129                 if (next->coder == NULL)
130                         return LZMA_MEM_ERROR;
131
132                 next->code = &stream_encode;
133                 next->end = &stream_encoder_end;
134                 next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
135         } else {
136                 // Free the previous buffer, if any.
137                 lzma_free(next->coder->header, allocator);
138         }
139
140         // At this point, next->coder->header points to nothing useful.
141         next->coder->header = NULL;
142
143         // Basic initializations
144         next->coder->sequence = SEQ_HEADERS;
145         next->coder->header_pos = 0;
146
147         // Initialize next->coder->stream_flags.
148         next->coder->stream_flags = (lzma_stream_flags){
149                 .check = options->check,
150                 .has_crc32 = options->has_crc32,
151                 .is_multi = false,
152         };
153
154         // Initialize next->coder->block_options.
155         next->coder->block_options = (lzma_options_block){
156                 .check = options->check,
157                 .has_crc32 = options->has_crc32,
158                 .has_eopm = options->uncompressed_size
159                                 == LZMA_VLI_VALUE_UNKNOWN,
160                 .is_metadata = false,
161                 .has_uncompressed_size_in_footer = options->uncompressed_size
162                                 == LZMA_VLI_VALUE_UNKNOWN,
163                 .has_backward_size = true,
164                 .handle_padding = false,
165                 .compressed_size = LZMA_VLI_VALUE_UNKNOWN,
166                 .uncompressed_size = options->uncompressed_size,
167                 .compressed_reserve = 0,
168                 .uncompressed_reserve = 0,
169                 .total_size = LZMA_VLI_VALUE_UNKNOWN,
170                 .total_limit = LZMA_VLI_VALUE_UNKNOWN,
171                 .uncompressed_limit = LZMA_VLI_VALUE_UNKNOWN,
172                 .padding = LZMA_BLOCK_HEADER_PADDING_AUTO,
173                 .alignment = options->alignment + LZMA_STREAM_HEADER_SIZE,
174         };
175         memcpy(next->coder->block_options.filters, options->filters,
176                                 sizeof(options->filters));
177
178         return_if_error(lzma_block_header_size(&next->coder->block_options));
179
180         // Encode Stream Flags and Block Header into next->coder->header.
181         next->coder->header_size = (size_t)(LZMA_STREAM_HEADER_SIZE)
182                         + next->coder->block_options.header_size;
183         next->coder->header = lzma_alloc(next->coder->header_size, allocator);
184         if (next->coder->header == NULL)
185                 return LZMA_MEM_ERROR;
186
187         return_if_error(lzma_stream_header_encode(next->coder->header,
188                         &next->coder->stream_flags));
189
190         return_if_error(lzma_block_header_encode(
191                         next->coder->header + LZMA_STREAM_HEADER_SIZE,
192                         &next->coder->block_options));
193
194         // Initialize the Block encoder.
195         return lzma_block_encoder_init(&next->coder->block_encoder, allocator,
196                         &next->coder->block_options);
197 }
198
199
200 /*
201 extern lzma_ret
202 lzma_stream_encoder_single_init(lzma_next_coder *next,
203                 lzma_allocator *allocator, const lzma_options_stream *options)
204 {
205         lzma_next_coder_init(stream_encoder_init, allocator, options);
206 }
207 */
208
209
210 extern LZMA_API lzma_ret
211 lzma_stream_encoder_single(
212                 lzma_stream *strm, const lzma_options_stream *options)
213 {
214         lzma_next_strm_init(strm, stream_encoder_init, options);
215
216         strm->internal->supported_actions[LZMA_RUN] = true;
217         strm->internal->supported_actions[LZMA_FINISH] = true;
218
219         return LZMA_OK;
220 }