Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmliblzma/liblzma/common/alone_decoder.c
3153 views
1
// SPDX-License-Identifier: 0BSD
2
3
///////////////////////////////////////////////////////////////////////////////
4
//
5
/// \file alone_decoder.c
6
/// \brief Decoder for LZMA_Alone files
7
//
8
// Author: Lasse Collin
9
//
10
///////////////////////////////////////////////////////////////////////////////
11
12
#include "alone_decoder.h"
13
#include "lzma_decoder.h"
14
#include "lz_decoder.h"
15
16
17
typedef struct {
18
lzma_next_coder next;
19
20
enum {
21
SEQ_PROPERTIES,
22
SEQ_DICTIONARY_SIZE,
23
SEQ_UNCOMPRESSED_SIZE,
24
SEQ_CODER_INIT,
25
SEQ_CODE,
26
} sequence;
27
28
/// If true, reject files that are unlikely to be .lzma files.
29
/// If false, more non-.lzma files get accepted and will give
30
/// LZMA_DATA_ERROR either immediately or after a few output bytes.
31
bool picky;
32
33
/// Position in the header fields
34
size_t pos;
35
36
/// Uncompressed size decoded from the header
37
lzma_vli uncompressed_size;
38
39
/// Memory usage limit
40
uint64_t memlimit;
41
42
/// Amount of memory actually needed (only an estimate)
43
uint64_t memusage;
44
45
/// Options decoded from the header needed to initialize
46
/// the LZMA decoder
47
lzma_options_lzma options;
48
} lzma_alone_coder;
49
50
51
static lzma_ret
52
alone_decode(void *coder_ptr, const lzma_allocator *allocator,
53
const uint8_t *restrict in, size_t *restrict in_pos,
54
size_t in_size, uint8_t *restrict out,
55
size_t *restrict out_pos, size_t out_size,
56
lzma_action action)
57
{
58
lzma_alone_coder *coder = coder_ptr;
59
60
while (*out_pos < out_size
61
&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
62
switch (coder->sequence) {
63
case SEQ_PROPERTIES:
64
if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
65
return LZMA_FORMAT_ERROR;
66
67
coder->sequence = SEQ_DICTIONARY_SIZE;
68
++*in_pos;
69
break;
70
71
case SEQ_DICTIONARY_SIZE:
72
coder->options.dict_size
73
|= (size_t)(in[*in_pos]) << (coder->pos * 8);
74
75
if (++coder->pos == 4) {
76
if (coder->picky && coder->options.dict_size
77
!= UINT32_MAX) {
78
// A hack to ditch tons of false positives:
79
// We allow only dictionary sizes that are
80
// 2^n or 2^n + 2^(n-1). LZMA_Alone created
81
// only files with 2^n, but accepts any
82
// dictionary size.
83
uint32_t d = coder->options.dict_size - 1;
84
d |= d >> 2;
85
d |= d >> 3;
86
d |= d >> 4;
87
d |= d >> 8;
88
d |= d >> 16;
89
++d;
90
91
if (d != coder->options.dict_size)
92
return LZMA_FORMAT_ERROR;
93
}
94
95
coder->pos = 0;
96
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
97
}
98
99
++*in_pos;
100
break;
101
102
case SEQ_UNCOMPRESSED_SIZE:
103
coder->uncompressed_size
104
|= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
105
++*in_pos;
106
if (++coder->pos < 8)
107
break;
108
109
// Another hack to ditch false positives: Assume that
110
// if the uncompressed size is known, it must be less
111
// than 256 GiB.
112
//
113
// FIXME? Without picky we allow > LZMA_VLI_MAX which doesn't
114
// really matter in this specific situation (> LZMA_VLI_MAX is
115
// safe in the LZMA decoder) but it's somewhat weird still.
116
if (coder->picky
117
&& coder->uncompressed_size != LZMA_VLI_UNKNOWN
118
&& coder->uncompressed_size
119
>= (LZMA_VLI_C(1) << 38))
120
return LZMA_FORMAT_ERROR;
121
122
// Use LZMA_FILTER_LZMA1EXT features to specify the
123
// uncompressed size and that the end marker is allowed
124
// even when the uncompressed size is known. Both .lzma
125
// header and LZMA1EXT use UINT64_MAX indicate that size
126
// is unknown.
127
coder->options.ext_flags = LZMA_LZMA1EXT_ALLOW_EOPM;
128
lzma_set_ext_size(coder->options, coder->uncompressed_size);
129
130
// Calculate the memory usage so that it is ready
131
// for SEQ_CODER_INIT.
132
coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
133
+ LZMA_MEMUSAGE_BASE;
134
135
coder->pos = 0;
136
coder->sequence = SEQ_CODER_INIT;
137
138
// Fall through
139
140
case SEQ_CODER_INIT: {
141
if (coder->memusage > coder->memlimit)
142
return LZMA_MEMLIMIT_ERROR;
143
144
lzma_filter_info filters[2] = {
145
{
146
.id = LZMA_FILTER_LZMA1EXT,
147
.init = &lzma_lzma_decoder_init,
148
.options = &coder->options,
149
}, {
150
.init = NULL,
151
}
152
};
153
154
return_if_error(lzma_next_filter_init(&coder->next,
155
allocator, filters));
156
157
coder->sequence = SEQ_CODE;
158
break;
159
}
160
161
case SEQ_CODE: {
162
return coder->next.code(coder->next.coder,
163
allocator, in, in_pos, in_size,
164
out, out_pos, out_size, action);
165
}
166
167
default:
168
return LZMA_PROG_ERROR;
169
}
170
171
return LZMA_OK;
172
}
173
174
175
static void
176
alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
177
{
178
lzma_alone_coder *coder = coder_ptr;
179
lzma_next_end(&coder->next, allocator);
180
lzma_free(coder, allocator);
181
return;
182
}
183
184
185
static lzma_ret
186
alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
187
uint64_t *old_memlimit, uint64_t new_memlimit)
188
{
189
lzma_alone_coder *coder = coder_ptr;
190
191
*memusage = coder->memusage;
192
*old_memlimit = coder->memlimit;
193
194
if (new_memlimit != 0) {
195
if (new_memlimit < coder->memusage)
196
return LZMA_MEMLIMIT_ERROR;
197
198
coder->memlimit = new_memlimit;
199
}
200
201
return LZMA_OK;
202
}
203
204
205
extern lzma_ret
206
lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
207
uint64_t memlimit, bool picky)
208
{
209
lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
210
211
lzma_alone_coder *coder = next->coder;
212
213
if (coder == NULL) {
214
coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
215
if (coder == NULL)
216
return LZMA_MEM_ERROR;
217
218
next->coder = coder;
219
next->code = &alone_decode;
220
next->end = &alone_decoder_end;
221
next->memconfig = &alone_decoder_memconfig;
222
coder->next = LZMA_NEXT_CODER_INIT;
223
}
224
225
coder->sequence = SEQ_PROPERTIES;
226
coder->picky = picky;
227
coder->pos = 0;
228
coder->options.dict_size = 0;
229
coder->options.preset_dict = NULL;
230
coder->options.preset_dict_size = 0;
231
coder->uncompressed_size = 0;
232
coder->memlimit = my_max(1, memlimit);
233
coder->memusage = LZMA_MEMUSAGE_BASE;
234
235
return LZMA_OK;
236
}
237
238
239
extern LZMA_API(lzma_ret)
240
lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
241
{
242
lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
243
244
strm->internal->supported_actions[LZMA_RUN] = true;
245
strm->internal->supported_actions[LZMA_FINISH] = true;
246
247
return LZMA_OK;
248
}
249
250