Coverage Report

Created: 2023-09-25 06:56

/src/xz/src/liblzma/simple/simple_coder.c
Line
Count
Source (jump to first uncovered line)
1
///////////////////////////////////////////////////////////////////////////////
2
//
3
/// \file       simple_coder.c
4
/// \brief      Wrapper for simple filters
5
///
6
/// Simple filters don't change the size of the data i.e. number of bytes
7
/// in equals the number of bytes out.
8
//
9
//  Author:     Lasse Collin
10
//
11
//  This file has been put into the public domain.
12
//  You can do whatever you want with this file.
13
//
14
///////////////////////////////////////////////////////////////////////////////
15
16
#include "simple_private.h"
17
18
19
/// Copied or encodes/decodes more data to out[].
20
static lzma_ret
21
copy_or_code(lzma_simple_coder *coder, const lzma_allocator *allocator,
22
    const uint8_t *restrict in, size_t *restrict in_pos,
23
    size_t in_size, uint8_t *restrict out,
24
    size_t *restrict out_pos, size_t out_size, lzma_action action)
25
414k
{
26
414k
  assert(!coder->end_was_reached);
27
28
414k
  if (coder->next.code == NULL) {
29
0
    lzma_bufcpy(in, in_pos, in_size, out, out_pos, out_size);
30
31
    // Check if end of stream was reached.
32
0
    if (coder->is_encoder && action == LZMA_FINISH
33
0
        && *in_pos == in_size)
34
0
      coder->end_was_reached = true;
35
36
414k
  } else {
37
    // Call the next coder in the chain to provide us some data.
38
414k
    const lzma_ret ret = coder->next.code(
39
414k
        coder->next.coder, allocator,
40
414k
        in, in_pos, in_size,
41
414k
        out, out_pos, out_size, action);
42
43
414k
    if (ret == LZMA_STREAM_END) {
44
275k
      assert(!coder->is_encoder
45
275k
          || action == LZMA_FINISH);
46
275k
      coder->end_was_reached = true;
47
48
275k
    } else if (ret != LZMA_OK) {
49
1.28k
      return ret;
50
1.28k
    }
51
414k
  }
52
53
413k
  return LZMA_OK;
54
414k
}
55
56
57
static size_t
58
call_filter(lzma_simple_coder *coder, uint8_t *buffer, size_t size)
59
161k
{
60
161k
  const size_t filtered = coder->filter(coder->simple,
61
161k
      coder->now_pos, coder->is_encoder,
62
161k
      buffer, size);
63
161k
  coder->now_pos += filtered;
64
161k
  return filtered;
65
161k
}
66
67
68
static lzma_ret
69
simple_code(void *coder_ptr, const lzma_allocator *allocator,
70
    const uint8_t *restrict in, size_t *restrict in_pos,
71
    size_t in_size, uint8_t *restrict out,
72
    size_t *restrict out_pos, size_t out_size, lzma_action action)
73
368k
{
74
368k
  lzma_simple_coder *coder = coder_ptr;
75
76
  // TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
77
  // in cases when the filter is able to filter everything. With most
78
  // simple filters it can be done at offset that is a multiple of 2,
79
  // 4, or 16. With x86 filter, it needs good luck, and thus cannot
80
  // be made to work predictably.
81
368k
  if (action == LZMA_SYNC_FLUSH)
82
0
    return LZMA_OPTIONS_ERROR;
83
84
  // Flush already filtered data from coder->buffer[] to out[].
85
368k
  if (coder->pos < coder->filtered) {
86
37.0k
    lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
87
37.0k
        out, out_pos, out_size);
88
89
    // If we couldn't flush all the filtered data, return to
90
    // application immediately.
91
37.0k
    if (coder->pos < coder->filtered)
92
2.00k
      return LZMA_OK;
93
94
35.0k
    if (coder->end_was_reached) {
95
101
      assert(coder->filtered == coder->size);
96
101
      return LZMA_STREAM_END;
97
101
    }
98
35.0k
  }
99
100
  // If we get here, there is no filtered data left in the buffer.
101
366k
  coder->filtered = 0;
