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