aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/common.h
blob: ca9c2f237d7aaf4ec7fbd34508f83c254aacd1b5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
///////////////////////////////////////////////////////////////////////////////
//
/// \file       common.h
/// \brief      Definitions common to the whole liblzma library
//
//  Copyright (C) 2007 Lasse Collin
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef LZMA_COMMON_H
#define LZMA_COMMON_H

#include "sysdefs.h"

// Don't use ifdef...
#if HAVE_VISIBILITY
#	define LZMA_API __attribute__((__visibility__("default")))
#else
#	define LZMA_API
#endif


/// Size of temporary buffers needed in some filters
#define LZMA_BUFFER_SIZE 4096


/// Internal helper filter used by Subblock decoder. It is mapped to an
/// otherwise invalid Filter ID, which is impossible to get from any input
/// file (even if malicious file).
#define LZMA_FILTER_SUBBLOCK_HELPER (UINT64_MAX - 2)


///////////
// Types //
///////////

typedef struct lzma_coder_s lzma_coder;

typedef struct lzma_next_coder_s lzma_next_coder;

typedef struct lzma_filter_info_s lzma_filter_info;


typedef lzma_ret (*lzma_init_function)(
		lzma_next_coder *next, lzma_allocator *allocator,
		const lzma_filter_info *filters);

typedef lzma_ret (*lzma_code_function)(
		lzma_coder *coder, lzma_allocator *allocator,
		const uint8_t *restrict in, size_t *restrict in_pos,
		size_t in_size, uint8_t *restrict out,
		size_t *restrict out_pos, size_t out_size,
		lzma_action action);

typedef void (*lzma_end_function)(
		lzma_coder *coder, lzma_allocator *allocator);


/// Hold data and function pointers of the next filter in the chain.
struct lzma_next_coder_s {
	/// Pointer to coder-specific data
	lzma_coder *coder;

	/// "Pointer" to init function. This is never called here.
	/// We need only to detect if we are initializing a coder
	/// that was allocated earlier. See code.c and next_coder.c.
	uintptr_t init;

	/// Pointer to function to do the actual coding
	lzma_code_function code;

	/// Pointer to function to free lzma_next_coder.coder
	lzma_end_function end;
};

#define LZMA_NEXT_CODER_INIT \
	(lzma_next_coder){ \
		.coder = NULL, \
		.init = 0, \
		.code = NULL, \
		.end = NULL, \
	}


struct lzma_internal_s {
	lzma_next_coder next;

	enum {
		ISEQ_RUN,
		ISEQ_SYNC_FLUSH,
		ISEQ_FULL_FLUSH,
		ISEQ_FINISH,
		ISEQ_END,
		ISEQ_ERROR,
	} sequence;

	bool supported_actions[4];
	bool allow_buf_error;
	size_t avail_in;
};


struct lzma_filter_info_s {
	/// Pointer to function used to initialize the filter.
	/// This is NULL to indicate end of array.
	lzma_init_function init;

	/// Pointer to filter's options structure
	void *options;

	/// Uncompressed size of the filter, or LZMA_VLI_VALUE_UNKNOWN
	/// if unknown.
	lzma_vli uncompressed_size;
};


/*
typedef struct {
	lzma_init_function init;
	uint32_t (*input_alignment)(lzma_vli id, const void *options);
	uint32_t (*output_alignment)(lzma_vli id, const void *options);
	bool changes_uncompressed_size;
	bool supports_eopm;
} lzma_filter_hook;
*/


///////////////
// Functions //
///////////////

/// Allocates memory
extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
		lzma_attribute((malloc));

/// Frees memory
extern void lzma_free(void *ptr, lzma_allocator *allocator);

/// Initializes lzma_stream FIXME desc
extern lzma_ret lzma_strm_init(lzma_stream *strm);

///
extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
		lzma_allocator *allocator, const lzma_filter_info *filters);

///
extern void lzma_next_coder_end(lzma_next_coder *next,
		lzma_allocator *allocator);


extern lzma_ret lzma_filter_flags_decoder_init(lzma_next_coder *next,
		lzma_allocator *allocator, lzma_options_filter *options);

extern lzma_ret lzma_block_header_decoder_init(lzma_next_coder *next,
		lzma_allocator *allocator, lzma_options_block *options);

extern lzma_ret lzma_stream_encoder_single_init(lzma_next_coder *next,
		lzma_allocator *allocator, const lzma_options_stream *options);

extern lzma_ret lzma_stream_decoder_init(
		lzma_next_coder *next, lzma_allocator *allocator,
		lzma_extra **header, lzma_extra **footer);


/// \brief      Wrapper for memcpy()
///
/// This function copies as much data as possible from in[] to out[] and
/// updates *in_pos and *out_pos accordingly.
///
static inline size_t
bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size,
		uint8_t *restrict out, size_t *restrict out_pos,
		size_t out_size)
{
	const size_t in_avail = in_size - *in_pos;
	const size_t out_avail = out_size - *out_pos;
	const size_t copy_size = MIN(in_avail, out_avail);

	memcpy(out + *out_pos, in + *in_pos, copy_size);

	*in_pos += copy_size;
	*out_pos += copy_size;

	return copy_size;
}


/// \brief      Initializing the next coder
///
/// lzma_next_coder can point to different types of coders. The existing
/// coder may be different than what we are initializing now. In that case
/// we must git rid of the old coder first. Otherwise we reuse the existing
/// coder structure.
///
#define lzma_next_coder_init2(next, allocator, cmpfunc, func, ...) \
do { \
	if ((uintptr_t)(&cmpfunc) != (next)->init) \
		lzma_next_coder_end(next, allocator); \
	const lzma_ret ret = func(next, __VA_ARGS__); \
	if (ret == LZMA_OK) { \
		(next)->init = (uintptr_t)(&cmpfunc); \
		assert((next)->code != NULL); \
		assert((next)->end != NULL); \
	} else { \
		lzma_next_coder_end(next, allocator); \
	} \
	return ret; \
} while (0)

/// \brief      Initializing lzma_next_coder
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_coder_init(func, next, allocator, ...) \
	lzma_next_coder_init2(next, allocator, \
			func, func, allocator, __VA_ARGS__)


/// \brief      Initializing lzma_stream
///
/// lzma_strm initialization with more detailed options.
#define lzma_next_strm_init2(strm, cmpfunc, func, ...) \
do { \
	lzma_ret ret = lzma_strm_init(strm); \
	if (ret != LZMA_OK) \
		return ret; \
	if ((uintptr_t)(&cmpfunc) != (strm)->internal->next.init) \
		lzma_next_coder_end(\
				&(strm)->internal->next, (strm)->allocator); \
	ret = func(&(strm)->internal->next, __VA_ARGS__); \
	if (ret != LZMA_OK) { \
		lzma_end(strm); \
		return ret; \
	} \
	(strm)->internal->next.init = (uintptr_t)(&cmpfunc); \
	assert((strm)->internal->next.code != NULL); \
	assert((strm)->internal->next.end != NULL); \
} while (0)

/// \brief      Initializing lzma_stream
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_strm_init(strm, func, ...) \
	lzma_next_strm_init2(strm, func, func, (strm)->allocator, __VA_ARGS__)


/// \brief      Return if expression doesn't evaluate to LZMA_OK
///
/// There are several situations where we want to return immediatelly
/// with the value of expr if it isn't LZMA_OK. This macro shortens
/// the code a bit.
///
#define return_if_error(expr) \
do { \
	const lzma_ret ret_ = expr; \
	if (ret_ != LZMA_OK) \
		return ret_; \
} while (0)

#endif