102
103
366k
  assert(!coder->end_was_reached);
104
105
  // If there is more output space left than there is unfiltered data
106
  // in coder->buffer[], flush coder->buffer[] to out[], and copy/code
107
  // more data to out[] hopefully filling it completely. Then filter
108
  // the data in out[]. This step is where most of the data gets
109
  // filtered if the buffer sizes used by the application are reasonable.
110
366k
  const size_t out_avail = out_size - *out_pos;
111
366k
  const size_t buf_avail = coder->size - coder->pos;
112
366k
  if (out_avail > buf_avail || buf_avail == 0) {
113
    // Store the old position so that we know from which byte
114
    // to start filtering.
115
358k
    const size_t out_start = *out_pos;
116
117
    // Flush data from coder->buffer[] to out[], but don't reset
118
    // coder->pos and coder->size yet. This way the coder can be
119
    // restarted if the next filter in the chain returns e.g.
120
    // LZMA_MEM_ERROR.
121
    //
122
    // Do the memcpy() conditionally because out can be NULL
123
    // (in which case buf_avail is always 0). Calling memcpy()
124
    // with a null-pointer is undefined even if the third
125
    // argument is 0.
126
358k
    if (buf_avail > 0)
127
30.2k
      memcpy(out + *out_pos, coder->buffer + coder->pos,
128
30.2k
          buf_avail);
129
130
358k
    *out_pos += buf_avail;
131
132
    // Copy/Encode/Decode more data to out[].
133
358k
    {
134
358k
      const lzma_ret ret = copy_or_code(coder, allocator,
135
358k
          in, in_pos, in_size,
136
358k
          out, out_pos, out_size, action);
137
358k
      assert(ret != LZMA_STREAM_END);
138
358k
      if (ret != LZMA_OK)
139
1.25k
        return ret;
140
358k
    }
141
142
    // Filter out[] unless there is nothing to filter.
143
    // This way we avoid null pointer + 0 (undefined behavior)
144
    // when out == NULL.
145
357k
    const size_t size = *out_pos - out_start;
146
357k
    const size_t filtered = size == 0 ? 0 : call_filter(
147
105k
        coder, out + out_start, size);
148
149
357k
    const size_t unfiltered = size - filtered;
150
357k
    assert(unfiltered <= coder->allocated / 2);
151
152
    // Now we can update coder->pos and coder->size, because
153
    // the next coder in the chain (if any) was successful.
154
357k
    coder->pos = 0;
155
357k
    coder->size = unfiltered;
156
157
357k
    if (coder->end_was_reached) {
158
      // The last byte has been copied to out[] already.
159
      // They are left as is.
160
275k
      coder->size = 0;
161
162
275k
    } else if (unfiltered > 0) {
163
      // There is unfiltered data left in out[]. Copy it to
164
      // coder->buffer[] and rewind *out_pos appropriately.
165
47.7k
      *out_pos -= unfiltered;
166
47.7k
      memcpy(coder->buffer, out + *out_pos, unfiltered);
167
47.7k
    }
168
357k
  } else if (coder->pos > 0) {
169
5.59k
    memmove(coder->buffer, coder->buffer + coder->pos, buf_avail);
170
5.59k
    coder->size -= coder->pos;
171
5.59k
    coder->pos = 0;
172
5.59k
  }
173
174
365k
  assert(coder->pos == 0);
175
176
  // If coder->buffer[] isn't empty, try to fill it by copying/decoding
177
  // more data. Then filter coder->buffer[] and copy the successfully
178
  // filtered data to out[]. It is probable, that some filtered and
179
  // unfiltered data will be left to coder->buffer[].
180
365k
  if (coder->size > 0) {
181
56.0k
    {
182
56.0k
      const lzma_ret ret = copy_or_code(coder, allocator,
183
56.0k
          in, in_pos, in_size,
184
56.0k
          coder->buffer, &coder->size,
185
56.0k
          coder->allocated, action);
186
56.0k
      assert(ret != LZMA_STREAM_END);
187
56.0k
      if (ret != LZMA_OK)
188
22
        return ret;
189
56.0k
    }
190
191
56.0k
    coder->filtered = call_filter(
192
56.0k
        coder, coder->buffer, coder->size);
193
194
    // Everything is considered to be filtered if coder->buffer[]
195
    // contains the last bytes of the data.
196
56.0k
    if (coder->end_was_reached)
197
109
      coder->filtered = coder->size;
198
199
    // Flush as much as possible.
200
56.0k
    lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
201
56.0k
        out, out_pos, out_size);
