xref: /freebsd/contrib/xz/src/liblzma/common/index_encoder.c (revision 128836d304d93f2d00eb14069c27089ab46c38d4)
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
index_encode(void * coder_ptr,const lzma_allocator * allocator lzma_attribute ((__unused__)),const uint8_t * restrict in lzma_attribute ((__unused__)),size_t * restrict in_pos lzma_attribute ((__unused__)),size_t in_size lzma_attribute ((__unused__)),uint8_t * restrict out,size_t * restrict out_pos,size_t out_size,lzma_action action lzma_attribute ((__unused__)))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 		FALLTHROUGH;
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 		FALLTHROUGH;
130 
131 	case SEQ_CRC32:
132 		// We don't use the main loop, because we don't want
133 		// coder->crc32 to be touched anymore.
134 		do {
135 			if (*out_pos == out_size)
136 				return LZMA_OK;
137 
138 			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
139 					& 0xFF;
140 			++*out_pos;
141 
142 		} while (++coder->pos < 4);
143 
144 		return LZMA_STREAM_END;
145 
146 	default:
147 		assert(0);
148 		return LZMA_PROG_ERROR;
149 	}
150 
151 out:
152 	// Update the CRC32.
153 	//
154 	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
155 	// In such a case we had no input and thus out_used == 0.
156 	{
157 		const size_t out_used = *out_pos - out_start;
158 		if (out_used > 0)
159 			coder->crc32 = lzma_crc32(out + out_start,
160 					out_used, coder->crc32);
161 	}
162 
163 	return ret;
164 }
165 
166 
167 static void
index_encoder_end(void * coder,const lzma_allocator * allocator)168 index_encoder_end(void *coder, const lzma_allocator *allocator)
169 {
170 	lzma_free(coder, allocator);
171 	return;
172 }
173 
174 
175 static void
index_encoder_reset(lzma_index_coder * coder,const lzma_index * i)176 index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
177 {
178 	lzma_index_iter_init(&coder->iter, i);
179 
180 	coder->sequence = SEQ_INDICATOR;
181 	coder->index = i;
182 	coder->pos = 0;
183 	coder->crc32 = 0;
184 
185 	return;
186 }
187 
188 
189 extern lzma_ret
lzma_index_encoder_init(lzma_next_coder * next,const lzma_allocator * allocator,const lzma_index * i)190 lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
191 		const lzma_index *i)
192 {
193 	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
194 
195 	if (i == NULL)
196 		return LZMA_PROG_ERROR;
197 
198 	if (next->coder == NULL) {
199 		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
200 		if (next->coder == NULL)
201 			return LZMA_MEM_ERROR;
202 
203 		next->code = &index_encode;
204 		next->end = &index_encoder_end;
205 	}
206 
207 	index_encoder_reset(next->coder, i);
208 
209 	return LZMA_OK;
210 }
211 
212 
213 extern LZMA_API(lzma_ret)
lzma_index_encoder(lzma_stream * strm,const lzma_index * i)214 lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
215 {
216 	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
217 
218 	strm->internal->supported_actions[LZMA_RUN] = true;
219 	strm->internal->supported_actions[LZMA_FINISH] = true;
220 
221 	return LZMA_OK;
222 }
223 
224 
225 extern LZMA_API(lzma_ret)
lzma_index_buffer_encode(const lzma_index * i,uint8_t * out,size_t * out_pos,size_t out_size)226 lzma_index_buffer_encode(const lzma_index *i,
227 		uint8_t *out, size_t *out_pos, size_t out_size)
228 {
229 	// Validate the arguments.
230 	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
231 		return LZMA_PROG_ERROR;
232 
233 	// Don't try to encode if there's not enough output space.
234 	if (out_size - *out_pos < lzma_index_size(i))
235 		return LZMA_BUF_ERROR;
236 
237 	// The Index encoder needs just one small data structure so we can
238 	// allocate it on stack.
239 	lzma_index_coder coder;
240 	index_encoder_reset(&coder, i);
241 
242 	// Do the actual encoding. This should never fail, but store
243 	// the original *out_pos just in case.
244 	const size_t out_start = *out_pos;
245 	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
246 			out, out_pos, out_size, LZMA_RUN);
247 
248 	if (ret == LZMA_STREAM_END) {
249 		ret = LZMA_OK;
250 	} else {
251 		// We should never get here, but just in case, restore the
252 		// output position and set the error accordingly if something
253 		// goes wrong and debugging isn't enabled.
254 		assert(0);
255 		*out_pos = out_start;
256 		ret = LZMA_PROG_ERROR;
257 	}
258 
259 	return ret;
260 }
261