]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_encoder.c
Beta was supposed to be API stable but I had forgot to rename
[icculus/xz.git] / src / liblzma / common / block_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_encoder.c
4 /// \brief      Encodes .xz Blocks
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 "block_encoder.h"
21 #include "filter_encoder.h"
22 #include "check.h"
23
24
25 /// The maximum size of a single Block is limited by the maximum size of
26 /// a Stream, which is 2^63 - 1 bytes (i.e. LZMA_VLI_MAX). We could
27 /// take into account the headers etc. to determine the exact maximum size
28 /// of the Compressed Data field, but the complexity would give us nothing
29 /// useful. Instead, limit the size of Compressed Data so that even with
30 /// biggest possible Block Header and Check fields the total encoded size of
31 /// the Block stays as valid VLI. This way we don't produce incorrect output
32 /// if someone will really try creating a Block of 8 EiB.
33 ///
34 /// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
35 /// the Compressed Data field, it will still stay in the proper limit.
36 #define COMPRESSED_SIZE_MAX ((LZMA_VLI_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
37                 - LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
38
39
40 struct lzma_coder_s {
41         /// The filters in the chain; initialized with lzma_raw_decoder_init().
42         lzma_next_coder next;
43
44         /// Encoding options; we also write Unpadded Size, Compressed Size,
45         /// and Uncompressed Size back to this structure when the encoding
46         /// has been finished.
47         lzma_block *block;
48
49         enum {
50                 SEQ_CODE,
51                 SEQ_PADDING,
52                 SEQ_CHECK,
53         } sequence;
54
55         /// Compressed Size calculated while encoding
56         lzma_vli compressed_size;
57
58         /// Uncompressed Size calculated while encoding
59         lzma_vli uncompressed_size;
60
61         /// Position in Block Padding and the Check fields
62         size_t pos;
63
64         /// Check of the uncompressed data
65         lzma_check_state check;
66 };
67
68
69 static lzma_ret
70 block_encode(lzma_coder *coder, lzma_allocator *allocator,
71                 const uint8_t *restrict in, size_t *restrict in_pos,
72                 size_t in_size, uint8_t *restrict out,
73                 size_t *restrict out_pos, size_t out_size, lzma_action action)
74 {
75         // Check that our amount of input stays in proper limits.
76         if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
77                 return LZMA_PROG_ERROR;
78
79         switch (coder->sequence) {
80         case SEQ_CODE: {
81                 const size_t in_start = *in_pos;
82                 const size_t out_start = *out_pos;
83
84                 const lzma_ret ret = coder->next.code(coder->next.coder,
85                                 allocator, in, in_pos, in_size,
86                                 out, out_pos, out_size, action);
87
88                 const size_t in_used = *in_pos - in_start;
89                 const size_t out_used = *out_pos - out_start;
90
91                 if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
92                         return LZMA_DATA_ERROR;
93
94                 coder->compressed_size += out_used;
95
96                 // No need to check for overflow because we have already
97                 // checked it at the beginning of this function.
98                 coder->uncompressed_size += in_used;
99
100                 lzma_check_update(&coder->check, coder->block->check,
101                                 in + in_start, in_used);
102
103                 if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
104                         return ret;
105
106                 assert(*in_pos == in_size);
107                 assert(action == LZMA_FINISH);
108
109                 // Copy the values into coder->block. The caller
110                 // may use this information to construct Index.
111                 coder->block->compressed_size = coder->compressed_size;
112                 coder->block->uncompressed_size = coder->uncompressed_size;
113
114                 coder->sequence = SEQ_PADDING;
115         }
116
117         // Fall through
118
119         case SEQ_PADDING:
120                 // Pad Compressed Data to a multiple of four bytes.
121                 while ((coder->compressed_size + coder->pos) & 3) {
122                         if (*out_pos >= out_size)
123                                 return LZMA_OK;
124
125                         out[*out_pos] = 0x00;
126                         ++*out_pos;
127                         ++coder->pos;
128                 }
129
130                 if (coder->block->check == LZMA_CHECK_NONE)
131                         return LZMA_STREAM_END;
132
133                 lzma_check_finish(&coder->check, coder->block->check);
134
135                 coder->pos = 0;
136                 coder->sequence = SEQ_CHECK;
137
138         // Fall through
139
140         case SEQ_CHECK: {
141                 const uint32_t check_size
142                                 = lzma_check_size(coder->block->check);
143
144                 while (*out_pos < out_size) {
145                         out[*out_pos] = coder->check.buffer.u8[coder->pos];
146                         ++*out_pos;
147
148                         if (++coder->pos == check_size)
149                                 return LZMA_STREAM_END;
150                 }
151
152                 return LZMA_OK;
153         }
154         }
155
156         return LZMA_PROG_ERROR;
157 }
158
159
160 static void
161 block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
162 {
163         lzma_next_end(&coder->next, allocator);
164         lzma_free(coder, allocator);
165         return;
166 }
167
168
169 extern lzma_ret
170 lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
171                 lzma_block *block)
172 {
173         lzma_next_coder_init(lzma_block_encoder_init, next, allocator);
174
175         if (block->version != 0)
176                 return LZMA_OPTIONS_ERROR;
177
178         // If the Check ID is not supported, we cannot calculate the check and
179         // thus not create a proper Block.
180         if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
181                 return LZMA_PROG_ERROR;
182
183         if (!lzma_check_is_supported(block->check))
184                 return LZMA_UNSUPPORTED_CHECK;
185
186         // Allocate and initialize *next->coder if needed.
187         if (next->coder == NULL) {
188                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
189                 if (next->coder == NULL)
190                         return LZMA_MEM_ERROR;
191
192                 next->code = &block_encode;
193                 next->end = &block_encoder_end;
194                 next->coder->next = LZMA_NEXT_CODER_INIT;
195         }
196
197         // Basic initializations
198         next->coder->sequence = SEQ_CODE;
199         next->coder->block = block;
200         next->coder->compressed_size = 0;
201         next->coder->uncompressed_size = 0;
202         next->coder->pos = 0;
203
204         // Initialize the check
205         lzma_check_init(&next->coder->check, block->check);
206
207         // Initialize the requested filters.
208         return lzma_raw_encoder_init(&next->coder->next, allocator,
209                         block->filters);
210 }
211
212
213 extern LZMA_API lzma_ret
214 lzma_block_encoder(lzma_stream *strm, lzma_block *block)
215 {
216         lzma_next_strm_init(lzma_block_encoder_init, strm, block);
217
218         strm->internal->supported_actions[LZMA_RUN] = true;
219         strm->internal->supported_actions[LZMA_FINISH] = true;
220
221         return LZMA_OK;
222 }