xref: /freebsd/contrib/xz/src/liblzma/common/index_encoder.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
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 typedef struct {
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 } lzma_index_coder;
41 
42 
43 static lzma_ret
44 index_encode(void *coder_ptr,
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 	lzma_index_coder *coder = coder_ptr;
54 
55 	// Position where to start calculating CRC32. The idea is that we
56 	// need to call lzma_crc32() only once per call to index_encode().
57 	const size_t out_start = *out_pos;
58 
59 	// Return value to use if we return at the end of this function.
60 	// We use "goto out" to jump out of the while-switch construct
61 	// instead of returning directly, because that way we don't need
62 	// to copypaste the lzma_crc32() call to many places.
63 	lzma_ret ret = LZMA_OK;
64 
65 	while (*out_pos < out_size)
66 	switch (coder->sequence) {
67 	case SEQ_INDICATOR:
68 		out[*out_pos] = INDEX_INDICATOR;
69 		++*out_pos;
70 		coder->sequence = SEQ_COUNT;
71 		break;
72 
73 	case SEQ_COUNT: {
74 		const lzma_vli count = lzma_index_block_count(coder->index);
75 		ret = lzma_vli_encode(count, &coder->pos,
76 				out, out_pos, out_size);
77 		if (ret != LZMA_STREAM_END)
78 			goto out;
79 
80 		ret = LZMA_OK;
81 		coder->pos = 0;
82 		coder->sequence = SEQ_NEXT;
83 		break;
84 	}
85 
86 	case SEQ_NEXT:
87 		if (lzma_index_iter_next(
88 				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
89 			// Get the size of the Index Padding field.
90 			coder->pos = lzma_index_padding_size(coder->index);
91 			assert(coder->pos <= 3);
92 			coder->sequence = SEQ_PADDING;
93 			break;
94 		}
95 
96 		coder->sequence = SEQ_UNPADDED;
97 
98 	// Fall through
99 
100 	case SEQ_UNPADDED:
101 	case SEQ_UNCOMPRESSED: {
102 		const lzma_vli size = coder->sequence == SEQ_UNPADDED
103 				? coder->iter.block.unpadded_size
104 				: coder->iter.block.uncompressed_size;
105 
106 		ret = lzma_vli_encode(size, &coder->pos,
107 				out, out_pos, out_size);
108 		if (ret != LZMA_STREAM_END)
109 			goto out;
110 
111 		ret = LZMA_OK;
112 		coder->pos = 0;
113 
114 		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
115 		++coder->sequence;
116 		break;
117 	}
118 
119 	case SEQ_PADDING:
120 		if (coder->pos > 0) {
121 			--coder->pos;
122 			out[(*out_pos)++] = 0x00;
123 			break;
124 		}
125 
126 		// Finish the CRC32 calculation.
127 		coder->crc32 = lzma_crc32(out + out_start,
128 				*out_pos - out_start, coder->crc32);
129 
130 		coder->sequence = SEQ_CRC32;
131 
132 	// Fall through
133 
134 	case SEQ_CRC32:
135 		// We don't use the main loop, because we don't want
136 		// coder->crc32 to be touched anymore.
137 		do {
138 			if (*out_pos == out_size)
139 				return LZMA_OK;
140 
141 			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
142 					& 0xFF;
143 			++*out_pos;
144 
145 		} while (++coder->pos < 4);
146 
147 		return LZMA_STREAM_END;
148 
149 	default:
150 		assert(0);
151 		return LZMA_PROG_ERROR;
152 	}
153 
154 out:
155 	// Update the CRC32.
156 	//
157 	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
158 	// In such a case we had no input and thus out_used == 0.
159 	{
160 		const size_t out_used = *out_pos - out_start;
161 		if (out_used > 0)
162 			coder->crc32 = lzma_crc32(out + out_start,
163 					out_used, coder->crc32);
164 	}
165 
166 	return ret;
167 }
168 
169 
170 static void
171 index_encoder_end(void *coder, const lzma_allocator *allocator)
172 {
173 	lzma_free(coder, allocator);
174 	return;
175 }
176 
177 
178 static void
179 index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
180 {
181 	lzma_index_iter_init(&coder->iter, i);
182 
183 	coder->sequence = SEQ_INDICATOR;
184 	coder->index = i;
185 	coder->pos = 0;
186 	coder->crc32 = 0;
187 
188 	return;
189 }
190 
191 
192 extern lzma_ret
193 lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
194 		const lzma_index *i)
195 {
196 	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
197 
198 	if (i == NULL)
199 		return LZMA_PROG_ERROR;
200 
201 	if (next->coder == NULL) {
202 		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
203 		if (next->coder == NULL)
204 			return LZMA_MEM_ERROR;
205 
206 		next->code = &index_encode;
207 		next->end = &index_encoder_end;
208 	}
209 
210 	index_encoder_reset(next->coder, i);
211 
212 	return LZMA_OK;
213 }
214 
215 
216 extern LZMA_API(lzma_ret)
217 lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
218 {
219 	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
220 
221 	strm->internal->supported_actions[LZMA_RUN] = true;
222 	strm->internal->supported_actions[LZMA_FINISH] = true;
223 
224 	return LZMA_OK;
225 }
226 
227 
228 extern LZMA_API(lzma_ret)
229 lzma_index_buffer_encode(const lzma_index *i,
230 		uint8_t *out, size_t *out_pos, size_t out_size)
231 {
232 	// Validate the arguments.
233 	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
234 		return LZMA_PROG_ERROR;
235 
236 	// Don't try to encode if there's not enough output space.
237 	if (out_size - *out_pos < lzma_index_size(i))
238 		return LZMA_BUF_ERROR;
239 
240 	// The Index encoder needs just one small data structure so we can
241 	// allocate it on stack.
242 	lzma_index_coder coder;
243 	index_encoder_reset(&coder, i);
244 
245 	// Do the actual encoding. This should never fail, but store
246 	// the original *out_pos just in case.
247 	const size_t out_start = *out_pos;
248 	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
249 			out, out_pos, out_size, LZMA_RUN);
250 
251 	if (ret == LZMA_STREAM_END) {
252 		ret = LZMA_OK;
253 	} else {
254 		// We should never get here, but just in case, restore the
255 		// output position and set the error accordingly if something
256 		// goes wrong and debugging isn't enabled.
257 		assert(0);
258 		*out_pos = out_start;
259 		ret = LZMA_PROG_ERROR;
260 	}
261 
262 	return ret;
263 }
264