]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/index_encoder.c
Add some single-call buffer-to-buffer coding functions.
[icculus/xz.git] / src / liblzma / common / index_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       index_encoder.c
4 /// \brief      Encodes the Index field
5 //
6 //  Copyright (C) 2008 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 "index_encoder.h"
21 #include "index.h"
22 #include "check.h"
23
24
25 struct lzma_coder_s {
26         enum {
27                 SEQ_INDICATOR,
28                 SEQ_COUNT,
29                 SEQ_UNPADDED,
30                 SEQ_UNCOMPRESSED,
31                 SEQ_NEXT,
32                 SEQ_PADDING,
33                 SEQ_CRC32,
34         } sequence;
35
36         /// Index given to us to encode. Note that we modify it in sense that
37         /// we read it, and read position is tracked in lzma_index structure.
38         lzma_index *index;
39
40         /// The current Index Record being encoded
41         lzma_index_record record;
42
43         /// Position in integers
44         size_t pos;
45
46         /// CRC32 of the List of Records field
47         uint32_t crc32;
48 };
49
50
51 static lzma_ret
52 index_encode(lzma_coder *coder,
53                 lzma_allocator *allocator lzma_attribute((unused)),
54                 const uint8_t *restrict in lzma_attribute((unused)),
55                 size_t *restrict in_pos lzma_attribute((unused)),
56                 size_t in_size lzma_attribute((unused)),
57                 uint8_t *restrict out, size_t *restrict out_pos,
58                 size_t out_size, lzma_action action lzma_attribute((unused)))
59 {
60         // Position where to start calculating CRC32. The idea is that we
61         // need to call lzma_crc32() only once per call to index_encode().
62         const size_t out_start = *out_pos;
63
64         // Return value to use if we return at the end of this function.
65         // We use "goto out" to jump out of the while-switch construct
66         // instead of returning directly, because that way we don't need
67         // to copypaste the lzma_crc32() call to many places.
68         lzma_ret ret = LZMA_OK;
69
70         while (*out_pos < out_size)
71         switch (coder->sequence) {
72         case SEQ_INDICATOR:
73                 out[*out_pos] = 0x00;
74                 ++*out_pos;
75                 coder->sequence = SEQ_COUNT;
76                 break;
77
78         case SEQ_COUNT: {
79                 const lzma_vli index_count = lzma_index_count(coder->index);
80                 ret = lzma_vli_encode(index_count, &coder->pos,
81                                 out, out_pos, out_size);
82                 if (ret != LZMA_STREAM_END)
83                         goto out;
84
85                 ret = LZMA_OK;
86                 coder->pos = 0;
87                 coder->sequence = SEQ_NEXT;
88                 break;
89         }
90
91         case SEQ_NEXT:
92                 if (lzma_index_read(coder->index, &coder->record)) {
93                         // Get the size of the Index Padding field.
94                         coder->pos = lzma_index_padding_size(coder->index);
95                         assert(coder->pos <= 3);
96                         coder->sequence = SEQ_PADDING;
97                         break;
98                 }
99
100                 // Unpadded Size must be within valid limits.
101                 if (coder->record.unpadded_size < UNPADDED_SIZE_MIN
102                                 || coder->record.unpadded_size
103                                         > UNPADDED_SIZE_MAX)
104                         return LZMA_PROG_ERROR;
105
106                 coder->sequence = SEQ_UNPADDED;
107
108         // Fall through
109
110         case SEQ_UNPADDED:
111         case SEQ_UNCOMPRESSED: {
112                 const lzma_vli size = coder->sequence == SEQ_UNPADDED
113                                 ? coder->record.unpadded_size
114                                 : coder->record.uncompressed_size;
115
116                 ret = lzma_vli_encode(size, &coder->pos,
117                                 out, out_pos, out_size);
118                 if (ret != LZMA_STREAM_END)
119                         goto out;
120
121                 ret = LZMA_OK;
122                 coder->pos = 0;
123
124                 // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
125                 ++coder->sequence;
126                 break;
127         }
128
129         case SEQ_PADDING:
130                 if (coder->pos > 0) {
131                         --coder->pos;
132                         out[(*out_pos)++] = 0x00;
133                         break;
134                 }
135
136                 // Finish the CRC32 calculation.
137                 coder->crc32 = lzma_crc32(out + out_start,
138                                 *out_pos - out_start, coder->crc32);
139
140                 coder->sequence = SEQ_CRC32;
141
142         // Fall through
143
144         case SEQ_CRC32:
145                 // We don't use the main loop, because we don't want
146                 // coder->crc32 to be touched anymore.
147                 do {
148                         if (*out_pos == out_size)
149                                 return LZMA_OK;
150
151                         out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
152                                         & 0xFF;
153                         ++*out_pos;
154
155                 } while (++coder->pos < 4);
156
157                 return LZMA_STREAM_END;
158
159         default:
160                 assert(0);
161                 return LZMA_PROG_ERROR;
162         }
163
164 out:
165         // Update the CRC32.
166         coder->crc32 = lzma_crc32(out + out_start,
167                         *out_pos - out_start, coder->crc32);
168
169         return ret;
170 }
171
172
173 static void
174 index_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
175 {
176         lzma_free(coder, allocator);
177         return;
178 }
179
180
181 static void
182 index_encoder_reset(lzma_coder *coder, lzma_index *i)
183 {
184         lzma_index_rewind(i);
185
186         coder->sequence = SEQ_INDICATOR;
187         coder->index = i;
188         coder->pos = 0;
189         coder->crc32 = 0;
190
191         return;
192 }
193
194
195 extern lzma_ret
196 lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
197                 lzma_index *i)
198 {
199         lzma_next_coder_init(lzma_index_encoder_init, next, allocator);
200
201         if (i == NULL)
202                 return LZMA_PROG_ERROR;
203
204         if (next->coder == NULL) {
205                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
206                 if (next->coder == NULL)
207                         return LZMA_MEM_ERROR;
208
209                 next->code = &index_encode;
210                 next->end = &index_encoder_end;
211         }
212
213         index_encoder_reset(next->coder, i);
214
215         return LZMA_OK;
216 }
217
218
219 extern LZMA_API lzma_ret
220 lzma_index_encoder(lzma_stream *strm, lzma_index *i)
221 {
222         lzma_next_strm_init(lzma_index_encoder_init, strm, i);
223
224         strm->internal->supported_actions[LZMA_RUN] = true;
225
226         return LZMA_OK;
227 }
228
229
230 extern LZMA_API lzma_ret
231 lzma_index_buffer_encode(lzma_index *i,
232                 uint8_t *out, size_t *out_pos, size_t out_size)
233 {
234         // Validate the arugments.
235         if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
236                 return LZMA_PROG_ERROR;
237
238         // Don't try to encode if there's not enough output space.
239         if (out_size - *out_pos < lzma_index_size(i))
240                 return LZMA_BUF_ERROR;
241
242         // The Index encoder needs just one small data structure so we can
243         // allocate it on stack.
244         lzma_coder coder;
245         index_encoder_reset(&coder, i);
246
247         // Do the actual encoding. This should never fail, but store
248         // the original *out_pos just in case.
249         const size_t out_start = *out_pos;
250         lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
251                         out, out_pos, out_size, LZMA_RUN);
252
253         if (ret == LZMA_STREAM_END) {
254                 ret = LZMA_OK;
255         } else {
256                 // We should never get here, but just in case, restore the
257                 // output position and set the error accordingly if something
258                 // goes wrong and debugging isn't enabled.
259                 assert(0);
260                 *out_pos = out_start;
261                 ret = LZMA_PROG_ERROR;
262         }
263
264         return ret;
265 }