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