| OLD | NEW |
| 1 /////////////////////////////////////////////////////////////////////////////// | 1 /////////////////////////////////////////////////////////////////////////////// |
| 2 // | 2 // |
| 3 /// \file coder.c | 3 /// \file coder.c |
| 4 /// \brief Compresses or uncompresses a file | 4 /// \brief Compresses or uncompresses a file |
| 5 // | 5 // |
| 6 // Author: Lasse Collin | 6 // Author: Lasse Collin |
| 7 // | 7 // |
| 8 // This file has been put into the public domain. | 8 // This file has been put into the public domain. |
| 9 // You can do whatever you want with this file. | 9 // You can do whatever you want with this file. |
| 10 // | 10 // |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 /// Input and output buffers | 35 /// Input and output buffers |
| 36 static io_buf in_buf; | 36 static io_buf in_buf; |
| 37 static io_buf out_buf; | 37 static io_buf out_buf; |
| 38 | 38 |
| 39 /// Number of filters. Zero indicates that we are using a preset. | 39 /// Number of filters. Zero indicates that we are using a preset. |
| 40 static size_t filters_count = 0; | 40 static size_t filters_count = 0; |
| 41 | 41 |
| 42 /// Number of the preset (0-9) | 42 /// Number of the preset (0-9) |
| 43 static size_t preset_number = 6; | 43 static size_t preset_number = 6; |
| 44 | 44 |
| 45 /// Indicate if no preset has been explicitly given. In that case, if we need | |
| 46 /// to auto-adjust for lower memory usage, we won't print a warning. | |
| 47 static bool preset_default = true; | |
| 48 | |
| 49 /// If a preset is used (no custom filter chain) and preset_extreme is true, | 45 /// If a preset is used (no custom filter chain) and preset_extreme is true, |
| 50 /// a significantly slower compression is used to achieve slightly better | 46 /// a significantly slower compression is used to achieve slightly better |
| 51 /// compression ratio. | 47 /// compression ratio. |
| 52 static bool preset_extreme = false; | 48 static bool preset_extreme = false; |
| 53 | 49 |
| 54 /// Integrity check type | 50 /// Integrity check type |
| 55 static lzma_check check; | 51 static lzma_check check; |
| 56 | 52 |
| 57 /// This becomes false if the --check=CHECK option is used. | 53 /// This becomes false if the --check=CHECK option is used. |
| 58 static bool check_default = true; | 54 static bool check_default = true; |
| 59 | 55 |
| 60 | 56 |
| 61 extern void | 57 extern void |
| 62 coder_set_check(lzma_check new_check) | 58 coder_set_check(lzma_check new_check) |
| 63 { | 59 { |
| 64 check = new_check; | 60 check = new_check; |
| 65 check_default = false; | 61 check_default = false; |
| 66 return; | 62 return; |
| 67 } | 63 } |
| 68 | 64 |
| 69 | 65 |
| 70 extern void | 66 extern void |
| 71 coder_set_preset(size_t new_preset) | 67 coder_set_preset(size_t new_preset) |
| 72 { | 68 { |
| 73 preset_number = new_preset; | 69 preset_number = new_preset; |
| 74 » preset_default = false; | 70 |
| 71 » // Setting a preset makes us forget a possibly defined custom |
| 72 » // filter chain. |
| 73 » while (filters_count > 0) { |
| 74 » » --filters_count; |
| 75 » » free(filters[filters_count].options); |
| 76 » » filters[filters_count].options = NULL; |
| 77 » } |
| 78 |
| 75 return; | 79 return; |
| 76 } | 80 } |
| 77 | 81 |
| 78 | 82 |
| 79 extern void | 83 extern void |
| 80 coder_set_extreme(void) | 84 coder_set_extreme(void) |
| 81 { | 85 { |
| 82 preset_extreme = true; | 86 preset_extreme = true; |
| 83 return; | 87 return; |
| 84 } | 88 } |
| 85 | 89 |
| 86 | 90 |
| 87 extern void | 91 extern void |
| 88 coder_add_filter(lzma_vli id, void *options) | 92 coder_add_filter(lzma_vli id, void *options) |
| 89 { | 93 { |
| 90 if (filters_count == LZMA_FILTERS_MAX) | 94 if (filters_count == LZMA_FILTERS_MAX) |
| 91 message_fatal(_("Maximum number of filters is four")); | 95 message_fatal(_("Maximum number of filters is four")); |
| 92 | 96 |
| 93 filters[filters_count].id = id; | 97 filters[filters_count].id = id; |
| 94 filters[filters_count].options = options; | 98 filters[filters_count].options = options; |
| 95 ++filters_count; | 99 ++filters_count; |
| 96 | 100 |
| 97 return; | 101 return; |
| 98 } | 102 } |
| 99 | 103 |
| 100 | 104 |
| 101 static void lzma_attribute((noreturn)) | 105 static void lzma_attribute((__noreturn__)) |
| 102 memlimit_too_small(uint64_t memory_usage) | 106 memlimit_too_small(uint64_t memory_usage) |
| 103 { | 107 { |
| 104 message(V_ERROR, _("Memory usage limit is too low for the given " | 108 message(V_ERROR, _("Memory usage limit is too low for the given " |
| 105 "filter setup.")); | 109 "filter setup.")); |
| 106 message_mem_needed(V_ERROR, memory_usage); | 110 message_mem_needed(V_ERROR, memory_usage); |
| 107 tuklib_exit(E_ERROR, E_ERROR, false); | 111 tuklib_exit(E_ERROR, E_ERROR, false); |
| 108 } | 112 } |
| 109 | 113 |
| 110 | 114 |
| 111 extern void | 115 extern void |
| (...skipping 22 matching lines...) Expand all Loading... |
| 134 preset_number |= LZMA_PRESET_EXTREME; | 138 preset_number |= LZMA_PRESET_EXTREME; |
| 135 | 139 |
| 136 if (lzma_lzma_preset(&opt_lzma, preset_number)) | 140 if (lzma_lzma_preset(&opt_lzma, preset_number)) |
| 137 message_bug(); | 141 message_bug(); |
| 138 | 142 |
| 139 // Use LZMA2 except with --format=lzma we use LZMA1. | 143 // Use LZMA2 except with --format=lzma we use LZMA1. |
| 140 filters[0].id = opt_format == FORMAT_LZMA | 144 filters[0].id = opt_format == FORMAT_LZMA |
| 141 ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2; | 145 ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2; |
| 142 filters[0].options = &opt_lzma; | 146 filters[0].options = &opt_lzma; |
| 143 filters_count = 1; | 147 filters_count = 1; |
| 144 } else { | |
| 145 preset_default = false; | |
| 146 } | 148 } |
| 147 | 149 |
| 148 // Terminate the filter options array. | 150 // Terminate the filter options array. |
| 149 filters[filters_count].id = LZMA_VLI_UNKNOWN; | 151 filters[filters_count].id = LZMA_VLI_UNKNOWN; |
| 150 | 152 |
| 151 // If we are using the .lzma format, allow exactly one filter | 153 // If we are using the .lzma format, allow exactly one filter |
| 152 // which has to be LZMA1. | 154 // which has to be LZMA1. |
| 153 if (opt_format == FORMAT_LZMA && (filters_count != 1 | 155 if (opt_format == FORMAT_LZMA && (filters_count != 1 |
| 154 || filters[0].id != LZMA_FILTER_LZMA1)) | 156 || filters[0].id != LZMA_FILTER_LZMA1)) |
| 155 message_fatal(_("The .lzma format supports only " | 157 message_fatal(_("The .lzma format supports only " |
| 156 "the LZMA1 filter")); | 158 "the LZMA1 filter")); |
| 157 | 159 |
| 158 // If we are using the .xz format, make sure that there is no LZMA1 | 160 // If we are using the .xz format, make sure that there is no LZMA1 |
| 159 // filter to prevent LZMA_PROG_ERROR. | 161 // filter to prevent LZMA_PROG_ERROR. |
| 160 if (opt_format == FORMAT_XZ) | 162 if (opt_format == FORMAT_XZ) |
| 161 for (size_t i = 0; i < filters_count; ++i) | 163 for (size_t i = 0; i < filters_count; ++i) |
| 162 if (filters[i].id == LZMA_FILTER_LZMA1) | 164 if (filters[i].id == LZMA_FILTER_LZMA1) |
| 163 message_fatal(_("LZMA1 cannot be used " | 165 message_fatal(_("LZMA1 cannot be used " |
| 164 "with the .xz format")); | 166 "with the .xz format")); |
| 165 | 167 |
| 166 // Print the selected filter chain. | 168 // Print the selected filter chain. |
| 167 message_filters_show(V_DEBUG, filters); | 169 message_filters_show(V_DEBUG, filters); |
| 168 | 170 |
| 169 // If using --format=raw, we can be decoding. The memusage function | 171 // If using --format=raw, we can be decoding. The memusage function |
| 170 // also validates the filter chain and the options used for the | 172 // also validates the filter chain and the options used for the |
| 171 // filters. | 173 // filters. |
| 172 » const uint64_t memory_limit = hardware_memlimit_get(); | 174 » const uint64_t memory_limit = hardware_memlimit_get(opt_mode); |
| 173 uint64_t memory_usage; | 175 uint64_t memory_usage; |
| 174 if (opt_mode == MODE_COMPRESS) | 176 if (opt_mode == MODE_COMPRESS) |
| 175 memory_usage = lzma_raw_encoder_memusage(filters); | 177 memory_usage = lzma_raw_encoder_memusage(filters); |
| 176 else | 178 else |
| 177 memory_usage = lzma_raw_decoder_memusage(filters); | 179 memory_usage = lzma_raw_decoder_memusage(filters); |
| 178 | 180 |
| 179 if (memory_usage == UINT64_MAX) | 181 if (memory_usage == UINT64_MAX) |
| 180 message_fatal(_("Unsupported filter chain or filter options")); | 182 message_fatal(_("Unsupported filter chain or filter options")); |
| 181 | 183 |
| 182 // Print memory usage info before possible dictionary | 184 // Print memory usage info before possible dictionary |
| 183 // size auto-adjusting. | 185 // size auto-adjusting. |
| 184 message_mem_needed(V_DEBUG, memory_usage); | 186 message_mem_needed(V_DEBUG, memory_usage); |
| 187 if (opt_mode == MODE_COMPRESS) { |
| 188 const uint64_t decmem = lzma_raw_decoder_memusage(filters); |
| 189 if (decmem != UINT64_MAX) |
| 190 message(V_DEBUG, _("Decompression will need " |
| 191 "%s MiB of memory."), uint64_to_str( |
| 192 round_up_to_mib(decmem), 0)); |
| 193 } |
| 185 | 194 |
| 186 if (memory_usage > memory_limit) { | 195 if (memory_usage > memory_limit) { |
| 187 // If --no-auto-adjust was used or we didn't find LZMA1 or | 196 // If --no-auto-adjust was used or we didn't find LZMA1 or |
| 188 // LZMA2 as the last filter, give an error immediately. | 197 // LZMA2 as the last filter, give an error immediately. |
| 189 // --format=raw implies --no-auto-adjust. | 198 // --format=raw implies --no-auto-adjust. |
| 190 if (!opt_auto_adjust || opt_format == FORMAT_RAW) | 199 if (!opt_auto_adjust || opt_format == FORMAT_RAW) |
| 191 memlimit_too_small(memory_usage); | 200 memlimit_too_small(memory_usage); |
| 192 | 201 |
| 193 assert(opt_mode == MODE_COMPRESS); | 202 assert(opt_mode == MODE_COMPRESS); |
| 194 | 203 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 if (memory_usage <= memory_limit) | 237 if (memory_usage <= memory_limit) |
| 229 break; | 238 break; |
| 230 | 239 |
| 231 // Otherwise 1 MiB down and try again. I hope this | 240 // Otherwise 1 MiB down and try again. I hope this |
| 232 // isn't too slow method for cases where the original | 241 // isn't too slow method for cases where the original |
| 233 // dict_size is very big. | 242 // dict_size is very big. |
| 234 opt->dict_size -= UINT32_C(1) << 20; | 243 opt->dict_size -= UINT32_C(1) << 20; |
| 235 } | 244 } |
| 236 | 245 |
| 237 // Tell the user that we decreased the dictionary size. | 246 // Tell the user that we decreased the dictionary size. |
| 238 » » // However, omit the message if no preset or custom chain | 247 » » message(V_WARNING, _("Adjusted LZMA%c dictionary size " |
| 239 » » // was given. FIXME: Always warn? | 248 » » » » "from %s MiB to %s MiB to not exceed " |
| 240 » » if (!preset_default) | 249 » » » » "the memory usage limit of %s MiB"), |
| 241 » » » message(V_WARNING, _("Adjusted LZMA%c dictionary size " | 250 » » » » filters[i].id == LZMA_FILTER_LZMA2 |
| 242 » » » » » "from %s MiB to %s MiB to not exceed " | 251 » » » » » ? '2' : '1', |
| 243 » » » » » "the memory usage limit of %s MiB"), | 252 » » » » uint64_to_str(orig_dict_size >> 20, 0), |
| 244 » » » » » filters[i].id == LZMA_FILTER_LZMA2 | 253 » » » » uint64_to_str(opt->dict_size >> 20, 1), |
| 245 » » » » » » ? '2' : '1', | 254 » » » » uint64_to_str(round_up_to_mib( |
| 246 » » » » » uint64_to_str(orig_dict_size >> 20, 0), | 255 » » » » » memory_limit), 2)); |
| 247 » » » » » uint64_to_str(opt->dict_size >> 20, 1), | |
| 248 » » » » » uint64_to_str(round_up_to_mib( | |
| 249 » » » » » » memory_limit), 2)); | |
| 250 } | 256 } |
| 251 | 257 |
| 252 /* | 258 /* |
| 253 // Limit the number of worker threads so that memory usage | 259 // Limit the number of worker threads so that memory usage |
| 254 // limit isn't exceeded. | 260 // limit isn't exceeded. |
| 255 assert(memory_usage > 0); | 261 assert(memory_usage > 0); |
| 256 size_t thread_limit = memory_limit / memory_usage; | 262 size_t thread_limit = memory_limit / memory_usage; |
| 257 if (thread_limit == 0) | 263 if (thread_limit == 0) |
| 258 thread_limit = 1; | 264 thread_limit = 1; |
| 259 | 265 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 // passthru mode with --test. | 405 // passthru mode with --test. |
| 400 if (opt_mode == MODE_DECOMPRESS | 406 if (opt_mode == MODE_DECOMPRESS |
| 401 && opt_stdout && opt_force) | 407 && opt_stdout && opt_force) |
| 402 return CODER_INIT_PASSTHRU; | 408 return CODER_INIT_PASSTHRU; |
| 403 | 409 |
| 404 ret = LZMA_FORMAT_ERROR; | 410 ret = LZMA_FORMAT_ERROR; |
| 405 break; | 411 break; |
| 406 | 412 |
| 407 case FORMAT_XZ: | 413 case FORMAT_XZ: |
| 408 ret = lzma_stream_decoder(&strm, | 414 ret = lzma_stream_decoder(&strm, |
| 409 » » » » » hardware_memlimit_get(), flags); | 415 » » » » » hardware_memlimit_get( |
| 416 » » » » » » MODE_DECOMPRESS), flags); |
| 410 break; | 417 break; |
| 411 | 418 |
| 412 case FORMAT_LZMA: | 419 case FORMAT_LZMA: |
| 413 ret = lzma_alone_decoder(&strm, | 420 ret = lzma_alone_decoder(&strm, |
| 414 » » » » » hardware_memlimit_get()); | 421 » » » » » hardware_memlimit_get( |
| 422 » » » » » » MODE_DECOMPRESS)); |
| 415 break; | 423 break; |
| 416 | 424 |
| 417 case FORMAT_RAW: | 425 case FORMAT_RAW: |
| 418 // Memory usage has already been checked in | 426 // Memory usage has already been checked in |
| 419 // coder_set_compression_settings(). | 427 // coder_set_compression_settings(). |
| 420 ret = lzma_raw_decoder(&strm, filters); | 428 ret = lzma_raw_decoder(&strm, filters); |
| 421 break; | 429 break; |
| 422 } | 430 } |
| 423 | 431 |
| 424 // Try to decode the headers. This will catch too low | 432 // Try to decode the headers. This will catch too low |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 } | 654 } |
| 647 } | 655 } |
| 648 } | 656 } |
| 649 | 657 |
| 650 // Close the file pair. It needs to know if coding was successful to | 658 // Close the file pair. It needs to know if coding was successful to |
| 651 // know if the source or target file should be unlinked. | 659 // know if the source or target file should be unlinked. |
| 652 io_close(pair, success); | 660 io_close(pair, success); |
| 653 | 661 |
| 654 return; | 662 return; |
| 655 } | 663 } |
| OLD | NEW |