]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/index_encoder.c
3005f835d01d1a91165c5b8e057d77a40fd9048a
[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_TOTAL,
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                 // Total Size must be a multiple of four.
101                 if (coder->record.total_size & 3)
102                         return LZMA_PROG_ERROR;
103
104                 coder->sequence = SEQ_TOTAL;
105
106         // Fall through
107
108         case SEQ_TOTAL:
109         case SEQ_UNCOMPRESSED: {
110                 const lzma_vli size = coder->sequence == SEQ_TOTAL
111                                 ? total_size_encode(coder->record.total_size)
112                                 : coder->record.uncompressed_size;
113
114                 ret = lzma_vli_encode(size, &coder->pos,
115                                 out, out_pos, out_size);
116                 if (ret != LZMA_STREAM_END)
117                         goto out;
118
119                 ret = LZMA_OK;
120                 coder->pos = 0;
121
122                 // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
123                 ++coder->sequence;
124                 break;
125         }
126
127         case SEQ_PADDING:
128                 if (coder->pos > 0) {
129                         --coder->pos;
130                         out[(*out_pos)++] = 0x00;
131                         break;
132                 }
133
134                 // Finish the CRC32 calculation.
135                 coder->crc32 = lzma_crc32(out + out_start,
136                                 *out_pos - out_start, coder->crc32);
137
138                 coder->sequence = SEQ_CRC32;
139
140         // Fall through
141
142         case SEQ_CRC32:
143                 // We don't use the main loop, because we don't want
144                 // coder->crc32 to be touched anymore.
145                 do {
146                         if (*out_pos == out_size)
147                                 return LZMA_OK;
148
149                         out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
150                                         & 0xFF;
151                         ++*out_pos;
152
153                 } while (++coder->pos < 4);
154
155                 return LZMA_STREAM_END;
156
157         default:
158                 assert(0);
159                 return LZMA_PROG_ERROR;
160         }
161
162 out:
163         // Update the CRC32.
164         coder->crc32 = lzma_crc32(out + out_start,
165                         *out_pos - out_start, coder->crc32);
166
167         return ret;
168 }
169
170
171 static void
172 index_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
173 {
174         lzma_free(coder, allocator);
175         return;
176 }
177
178
179 extern lzma_ret
180 lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
181                 lzma_index *i)
182 {
183         lzma_next_coder_init(lzma_index_encoder_init, next, allocator);
184
185         if (i == NULL)
186                 return LZMA_PROG_ERROR;
187
188         if (next->coder == NULL) {
189                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
190                 if (next->coder == NULL)
191                         return LZMA_MEM_ERROR;
192
193                 next->code = &index_encode;
194                 next->end = &index_encoder_end;
195         }
196
197         lzma_index_rewind(i);
198
199         next->coder->sequence = SEQ_INDICATOR;
200         next->coder->index = i;
201         next->coder->pos = 0;
202         next->coder->crc32 = 0;
203
204         return LZMA_OK;
205 }
206
207
208 extern LZMA_API lzma_ret
209 lzma_index_encoder(lzma_stream *strm, lzma_index *i)
210 {
211         lzma_next_strm_init(lzma_index_encoder_init, strm, i);
212
213         strm->internal->supported_actions[LZMA_RUN] = true;
214
215         return LZMA_OK;
216 }