202
56.0k
  }
203
204
  // Check if we got everything done.
205
365k
  if (coder->end_was_reached && coder->pos == coder->size)
206
275k
    return LZMA_STREAM_END;
207
208
89.9k
  return LZMA_OK;
209
365k
}
210
211
212
static void
213
simple_coder_end(void *coder_ptr, const lzma_allocator *allocator)
214
163k
{
215
163k
  lzma_simple_coder *coder = coder_ptr;
216
163k
  lzma_next_end(&coder->next, allocator);
217
163k
  lzma_free(coder->simple, allocator);
218
163k
  lzma_free(coder, allocator);
219
163k
  return;
220
163k
}
221
222
223
static lzma_ret
224
simple_coder_update(void *coder_ptr, const lzma_allocator *allocator,
225
    const lzma_filter *filters_null lzma_attribute((__unused__)),
226
    const lzma_filter *reversed_filters)
227
0
{
228
0
  lzma_simple_coder *coder = coder_ptr;
229
230
  // No update support, just call the next filter in the chain.
231
0
  return lzma_next_filter_update(
232
0
      &coder->next, allocator, reversed_filters + 1);
233
0
}
234
235
236
extern lzma_ret
237
lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
238
    const lzma_filter_info *filters,
239
    size_t (*filter)(void *simple, uint32_t now_pos,
240
      bool is_encoder, uint8_t *buffer, size_t size),
241
    size_t simple_size, size_t unfiltered_max,
242
    uint32_t alignment, bool is_encoder)
243
284k
{
244
  // Allocate memory for the lzma_simple_coder structure if needed.
245
284k
  lzma_simple_coder *coder = next->coder;
246
284k
  if (coder == NULL) {
247
    // Here we allocate space also for the temporary buffer. We
248
    // need twice the size of unfiltered_max, because then it
249
    // is always possible to filter at least unfiltered_max bytes
250
    // more data in coder->buffer[] if it can be filled completely.
251
163k
    coder = lzma_alloc(sizeof(lzma_simple_coder)
252
163k
        + 2 * unfiltered_max, allocator);
253
163k
    if (coder == NULL)
254
0
      return LZMA_MEM_ERROR;
255
256
163k
    next->coder = coder;
257
163k
    next->code = &simple_code;
258
163k
    next->end = &simple_coder_end;
259
163k
    next->update = &simple_coder_update;
260
261
163k
    coder->next = LZMA_NEXT_CODER_INIT;
262
163k
    coder->filter = filter;
263
163k
    coder->allocated = 2 * unfiltered_max;
264
265
    // Allocate memory for filter-specific data structure.
266
163k
    if (simple_size > 0) {
267
4.20k
      coder->simple = lzma_alloc(simple_size, allocator);
268
4.20k
      if (coder->simple == NULL)
269
0
        return LZMA_MEM_ERROR;
270
159k
    } else {
271
159k
      coder->simple = NULL;
272
159k
    }
273
163k
  }
274
275
284k
  if (filters[0].options != NULL) {
276
740
    const lzma_options_bcj *simple = filters[0].options;
277
740
    coder->now_pos = simple->start_offset;
278
740
    if (coder->now_pos & (alignment - 1))
279
6
      return LZMA_OPTIONS_ERROR;
280
283k
  } else {
281
283k
    coder->now_pos = 0;
282
283k
  }
283
284
  // Reset variables.
285
284k
  coder->is_encoder = is_encoder;
286
284k
  coder->end_was_reached = false;
287
284k
  coder->pos = 0;
288
284k
  coder->filtered = 0;
289
284k
  coder->size = 0;
290
291
284k
  return lzma_next_filter_init(&coder->next, allocator, filters + 1);
292
284k
}