Rizin
unix-like reverse engineering framework and cli tools
filter_common.c
Go to the documentation of this file.
1 //
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 //
12 
13 #include "filter_common.h"
14 
15 
16 static const struct {
19 
21  size_t options_size;
22 
26 
29  bool last_ok;
30 
35 
36 } features[] = {
37 #if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
38  {
39  .id = LZMA_FILTER_LZMA1,
40  .options_size = sizeof(lzma_options_lzma),
41  .non_last_ok = false,
42  .last_ok = true,
43  .changes_size = true,
44  },
45 #endif
46 #if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
47  {
48  .id = LZMA_FILTER_LZMA2,
49  .options_size = sizeof(lzma_options_lzma),
50  .non_last_ok = false,
51  .last_ok = true,
52  .changes_size = true,
53  },
54 #endif
55 #if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
56  {
57  .id = LZMA_FILTER_X86,
58  .options_size = sizeof(lzma_options_bcj),
59  .non_last_ok = true,
60  .last_ok = false,
61  .changes_size = false,
62  },
63 #endif
64 #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
65  {
66  .id = LZMA_FILTER_POWERPC,
67  .options_size = sizeof(lzma_options_bcj),
68  .non_last_ok = true,
69  .last_ok = false,
70  .changes_size = false,
71  },
72 #endif
73 #if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
74  {
75  .id = LZMA_FILTER_IA64,
76  .options_size = sizeof(lzma_options_bcj),
77  .non_last_ok = true,
78  .last_ok = false,
79  .changes_size = false,
80  },
81 #endif
82 #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
83  {
84  .id = LZMA_FILTER_ARM,
85  .options_size = sizeof(lzma_options_bcj),
86  .non_last_ok = true,
87  .last_ok = false,
88  .changes_size = false,
89  },
90 #endif
91 #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
92  {
94  .options_size = sizeof(lzma_options_bcj),
95  .non_last_ok = true,
96  .last_ok = false,
97  .changes_size = false,
98  },
99 #endif
100 #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
101  {
102  .id = LZMA_FILTER_SPARC,
103  .options_size = sizeof(lzma_options_bcj),
104  .non_last_ok = true,
105  .last_ok = false,
106  .changes_size = false,
107  },
108 #endif
109 #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
110  {
111  .id = LZMA_FILTER_DELTA,
112  .options_size = sizeof(lzma_options_delta),
113  .non_last_ok = true,
114  .last_ok = false,
115  .changes_size = false,
116  },
117 #endif
118  {
119  .id = LZMA_VLI_UNKNOWN
120  }
121 };
122 
123 
125 lzma_filters_copy(const lzma_filter *src, lzma_filter *dest,
126  const lzma_allocator *allocator)
127 {
128  if (src == NULL || dest == NULL)
129  return LZMA_PROG_ERROR;
130 
131  lzma_ret ret;
132  size_t i;
133  for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
134  // There must be a maximum of four filters plus
135  // the array terminator.
136  if (i == LZMA_FILTERS_MAX) {
137  ret = LZMA_OPTIONS_ERROR;
138  goto error;
139  }
140 
141  dest[i].id = src[i].id;
142 
143  if (src[i].options == NULL) {
144  dest[i].options = NULL;
145  } else {
146  // See if the filter is supported only when the
147  // options is not NULL. This might be convenient
148  // sometimes if the app is actually copying only
149  // a partial filter chain with a place holder ID.
150  //
151  // When options is not NULL, the Filter ID must be
152  // supported by us, because otherwise we don't know
153  // how big the options are.
154  size_t j;
155  for (j = 0; src[i].id != features[j].id; ++j) {
156  if (features[j].id == LZMA_VLI_UNKNOWN) {
157  ret = LZMA_OPTIONS_ERROR;
158  goto error;
159  }
160  }
161 
162  // Allocate and copy the options.
163  dest[i].options = lzma_alloc(features[j].options_size,
164  allocator);
165  if (dest[i].options == NULL) {
166  ret = LZMA_MEM_ERROR;
167  goto error;
168  }
169 
172  }
173  }
174 
175  // Terminate the filter array.
176  assert(i <= LZMA_FILTERS_MAX + 1);
177  dest[i].id = LZMA_VLI_UNKNOWN;
178  dest[i].options = NULL;
179 
180  return LZMA_OK;
181 
182 error:
183  // Free the options which we have already allocated.
184  while (i-- > 0) {
186  dest[i].options = NULL;
187  }
188 
189  return ret;
190 }
191 
192 
193 static lzma_ret
195 {
196  // There must be at least one filter.
197  if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
198  return LZMA_PROG_ERROR;
199 
200  // Number of non-last filters that may change the size of the data
201  // significantly (that is, more than 1-2 % or so).
202  size_t changes_size_count = 0;
203 
204  // True if it is OK to add a new filter after the current filter.
205  bool non_last_ok = true;
206 
207  // True if the last filter in the given chain is actually usable as
208  // the last filter. Only filters that support embedding End of Payload
209  // Marker can be used as the last filter in the chain.
210  bool last_ok = false;
211 
212  size_t i = 0;
213  do {
214  size_t j;
215  for (j = 0; filters[i].id != features[j].id; ++j)
216  if (features[j].id == LZMA_VLI_UNKNOWN)
217  return LZMA_OPTIONS_ERROR;
218 
219  // If the previous filter in the chain cannot be a non-last
220  // filter, the chain is invalid.
221  if (!non_last_ok)
222  return LZMA_OPTIONS_ERROR;
223 
224  non_last_ok = features[j].non_last_ok;
225  last_ok = features[j].last_ok;
226  changes_size_count += features[j].changes_size;
227 
228  } while (filters[++i].id != LZMA_VLI_UNKNOWN);
229 
230  // There must be 1-4 filters. The last filter must be usable as
231  // the last filter in the chain. A maximum of three filters are
232  // allowed to change the size of the data.
233  if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
234  return LZMA_OPTIONS_ERROR;
235 
236  *count = i;
237  return LZMA_OK;
238 }
239 
240 
241 extern lzma_ret
243  const lzma_filter *options,
244  lzma_filter_find coder_find, bool is_encoder)
245 {
246  // Do some basic validation and get the number of filters.
247  size_t count;
249 
250  // Set the filter functions and copy the options pointer.
252  if (is_encoder) {
253  for (size_t i = 0; i < count; ++i) {
254  // The order of the filters is reversed in the
255  // encoder. It allows more efficient handling
256  // of the uncompressed data.
257  const size_t j = count - i - 1;
258 
259  const lzma_filter_coder *const fc
260  = coder_find(options[i].id);
261  if (fc == NULL || fc->init == NULL)
262  return LZMA_OPTIONS_ERROR;
263 
264  filters[j].id = options[i].id;
265  filters[j].init = fc->init;
266  filters[j].options = options[i].options;
267  }
268  } else {
269  for (size_t i = 0; i < count; ++i) {
270  const lzma_filter_coder *const fc
271  = coder_find(options[i].id);
272  if (fc == NULL || fc->init == NULL)
273  return LZMA_OPTIONS_ERROR;
274 
275  filters[i].id = options[i].id;
276  filters[i].init = fc->init;
277  filters[i].options = options[i].options;
278  }
279  }
280 
281  // Terminate the array.
283  filters[count].init = NULL;
284 
285  // Initialize the filters.
286  const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
287  if (ret != LZMA_OK)
288  lzma_next_end(next, allocator);
289 
290  return ret;
291 }
292 
293 
294 extern uint64_t
296  const lzma_filter *filters)
297 {
298  // The chain has to have at least one filter.
299  {
300  size_t tmp;
301  if (validate_chain(filters, &tmp) != LZMA_OK)
302  return UINT64_MAX;
303  }
304 
305  uint64_t total = 0;
306  size_t i = 0;
307 
308  do {
309  const lzma_filter_coder *const fc
310  = coder_find(filters[i].id);
311  if (fc == NULL)
312  return UINT64_MAX; // Unsupported Filter ID
313 
314  if (fc->memusage == NULL) {
315  // This filter doesn't have a function to calculate
316  // the memory usage and validate the options. Such
317  // filters need only little memory, so we use 1 KiB
318  // as a good estimate. They also accept all possible
319  // options, so there's no need to worry about lack
320  // of validation.
321  total += 1024;
322  } else {
323  // Call the filter-specific memory usage calculation
324  // function.
325  const uint64_t usage
326  = fc->memusage(filters[i].options);
327  if (usage == UINT64_MAX)
328  return UINT64_MAX; // Invalid options
329 
330  total += usage;
331  }
332  } while (filters[++i].id != LZMA_VLI_UNKNOWN);
333 
334  // Add some fixed amount of extra. It's to compensate memory usage
335  // of Stream, Block etc. coders, malloc() overhead, stack etc.
336  return total + LZMA_MEMUSAGE_BASE;
337 }
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
#define LZMA_FILTER_IA64
Definition: bcj.h:32
#define LZMA_FILTER_ARM
Definition: bcj.h:37
#define LZMA_FILTER_SPARC
Definition: bcj.h:47
#define LZMA_FILTER_ARMTHUMB
Definition: bcj.h:42
#define LZMA_FILTER_X86
Definition: bcj.h:22
#define LZMA_FILTER_POWERPC
Definition: bcj.h:27
const lzma_allocator * allocator
Definition: block.h:377
void usage(const char *message)
const lzma_filter * filters
Definition: container.h:315
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
#define LZMA_FILTER_DELTA
Filter ID.
Definition: delta.h:25
#define LZMA_FILTERS_MAX
Maximum number of filters in a chain.
Definition: filter.h:26
uint64_t lzma_raw_coder_memusage(lzma_filter_find coder_find, const lzma_filter *filters)
LZMA_API(lzma_ret)
lzma_vli id
Filter ID.
Definition: filter_common.c:18
static lzma_ret validate_chain(const lzma_filter *filters, size_t *count)
bool changes_size
Definition: filter_common.c:34
bool last_ok
Definition: filter_common.c:29
bool non_last_ok
Definition: filter_common.c:25
static const struct @646 features[]
size_t options_size
Size of the filter-specific options structure.
Definition: filter_common.c:21
lzma_ret lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *options, lzma_filter_find coder_find, bool is_encoder)
Filter-specific stuff common for both encoder and decoder.
const lzma_filter_coder *(* lzma_filter_find)(lzma_vli id)
Definition: filter_common.h:35
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static const char struct stat static buf struct stat static buf static vhangup int options
Definition: sflib.h:145
char * dest
Definition: lz4.h:697
#define LZMA_FILTER_LZMA2
LZMA2 Filter ID.
Definition: lzma12.h:40
#define LZMA_FILTER_LZMA1
LZMA1 Filter ID.
Definition: lzma12.h:30
assert(limit<=UINT32_MAX/2)
unsigned long uint64_t
Definition: sftypes.h:28
#define UINT64_MAX
Custom functions for memory handling.
Definition: base.h:372
Both lzma_filter_encoder and lzma_filter_decoder begin with these members.
Definition: filter_common.h:20
uint64_t(* memusage)(const void *options)
Definition: filter_common.h:30
lzma_init_function init
Definition: filter_common.h:26
Filter options.
Definition: filter.h:43
void * options
Pointer to filter-specific options structure.
Definition: filter.h:63
lzma_vli id
Filter ID.
Definition: filter.h:54
Hold data and function pointers of the next filter in the chain.
Definition: common.h:135
Options for BCJ filters.
Definition: bcj.h:73
Options for the Delta filter.
Definition: delta.h:45
Options specific to the LZMA1 and LZMA2 filters.
Definition: lzma12.h:185
#define LZMA_MEMUSAGE_BASE
Definition: common.h:63
#define return_if_error(expr)
Return if expression doesn't evaluate to LZMA_OK.
Definition: common.h:278
void * lzma_alloc(size_t size, const lzma_allocator *allocator) lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
Allocates memory.
void error(const char *msg)
Definition: untgz.c:593
uint64_t lzma_vli
Variable-length integer type.
Definition: vli.h:63
#define LZMA_VLI_UNKNOWN
VLI value to denote that the value is unknown.
Definition: vli.h:39
lzma_ret
Return values used by several functions in liblzma.
Definition: base.h:57
@ LZMA_PROG_ERROR
Programming error.
Definition: base.h:218
@ LZMA_MEM_ERROR
Cannot allocate memory.
Definition: base.h:128
@ LZMA_OPTIONS_ERROR
Invalid or unsupported options.
Definition: base.h:160
@ LZMA_OK
Operation completed successfully.
Definition: base.h:58
lzma_ret lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters)
Definition: common.c:116
void lzma_free(void *ptr, const lzma_allocator *allocator)
Frees memory.
Definition: common.c:78
void lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
Definition: common.c:145