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 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 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 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 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) 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