Rizin
unix-like reverse engineering framework and cli tools
stream_encoder.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 "block_encoder.h"
14 #include "index_encoder.h"
15 
16 
17 typedef struct {
18  enum {
19  SEQ_STREAM_HEADER,
21  SEQ_BLOCK_HEADER,
24  SEQ_STREAM_FOOTER,
25  } sequence;
26 
31 
34 
36  lzma_block block_options;
37 
40 
45 
48 
50  size_t buffer_pos;
51 
53  size_t buffer_size;
54 
59 
60 
61 static lzma_ret
63 {
64  // Prepare the Block options. Even though Block encoder doesn't need
65  // compressed_size, uncompressed_size, and header_size to be
66  // initialized, it is a good idea to do it here, because this way
67  // we catch if someone gave us Filter ID that cannot be used in
68  // Blocks/Streams.
71 
72  return_if_error(lzma_block_header_size(&coder->block_options));
73 
74  // Initialize the actual Block encoder.
76  &coder->block_options);
77 }
78 
79 
80 static lzma_ret
81 stream_encode(void *coder_ptr, const lzma_allocator *allocator,
82  const uint8_t *restrict in, size_t *restrict in_pos,
83  size_t in_size, uint8_t *restrict out,
84  size_t *restrict out_pos, size_t out_size, lzma_action action)
85 {
86  lzma_stream_coder *coder = coder_ptr;
87 
88  // Main loop
89  while (*out_pos < out_size)
90  switch (coder->sequence) {
91  case SEQ_STREAM_HEADER:
92  case SEQ_BLOCK_HEADER:
93  case SEQ_STREAM_FOOTER:
94  lzma_bufcpy(coder->buffer, &coder->buffer_pos,
95  coder->buffer_size, out, out_pos, out_size);
96  if (coder->buffer_pos < coder->buffer_size)
97  return LZMA_OK;
98 
99  if (coder->sequence == SEQ_STREAM_FOOTER)
100  return LZMA_STREAM_END;
101 
102  coder->buffer_pos = 0;
103  ++coder->sequence;
104  break;
105 
106  case SEQ_BLOCK_INIT: {
107  if (*in_pos == in_size) {
108  // If we are requested to flush or finish the current
109  // Block, return LZMA_STREAM_END immediately since
110  // there's nothing to do.
111  if (action != LZMA_FINISH)
112  return action == LZMA_RUN
114 
115  // The application had used LZMA_FULL_FLUSH to finish
116  // the previous Block, but now wants to finish without
117  // encoding new data, or it is simply creating an
118  // empty Stream with no Blocks.
119  //
120  // Initialize the Index encoder, and continue to
121  // actually encoding the Index.
123  &coder->index_encoder, allocator,
124  coder->index));
125  coder->sequence = SEQ_INDEX_ENCODE;
126  break;
127  }
128 
129  // Initialize the Block encoder unless it was already
130  // initialized by stream_encoder_init() or
131  // stream_encoder_update().
132  if (!coder->block_encoder_is_initialized)
134 
135  // Make it false so that we don't skip the initialization
136  // with the next Block.
137  coder->block_encoder_is_initialized = false;
138 
139  // Encode the Block Header. This shouldn't fail since we have
140  // already initialized the Block encoder.
141  if (lzma_block_header_encode(&coder->block_options,
142  coder->buffer) != LZMA_OK)
143  return LZMA_PROG_ERROR;
144 
145  coder->buffer_size = coder->block_options.header_size;
146  coder->sequence = SEQ_BLOCK_HEADER;
147  break;
148  }
149 
150  case SEQ_BLOCK_ENCODE: {
151  static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
152  LZMA_RUN,
154  LZMA_FINISH,
155  LZMA_FINISH,
156  LZMA_FINISH,
157  };
158 
159  const lzma_ret ret = coder->block_encoder.code(
160  coder->block_encoder.coder, allocator,
161  in, in_pos, in_size,
162  out, out_pos, out_size, convert[action]);
163  if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
164  return ret;
165 
166  // Add a new Index Record.
167  const lzma_vli unpadded_size = lzma_block_unpadded_size(
168  &coder->block_options);
169  assert(unpadded_size != 0);
170  return_if_error(lzma_index_append(coder->index, allocator,
173 
174  coder->sequence = SEQ_BLOCK_INIT;
175  break;
176  }
177 
178  case SEQ_INDEX_ENCODE: {
179  // Call the Index encoder. It doesn't take any input, so
180  // those pointers can be NULL.
181  const lzma_ret ret = coder->index_encoder.code(
182  coder->index_encoder.coder, allocator,
183  NULL, NULL, 0,
184  out, out_pos, out_size, LZMA_RUN);
185  if (ret != LZMA_STREAM_END)
186  return ret;
187 
188  // Encode the Stream Footer into coder->buffer.
189  const lzma_stream_flags stream_flags = {
190  .version = 0,
191  .backward_size = lzma_index_size(coder->index),
192  .check = coder->block_options.check,
193  };
194 
195  if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
196  != LZMA_OK)
197  return LZMA_PROG_ERROR;
198 
200  coder->sequence = SEQ_STREAM_FOOTER;
201  break;
202  }
203 
204  default:
205  assert(0);
206  return LZMA_PROG_ERROR;
207  }
208 
209  return LZMA_OK;
210 }
211 
212 
213 static void
215 {
216  lzma_stream_coder *coder = coder_ptr;
217 
220  lzma_index_end(coder->index, allocator);
221 
222  for (size_t i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
223  lzma_free(coder->filters[i].options, allocator);
224 
225  lzma_free(coder, allocator);
226  return;
227 }
228 
229 
230 static lzma_ret
232  const lzma_filter *filters,
233  const lzma_filter *reversed_filters)
234 {
235  lzma_stream_coder *coder = coder_ptr;
236 
237  if (coder->sequence <= SEQ_BLOCK_INIT) {
238  // There is no incomplete Block waiting to be finished,
239  // thus we can change the whole filter chain. Start by
240  // trying to initialize the Block encoder with the new
241  // chain. This way we detect if the chain is valid.
242  coder->block_encoder_is_initialized = false;
244  const lzma_ret ret = block_encoder_init(coder, allocator);
245  coder->block_options.filters = coder->filters;
246  if (ret != LZMA_OK)
247  return ret;
248 
249  coder->block_encoder_is_initialized = true;
250 
251  } else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
252  // We are in the middle of a Block. Try to update only
253  // the filter-specific options.
255  coder->block_encoder.coder, allocator,
256  filters, reversed_filters));
257  } else {
258  // Trying to update the filter chain when we are already
259  // encoding Index or Stream Footer.
260  return LZMA_PROG_ERROR;
261  }
262 
263  // Free the copy of the old chain and make a copy of the new chain.
264  for (size_t i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
265  lzma_free(coder->filters[i].options, allocator);
266 
267  return lzma_filters_copy(filters, coder->filters, allocator);
268 }
269 
270 
271 static lzma_ret
274 {
276 
277  if (filters == NULL)
278  return LZMA_PROG_ERROR;
279 
280  lzma_stream_coder *coder = next->coder;
281 
282  if (coder == NULL) {
283  coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
284  if (coder == NULL)
285  return LZMA_MEM_ERROR;
286 
287  next->coder = coder;
288  next->code = &stream_encode;
289  next->end = &stream_encoder_end;
290  next->update = &stream_encoder_update;
291 
292  coder->filters[0].id = LZMA_VLI_UNKNOWN;
295  coder->index = NULL;
296  }
297 
298  // Basic initializations
299  coder->sequence = SEQ_STREAM_HEADER;
300  coder->block_options.version = 0;
301  coder->block_options.check = check;
302 
303  // Initialize the Index
304  lzma_index_end(coder->index, allocator);
305  coder->index = lzma_index_init(allocator);
306  if (coder->index == NULL)
307  return LZMA_MEM_ERROR;
308 
309  // Encode the Stream Header
310  lzma_stream_flags stream_flags = {
311  .version = 0,
312  .check = check,
313  };
314  return_if_error(lzma_stream_header_encode(
315  &stream_flags, coder->buffer));
316 
317  coder->buffer_pos = 0;
319 
320  // Initialize the Block encoder. This way we detect unsupported
321  // filter chains when initializing the Stream encoder instead of
322  // giving an error after Stream Header has already written out.
323  return stream_encoder_update(coder, allocator, filters, NULL);
324 }
325 
326 
328 lzma_stream_encoder(lzma_stream *strm,
330 {
332 
338 
339  return LZMA_OK;
340 }
lzma_check
Type of the integrity check (Check ID)
Definition: check.h:27
lzma_index ** i
Definition: index.h:629
const lzma_allocator lzma_vli unpadded_size
Definition: index.h:345
const lzma_allocator const uint8_t size_t uint8_t size_t * out_pos
Definition: block.h:528
const lzma_allocator const uint8_t size_t * in_pos
Definition: block.h:579
const lzma_allocator const uint8_t size_t in_size
Definition: block.h:527
const lzma_allocator * allocator
Definition: block.h:377
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define LZMA_BLOCK_HEADER_SIZE_MAX
Definition: block.h:74
lzma_ret lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, lzma_block *block)
Encodes .xz Blocks.
lzma_check check
Definition: container.h:292
const lzma_filter * filters
Definition: container.h:315
#define NULL
Definition: cris-opc.c:27
#define LZMA_FILTERS_MAX
Maximum number of filters in a chain.
Definition: filter.h:26
static lzma_stream strm
Definition: full_flush.c:20
lzma_ret lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_index *i)
Encodes the Index field.
#define restrict
assert(limit<=UINT32_MAX/2)
def convert(trace_codes, trap_json)
unsigned char uint8_t
Definition: sftypes.h:31
LZMA_API(lzma_ret)
static void stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
static lzma_ret stream_encode(void *coder_ptr, const 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)
static lzma_ret stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *filters, lzma_check check)
static lzma_ret block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
static lzma_ret stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator, const lzma_filter *filters, const lzma_filter *reversed_filters)
struct lzma_stream_coder_s lzma_stream_coder
#define LZMA_STREAM_HEADER_SIZE
Size of Stream Header and Stream Footer.
Definition: stream_flags.h:27
Definition: buffer.h:15
Custom functions for memory handling.
Definition: base.h:372
Options for the Block and Block Header encoders and decoders.
Definition: block.h:30
lzma_vli uncompressed_size
Uncompressed Size in bytes.
Definition: block.h:172
lzma_filter * filters
Array of filters.
Definition: block.h:200
uint32_t header_size
Size of the Block Header field.
Definition: block.h:72
lzma_check check
Type of integrity Check.
Definition: block.h:93
lzma_vli compressed_size
Size of the Compressed Data in bytes.
Definition: block.h:148
uint32_t version
Block format version.
Definition: block.h:52
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
bool supported_actions[LZMA_ACTION_MAX+1]
Indicates which lzma_action values are allowed by next.code.
Definition: common.h:220
Hold data and function pointers of the next filter in the chain.
Definition: common.h:135
lzma_code_function code
Pointer to function to do the actual coding.
Definition: common.h:150
void * coder
Pointer to coder-specific data.
Definition: common.h:137
lzma_end_function end
Definition: common.h:155
lzma_ret(* update)(void *coder, const lzma_allocator *allocator, const lzma_filter *filters, const lzma_filter *reversed_filters)
Definition: common.h:173
uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX]
lzma_next_coder index_encoder
lzma_index * index
Index to hold sizes of the Blocks.
lzma_block block_options
Options for the Block encoder.
enum lzma_stream_coder::@652 sequence
size_t buffer_pos
Read position in buffer[].
bool block_encoder_is_initialized
size_t buffer_size
Total number of bytes in buffer[].
lzma_filter filters[LZMA_FILTERS_MAX+1]
The filter chain currently in use.
lzma_next_coder block_encoder
Block.
Options for encoding/decoding Stream Header and Stream Footer.
Definition: stream_flags.h:33
uint32_t version
Stream Flags format version.
Definition: stream_flags.h:51
Passing data to and from liblzma.
Definition: base.h:485
lzma_internal * internal
Definition: base.h:505
#define LZMA_NEXT_CODER_INIT
Macro to initialize lzma_next_coder structure.
Definition: common.h:180
#define return_if_error(expr)
Return if expression doesn't evaluate to LZMA_OK.
Definition: common.h:278
#define lzma_next_coder_init(func, next, allocator)
Definition: common.h:291
#define LZMA_ACTION_MAX
Largest valid lzma_action value as unsigned integer.
Definition: common.h:81
#define lzma_next_strm_init(func, strm,...)
Definition: common.h:303
void * lzma_alloc(size_t size, const lzma_allocator *allocator) lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
Allocates memory.
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_STREAM_END
End of stream was reached.
Definition: base.h:63
@ LZMA_OK
Operation completed successfully.
Definition: base.h:58
lzma_action
The ‘action’ argument for lzma_code()
Definition: base.h:250
@ LZMA_SYNC_FLUSH
Make all the input available at output.
Definition: base.h:265
@ LZMA_FINISH
Finish the coding operation.
Definition: base.h:328
@ LZMA_RUN
Continue coding.
Definition: base.h:251
@ LZMA_FULL_FLUSH
Finish encoding of the current Block.
Definition: base.h:290
@ LZMA_FULL_BARRIER
Finish encoding of the current Block.
Definition: base.h:305
void lzma_free(void *ptr, const lzma_allocator *allocator)
Frees memory.
Definition: common.c:78
size_t lzma_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)
Definition: common.c:94
void lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
Definition: common.c:145