1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Listing information about .xz files
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
14 #include "tuklib_integer.h"
17 /// Information about a .xz file
19 /// Combined Index of all Streams in the file
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
34 #define XZ_FILE_INFO_INIT { NULL, 0, 0, true }
37 /// Information about a .xz Block
39 /// Size of the Block Header
42 /// A few of the Block Flags as a string
45 /// Size of the Compressed Data field in the Block
46 lzma_vli compressed_size
;
48 /// Decoder memory usage for this Block
51 /// The filter chain of this Block in human-readable form
52 char filter_chain
[FILTERS_STR_SIZE
];
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.
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.
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
102 uint64_t compressed_size
;
103 uint64_t uncompressed_size
;
104 uint64_t stream_padding
;
105 uint64_t memusage_max
;
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
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.
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
);
130 if (pair
->src_st
.st_size
< 2 * LZMA_STREAM_HEADER_SIZE
) {
131 message_error(_("%s: Too small to be a valid .xz file"),
137 lzma_stream_flags header_flags
;
138 lzma_stream_flags footer_flags
;
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.
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
));
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.
171 if (pos
< LZMA_STREAM_HEADER_SIZE
) {
172 message_error("%s: %s", pair
->src_name
,
178 if (io_pread(pair
, &buf
,
179 LZMA_STREAM_HEADER_SIZE
, pos
))
182 // Stream Padding is always a multiple of four bytes.
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.
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
,
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
));
214 // Set pos to the beginning of the Index.
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
)
229 ret
= lzma_index_decoder(&strm
, &this_index
, memlimit
);
230 if (ret
!= LZMA_OK
) {
231 message_error("%s: %s", pair
->src_name
,
237 // Don't give the decoder more input than the
239 strm
.avail_in
= my_min(IO_BUFFER_SIZE
, index_size
);
240 if (io_pread(pair
, &buf
, strm
.avail_in
, pos
))
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
,
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
)
279 message_mem_needed(V_ERROR
, needed
);
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
));
294 pos
-= lzma_index_total_size(this_index
);
295 if (io_pread(pair
, &buf
, LZMA_STREAM_HEADER_SIZE
, pos
))
298 ret
= lzma_stream_header_decode(&header_flags
, buf
.u8
);
299 if (ret
!= LZMA_OK
) {
300 message_error("%s: %s", pair
->src_name
,
305 ret
= lzma_stream_flags_compare(&header_flags
, &footer_flags
);
306 if (ret
!= LZMA_OK
) {
307 message_error("%s: %s", pair
->src_name
,
312 // Store the decoded Stream Flags into this_index. This is
313 // needed so that we can print which Check is used in each
315 ret
= lzma_index_stream_flags(this_index
, &footer_flags
);
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
);
325 if (combined_index
!= NULL
) {
326 // Append the earlier decoded Indexes
328 ret
= lzma_index_cat(
329 this_index
, combined_index
, NULL
);
330 if (ret
!= LZMA_OK
) {
331 message_error("%s: %s", pair
->src_name
,
337 combined_index
= this_index
;
340 xfi
->stream_padding
+= stream_padding
;
346 // All OK. Make combined_index available to the caller.
347 xfi
->idx
= combined_index
;
351 // Something went wrong, free the allocated memory.
353 lzma_index_end(combined_index
, NULL
);
354 lzma_index_end(this_index
, NULL
);
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.
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
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
);
378 if (io_pread(pair
, &buf
, size
, iter
->block
.compressed_file_offset
))
381 // Zero would mean Index Indicator and thus not a valid 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.
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
)
401 // Decode the Block Header.
402 switch (lzma_block_header_decode(&block
, NULL
, buf
.u8
)) {
406 case LZMA_OPTIONS_ERROR
:
407 message_error("%s: %s", pair
->src_name
,
408 message_strm(LZMA_OPTIONS_ERROR
));
411 case LZMA_DATA_ERROR
:
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
423 bhi
->flags
[1] = block
.uncompressed_size
!= LZMA_VLI_UNKNOWN
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
)) {
439 case LZMA_DATA_ERROR
:
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
);
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
474 for (size_t i
= 0; filters
[i
].id
!= LZMA_VLI_UNKNOWN
; ++i
)
475 free(filters
[i
].options
);
481 /// \brief Parse the Check field and put it into check_value[]
483 /// \return False on success, true on error.
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
), "---");
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
;
498 if (io_pread(pair
, &buf
, size
, offset
))
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.
505 snprintf(check_value
, sizeof(check_value
),
506 "%08" PRIx32
, conv32le(buf
.u32
[0]));
508 snprintf(check_value
, sizeof(check_value
),
509 "%016" PRIx64
, conv64le(buf
.u64
[0]));
511 for (size_t i
= 0; i
< size
; ++i
)
512 snprintf(check_value
+ i
* 2, 3, "%02x", buf
.u8
[i
]);
518 /// \brief Parse detailed information about a Block
520 /// Since this requires seek(s), listing information about all Blocks can
523 /// \param pair Input file
524 /// \param iter Location of the Block whose Check value should
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.
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
))
539 if (parse_check_value(pair
, iter
))
546 /// \brief Get the compression ratio
548 /// This has slightly different format than that is used in message.c.
550 get_ratio(uint64_t compressed_size
, uint64_t uncompressed_size
)
552 if (uncompressed_size
== 0)
555 const double ratio
= (double)(compressed_size
)
556 / (double)(uncompressed_size
);
561 snprintf(buf
, sizeof(buf
), "%.3f", ratio
);
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.
577 get_check_names(char buf
[CHECKS_STR_SIZE
],
578 uint32_t checks
, bool space_after_comma
)
583 size_t left
= CHECKS_STR_SIZE
;
585 const char *sep
= space_after_comma
? ", " : ",";
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",
592 opt_robot
? check_names
[i
]
593 : _(check_names
[i
]));
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 "
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
)),
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],
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));
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
693 puts(_(" Streams:\n Stream Blocks"
694 " CompOffset UncompOffset"
695 " CompSize UncompSize Ratio"
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"));
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, "");
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
))
774 const char *cols1
[4] = {
775 uint64_to_str(iter
.stream
.number
, 0),
777 iter
.block
.number_in_stream
, 1),
779 iter
.block
.compressed_file_offset
, 2),
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),
805 const lzma_vli compressed_size
806 = iter
.block
.unpadded_size
809 iter
.stream
.flags
->check
);
811 const char *cols3
[6] = {
813 uint64_to_str(bhi
.header_size
, 0),
815 uint64_to_str(compressed_size
, 1),
817 round_up_to_mib(bhi
.memusage
),
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],
827 tuklib_mbstr_fw(cols3
[3], 15),
829 tuklib_mbstr_fw(cols3
[4], 7), cols3
[4],
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"));
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
)),
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",
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
892 pair
, &iter
, &bhi
, xfi
))
895 printf("block\t%" PRIu64
"\t%" PRIu64
"\t%" PRIu64
896 "\t%" PRIu64
"\t%" PRIu64
897 "\t%" PRIu64
"\t%" PRIu64
"\t%s\t%s",
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
923 if (message_verbosity_get() >= V_DEBUG
)
924 printf("summary\t%" PRIu64
"\t%s\n",
926 xfi
->all_have_sizes
? "yes" : "no");
933 update_totals(const xz_file_info
*xfi
)
935 // TODO: Integer overflow checks
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
;
954 print_totals_basic(void)
956 // Print a separator line.
958 memset(line
, '-', sizeof(line
));
959 line
[sizeof(line
) - 1] = '\0';
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
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
),
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));
996 print_totals_adv(void)
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"));
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
,
1027 totals
.compressed_size
,
1028 totals
.uncompressed_size
,
1029 get_ratio(totals
.compressed_size
,
1030 totals
.uncompressed_size
),
1032 totals
.stream_padding
,
1035 if (message_verbosity_get() >= V_DEBUG
)
1036 printf("\t%" PRIu64
"\t%s",
1037 totals
.memusage_max
,
1038 totals
.all_have_sizes
? "yes" : "no");
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();
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 "
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.
1087 file_pair
*pair
= io_open_src(filename
);
1091 xz_file_info xfi
= XZ_FILE_INFO_INIT
;
1092 if (!parse_indexes(&xfi
, pair
)) {
1095 // We have three main modes:
1096 // - --robot, which has submodes if --verbose is specified
1098 // - Normal --list without --verbose
1099 // - --list with one or two --verbose
1101 fail
= print_info_robot(&xfi
, pair
);
1102 else if (message_verbosity_get() <= V_WARNING
)
1103 fail
= print_info_basic(&xfi
, pair
);
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
1111 update_totals(&xfi
);
1113 lzma_index_end(xfi
.idx
, NULL
);
1116 io_close(pair
, false);