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 |