]> icculus.org git repositories - icculus/xz.git/blob - src/xz/list.c
Disable the memory usage limiter by default.
[icculus/xz.git] / src / xz / list.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       list.c
4 /// \brief      Listing information about .xz 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 "private.h"
14 #include "tuklib_integer.h"
15
16
17 /// Information about a .xz file
18 typedef struct {
19         /// Combined Index of all Streams in the file
20         lzma_index *idx;
21
22         /// Total amount of Stream Padding
23         uint64_t stream_padding;
24
25         /// Highest memory usage so far
26         uint64_t memusage_max;
27
28         /// True if all Blocks so far have Compressed Size and
29         /// Uncompressed Size fields
30         bool all_have_sizes;
31
32 } xz_file_info;
33
34 #define XZ_FILE_INFO_INIT { NULL, 0, 0, true }
35
36
37 /// Information about a .xz Block
38 typedef struct {
39         /// Size of the Block Header
40         uint32_t header_size;
41
42         /// A few of the Block Flags as a string
43         char flags[3];
44
45         /// Size of the Compressed Data field in the Block
46         lzma_vli compressed_size;
47
48         /// Decoder memory usage for this Block
49         uint64_t memusage;
50
51         /// The filter chain of this Block in human-readable form
52         const char *filter_chain;
53
54 } block_header_info;
55
56
57 /// Check ID to string mapping
58 static const char check_names[LZMA_CHECK_ID_MAX + 1][12] = {
59         "None",
60         "CRC32",
61         "Unknown-2",
62         "Unknown-3",
63         "CRC64",
64         "Unknown-5",
65         "Unknown-6",
66         "Unknown-7",
67         "Unknown-8",
68         "Unknown-9",
69         "SHA-256",
70         "Unknown-11",
71         "Unknown-12",
72         "Unknown-13",
73         "Unknown-14",
74         "Unknown-15",
75 };
76
77
78 /// Value of the Check field as hexadecimal string.
79 /// This is set by parse_check_value().
80 static char check_value[2 * LZMA_CHECK_SIZE_MAX + 1];
81
82
83 /// Totals that are displayed if there was more than one file.
84 /// The "files" counter is also used in print_info_adv() to show
85 /// the file number.
86 static struct {
87         uint64_t files;
88         uint64_t streams;
89         uint64_t blocks;
90         uint64_t compressed_size;
91         uint64_t uncompressed_size;
92         uint64_t stream_padding;
93         uint64_t memusage_max;
94         uint32_t checks;
95         bool all_have_sizes;
96 } totals = { 0, 0, 0, 0, 0, 0, 0, 0, true };
97
98
99 /// \brief      Parse the Index(es) from the given .xz file
100 ///
101 /// \param      xfi     Pointer to structure where the decoded information
102 ///                     is stored.
103 /// \param      pair    Input file
104 ///
105 /// \return     On success, false is returned. On error, true is returned.
106 ///
107 // TODO: This function is pretty big. liblzma should have a function that
108 // takes a callback function to parse the Index(es) from a .xz file to make
109 // it easy for applications.
110 static bool
111 parse_indexes(xz_file_info *xfi, file_pair *pair)
112 {
113         if (pair->src_st.st_size <= 0) {
114                 message_error(_("%s: File is empty"), pair->src_name);
115                 return true;
116         }
117
118         if (pair->src_st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) {
119                 message_error(_("%s: Too small to be a valid .xz file"),
120                                 pair->src_name);
121                 return true;
122         }
123
124         io_buf buf;
125         lzma_stream_flags header_flags;
126         lzma_stream_flags footer_flags;
127         lzma_ret ret;
128
129         // lzma_stream for the Index decoder
130         lzma_stream strm = LZMA_STREAM_INIT;
131
132         // All Indexes decoded so far
133         lzma_index *combined_index = NULL;
134
135         // The Index currently being decoded
136         lzma_index *this_index = NULL;
137
138         // Current position in the file. We parse the file backwards so
139         // initialize it to point to the end of the file.
140         off_t pos = pair->src_st.st_size;
141
142         // Each loop iteration decodes one Index.
143         do {
144                 // Check that there is enough data left to contain at least
145                 // the Stream Header and Stream Footer. This check cannot
146                 // fail in the first pass of this loop.
147                 if (pos < 2 * LZMA_STREAM_HEADER_SIZE) {
148                         message_error("%s: %s", pair->src_name,
149                                         message_strm(LZMA_DATA_ERROR));
150                         goto error;
151                 }
152
153                 pos -= LZMA_STREAM_HEADER_SIZE;
154                 lzma_vli stream_padding = 0;
155
156                 // Locate the Stream Footer. There may be Stream Padding which
157                 // we must skip when reading backwards.
158                 while (true) {
159                         if (pos < LZMA_STREAM_HEADER_SIZE) {
160                                 message_error("%s: %s", pair->src_name,
161                                                 message_strm(
162                                                         LZMA_DATA_ERROR));
163                                 goto error;
164                         }
165
166                         if (io_pread(pair, &buf,
167                                         LZMA_STREAM_HEADER_SIZE, pos))
168                                 goto error;
169
170                         // Stream Padding is always a multiple of four bytes.
171                         int i = 2;
172                         if (buf.u32[i] != 0)
173                                 break;
174
175                         // To avoid calling io_pread() for every four bytes
176                         // of Stream Padding, take advantage that we read
177                         // 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
178                         // check them too before calling io_pread() again.
179                         do {
180                                 stream_padding += 4;
181                                 pos -= 4;
182                                 --i;
183                         } while (i >= 0 && buf.u32[i] == 0);
184                 }
185
186                 // Decode the Stream Footer.
187                 ret = lzma_stream_footer_decode(&footer_flags, buf.u8);
188                 if (ret != LZMA_OK) {
189                         message_error("%s: %s", pair->src_name,
190                                         message_strm(ret));
191                         goto error;
192                 }
193
194                 // Check that the size of the Index field looks sane.
195                 lzma_vli index_size = footer_flags.backward_size;
196                 if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) {
197                         message_error("%s: %s", pair->src_name,
198                                         message_strm(LZMA_DATA_ERROR));
199                         goto error;
200                 }
201
202                 // Set pos to the beginning of the Index.
203                 pos -= index_size;
204
205                 // See how much memory we can use for decoding this Index.
206                 uint64_t memlimit = hardware_memlimit_get(MODE_LIST);
207                 uint64_t memused = 0;
208                 if (combined_index != NULL) {
209                         memused = lzma_index_memused(combined_index);
210                         if (memused > memlimit)
211                                 message_bug();
212
213                         memlimit -= memused;
214                 }
215
216                 // Decode the Index.
217                 ret = lzma_index_decoder(&strm, &this_index, memlimit);
218                 if (ret != LZMA_OK) {
219                         message_error("%s: %s", pair->src_name,
220                                         message_strm(ret));
221                         goto error;
222                 }
223
224                 do {
225                         // Don't give the decoder more input than the
226                         // Index size.
227                         strm.avail_in = my_min(IO_BUFFER_SIZE, index_size);
228                         if (io_pread(pair, &buf, strm.avail_in, pos))
229                                 goto error;
230
231                         pos += strm.avail_in;
232                         index_size -= strm.avail_in;
233
234                         strm.next_in = buf.u8;
235                         ret = lzma_code(&strm, LZMA_RUN);
236
237                 } while (ret == LZMA_OK);
238
239                 // If the decoding seems to be successful, check also that
240                 // the Index decoder consumed as much input as indicated
241                 // by the Backward Size field.
242                 if (ret == LZMA_STREAM_END)
243                         if (index_size != 0 || strm.avail_in != 0)
244                                 ret = LZMA_DATA_ERROR;
245
246                 if (ret != LZMA_STREAM_END) {
247                         // LZMA_BUFFER_ERROR means that the Index decoder
248                         // would have liked more input than what the Index
249                         // size should be according to Stream Footer.
250                         // The message for LZMA_DATA_ERROR makes more
251                         // sense in that case.
252                         if (ret == LZMA_BUF_ERROR)
253                                 ret = LZMA_DATA_ERROR;
254
255                         message_error("%s: %s", pair->src_name,
256                                         message_strm(ret));
257
258                         // If the error was too low memory usage limit,
259                         // show also how much memory would have been needed.
260                         if (ret == LZMA_MEMLIMIT_ERROR) {
261                                 uint64_t needed = lzma_memusage(&strm);
262                                 if (UINT64_MAX - needed < memused)
263                                         needed = UINT64_MAX;
264                                 else
265                                         needed += memused;
266
267                                 message_mem_needed(V_ERROR, needed);
268                         }
269
270                         goto error;
271                 }
272
273                 // Decode the Stream Header and check that its Stream Flags
274                 // match the Stream Footer.
275                 pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
276                 if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) {
277                         message_error("%s: %s", pair->src_name,
278                                         message_strm(LZMA_DATA_ERROR));
279                         goto error;
280                 }
281
282                 pos -= lzma_index_total_size(this_index);
283                 if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos))
284                         goto error;
285
286                 ret = lzma_stream_header_decode(&header_flags, buf.u8);
287                 if (ret != LZMA_OK) {
288                         message_error("%s: %s", pair->src_name,
289                                         message_strm(ret));
290                         goto error;
291                 }
292
293                 ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
294                 if (ret != LZMA_OK) {
295                         message_error("%s: %s", pair->src_name,
296                                         message_strm(ret));
297                         goto error;
298                 }
299
300                 // Store the decoded Stream Flags into this_index. This is
301                 // needed so that we can print which Check is used in each
302                 // Stream.
303                 ret = lzma_index_stream_flags(this_index, &footer_flags);
304                 if (ret != LZMA_OK)
305                         message_bug();
306
307                 // Store also the size of the Stream Padding field. It is
308                 // needed to show the offsets of the Streams correctly.
309                 ret = lzma_index_stream_padding(this_index, stream_padding);
310                 if (ret != LZMA_OK)
311                         message_bug();
312
313                 if (combined_index != NULL) {
314                         // Append the earlier decoded Indexes
315                         // after this_index.
316                         ret = lzma_index_cat(
317                                         this_index, combined_index, NULL);
318                         if (ret != LZMA_OK) {
319                                 message_error("%s: %s", pair->src_name,
320                                                 message_strm(ret));
321                                 goto error;
322                         }
323                 }
324
325                 combined_index = this_index;
326                 this_index = NULL;
327
328                 xfi->stream_padding += stream_padding;
329
330         } while (pos > 0);
331
332         lzma_end(&strm);
333
334         // All OK. Make combined_index available to the caller.
335         xfi->idx = combined_index;
336         return false;
337
338 error:
339         // Something went wrong, free the allocated memory.
340         lzma_end(&strm);
341         lzma_index_end(combined_index, NULL);
342         lzma_index_end(this_index, NULL);
343         return true;
344 }
345
346
347 /// \brief      Parse the Block Header
348 ///
349 /// The result is stored into *bhi. The caller takes care of initializing it.
350 ///
351 /// \return     False on success, true on error.
352 static bool
353 parse_block_header(file_pair *pair, const lzma_index_iter *iter,
354                 block_header_info *bhi, xz_file_info *xfi)
355 {
356 #if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
357 #       error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
358 #endif
359
360         // Get the whole Block Header with one read, but don't read past
361         // the end of the Block (or even its Check field).
362         const uint32_t size = my_min(iter->block.total_size
363                                 - lzma_check_size(iter->stream.flags->check),
364                         LZMA_BLOCK_HEADER_SIZE_MAX);
365         io_buf buf;
366         if (io_pread(pair, &buf, size, iter->block.compressed_file_offset))
367                 return true;
368
369         // Zero would mean Index Indicator and thus not a valid Block.
370         if (buf.u8[0] == 0)
371                 goto data_error;
372
373         lzma_block block;
374         lzma_filter filters[LZMA_FILTERS_MAX + 1];
375
376         // Initialize the pointers so that they can be passed to free().
377         for (size_t i = 0; i < ARRAY_SIZE(filters); ++i)
378                 filters[i].options = NULL;
379
380         // Initialize the block structure and decode Block Header Size.
381         block.version = 0;
382         block.check = iter->stream.flags->check;
383         block.filters = filters;
384
385         block.header_size = lzma_block_header_size_decode(buf.u8[0]);
386         if (block.header_size > size)
387                 goto data_error;
388
389         // Decode the Block Header.
390         switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
391         case LZMA_OK:
392                 break;
393
394         case LZMA_OPTIONS_ERROR:
395                 message_error("%s: %s", pair->src_name,
396                                 message_strm(LZMA_OPTIONS_ERROR));
397                 return true;
398
399         case LZMA_DATA_ERROR:
400                 goto data_error;
401
402         default:
403                 message_bug();
404         }
405
406         // Check the Block Flags. These must be done before calling
407         // lzma_block_compressed_size(), because it overwrites
408         // block.compressed_size.
409         bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
410                         ? 'c' : '-';
411         bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
412                         ? 'u' : '-';
413         bhi->flags[2] = '\0';
414
415         // Collect information if all Blocks have both Compressed Size
416         // and Uncompressed Size fields. They can be useful e.g. for
417         // multi-threaded decompression so it can be useful to know it.
418         xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
419                         && block.uncompressed_size != LZMA_VLI_UNKNOWN;
420
421         // Validate or set block.compressed_size.
422         switch (lzma_block_compressed_size(&block,
423                         iter->block.unpadded_size)) {
424         case LZMA_OK:
425                 break;
426
427         case LZMA_DATA_ERROR:
428                 goto data_error;
429
430         default:
431                 message_bug();
432         }
433
434         // Copy the known sizes.
435         bhi->header_size = block.header_size;
436         bhi->compressed_size = block.compressed_size;
437
438         // Calculate the decoder memory usage and update the maximum
439         // memory usage of this Block.
440         bhi->memusage = lzma_raw_decoder_memusage(filters);
441         if (xfi->memusage_max < bhi->memusage)
442                 xfi->memusage_max = bhi->memusage;
443
444         // Convert the filter chain to human readable form.
445         bhi->filter_chain = message_filters_to_str(filters, false);
446
447         // Free the memory allocated by lzma_block_header_decode().
448         for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
449                 free(filters[i].options);
450
451         return false;
452
453 data_error:
454         // Show the error message.
455         message_error("%s: %s", pair->src_name,
456                         message_strm(LZMA_DATA_ERROR));
457
458         // Free the memory allocated by lzma_block_header_decode().
459         // This is truly needed only if we get here after a succcessful
460         // call to lzma_block_header_decode() but it doesn't hurt to
461         // always do it.
462         for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
463                 free(filters[i].options);
464
465         return true;
466 }
467
468
469 /// \brief      Parse the Check field and put it into check_value[]
470 ///
471 /// \return     False on success, true on error.
472 static bool
473 parse_check_value(file_pair *pair, const lzma_index_iter *iter)
474 {
475         // Don't read anything from the file if there is no integrity Check.
476         if (iter->stream.flags->check == LZMA_CHECK_NONE) {
477                 snprintf(check_value, sizeof(check_value), "---");
478                 return false;
479         }
480
481         // Locate and read the Check field.
482         const uint32_t size = lzma_check_size(iter->stream.flags->check);
483         const off_t offset = iter->block.compressed_file_offset
484                         + iter->block.total_size - size;
485         io_buf buf;
486         if (io_pread(pair, &buf, size, offset))
487                 return true;
488
489         // CRC32 and CRC64 are in little endian. Guess that all the future
490         // 32-bit and 64-bit Check values are little endian too. It shouldn't
491         // be a too big problem if this guess is wrong.
492         if (size == 4)
493                 snprintf(check_value, sizeof(check_value),
494                                 "%08" PRIx32, conv32le(buf.u32[0]));
495         else if (size == 8)
496                 snprintf(check_value, sizeof(check_value),
497                                 "%016" PRIx64, conv64le(buf.u64[0]));
498         else
499                 for (size_t i = 0; i < size; ++i)
500                         snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);
501
502         return false;
503 }
504
505
506 /// \brief      Parse detailed information about a Block
507 ///
508 /// Since this requires seek(s), listing information about all Blocks can
509 /// be slow.
510 ///
511 /// \param      pair    Input file
512 /// \param      iter    Location of the Block whose Check value should
513 ///                     be printed.
514 /// \param      bhi     Pointer to structure where to store the information
515 ///                     about the Block Header field.
516 ///
517 /// \return     False on success, true on error. If an error occurs,
518 ///             the error message is printed too so the caller doesn't
519 ///             need to worry about that.
520 static bool
521 parse_details(file_pair *pair, const lzma_index_iter *iter,
522                 block_header_info *bhi, xz_file_info *xfi)
523 {
524         if (parse_block_header(pair, iter, bhi, xfi))
525                 return true;
526
527         if (parse_check_value(pair, iter))
528                 return true;
529
530         return false;
531 }
532
533
534 /// \brief      Get the compression ratio
535 ///
536 /// This has slightly different format than that is used by in message.c.
537 static const char *
538 get_ratio(uint64_t compressed_size, uint64_t uncompressed_size)
539 {
540         if (uncompressed_size == 0)
541                 return "---";
542
543         const double ratio = (double)(compressed_size)
544                         / (double)(uncompressed_size);
545         if (ratio > 9.999)
546                 return "---";
547
548         static char buf[6];
549         snprintf(buf, sizeof(buf), "%.3f", ratio);
550         return buf;
551 }
552
553
554 /// \brief      Get a comma-separated list of Check names
555 ///
556 /// \param      checks  Bit mask of Checks to print
557 /// \param      space_after_comma
558 ///                     It's better to not use spaces in table-like listings,
559 ///                     but in more verbose formats a space after a comma
560 ///                     is good for readability.
561 static const char *
562 get_check_names(uint32_t checks, bool space_after_comma)
563 {
564         assert(checks != 0);
565
566         static char buf[sizeof(check_names)];
567         char *pos = buf;
568         size_t left = sizeof(buf);
569
570         const char *sep = space_after_comma ? ", " : ",";
571         bool comma = false;
572
573         for (size_t i = 0; i <= LZMA_CHECK_ID_MAX; ++i) {
574                 if (checks & (UINT32_C(1) << i)) {
575                         my_snprintf(&pos, &left, "%s%s",
576                                         comma ? sep : "", check_names[i]);
577                         comma = true;
578                 }
579         }
580
581         return buf;
582 }
583
584
585 static bool
586 print_info_basic(const xz_file_info *xfi, file_pair *pair)
587 {
588         static bool headings_displayed = false;
589         if (!headings_displayed) {
590                 headings_displayed = true;
591                 // TRANSLATORS: These are column titles. From Strms (Streams)
592                 // to Ratio, the columns are right aligned. Check and Filename
593                 // are left aligned. If you need longer words, it's OK to
594                 // use two lines here. Test with xz --list.
595                 puts(_("Strms  Blocks   Compressed Uncompressed  Ratio  "
596                                 "Check   Filename"));
597         }
598
599         printf("%5s %7s  %11s  %11s  %5s  %-7s %s\n",
600                         uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
601                         uint64_to_str(lzma_index_block_count(xfi->idx), 1),
602                         uint64_to_nicestr(lzma_index_file_size(xfi->idx),
603                                 NICESTR_B, NICESTR_TIB, false, 2),
604                         uint64_to_nicestr(
605                                 lzma_index_uncompressed_size(xfi->idx),
606                                 NICESTR_B, NICESTR_TIB, false, 3),
607                         get_ratio(lzma_index_file_size(xfi->idx),
608                                 lzma_index_uncompressed_size(xfi->idx)),
609                         get_check_names(lzma_index_checks(xfi->idx), false),
610                         pair->src_name);
611
612         return false;
613 }
614
615
616 static void
617 print_adv_helper(uint64_t stream_count, uint64_t block_count,
618                 uint64_t compressed_size, uint64_t uncompressed_size,
619                 uint32_t checks, uint64_t stream_padding)
620 {
621         printf(_("  Streams:            %s\n"),
622                         uint64_to_str(stream_count, 0));
623         printf(_("  Blocks:             %s\n"),
624                         uint64_to_str(block_count, 0));
625         printf(_("  Compressed size:    %s\n"),
626                         uint64_to_nicestr(compressed_size,
627                                 NICESTR_B, NICESTR_TIB, true, 0));
628         printf(_("  Uncompressed size:  %s\n"),
629                         uint64_to_nicestr(uncompressed_size,
630                                 NICESTR_B, NICESTR_TIB, true, 0));
631         printf(_("  Ratio:              %s\n"),
632                         get_ratio(compressed_size, uncompressed_size));
633         printf(_("  Check:              %s\n"),
634                         get_check_names(checks, true));
635         printf(_("  Stream padding:     %s\n"),
636                         uint64_to_nicestr(stream_padding,
637                                 NICESTR_B, NICESTR_TIB, true, 0));
638         return;
639 }
640
641
642 static bool
643 print_info_adv(xz_file_info *xfi, file_pair *pair)
644 {
645         // Print the overall information.
646         print_adv_helper(lzma_index_stream_count(xfi->idx),
647                         lzma_index_block_count(xfi->idx),
648                         lzma_index_file_size(xfi->idx),
649                         lzma_index_uncompressed_size(xfi->idx),
650                         lzma_index_checks(xfi->idx),
651                         xfi->stream_padding);
652
653         // Size of the biggest Check. This is used to calculate the width
654         // of the CheckVal field. The table would get insanely wide if
655         // we always reserved space for 64-byte Check (128 chars as hex).
656         uint32_t check_max = 0;
657
658         // Print information about the Streams.
659         puts(_("  Streams:\n    Stream    Blocks"
660                         "      CompOffset    UncompOffset"
661                         "        CompSize      UncompSize  Ratio"
662                         "  Check      Padding"));
663
664         lzma_index_iter iter;
665         lzma_index_iter_init(&iter, xfi->idx);
666
667         while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
668                 printf("    %6s %9s %15s %15s ",
669                                 uint64_to_str(iter.stream.number, 0),
670                                 uint64_to_str(iter.stream.block_count, 1),
671                                 uint64_to_str(
672                                         iter.stream.compressed_offset, 2),
673                                 uint64_to_str(
674                                         iter.stream.uncompressed_offset, 3));
675                 printf("%15s %15s  %5s  %-10s %7s\n",
676                                 uint64_to_str(iter.stream.compressed_size, 0),
677                                 uint64_to_str(
678                                         iter.stream.uncompressed_size, 1),
679                                 get_ratio(iter.stream.compressed_size,
680                                         iter.stream.uncompressed_size),
681                                 check_names[iter.stream.flags->check],
682                                 uint64_to_str(iter.stream.padding, 2));
683
684                 // Update the maximum Check size.
685                 if (lzma_check_size(iter.stream.flags->check) > check_max)
686                         check_max = lzma_check_size(iter.stream.flags->check);
687         }
688
689         // Cache the verbosity level to a local variable.
690         const bool detailed = message_verbosity_get() >= V_DEBUG;
691
692         // Information collected from Block Headers
693         block_header_info bhi;
694
695         // Print information about the Blocks but only if there is
696         // at least one Block.
697         if (lzma_index_block_count(xfi->idx) > 0) {
698                 // Calculate the width of the CheckVal field.
699                 const int checkval_width = my_max(8, 2 * check_max);
700
701                 // Print the headings.
702                 printf(_("  Blocks:\n    Stream     Block"
703                         "      CompOffset    UncompOffset"
704                         "       TotalSize      UncompSize  Ratio  Check"));
705
706                 if (detailed)
707                         printf(_("      %-*s  Header  Flags        CompSize"
708                                         "    MemUsage  Filters"),
709                                         checkval_width, _("CheckVal"));
710
711                 putchar('\n');
712
713                 lzma_index_iter_init(&iter, xfi->idx);
714
715                 // Iterate over the Blocks.
716                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
717                         if (detailed && parse_details(pair, &iter, &bhi, xfi))
718                                         return true;
719
720                         printf("    %6s %9s %15s %15s ",
721                                 uint64_to_str(iter.stream.number, 0),
722                                 uint64_to_str(
723                                         iter.block.number_in_stream, 1),
724                                 uint64_to_str(
725                                         iter.block.compressed_file_offset, 2),
726                                 uint64_to_str(
727                                         iter.block.uncompressed_file_offset,
728                                         3));
729                         printf("%15s %15s  %5s  %-*s",
730                                 uint64_to_str(iter.block.total_size, 0),
731                                 uint64_to_str(iter.block.uncompressed_size,
732                                                 1),
733                                 get_ratio(iter.block.total_size,
734                                         iter.block.uncompressed_size),
735                                 detailed ? 11 : 1,
736                                 check_names[iter.stream.flags->check]);
737
738                         if (detailed) {
739                                 // Show MiB for memory usage, because it
740                                 // is the only size which is not in bytes.
741                                 const lzma_vli compressed_size
742                                                 = iter.block.unpadded_size
743                                                 - bhi.header_size
744                                                 - lzma_check_size(
745                                                 iter.stream.flags->check);
746                                 printf("%-*s  %6s  %-5s %15s %7s MiB  %s",
747                                         checkval_width, check_value,
748                                         uint64_to_str(bhi.header_size, 0),
749                                         bhi.flags,
750                                         uint64_to_str(compressed_size, 1),
751                                         uint64_to_str(
752                                                 round_up_to_mib(bhi.memusage),
753                                                 2),
754                                         bhi.filter_chain);
755                         }
756
757                         putchar('\n');
758                 }
759         }
760
761         if (detailed) {
762                 printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
763                                 round_up_to_mib(xfi->memusage_max), 0));
764                 printf(_("  Sizes in headers:   %s\n"),
765                                 xfi->all_have_sizes ? _("Yes") : _("No"));
766         }
767
768         return false;
769 }
770
771
772 static bool
773 print_info_robot(xz_file_info *xfi, file_pair *pair)
774 {
775         printf("name\t%s\n", pair->src_name);
776
777         printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
778                         "\t%s\t%s\t%" PRIu64 "\n",
779                         lzma_index_stream_count(xfi->idx),
780                         lzma_index_block_count(xfi->idx),
781                         lzma_index_file_size(xfi->idx),
782                         lzma_index_uncompressed_size(xfi->idx),
783                         get_ratio(lzma_index_file_size(xfi->idx),
784                                 lzma_index_uncompressed_size(xfi->idx)),
785                         get_check_names(lzma_index_checks(xfi->idx), false),
786                         xfi->stream_padding);
787
788         if (message_verbosity_get() >= V_VERBOSE) {
789                 lzma_index_iter iter;
790                 lzma_index_iter_init(&iter, xfi->idx);
791
792                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
793                         printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
794                                 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
795                                 "\t%s\t%s\t%" PRIu64 "\n",
796                                 iter.stream.number,
797                                 iter.stream.block_count,
798                                 iter.stream.compressed_offset,
799                                 iter.stream.uncompressed_offset,
800                                 iter.stream.compressed_size,
801                                 iter.stream.uncompressed_size,
802                                 get_ratio(iter.stream.compressed_size,
803                                         iter.stream.uncompressed_size),
804                                 check_names[iter.stream.flags->check],
805                                 iter.stream.padding);
806
807                 lzma_index_iter_rewind(&iter);
808                 block_header_info bhi;
809
810                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
811                         if (message_verbosity_get() >= V_DEBUG
812                                         && parse_details(
813                                                 pair, &iter, &bhi, xfi))
814                                 return true;
815
816                         printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
817                                         "\t%" PRIu64 "\t%" PRIu64
818                                         "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
819                                         iter.stream.number,
820                                         iter.block.number_in_stream,
821                                         iter.block.number_in_file,
822                                         iter.block.compressed_file_offset,
823                                         iter.block.uncompressed_file_offset,
824                                         iter.block.total_size,
825                                         iter.block.uncompressed_size,
826                                         get_ratio(iter.block.total_size,
827                                                 iter.block.uncompressed_size),
828                                         check_names[iter.stream.flags->check]);
829
830                         if (message_verbosity_get() >= V_DEBUG)
831                                 printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
832                                                 "\t%" PRIu64 "\t%s",
833                                                 check_value,
834                                                 bhi.header_size,
835                                                 bhi.flags,
836                                                 bhi.compressed_size,
837                                                 bhi.memusage,
838                                                 bhi.filter_chain);
839
840                         putchar('\n');
841                 }
842         }
843
844         if (message_verbosity_get() >= V_DEBUG)
845                 printf("summary\t%" PRIu64 "\t%s\n",
846                                 xfi->memusage_max,
847                                 xfi->all_have_sizes ? "yes" : "no");
848
849         return false;
850 }
851
852
853 static void
854 update_totals(const xz_file_info *xfi)
855 {
856         // TODO: Integer overflow checks
857         ++totals.files;
858         totals.streams += lzma_index_stream_count(xfi->idx);
859         totals.blocks += lzma_index_block_count(xfi->idx);
860         totals.compressed_size += lzma_index_file_size(xfi->idx);
861         totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
862         totals.stream_padding += xfi->stream_padding;
863         totals.checks |= lzma_index_checks(xfi->idx);
864
865         if (totals.memusage_max < xfi->memusage_max)
866                 totals.memusage_max = xfi->memusage_max;
867
868         totals.all_have_sizes &= xfi->all_have_sizes;
869
870         return;
871 }
872
873
874 static void
875 print_totals_basic(void)
876 {
877         // Print a separator line.
878         char line[80];
879         memset(line, '-', sizeof(line));
880         line[sizeof(line) - 1] = '\0';
881         puts(line);
882
883         // Print the totals except the file count, which needs
884         // special handling.
885         printf("%5s %7s  %11s  %11s  %5s  %-7s ",
886                         uint64_to_str(totals.streams, 0),
887                         uint64_to_str(totals.blocks, 1),
888                         uint64_to_nicestr(totals.compressed_size,
889                                 NICESTR_B, NICESTR_TIB, false, 2),
890                         uint64_to_nicestr(totals.uncompressed_size,
891                                 NICESTR_B, NICESTR_TIB, false, 3),
892                         get_ratio(totals.compressed_size,
893                                 totals.uncompressed_size),
894                         get_check_names(totals.checks, false));
895
896         // Since we print totals only when there are at least two files,
897         // the English message will always use "%s files". But some other
898         // languages need different forms for different plurals so we
899         // have to translate this string still.
900         //
901         // TRANSLATORS: This simply indicates the number of files shown
902         // by --list even though the format string uses %s.
903         printf(N_("%s file", "%s files\n",
904                         totals.files <= ULONG_MAX ? totals.files
905                                 : (totals.files % 1000000) + 1000000),
906                         uint64_to_str(totals.files, 0));
907
908         return;
909 }
910
911
912 static void
913 print_totals_adv(void)
914 {
915         putchar('\n');
916         puts(_("Totals:"));
917         printf(_("  Number of files:    %s\n"),
918                         uint64_to_str(totals.files, 0));
919         print_adv_helper(totals.streams, totals.blocks,
920                         totals.compressed_size, totals.uncompressed_size,
921                         totals.checks, totals.stream_padding);
922
923         if (message_verbosity_get() >= V_DEBUG) {
924                 printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
925                                 round_up_to_mib(totals.memusage_max), 0));
926                 printf(_("  Sizes in headers:   %s\n"),
927                                 totals.all_have_sizes ? _("Yes") : _("No"));
928         }
929
930         return;
931 }
932
933
934 static void
935 print_totals_robot(void)
936 {
937         printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
938                         "\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
939                         totals.streams,
940                         totals.blocks,
941                         totals.compressed_size,
942                         totals.uncompressed_size,
943                         get_ratio(totals.compressed_size,
944                                 totals.uncompressed_size),
945                         get_check_names(totals.checks, false),
946                         totals.stream_padding,
947                         totals.files);
948
949         if (message_verbosity_get() >= V_DEBUG)
950                 printf("\t%" PRIu64 "\t%s",
951                                 totals.memusage_max,
952                                 totals.all_have_sizes ? "yes" : "no");
953
954         putchar('\n');
955
956         return;
957 }
958
959
960 extern void
961 list_totals(void)
962 {
963         if (opt_robot) {
964                 // Always print totals in --robot mode. It can be convenient
965                 // in some cases and doesn't complicate usage of the
966                 // single-file case much.
967                 print_totals_robot();
968
969         } else if (totals.files > 1) {
970                 // For non-robot mode, totals are printed only if there
971                 // is more than one file.
972                 if (message_verbosity_get() <= V_WARNING)
973                         print_totals_basic();
974                 else
975                         print_totals_adv();
976         }
977
978         return;
979 }
980
981
982 extern void
983 list_file(const char *filename)
984 {
985         if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
986                 message_fatal(_("--list works only on .xz files "
987                                 "(--format=xz or --format=auto)"));
988
989         message_filename(filename);
990
991         if (filename == stdin_filename) {
992                 message_error(_("--list does not support reading from "
993                                 "standard input"));
994                 return;
995         }
996
997         // Unset opt_stdout so that io_open_src() won't accept special files.
998         // Set opt_force so that io_open_src() will follow symlinks.
999         opt_stdout = false;
1000         opt_force = true;
1001         file_pair *pair = io_open_src(filename);
1002         if (pair == NULL)
1003                 return;
1004
1005         xz_file_info xfi = XZ_FILE_INFO_INIT;
1006         if (!parse_indexes(&xfi, pair)) {
1007                 bool fail;
1008
1009                 // We have three main modes:
1010                 //  - --robot, which has submodes if --verbose is specified
1011                 //    once or twice
1012                 //  - Normal --list without --verbose
1013                 //  - --list with one or two --verbose
1014                 if (opt_robot)
1015                         fail = print_info_robot(&xfi, pair);
1016                 else if (message_verbosity_get() <= V_WARNING)
1017                         fail = print_info_basic(&xfi, pair);
1018                 else
1019                         fail = print_info_adv(&xfi, pair);
1020
1021                 // Update the totals that are displayed after all
1022                 // the individual files have been listed. Don't count
1023                 // broken files.
1024                 if (!fail)
1025                         update_totals(&xfi);
1026
1027                 lzma_index_end(xfi.idx, NULL);
1028         }
1029
1030         io_close(pair, false);
1031         return;
1032 }