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