GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / tools / misc / xz / src / xz / list.c
blob1c93718b13823f51817f3d031bde1f59235103ec
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.
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "private.h"
14 #include "tuklib_integer.h"
17 /// Information about a .xz file
18 typedef struct {
19 /// Combined Index of all Streams in the file
20 lzma_index *idx;
22 /// Total amount of Stream Padding
23 uint64_t stream_padding;
25 /// Highest memory usage so far
26 uint64_t memusage_max;
28 /// True if all Blocks so far have Compressed Size and
29 /// Uncompressed Size fields
30 bool all_have_sizes;
32 } xz_file_info;
34 #define XZ_FILE_INFO_INIT { NULL, 0, 0, true }
37 /// Information about a .xz Block
38 typedef struct {
39 /// Size of the Block Header
40 uint32_t header_size;
42 /// A few of the Block Flags as a string
43 char flags[3];
45 /// Size of the Compressed Data field in the Block
46 lzma_vli compressed_size;
48 /// Decoder memory usage for this Block
49 uint64_t memusage;
51 /// The filter chain of this Block in human-readable form
52 char filter_chain[FILTERS_STR_SIZE];
54 } block_header_info;
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"),
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
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];
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 };
111 /// \brief Parse the Index(es) from the given .xz file
113 /// \param xfi Pointer to structure where the decoded information
114 /// is stored.
115 /// \param pair Input file
117 /// \return On success, false is returned. On error, true is returned.
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)
125 if (pair->src_st.st_size <= 0) {
126 message_error(_("%s: File is empty"), pair->src_name);
127 return true;
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;
136 io_buf buf;
137 lzma_stream_flags header_flags;
138 lzma_stream_flags footer_flags;
139 lzma_ret ret;
141 // lzma_stream for the Index decoder
142 lzma_stream strm = LZMA_STREAM_INIT;
144 // All Indexes decoded so far
145 lzma_index *combined_index = NULL;
147 // The Index currently being decoded
148 lzma_index *this_index = NULL;
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;
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;
165 pos -= LZMA_STREAM_HEADER_SIZE;
166 lzma_vli stream_padding = 0;
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;
178 if (io_pread(pair, &buf,
179 LZMA_STREAM_HEADER_SIZE, pos))
180 goto error;
182 // Stream Padding is always a multiple of four bytes.
183 int i = 2;
184 if (buf.u32[i] != 0)
185 break;
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);
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;
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;
214 // Set pos to the beginning of the Index.
215 pos -= index_size;
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();
225 memlimit -= memused;
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;
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;
243 pos += strm.avail_in;
244 index_size -= strm.avail_in;
246 strm.next_in = buf.u8;
247 ret = lzma_code(&strm, LZMA_RUN);
249 } while (ret == LZMA_OK);
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;
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;
267 message_error("%s: %s", pair->src_name,
268 message_strm(ret));
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;
279 message_mem_needed(V_ERROR, needed);
282 goto error;
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;
294 pos -= lzma_index_total_size(this_index);
295 if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos))
296 goto error;
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;
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;
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();
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();
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;
337 combined_index = this_index;
338 this_index = NULL;
340 xfi->stream_padding += stream_padding;
342 } while (pos > 0);
344 lzma_end(&strm);
346 // All OK. Make combined_index available to the caller.
347 xfi->idx = combined_index;
348 return false;
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;
359 /// \brief Parse the Block Header
361 /// The result is stored into *bhi. The caller takes care of initializing it.
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)
368 #if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
369 # error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
370 #endif
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;
381 // Zero would mean Index Indicator and thus not a valid Block.
382 if (buf.u8[0] == 0)
383 goto data_error;
385 lzma_block block;
386 lzma_filter filters[LZMA_FILTERS_MAX + 1];
388 // Initialize the pointers so that they can be passed to free().
389 for (size_t i = 0; i < ARRAY_SIZE(filters); ++i)
390 filters[i].options = NULL;
392 // Initialize the block structure and decode Block Header Size.
393 block.version = 0;
394 block.check = iter->stream.flags->check;
395 block.filters = filters;
397 block.header_size = lzma_block_header_size_decode(buf.u8[0]);
398 if (block.header_size > size)
399 goto data_error;
401 // Decode the Block Header.
402 switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
403 case LZMA_OK:
404 break;
406 case LZMA_OPTIONS_ERROR:
407 message_error("%s: %s", pair->src_name,
408 message_strm(LZMA_OPTIONS_ERROR));
409 return true;
411 case LZMA_DATA_ERROR:
412 goto data_error;
414 default:
415 message_bug();
418 // Check the Block Flags. These must be done before calling
419 // lzma_block_compressed_size(), because it overwrites
420 // block.compressed_size.
421 bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
422 ? 'c' : '-';
423 bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
424 ? 'u' : '-';
425 bhi->flags[2] = '\0';
427 // Collect information if all Blocks have both Compressed Size
428 // and Uncompressed Size fields. They can be useful e.g. for
429 // multi-threaded decompression so it can be useful to know it.
430 xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
431 && block.uncompressed_size != LZMA_VLI_UNKNOWN;
433 // Validate or set block.compressed_size.
434 switch (lzma_block_compressed_size(&block,
435 iter->block.unpadded_size)) {
436 case LZMA_OK:
437 break;
439 case LZMA_DATA_ERROR:
440 goto data_error;
442 default:
443 message_bug();
446 // Copy the known sizes.
447 bhi->header_size = block.header_size;
448 bhi->compressed_size = block.compressed_size;
450 // Calculate the decoder memory usage and update the maximum
451 // memory usage of this Block.
452 bhi->memusage = lzma_raw_decoder_memusage(filters);
453 if (xfi->memusage_max < bhi->memusage)
454 xfi->memusage_max = bhi->memusage;
456 // Convert the filter chain to human readable form.
457 message_filters_to_str(bhi->filter_chain, filters, false);
459 // Free the memory allocated by lzma_block_header_decode().
460 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
461 free(filters[i].options);
463 return false;
465 data_error:
466 // Show the error message.
467 message_error("%s: %s", pair->src_name,
468 message_strm(LZMA_DATA_ERROR));
470 // Free the memory allocated by lzma_block_header_decode().
471 // This is truly needed only if we get here after a succcessful
472 // call to lzma_block_header_decode() but it doesn't hurt to
473 // always do it.
474 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
475 free(filters[i].options);
477 return true;
481 /// \brief Parse the Check field and put it into check_value[]
483 /// \return False on success, true on error.
484 static bool
485 parse_check_value(file_pair *pair, const lzma_index_iter *iter)
487 // Don't read anything from the file if there is no integrity Check.
488 if (iter->stream.flags->check == LZMA_CHECK_NONE) {
489 snprintf(check_value, sizeof(check_value), "---");
490 return false;
493 // Locate and read the Check field.
494 const uint32_t size = lzma_check_size(iter->stream.flags->check);
495 const off_t offset = iter->block.compressed_file_offset
496 + iter->block.total_size - size;
497 io_buf buf;
498 if (io_pread(pair, &buf, size, offset))
499 return true;
501 // CRC32 and CRC64 are in little endian. Guess that all the future
502 // 32-bit and 64-bit Check values are little endian too. It shouldn't
503 // be a too big problem if this guess is wrong.
504 if (size == 4)
505 snprintf(check_value, sizeof(check_value),
506 "%08" PRIx32, conv32le(buf.u32[0]));
507 else if (size == 8)
508 snprintf(check_value, sizeof(check_value),
509 "%016" PRIx64, conv64le(buf.u64[0]));
510 else
511 for (size_t i = 0; i < size; ++i)
512 snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);
514 return false;
518 /// \brief Parse detailed information about a Block
520 /// Since this requires seek(s), listing information about all Blocks can
521 /// be slow.
523 /// \param pair Input file
524 /// \param iter Location of the Block whose Check value should
525 /// be printed.
526 /// \param bhi Pointer to structure where to store the information
527 /// about the Block Header field.
529 /// \return False on success, true on error. If an error occurs,
530 /// the error message is printed too so the caller doesn't
531 /// need to worry about that.
532 static bool
533 parse_details(file_pair *pair, const lzma_index_iter *iter,
534 block_header_info *bhi, xz_file_info *xfi)
536 if (parse_block_header(pair, iter, bhi, xfi))
537 return true;
539 if (parse_check_value(pair, iter))
540 return true;
542 return false;
546 /// \brief Get the compression ratio
548 /// This has slightly different format than that is used in message.c.
549 static const char *
550 get_ratio(uint64_t compressed_size, uint64_t uncompressed_size)
552 if (uncompressed_size == 0)
553 return "---";
555 const double ratio = (double)(compressed_size)
556 / (double)(uncompressed_size);
557 if (ratio > 9.999)
558 return "---";
560 static char buf[16];
561 snprintf(buf, sizeof(buf), "%.3f", ratio);
562 return buf;
566 /// \brief Get a comma-separated list of Check names
568 /// The check names are translated with gettext except when in robot mode.
570 /// \param buf Buffer to hold the resulting string
571 /// \param checks Bit mask of Checks to print
572 /// \param space_after_comma
573 /// It's better to not use spaces in table-like listings,
574 /// but in more verbose formats a space after a comma
575 /// is good for readability.
576 static void
577 get_check_names(char buf[CHECKS_STR_SIZE],
578 uint32_t checks, bool space_after_comma)
580 assert(checks != 0);
582 char *pos = buf;
583 size_t left = CHECKS_STR_SIZE;
585 const char *sep = space_after_comma ? ", " : ",";
586 bool comma = false;
588 for (size_t i = 0; i <= LZMA_CHECK_ID_MAX; ++i) {
589 if (checks & (UINT32_C(1) << i)) {
590 my_snprintf(&pos, &left, "%s%s",
591 comma ? sep : "",
592 opt_robot ? check_names[i]
593 : _(check_names[i]));
594 comma = true;
598 return;
602 static bool
603 print_info_basic(const xz_file_info *xfi, file_pair *pair)
605 static bool headings_displayed = false;
606 if (!headings_displayed) {
607 headings_displayed = true;
608 // TRANSLATORS: These are column headings. From Strms (Streams)
609 // to Ratio, the columns are right aligned. Check and Filename
610 // are left aligned. If you need longer words, it's OK to
611 // use two lines here. Test with "xz -l foo.xz".
612 puts(_("Strms Blocks Compressed Uncompressed Ratio "
613 "Check Filename"));
616 char checks[CHECKS_STR_SIZE];
617 get_check_names(checks, lzma_index_checks(xfi->idx), false);
619 const char *cols[7] = {
620 uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
621 uint64_to_str(lzma_index_block_count(xfi->idx), 1),
622 uint64_to_nicestr(lzma_index_file_size(xfi->idx),
623 NICESTR_B, NICESTR_TIB, false, 2),
624 uint64_to_nicestr(lzma_index_uncompressed_size(xfi->idx),
625 NICESTR_B, NICESTR_TIB, false, 3),
626 get_ratio(lzma_index_file_size(xfi->idx),
627 lzma_index_uncompressed_size(xfi->idx)),
628 checks,
629 pair->src_name,
631 printf("%*s %*s %*s %*s %*s %-*s %s\n",
632 tuklib_mbstr_fw(cols[0], 5), cols[0],
633 tuklib_mbstr_fw(cols[1], 7), cols[1],
634 tuklib_mbstr_fw(cols[2], 11), cols[2],
635 tuklib_mbstr_fw(cols[3], 11), cols[3],
636 tuklib_mbstr_fw(cols[4], 5), cols[4],
637 tuklib_mbstr_fw(cols[5], 7), cols[5],
638 cols[6]);
640 return false;
644 static void
645 print_adv_helper(uint64_t stream_count, uint64_t block_count,
646 uint64_t compressed_size, uint64_t uncompressed_size,
647 uint32_t checks, uint64_t stream_padding)
649 char checks_str[CHECKS_STR_SIZE];
650 get_check_names(checks_str, checks, true);
652 printf(_(" Streams: %s\n"),
653 uint64_to_str(stream_count, 0));
654 printf(_(" Blocks: %s\n"),
655 uint64_to_str(block_count, 0));
656 printf(_(" Compressed size: %s\n"),
657 uint64_to_nicestr(compressed_size,
658 NICESTR_B, NICESTR_TIB, true, 0));
659 printf(_(" Uncompressed size: %s\n"),
660 uint64_to_nicestr(uncompressed_size,
661 NICESTR_B, NICESTR_TIB, true, 0));
662 printf(_(" Ratio: %s\n"),
663 get_ratio(compressed_size, uncompressed_size));
664 printf(_(" Check: %s\n"), checks_str);
665 printf(_(" Stream padding: %s\n"),
666 uint64_to_nicestr(stream_padding,
667 NICESTR_B, NICESTR_TIB, true, 0));
668 return;
672 static bool
673 print_info_adv(xz_file_info *xfi, file_pair *pair)
675 // Print the overall information.
676 print_adv_helper(lzma_index_stream_count(xfi->idx),
677 lzma_index_block_count(xfi->idx),
678 lzma_index_file_size(xfi->idx),
679 lzma_index_uncompressed_size(xfi->idx),
680 lzma_index_checks(xfi->idx),
681 xfi->stream_padding);
683 // Size of the biggest Check. This is used to calculate the width
684 // of the CheckVal field. The table would get insanely wide if
685 // we always reserved space for 64-byte Check (128 chars as hex).
686 uint32_t check_max = 0;
688 // Print information about the Streams.
690 // TRANSLATORS: The second line is column headings. All except
691 // Check are right aligned; Check is left aligned. Test with
692 // "xz -lv foo.xz".
693 puts(_(" Streams:\n Stream Blocks"
694 " CompOffset UncompOffset"
695 " CompSize UncompSize Ratio"
696 " Check Padding"));
698 lzma_index_iter iter;
699 lzma_index_iter_init(&iter, xfi->idx);
701 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
702 const char *cols1[4] = {
703 uint64_to_str(iter.stream.number, 0),
704 uint64_to_str(iter.stream.block_count, 1),
705 uint64_to_str(iter.stream.compressed_offset, 2),
706 uint64_to_str(iter.stream.uncompressed_offset, 3),
708 printf(" %*s %*s %*s %*s ",
709 tuklib_mbstr_fw(cols1[0], 6), cols1[0],
710 tuklib_mbstr_fw(cols1[1], 9), cols1[1],
711 tuklib_mbstr_fw(cols1[2], 15), cols1[2],
712 tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
714 const char *cols2[5] = {
715 uint64_to_str(iter.stream.compressed_size, 0),
716 uint64_to_str(iter.stream.uncompressed_size, 1),
717 get_ratio(iter.stream.compressed_size,
718 iter.stream.uncompressed_size),
719 _(check_names[iter.stream.flags->check]),
720 uint64_to_str(iter.stream.padding, 2),
722 printf("%*s %*s %*s %-*s %*s\n",
723 tuklib_mbstr_fw(cols2[0], 15), cols2[0],
724 tuklib_mbstr_fw(cols2[1], 15), cols2[1],
725 tuklib_mbstr_fw(cols2[2], 5), cols2[2],
726 tuklib_mbstr_fw(cols2[3], 10), cols2[3],
727 tuklib_mbstr_fw(cols2[4], 7), cols2[4]);
729 // Update the maximum Check size.
730 if (lzma_check_size(iter.stream.flags->check) > check_max)
731 check_max = lzma_check_size(iter.stream.flags->check);
734 // Cache the verbosity level to a local variable.
735 const bool detailed = message_verbosity_get() >= V_DEBUG;
737 // Information collected from Block Headers
738 block_header_info bhi;
740 // Print information about the Blocks but only if there is
741 // at least one Block.
742 if (lzma_index_block_count(xfi->idx) > 0) {
743 // Calculate the width of the CheckVal field.
744 const int checkval_width = my_max(8, 2 * check_max);
746 // TRANSLATORS: The second line is column headings. All
747 // except Check are right aligned; Check is left aligned.
748 printf(_(" Blocks:\n Stream Block"
749 " CompOffset UncompOffset"
750 " TotalSize UncompSize Ratio Check"));
752 if (detailed) {
753 // TRANSLATORS: These are additional column headings
754 // for the most verbose listing mode. CheckVal
755 // (Check value), Flags, and Filters are left aligned.
756 // Header (Block Header Size), CompSize, and MemUsage
757 // are right aligned. %*s is replaced with 0-120
758 // spaces to make the CheckVal column wide enough.
759 // Test with "xz -lvv foo.xz".
760 printf(_(" CheckVal %*s Header Flags "
761 "CompSize MemUsage Filters"),
762 checkval_width - 8, "");
765 putchar('\n');
767 lzma_index_iter_init(&iter, xfi->idx);
769 // Iterate over the Blocks.
770 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
771 if (detailed && parse_details(pair, &iter, &bhi, xfi))
772 return true;
774 const char *cols1[4] = {
775 uint64_to_str(iter.stream.number, 0),
776 uint64_to_str(
777 iter.block.number_in_stream, 1),
778 uint64_to_str(
779 iter.block.compressed_file_offset, 2),
780 uint64_to_str(
781 iter.block.uncompressed_file_offset, 3)
783 printf(" %*s %*s %*s %*s ",
784 tuklib_mbstr_fw(cols1[0], 6), cols1[0],
785 tuklib_mbstr_fw(cols1[1], 9), cols1[1],
786 tuklib_mbstr_fw(cols1[2], 15), cols1[2],
787 tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
789 const char *cols2[4] = {
790 uint64_to_str(iter.block.total_size, 0),
791 uint64_to_str(iter.block.uncompressed_size,
793 get_ratio(iter.block.total_size,
794 iter.block.uncompressed_size),
795 _(check_names[iter.stream.flags->check])
797 printf("%*s %*s %*s %-*s",
798 tuklib_mbstr_fw(cols2[0], 15), cols2[0],
799 tuklib_mbstr_fw(cols2[1], 15), cols2[1],
800 tuklib_mbstr_fw(cols2[2], 5), cols2[2],
801 tuklib_mbstr_fw(cols2[3], detailed ? 11 : 1),
802 cols2[3]);
804 if (detailed) {
805 const lzma_vli compressed_size
806 = iter.block.unpadded_size
807 - bhi.header_size
808 - lzma_check_size(
809 iter.stream.flags->check);
811 const char *cols3[6] = {
812 check_value,
813 uint64_to_str(bhi.header_size, 0),
814 bhi.flags,
815 uint64_to_str(compressed_size, 1),
816 uint64_to_str(
817 round_up_to_mib(bhi.memusage),
819 bhi.filter_chain
821 // Show MiB for memory usage, because it
822 // is the only size which is not in bytes.
823 printf("%-*s %*s %-5s %*s %*s MiB %s",
824 checkval_width, cols3[0],
825 tuklib_mbstr_fw(cols3[1], 6), cols3[1],
826 cols3[2],
827 tuklib_mbstr_fw(cols3[3], 15),
828 cols3[3],
829 tuklib_mbstr_fw(cols3[4], 7), cols3[4],
830 cols3[5]);
833 putchar('\n');
837 if (detailed) {
838 printf(_(" Memory needed: %s MiB\n"), uint64_to_str(
839 round_up_to_mib(xfi->memusage_max), 0));
840 printf(_(" Sizes in headers: %s\n"),
841 xfi->all_have_sizes ? _("Yes") : _("No"));
844 return false;
848 static bool
849 print_info_robot(xz_file_info *xfi, file_pair *pair)
851 char checks[CHECKS_STR_SIZE];
852 get_check_names(checks, lzma_index_checks(xfi->idx), false);
854 printf("name\t%s\n", pair->src_name);
856 printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
857 "\t%s\t%s\t%" PRIu64 "\n",
858 lzma_index_stream_count(xfi->idx),
859 lzma_index_block_count(xfi->idx),
860 lzma_index_file_size(xfi->idx),
861 lzma_index_uncompressed_size(xfi->idx),
862 get_ratio(lzma_index_file_size(xfi->idx),
863 lzma_index_uncompressed_size(xfi->idx)),
864 checks,
865 xfi->stream_padding);
867 if (message_verbosity_get() >= V_VERBOSE) {
868 lzma_index_iter iter;
869 lzma_index_iter_init(&iter, xfi->idx);
871 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
872 printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
873 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
874 "\t%s\t%s\t%" PRIu64 "\n",
875 iter.stream.number,
876 iter.stream.block_count,
877 iter.stream.compressed_offset,
878 iter.stream.uncompressed_offset,
879 iter.stream.compressed_size,
880 iter.stream.uncompressed_size,
881 get_ratio(iter.stream.compressed_size,
882 iter.stream.uncompressed_size),
883 check_names[iter.stream.flags->check],
884 iter.stream.padding);
886 lzma_index_iter_rewind(&iter);
887 block_header_info bhi;
889 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
890 if (message_verbosity_get() >= V_DEBUG
891 && parse_details(
892 pair, &iter, &bhi, xfi))
893 return true;
895 printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
896 "\t%" PRIu64 "\t%" PRIu64
897 "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
898 iter.stream.number,
899 iter.block.number_in_stream,
900 iter.block.number_in_file,
901 iter.block.compressed_file_offset,
902 iter.block.uncompressed_file_offset,
903 iter.block.total_size,
904 iter.block.uncompressed_size,
905 get_ratio(iter.block.total_size,
906 iter.block.uncompressed_size),
907 check_names[iter.stream.flags->check]);
909 if (message_verbosity_get() >= V_DEBUG)
910 printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
911 "\t%" PRIu64 "\t%s",
912 check_value,
913 bhi.header_size,
914 bhi.flags,
915 bhi.compressed_size,
916 bhi.memusage,
917 bhi.filter_chain);
919 putchar('\n');
923 if (message_verbosity_get() >= V_DEBUG)
924 printf("summary\t%" PRIu64 "\t%s\n",
925 xfi->memusage_max,
926 xfi->all_have_sizes ? "yes" : "no");
928 return false;
932 static void
933 update_totals(const xz_file_info *xfi)
935 // TODO: Integer overflow checks
936 ++totals.files;
937 totals.streams += lzma_index_stream_count(xfi->idx);
938 totals.blocks += lzma_index_block_count(xfi->idx);
939 totals.compressed_size += lzma_index_file_size(xfi->idx);
940 totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
941 totals.stream_padding += xfi->stream_padding;
942 totals.checks |= lzma_index_checks(xfi->idx);
944 if (totals.memusage_max < xfi->memusage_max)
945 totals.memusage_max = xfi->memusage_max;
947 totals.all_have_sizes &= xfi->all_have_sizes;
949 return;
953 static void
954 print_totals_basic(void)
956 // Print a separator line.
957 char line[80];
958 memset(line, '-', sizeof(line));
959 line[sizeof(line) - 1] = '\0';
960 puts(line);
962 // Get the check names.
963 char checks[CHECKS_STR_SIZE];
964 get_check_names(checks, totals.checks, false);
966 // Print the totals except the file count, which needs
967 // special handling.
968 printf("%5s %7s %11s %11s %5s %-7s ",
969 uint64_to_str(totals.streams, 0),
970 uint64_to_str(totals.blocks, 1),
971 uint64_to_nicestr(totals.compressed_size,
972 NICESTR_B, NICESTR_TIB, false, 2),
973 uint64_to_nicestr(totals.uncompressed_size,
974 NICESTR_B, NICESTR_TIB, false, 3),
975 get_ratio(totals.compressed_size,
976 totals.uncompressed_size),
977 checks);
979 // Since we print totals only when there are at least two files,
980 // the English message will always use "%s files". But some other
981 // languages need different forms for different plurals so we
982 // have to translate this with ngettext().
984 // TRANSLATORS: %s is an integer. Only the plural form of this
985 // message is used (e.g. "2 files"). Test with "xz -l foo.xz bar.xz".
986 printf(ngettext("%s file\n", "%s files\n",
987 totals.files <= ULONG_MAX ? totals.files
988 : (totals.files % 1000000) + 1000000),
989 uint64_to_str(totals.files, 0));
991 return;
995 static void
996 print_totals_adv(void)
998 putchar('\n');
999 puts(_("Totals:"));
1000 printf(_(" Number of files: %s\n"),
1001 uint64_to_str(totals.files, 0));
1002 print_adv_helper(totals.streams, totals.blocks,
1003 totals.compressed_size, totals.uncompressed_size,
1004 totals.checks, totals.stream_padding);
1006 if (message_verbosity_get() >= V_DEBUG) {
1007 printf(_(" Memory needed: %s MiB\n"), uint64_to_str(
1008 round_up_to_mib(totals.memusage_max), 0));
1009 printf(_(" Sizes in headers: %s\n"),
1010 totals.all_have_sizes ? _("Yes") : _("No"));
1013 return;
1017 static void
1018 print_totals_robot(void)
1020 char checks[CHECKS_STR_SIZE];
1021 get_check_names(checks, totals.checks, false);
1023 printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1024 "\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
1025 totals.streams,
1026 totals.blocks,
1027 totals.compressed_size,
1028 totals.uncompressed_size,
1029 get_ratio(totals.compressed_size,
1030 totals.uncompressed_size),
1031 checks,
1032 totals.stream_padding,
1033 totals.files);
1035 if (message_verbosity_get() >= V_DEBUG)
1036 printf("\t%" PRIu64 "\t%s",
1037 totals.memusage_max,
1038 totals.all_have_sizes ? "yes" : "no");
1040 putchar('\n');
1042 return;
1046 extern void
1047 list_totals(void)
1049 if (opt_robot) {
1050 // Always print totals in --robot mode. It can be convenient
1051 // in some cases and doesn't complicate usage of the
1052 // single-file case much.
1053 print_totals_robot();
1055 } else if (totals.files > 1) {
1056 // For non-robot mode, totals are printed only if there
1057 // is more than one file.
1058 if (message_verbosity_get() <= V_WARNING)
1059 print_totals_basic();
1060 else
1061 print_totals_adv();
1064 return;
1068 extern void
1069 list_file(const char *filename)
1071 if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
1072 message_fatal(_("--list works only on .xz files "
1073 "(--format=xz or --format=auto)"));
1075 message_filename(filename);
1077 if (filename == stdin_filename) {
1078 message_error(_("--list does not support reading from "
1079 "standard input"));
1080 return;
1083 // Unset opt_stdout so that io_open_src() won't accept special files.
1084 // Set opt_force so that io_open_src() will follow symlinks.
1085 opt_stdout = false;
1086 opt_force = true;
1087 file_pair *pair = io_open_src(filename);
1088 if (pair == NULL)
1089 return;
1091 xz_file_info xfi = XZ_FILE_INFO_INIT;
1092 if (!parse_indexes(&xfi, pair)) {
1093 bool fail;
1095 // We have three main modes:
1096 // - --robot, which has submodes if --verbose is specified
1097 // once or twice
1098 // - Normal --list without --verbose
1099 // - --list with one or two --verbose
1100 if (opt_robot)
1101 fail = print_info_robot(&xfi, pair);
1102 else if (message_verbosity_get() <= V_WARNING)
1103 fail = print_info_basic(&xfi, pair);
1104 else
1105 fail = print_info_adv(&xfi, pair);
1107 // Update the totals that are displayed after all
1108 // the individual files have been listed. Don't count
1109 // broken files.
1110 if (!fail)
1111 update_totals(&xfi);
1113 lzma_index_end(xfi.idx, NULL);
1116 io_close(pair, false);
1117 return;