Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmliblzma/liblzma/common/block_decoder.c
Line
Count
Source
1
// SPDX-License-Identifier: 0BSD
2
3
///////////////////////////////////////////////////////////////////////////////
4
//
5
/// \file       block_decoder.c
6
/// \brief      Decodes .xz Blocks
7
//
8
//  Author:     Lasse Collin
9
//
10
///////////////////////////////////////////////////////////////////////////////
11
12
#include "block_decoder.h"
13
#include "filter_decoder.h"
14
#include "check.h"
15
16
17
typedef struct {
18
  enum {
19
    SEQ_CODE,
20
    SEQ_PADDING,
21
    SEQ_CHECK,
22
  } sequence;
23
24
  /// The filters in the chain; initialized with lzma_raw_decoder_init().
25
  lzma_next_coder next;
26
27
  /// Decoding options; we also write Compressed Size and Uncompressed
28
  /// Size back to this structure when the decoding has been finished.
29
  lzma_block *block;
30
31
  /// Compressed Size calculated while decoding
32
  lzma_vli compressed_size;
33
34
  /// Uncompressed Size calculated while decoding
35
  lzma_vli uncompressed_size;
36
37
  /// Maximum allowed Compressed Size; this takes into account the
38
  /// size of the Block Header and Check fields when Compressed Size
39
  /// is unknown.
40
  lzma_vli compressed_limit;
41
42
  /// Maximum allowed Uncompressed Size.
43
  lzma_vli uncompressed_limit;
44
45
  /// Position when reading the Check field
46
  size_t check_pos;
47
48
  /// Check of the uncompressed data
49
  lzma_check_state check;
50
51
  /// True if the integrity check won't be calculated and verified.
52
  bool ignore_check;
53
} lzma_block_coder;
54
55
56
static inline bool
57
is_size_valid(lzma_vli size, lzma_vli reference)
58
640
{
59
640
  return reference == LZMA_VLI_UNKNOWN || reference == size;
60
640
}
61
62
63
static lzma_ret
64
block_decode(void *coder_ptr, const lzma_allocator *allocator,
65
    const uint8_t *restrict in, size_t *restrict in_pos,
66
    size_t in_size, uint8_t *restrict out,
67
    size_t *restrict out_pos, size_t out_size, lzma_action action)
68
1.71k
{
69
1.71k
  lzma_block_coder *coder = coder_ptr;
70
71
1.71k
  switch (coder->sequence) {
72
1.65k
  case SEQ_CODE: {
73
1.65k
    const size_t in_start = *in_pos;
74
1.65k
    const size_t out_start = *out_pos;
75
76
    // Limit the amount of input and output space that we give
77
    // to the raw decoder based on the information we have
78
    // (or don't have) from Block Header.
79
1.65k
    const size_t in_stop = *in_pos + (size_t)my_min(
80
1.65k
      in_size - *in_pos,
81
1.65k
      coder->compressed_limit - coder->compressed_size);
82
1.65k
    const size_t out_stop = *out_pos + (size_t)my_min(
83
1.65k
      out_size - *out_pos,
84
1.65k
      coder->uncompressed_limit - coder->uncompressed_size);
85
86
1.65k
    const lzma_ret ret = coder->next.code(coder->next.coder,
87
1.65k
        allocator, in, in_pos, in_stop,
88
1.65k
        out, out_pos, out_stop, action);
89
90
1.65k
    const size_t in_used = *in_pos - in_start;
91
1.65k
    const size_t out_used = *out_pos - out_start;
92
93
    // Because we have limited the input and output sizes,
94
    // we know that these cannot grow too big or overflow.
95
1.65k
    coder->compressed_size += in_used;
96
1.65k
    coder->uncompressed_size += out_used;
97
98
1.65k
    if (ret == LZMA_OK) {
99
1.19k
      const bool comp_done = coder->compressed_size
100
1.19k
          == coder->block->compressed_size;
101
1.19k
      const bool uncomp_done = coder->uncompressed_size
102
1.19k
          == coder->block->uncompressed_size;
103
104
      // If both input and output amounts match the sizes
105
      // in Block Header but we still got LZMA_OK instead
106
      // of LZMA_STREAM_END, the file is broken.
107
1.19k
      if (comp_done && uncomp_done)
108
0
        return LZMA_DATA_ERROR;
109
110
      // If the decoder has consumed all the input that it
111
      // needs but it still couldn't fill the output buffer
112
      // or return LZMA_STREAM_END, the file is broken.
113
1.19k
      if (comp_done && *out_pos < out_size)
114
2
        return LZMA_DATA_ERROR;
115
116
      // If the decoder has produced all the output but
117
      // it still didn't return LZMA_STREAM_END or consume
118
      // more input (for example, detecting an end of
119
      // payload marker may need more input but produce
120
      // no output) the file is broken.
121
1.18k
      if (uncomp_done && *in_pos < in_size)
122
18
        return LZMA_DATA_ERROR;
123
1.18k
    }
124
125
    // Don't waste time updating the integrity check if it will be
126
    // ignored. Also skip it if no new output was produced. This
127
    // avoids null pointer + 0 (undefined behavior) when out == 0.
128
1.63k
    if (!coder->ignore_check && out_used > 0)
129
432
      lzma_check_update(&coder->check, coder->block->check,
130
432
          out + out_start, out_used);
131
132
1.63k
    if (ret != LZMA_STREAM_END)
133
1.28k
      return ret;
134
135
    // Compressed and Uncompressed Sizes are now at their final
136
    // values. Verify that they match the values given to us.
137
352
    if (!is_size_valid(coder->compressed_size,
138
352
          coder->block->compressed_size)
139
288
        || !is_size_valid(coder->uncompressed_size,
140
288
          coder->block->uncompressed_size))
141
74
      return LZMA_DATA_ERROR;
142
143
    // Copy the values into coder->block. The caller
144
    // may use this information to construct Index.
145
278
    coder->block->compressed_size = coder->compressed_size;
146
278
    coder->block->uncompressed_size = coder->uncompressed_size;
147
148
278
    coder->sequence = SEQ_PADDING;
149
278
  }
150
151
  // Fall through
152
153
294
  case SEQ_PADDING:
154
    // Compressed Data is padded to a multiple of four bytes.
155
1.04k
    while (coder->compressed_size & 3) {
156
798
      if (*in_pos >= in_size)
157
24
        return LZMA_OK;
158
159
      // We use compressed_size here just get the Padding
160
      // right. The actual Compressed Size was stored to
161
      // coder->block already, and won't be modified by
162
      // us anymore.
163
774
      ++coder->compressed_size;
164
165
774
      if (in[(*in_pos)++] != 0x00)
166
20
        return LZMA_DATA_ERROR;
167
774
    }
168
169
250
    if (coder->block->check == LZMA_CHECK_NONE)
170
2
      return LZMA_STREAM_END;
171
172
248
    if (!coder->ignore_check)
173
248
      lzma_check_finish(&coder->check, coder->block->check);
174
175
248
    coder->sequence = SEQ_CHECK;
176
177
  // Fall through
178
179
292
  case SEQ_CHECK: {
180
292
    const size_t check_size = lzma_check_size(coder->block->check);
181
292
    lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
182
292
        &coder->check_pos, check_size);
183
292
    if (coder->check_pos < check_size)
184
66
      return LZMA_OK;
185
186
    // Validate the Check only if we support it.
187
    // coder->check.buffer may be uninitialized
188
    // when the Check ID is not supported.
189
226
    if (!coder->ignore_check
190
226
        && lzma_check_is_supported(coder->block->check)
191
26
        && memcmp(coder->block->raw_check,
192
26
          coder->check.buffer.u8,
193
26
          check_size) != 0)
194
18
      return LZMA_DATA_ERROR;
195
196
208
    return LZMA_STREAM_END;
197
226
  }
198
1.71k
  }
