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