]> icculus.org git repositories - icculus/xz.git/blob - src/xz/list.c
xz: Hopefully ease translating the messages in list.c.
[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 headings. 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 -l foo.xz".
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         //
660         // TRANSLATORS: The second line is column headings. All except
661         // Check are right aligned; Check is left aligned. Test with
662         // "xz -lv foo.xz".
663         puts(_("  Streams:\n    Stream    Blocks"
664                         "      CompOffset    UncompOffset"
665                         "        CompSize      UncompSize  Ratio"
666                         "  Check      Padding"));
667
668         lzma_index_iter iter;
669         lzma_index_iter_init(&iter, xfi->idx);
670
671         while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
672                 printf("    %6s %9s %15s %15s ",
673                                 uint64_to_str(iter.stream.number, 0),
674                                 uint64_to_str(iter.stream.block_count, 1),
675                                 uint64_to_str(
676                                         iter.stream.compressed_offset, 2),
677                                 uint64_to_str(
678                                         iter.stream.uncompressed_offset, 3));
679                 printf("%15s %15s  %5s  %-10s %7s\n",
680                                 uint64_to_str(iter.stream.compressed_size, 0),
681                                 uint64_to_str(
682                                         iter.stream.uncompressed_size, 1),
683                                 get_ratio(iter.stream.compressed_size,
684                                         iter.stream.uncompressed_size),
685                                 check_names[iter.stream.flags->check],
686                                 uint64_to_str(iter.stream.padding, 2));
687
688                 // Update the maximum Check size.
689                 if (lzma_check_size(iter.stream.flags->check) > check_max)
690                         check_max = lzma_check_size(iter.stream.flags->check);
691         }
692
693         // Cache the verbosity level to a local variable.
694         const bool detailed = message_verbosity_get() >= V_DEBUG;
695
696         // Information collected from Block Headers
697         block_header_info bhi;
698
699         // Print information about the Blocks but only if there is
700         // at least one Block.
701         if (lzma_index_block_count(xfi->idx) > 0) {
702                 // Calculate the width of the CheckVal field.
703                 const int checkval_width = my_max(8, 2 * check_max);
704
705                 // TRANSLATORS: The second line is column headings. All
706                 // except Check are right aligned; Check is left aligned.
707                 printf(_("  Blocks:\n    Stream     Block"
708                         "      CompOffset    UncompOffset"
709                         "       TotalSize      UncompSize  Ratio  Check"));
710
711                 if (detailed) {
712                         // TRANSLATORS: These are additional column headings
713                         // for the most verbose listing mode. CheckVal
714                         // (Check value), Flags, and Filters are left aligned.
715                         // Header (Block Header Size), CompSize, and MemUsage
716                         // are right aligned. %*s is replaced with 0-120
717                         // spaces to make the CheckVal column wide enough.
718                         // Test with "xz -lvv foo.xz".
719                         printf(_("      CheckVal %*s Header  Flags        "
720                                         "CompSize    MemUsage  Filters"),
721                                         checkval_width - 8, "");
722                 }
723
724                 putchar('\n');
725
726                 lzma_index_iter_init(&iter, xfi->idx);
727
728                 // Iterate over the Blocks.
729                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
730                         if (detailed && parse_details(pair, &iter, &bhi, xfi))
731                                         return true;
732
733                         printf("    %6s %9s %15s %15s ",
734                                 uint64_to_str(iter.stream.number, 0),
735                                 uint64_to_str(
736                                         iter.block.number_in_stream, 1),
737                                 uint64_to_str(
738                                         iter.block.compressed_file_offset, 2),
739                                 uint64_to_str(
740                                         iter.block.uncompressed_file_offset,
741                                         3));
742                         printf("%15s %15s  %5s  %-*s",
743                                 uint64_to_str(iter.block.total_size, 0),
744                                 uint64_to_str(iter.block.uncompressed_size,
745                                                 1),
746                                 get_ratio(iter.block.total_size,
747                                         iter.block.uncompressed_size),
748                                 detailed ? 11 : 1,
749                                 check_names[iter.stream.flags->check]);
750
751                         if (detailed) {
752                                 // Show MiB for memory usage, because it
753                                 // is the only size which is not in bytes.
754                                 const lzma_vli compressed_size
755                                                 = iter.block.unpadded_size
756                                                 - bhi.header_size
757                                                 - lzma_check_size(
758                                                 iter.stream.flags->check);
759                                 printf("%-*s  %6s  %-5s %15s %7s MiB  %s",
760                                         checkval_width, check_value,
761                                         uint64_to_str(bhi.header_size, 0),
762                                         bhi.flags,
763                                         uint64_to_str(compressed_size, 1),
764                                         uint64_to_str(
765                                                 round_up_to_mib(bhi.memusage),
766                                                 2),
767                                         bhi.filter_chain);
768                         }
769
770                         putchar('\n');
771                 }
772         }
773
774         if (detailed) {
775                 printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
776                                 round_up_to_mib(xfi->memusage_max), 0));
777                 printf(_("  Sizes in headers:   %s\n"),
778                                 xfi->all_have_sizes ? _("Yes") : _("No"));
779         }
780
781         return false;
782 }
783
784
785 static bool
786 print_info_robot(xz_file_info *xfi, file_pair *pair)
787 {
788         printf("name\t%s\n", pair->src_name);
789
790         printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
791                         "\t%s\t%s\t%" PRIu64 "\n",
792                         lzma_index_stream_count(xfi->idx),
793                         lzma_index_block_count(xfi->idx),
794                         lzma_index_file_size(xfi->idx),
795                         lzma_index_uncompressed_size(xfi->idx),
796                         get_ratio(lzma_index_file_size(xfi->idx),
797                                 lzma_index_uncompressed_size(xfi->idx)),
798                         get_check_names(lzma_index_checks(xfi->idx), false),
799                         xfi->stream_padding);
800
801         if (message_verbosity_get() >= V_VERBOSE) {
802                 lzma_index_iter iter;
803                 lzma_index_iter_init(&iter, xfi->idx);
804
805                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
806                         printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
807                                 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
808                                 "\t%s\t%s\t%" PRIu64 "\n",
809                                 iter.stream.number,
810                                 iter.stream.block_count,
811                                 iter.stream.compressed_offset,
812                                 iter.stream.uncompressed_offset,
813                                 iter.stream.compressed_size,
814                                 iter.stream.uncompressed_size,
815                                 get_ratio(iter.stream.compressed_size,
816                                         iter.stream.uncompressed_size),
817                                 check_names[iter.stream.flags->check],
818                                 iter.stream.padding);
819
820                 lzma_index_iter_rewind(&iter);
821                 block_header_info bhi;
822
823                 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
824                         if (message_verbosity_get() >= V_DEBUG
825                                         && parse_details(
826                                                 pair, &iter, &bhi, xfi))
827                                 return true;
828
829                         printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
830                                         "\t%" PRIu64 "\t%" PRIu64
831                                         "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
832                                         iter.stream.number,
833                                         iter.block.number_in_stream,
834                                         iter.block.number_in_file,
835                                         iter.block.compressed_file_offset,
836                                         iter.block.uncompressed_file_offset,
837                                         iter.block.total_size,
838                                         iter.block.uncompressed_size,
839                                         get_ratio(iter.block.total_size,
840                                                 iter.block.uncompressed_size),
841                                         check_names[iter.stream.flags->check]);
842
843                         if (message_verbosity_get() >= V_DEBUG)
844                                 printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
845                                                 "\t%" PRIu64 "\t%s",
846                                                 check_value,
847                                                 bhi.header_size,
848                                                 bhi.flags,
849                                                 bhi.compressed_size,
850                                                 bhi.memusage,
851                                                 bhi.filter_chain);
852
853                         putchar('\n');
854                 }
855         }
856
857         if (message_verbosity_get() >= V_DEBUG)
858                 printf("summary\t%" PRIu64 "\t%s\n",
859                                 xfi->memusage_max,
860                                 xfi->all_have_sizes ? "yes" : "no");
861
862         return false;
863 }
864
865
866 static void
867 update_totals(const xz_file_info *xfi)
868 {
869         // TODO: Integer overflow checks
870         ++totals.files;
871         totals.streams += lzma_index_stream_count(xfi->idx);
872         totals.blocks += lzma_index_block_count(xfi->idx);
873         totals.compressed_size += lzma_index_file_size(xfi->idx);
874         totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
875         totals.stream_padding += xfi->stream_padding;
876         totals.checks |= lzma_index_checks(xfi->idx);
877
878         if (totals.memusage_max < xfi->memusage_max)
879                 totals.memusage_max = xfi->memusage_max;
880
881         totals.all_have_sizes &= xfi->all_have_sizes;
882
883         return;
884 }
885
886
887 static void
888 print_totals_basic(void)
889 {
890         // Print a separator line.
891         char line[80];
892         memset(line, '-', sizeof(line));
893         line[sizeof(line) - 1] = '\0';
894         puts(line);
895
896         // Print the totals except the file count, which needs
897         // special handling.
898         printf("%5s %7s  %11s  %11s  %5s  %-7s ",
899                         uint64_to_str(totals.streams, 0),
900                         uint64_to_str(totals.blocks, 1),
901                         uint64_to_nicestr(totals.compressed_size,
902                                 NICESTR_B, NICESTR_TIB, false, 2),
903                         uint64_to_nicestr(totals.uncompressed_size,
904                                 NICESTR_B, NICESTR_TIB, false, 3),
905                         get_ratio(totals.compressed_size,
906                                 totals.uncompressed_size),
907                         get_check_names(totals.checks, false));
908
909         // Since we print totals only when there are at least two files,
910         // the English message will always use "%s files". But some other
911         // languages need different forms for different plurals so we
912         // have to translate this with N_().
913         //
914         // TRANSLATORS: %s is an integer. Only the plural form of this
915         // message is used (e.g. "2 files"). Test with "xz -l foo.xz bar.xz".
916         printf(N_("%s file", "%s files\n",
917                         totals.files <= ULONG_MAX ? totals.files
918                                 : (totals.files % 1000000) + 1000000),
919                         uint64_to_str(totals.files, 0));
920
921         return;
922 }
923
924
925 static void
926 print_totals_adv(void)
927 {
928         putchar('\n');
929         puts(_("Totals:"));
930         printf(_("  Number of files:    %s\n"),
931                         uint64_to_str(totals.files, 0));
932         print_adv_helper(totals.streams, totals.blocks,
933                         totals.compressed_size, totals.uncompressed_size,
934                         totals.checks, totals.stream_padding);
935
936         if (message_verbosity_get() >= V_DEBUG) {
937                 printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
938                                 round_up_to_mib(totals.memusage_max), 0));
939                 printf(_("  Sizes in headers:   %s\n"),
940                                 totals.all_have_sizes ? _("Yes") : _("No"));
941         }
942
943         return;
944 }
945
946
947 static void
948 print_totals_robot(void)
949 {
950         printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
951                         "\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
952                         totals.streams,
953                         totals.blocks,
954                         totals.compressed_size,
955                         totals.uncompressed_size,
956                         get_ratio(totals.compressed_size,
957                                 totals.uncompressed_size),
958                         get_check_names(totals.checks, false),
959                         totals.stream_padding,
960                         totals.files);
961
962         if (message_verbosity_get() >= V_DEBUG)
963                 printf("\t%" PRIu64 "\t%s",
964                                 totals.memusage_max,
965                                 totals.all_have_sizes ? "yes" : "no");
966
967         putchar('\n');
968
969         return;
970 }
971
972
973 extern void
974 list_totals(void)
975 {
976         if (opt_robot) {
977                 // Always print totals in --robot mode. It can be convenient
978                 // in some cases and doesn't complicate usage of the
979                 // single-file case much.
980                 print_totals_robot();
981
982         } else if (totals.files > 1) {
983                 // For non-robot mode, totals are printed only if there
984                 // is more than one file.
985                 if (message_verbosity_get() <= V_WARNING)
986                         print_totals_basic();
987                 else
988                         print_totals_adv();
989         }
990
991         return;
992 }
993
994
995 extern void
996 list_file(const char *filename)
997 {
998         if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
999                 message_fatal(_("--list works only on .xz files "
1000                                 "(--format=xz or --format=auto)"));
1001
1002         message_filename(filename);
1003
1004         if (filename == stdin_filename) {
1005                 message_error(_("--list does not support reading from "
1006                                 "standard input"));
1007                 return;
1008         }
1009
1010         // Unset opt_stdout so that io_open_src() won't accept special files.
1011         // Set opt_force so that io_open_src() will follow symlinks.
1012         opt_stdout = false;
1013         opt_force = true;
1014         file_pair *pair = io_open_src(filename);
1015         if (pair == NULL)
1016                 return;
1017
1018         xz_file_info xfi = XZ_FILE_INFO_INIT;
1019         if (!parse_indexes(&xfi, pair)) {
1020                 bool fail;
1021
1022                 // We have three main modes:
1023                 //  - --robot, which has submodes if --verbose is specified
1024                 //    once or twice
1025                 //  - Normal --list without --verbose
1026                 //  - --list with one or two --verbose
1027                 if (opt_robot)
1028                         fail = print_info_robot(&xfi, pair);
1029                 else if (message_verbosity_get() <= V_WARNING)
1030                         fail = print_info_basic(&xfi, pair);
1031                 else
1032                         fail = print_info_adv(&xfi, pair);
1033
1034                 // Update the totals that are displayed after all
1035                 // the individual files have been listed. Don't count
1036                 // broken files.
1037                 if (!fail)
1038                         update_totals(&xfi);
1039
1040                 lzma_index_end(xfi.idx, NULL);
1041         }
1042
1043         io_close(pair, false);
1044         return;
1045 }