Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: src/xzdec/xzdec.c

Issue 7109015: Update XZ Utils to 5.0.3 (in deps) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/xz/
Patch Set: Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/xzdec/xzdec.1 ('k') | tests/Makefile.am » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /////////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////////
2 // 2 //
3 /// \file xzdec.c 3 /// \file xzdec.c
4 /// \brief Simple single-threaded tool to uncompress .xz or .lzma files 4 /// \brief Simple single-threaded tool to uncompress .xz or .lzma files
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 17 matching lines...) Expand all
28 #endif 28 #endif
29 29
30 30
31 #ifdef LZMADEC 31 #ifdef LZMADEC
32 # define TOOL_FORMAT "lzma" 32 # define TOOL_FORMAT "lzma"
33 #else 33 #else
34 # define TOOL_FORMAT "xz" 34 # define TOOL_FORMAT "xz"
35 #endif 35 #endif
36 36
37 37
38 /// Number of bytes to use memory at maximum
39 static uint64_t memlimit;
40
41 /// Total amount of physical RAM
42 static uint64_t total_ram;
43
44 /// Error messages are suppressed if this is zero, which is the case when 38 /// Error messages are suppressed if this is zero, which is the case when
45 /// --quiet has been given at least twice. 39 /// --quiet has been given at least twice.
46 static unsigned int display_errors = 2; 40 static unsigned int display_errors = 2;
47 41
48 42
49 static void lzma_attribute((format(printf, 1, 2))) 43 static void lzma_attribute((__format__(__printf__, 1, 2)))
50 my_errorf(const char *fmt, ...) 44 my_errorf(const char *fmt, ...)
51 { 45 {
52 va_list ap; 46 va_list ap;
53 va_start(ap, fmt); 47 va_start(ap, fmt);
54 48
55 if (display_errors) { 49 if (display_errors) {
56 fprintf(stderr, "%s: ", progname); 50 fprintf(stderr, "%s: ", progname);
57 vfprintf(stderr, fmt, ap); 51 vfprintf(stderr, fmt, ap);
58 fprintf(stderr, "\n"); 52 fprintf(stderr, "\n");
59 } 53 }
60 54
61 va_end(ap); 55 va_end(ap);
62 return; 56 return;
63 } 57 }
64 58
65 59
66 static void lzma_attribute((noreturn)) 60 static void lzma_attribute((__noreturn__))
67 help(void) 61 help(void)
68 { 62 {
69 // Round up to the next MiB and do it correctly also with UINT64_MAX.
70 const uint64_t mem_mib = (memlimit >> 20)
71 + ((memlimit & ((UINT32_C(1) << 20) - 1)) != 0);
72
73 printf( 63 printf(
74 "Usage: %s [OPTION]... [FILE]...\n" 64 "Usage: %s [OPTION]... [FILE]...\n"
75 "Uncompress files in the ." TOOL_FORMAT " format to the standard output.\n" 65 "Uncompress files in the ." TOOL_FORMAT " format to the standard output.\n"
76 "\n" 66 "\n"
77 " -c, --stdout (ignored)\n" 67 " -c, --stdout (ignored)\n"
78 " -d, --decompress (ignored)\n" 68 " -d, --decompress (ignored)\n"
79 " -k, --keep (ignored)\n" 69 " -k, --keep (ignored)\n"
80 " -M, --memory=NUM use NUM bytes of memory at maximum (0 means default)\n"
81 " -q, --quiet specify *twice* to suppress errors\n" 70 " -q, --quiet specify *twice* to suppress errors\n"
82 " -Q, --no-warn (ignored)\n" 71 " -Q, --no-warn (ignored)\n"
83 " -h, --help display this help and exit\n" 72 " -h, --help display this help and exit\n"
84 " -V, --version display the version number and exit\n" 73 " -V, --version display the version number and exit\n"
85 "\n" 74 "\n"
86 "With no FILE, or when FILE is -, read standard input.\n" 75 "With no FILE, or when FILE is -, read standard input.\n"
87 "\n" 76 "\n"
88 "On this system and configuration, this program will use a maximum of roughly\n"
89 "%" PRIu64 " MiB RAM.\n"
90 "\n"
91 "Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n" 77 "Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n"
92 PACKAGE_NAME " home page: <" PACKAGE_URL ">\n", progname, mem_mib); 78 PACKAGE_NAME " home page: <" PACKAGE_URL ">\n", progname);
79
93 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors); 80 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors);
94 } 81 }
95 82
96 83
97 static void lzma_attribute((noreturn)) 84 static void lzma_attribute((__noreturn__))
98 version(void) 85 version(void)
99 { 86 {
100 printf(TOOL_FORMAT "dec (" PACKAGE_NAME ") " LZMA_VERSION_STRING "\n" 87 printf(TOOL_FORMAT "dec (" PACKAGE_NAME ") " LZMA_VERSION_STRING "\n"
101 "liblzma %s\n", lzma_version_string()); 88 "liblzma %s\n", lzma_version_string());
102 89
103 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors); 90 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors);
104 } 91 }
105 92
106 93
107 /// Find out the amount of physical memory (RAM) in the system, and set
108 /// the memory usage limit to the given percentage of RAM.
109 static void
110 memlimit_set_percentage(uint32_t percentage)
111 {
112 memlimit = percentage * total_ram / 100;
113 return;
114 }
115
116
117 /// Set the memory usage limit to give number of bytes. Zero is a special
118 /// value to indicate the default limit.
119 static void
120 memlimit_set(uint64_t new_memlimit)
121 {
122 if (new_memlimit != 0) {
123 memlimit = new_memlimit;
124 } else {
125 memlimit = 40 * total_ram / 100;
126 if (memlimit < UINT64_C(80) * 1024 * 1024) {
127 memlimit = 80 * total_ram / 100;
128 if (memlimit > UINT64_C(80) * 1024 * 1024)
129 memlimit = UINT64_C(80) * 1024 * 1024;
130 }
131 }
132
133 return;
134 }
135
136
137 /// Get the total amount of physical RAM and set the memory usage limit
138 /// to the default value.
139 static void
140 memlimit_init(void)
141 {
142 // If we cannot determine the amount of RAM, use the assumption
143 // defined by the configure script.
144 total_ram = lzma_physmem();
145 if (total_ram == 0)
146 total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024;
147
148 memlimit_set(0);
149 return;
150 }
151
152
153 /// \brief Convert a string to uint64_t
154 ///
155 /// This is rudely copied from src/xz/util.c and modified a little. :-(
156 /// Since this function is used only for parsing the memory usage limit,
157 /// this cheats a little and saturates too big values to UINT64_MAX instead
158 /// of giving an error.
159 ///
160 /// \param max Return value when the string "max" was specified.
161 ///
162 static uint64_t
163 str_to_uint64(const char *value, uint64_t max)
164 {
165 uint64_t result = 0;
166
167 // Accept special value "max".
168 if (strcmp(value, "max") == 0)
169 return max;
170
171 if (*value < '0' || *value > '9') {
172 my_errorf("%s: Value is not a non-negative decimal integer",
173 value);
174 exit(EXIT_FAILURE);
175 }
176
177 do {
178 // Don't overflow.
179 if (result > UINT64_MAX / 10)
180 return UINT64_MAX;
181
182 result *= 10;
183
184 // Another overflow check
185 const uint32_t add = *value - '0';
186 if (UINT64_MAX - add < result)
187 return UINT64_MAX;
188
189 result += add;
190 ++value;
191 } while (*value >= '0' && *value <= '9');
192
193 if (*value != '\0') {
194 // Look for suffix.
195 uint64_t multiplier = 0;
196 if (*value == 'k' || *value == 'K')
197 multiplier = UINT64_C(1) << 10;
198 else if (*value == 'm' || *value == 'M')
199 multiplier = UINT64_C(1) << 20;
200 else if (*value == 'g' || *value == 'G')
201 multiplier = UINT64_C(1) << 30;
202
203 ++value;
204
205 // Allow also e.g. Ki, KiB, and KB.
206 if (*value != '\0' && strcmp(value, "i") != 0
207 && strcmp(value, "iB") != 0
208 && strcmp(value, "B") != 0)
209 multiplier = 0;
210
211 if (multiplier == 0) {
212 my_errorf("%s: Invalid suffix", value - 1);
213 exit(EXIT_FAILURE);
214 }
215
216 // Don't overflow here either.
217 if (result > UINT64_MAX / multiplier)
218 result = UINT64_MAX;
219 else
220 result *= multiplier;
221 }
222
223 return result;
224 }
225
226
227 /// Parses command line options. 94 /// Parses command line options.
228 static void 95 static void
229 parse_options(int argc, char **argv) 96 parse_options(int argc, char **argv)
230 { 97 {
231 static const char short_opts[] = "cdkM:hqQV"; 98 static const char short_opts[] = "cdkM:hqQV";
232 static const struct option long_opts[] = { 99 static const struct option long_opts[] = {
233 { "stdout", no_argument, NULL, 'c' }, 100 { "stdout", no_argument, NULL, 'c' },
234 { "to-stdout", no_argument, NULL, 'c' }, 101 { "to-stdout", no_argument, NULL, 'c' },
235 { "decompress", no_argument, NULL, 'd' }, 102 { "decompress", no_argument, NULL, 'd' },
236 { "uncompress", no_argument, NULL, 'd' }, 103 { "uncompress", no_argument, NULL, 'd' },
237 { "keep", no_argument, NULL, 'k' }, 104 { "keep", no_argument, NULL, 'k' },
238 { "memory", required_argument, NULL, 'M' },
239 { "quiet", no_argument, NULL, 'q' }, 105 { "quiet", no_argument, NULL, 'q' },
240 { "no-warn", no_argument, NULL, 'Q' }, 106 { "no-warn", no_argument, NULL, 'Q' },
241 { "help", no_argument, NULL, 'h' }, 107 { "help", no_argument, NULL, 'h' },
242 { "version", no_argument, NULL, 'V' }, 108 { "version", no_argument, NULL, 'V' },
243 { NULL, 0, NULL, 0 } 109 { NULL, 0, NULL, 0 }
244 }; 110 };
245 111
246 int c; 112 int c;
247 113
248 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) 114 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
249 != -1) { 115 != -1) {
250 switch (c) { 116 switch (c) {
251 case 'c': 117 case 'c':
252 case 'd': 118 case 'd':
253 case 'k': 119 case 'k':
254 case 'Q': 120 case 'Q':
255 break; 121 break;
256 122
257 case 'M': {
258 // Support specifying the limit as a percentage of
259 // installed physical RAM.
260 const size_t len = strlen(optarg);
261 if (len > 0 && optarg[len - 1] == '%') {
262 // Memory limit is a percentage of total
263 // installed RAM.
264 optarg[len - 1] = '\0';
265 const uint64_t percentage
266 = str_to_uint64(optarg, 100);
267 if (percentage < 1 || percentage > 100) {
268 my_errorf("Percentage must be in "
269 "the range [1, 100]");
270 exit(EXIT_FAILURE);
271 }
272
273 memlimit_set_percentage(percentage);
274 } else {
275 memlimit_set(str_to_uint64(
276 optarg, UINT64_MAX));
277 }
278
279 break;
280 }
281
282 case 'q': 123 case 'q':
283 if (display_errors > 0) 124 if (display_errors > 0)
284 --display_errors; 125 --display_errors;
285 126
286 break; 127 break;
287 128
288 case 'h': 129 case 'h':
289 help(); 130 help();
290 131
291 case 'V': 132 case 'V':
292 version(); 133 version();
293 134
294 default: 135 default:
295 exit(EXIT_FAILURE); 136 exit(EXIT_FAILURE);
296 } 137 }
297 } 138 }
298 139
299 return; 140 return;
300 } 141 }
301 142
302 143
303 static void 144 static void
304 uncompress(lzma_stream *strm, FILE *file, const char *filename) 145 uncompress(lzma_stream *strm, FILE *file, const char *filename)
305 { 146 {
306 lzma_ret ret; 147 lzma_ret ret;
307 148
308 // Initialize the decoder 149 // Initialize the decoder
309 #ifdef LZMADEC 150 #ifdef LZMADEC
310 » ret = lzma_alone_decoder(strm, memlimit); 151 » ret = lzma_alone_decoder(strm, UINT64_MAX);
311 #else 152 #else
312 » ret = lzma_stream_decoder(strm, memlimit, LZMA_CONCATENATED); 153 » ret = lzma_stream_decoder(strm, UINT64_MAX, LZMA_CONCATENATED);
313 #endif 154 #endif
314 155
315 // The only reasonable error here is LZMA_MEM_ERROR. 156 // The only reasonable error here is LZMA_MEM_ERROR.
316 // FIXME: Maybe also LZMA_MEMLIMIT_ERROR in future?
317 if (ret != LZMA_OK) { 157 if (ret != LZMA_OK) {
318 my_errorf("%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM) 158 my_errorf("%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM)
319 : "Internal error (bug)"); 159 : "Internal error (bug)");
320 exit(EXIT_FAILURE); 160 exit(EXIT_FAILURE);
321 } 161 }
322 162
323 // Input and output buffers 163 // Input and output buffers
324 uint8_t in_buf[BUFSIZ]; 164 uint8_t in_buf[BUFSIZ];
325 uint8_t out_buf[BUFSIZ]; 165 uint8_t out_buf[BUFSIZ];
326 166
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 return; 234 return;
395 #endif 235 #endif
396 } 236 }
397 237
398 const char *msg; 238 const char *msg;
399 switch (ret) { 239 switch (ret) {
400 case LZMA_MEM_ERROR: 240 case LZMA_MEM_ERROR:
401 msg = strerror(ENOMEM); 241 msg = strerror(ENOMEM);
402 break; 242 break;
403 243
404 case LZMA_MEMLIMIT_ERROR:
405 msg = "Memory usage limit reached";
406 break;
407
408 case LZMA_FORMAT_ERROR: 244 case LZMA_FORMAT_ERROR:
409 msg = "File format not recognized"; 245 msg = "File format not recognized";
410 break; 246 break;
411 247
412 case LZMA_OPTIONS_ERROR: 248 case LZMA_OPTIONS_ERROR:
413 // FIXME: Better message? 249 // FIXME: Better message?
414 msg = "Unsupported compression options"; 250 msg = "Unsupported compression options";
415 break; 251 break;
416 252
417 case LZMA_DATA_ERROR: 253 case LZMA_DATA_ERROR:
(...skipping 15 matching lines...) Expand all
433 } 269 }
434 } 270 }
435 271
436 272
437 int 273 int
438 main(int argc, char **argv) 274 main(int argc, char **argv)
439 { 275 {
440 // Initialize progname which we will be used in error messages. 276 // Initialize progname which we will be used in error messages.
441 tuklib_progname_init(argv); 277 tuklib_progname_init(argv);
442 278
443 // Set the default memory usage limit. This is needed before parsing
444 // the command line arguments.
445 memlimit_init();
446
447 // Parse the command line options. 279 // Parse the command line options.
448 parse_options(argc, argv); 280 parse_options(argc, argv);
449 281
450 // The same lzma_stream is used for all files that we decode. This way 282 // The same lzma_stream is used for all files that we decode. This way
451 // we don't need to reallocate memory for every file if they use same 283 // we don't need to reallocate memory for every file if they use same
452 // compression settings. 284 // compression settings.
453 lzma_stream strm = LZMA_STREAM_INIT; 285 lzma_stream strm = LZMA_STREAM_INIT;
454 286
455 // Some systems require setting stdin and stdout to binary mode. 287 // Some systems require setting stdin and stdout to binary mode.
456 #ifdef TUKLIB_DOSLIKE 288 #ifdef TUKLIB_DOSLIKE
(...skipping 25 matching lines...) Expand all
482 } 314 }
483 315
484 #ifndef NDEBUG 316 #ifndef NDEBUG
485 // Free the memory only when debugging. Freeing wastes some time, 317 // Free the memory only when debugging. Freeing wastes some time,
486 // but allows detecting possible memory leaks with Valgrind. 318 // but allows detecting possible memory leaks with Valgrind.
487 lzma_end(&strm); 319 lzma_end(&strm);
488 #endif 320 #endif
489 321
490 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors); 322 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, display_errors);
491 } 323 }
OLDNEW
« no previous file with comments | « src/xzdec/xzdec.1 ('k') | tests/Makefile.am » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698