199
200
0
  return LZMA_PROG_ERROR;
201
1.71k
}
202
203
204
static void
205
block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
206
864
{
207
864
  lzma_block_coder *coder = coder_ptr;
208
864
  lzma_next_end(&coder->next, allocator);
209
864
  lzma_free(coder, allocator);
210
864
  return;
211
864
}
212
213
214
extern lzma_ret
215
lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
216
    lzma_block *block)
217
872
{
218
872
  lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
219
220
  // Validate the options. lzma_block_unpadded_size() does that for us
221
  // except for Uncompressed Size and filters. Filters are validated
222
  // by the raw decoder.
223
872
  if (lzma_block_unpadded_size(block) == 0
224
872
      || !lzma_vli_is_valid(block->uncompressed_size))
225
0
    return LZMA_PROG_ERROR;
226
227
  // Allocate *next->coder if needed.
228
872
  lzma_block_coder *coder = next->coder;
229
872
  if (coder == NULL) {
230
864
    coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
231
864
    if (coder == NULL)
232
0
      return LZMA_MEM_ERROR;
233
234
864
    next->coder = coder;
235
864
    next->code = &block_decode;
236
864
    next->end = &block_decoder_end;
237
864
    coder->next = LZMA_NEXT_CODER_INIT;
238
864
  }
239
240
  // Basic initializations
241
872
  coder->sequence = SEQ_CODE;
242
872
  coder->block = block;
243
872
  coder->compressed_size = 0;
244
872
  coder->uncompressed_size = 0;
245
246
  // If Compressed Size is not known, we calculate the maximum allowed
247
  // value so that encoded size of the Block (including Block Padding)
248
  // is still a valid VLI and a multiple of four.
249
872
  coder->compressed_limit
250
872
      = block->compressed_size == LZMA_VLI_UNKNOWN
251
872
        ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
252
470
          - block->header_size
253
470
          - lzma_check_size(block->check)
254
872
        : block->compressed_size;
255
256
  // With Uncompressed Size this is simpler. If Block Header lacks
257
  // the size info, then LZMA_VLI_MAX is the maximum possible
258
  // Uncompressed Size.
259
872
  coder->uncompressed_limit
260
872
      = block->uncompressed_size == LZMA_VLI_UNKNOWN
261
872
        ? LZMA_VLI_MAX
262
872
        : block->uncompressed_size;
263
264
  // Initialize the check. It's caller's problem if the Check ID is not
265
  // supported, and the Block decoder cannot verify the Check field.
266
  // Caller can test lzma_check_is_supported(block->check).
267
872
  coder->check_pos = 0;
268
872
  lzma_check_init(&coder->check, block->check);
269
270
872
  coder->ignore_check = block->version >= 1
271
872
      ? block->ignore_check : false;
272
273
  // Initialize the filter chain.
274
872
  return lzma_raw_decoder_init(&coder->next, allocator,
275
872
      block->filters);
276
872
}
277
278
279
extern LZMA_API(lzma_ret)
280
lzma_block_decoder(lzma_stream *strm, lzma_block *block)
281
0
{
282
0
  lzma_next_strm_init(lzma_block_decoder_init, strm, block);
283
284
0
  strm->internal->supported_actions[LZMA_RUN] = true;
285
0
  strm->internal->supported_actions[LZMA_FINISH] = true;
286
287
0
  return LZMA_OK;
288
0
}