xref: /freebsd/contrib/xz/src/xz/list.c (revision 15f0b8c3)
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 	/// Oldest XZ Utils version that will decompress the file
33 	uint32_t min_version;
34 
35 } xz_file_info;
36 
37 #define XZ_FILE_INFO_INIT { NULL, 0, 0, true, 50000002 }
38 
39 
40 /// Information about a .xz Block
41 typedef struct {
42 	/// Size of the Block Header
43 	uint32_t header_size;
44 
45 	/// A few of the Block Flags as a string
46 	char flags[3];
47 
48 	/// Size of the Compressed Data field in the Block
49 	lzma_vli compressed_size;
50 
51 	/// Decoder memory usage for this Block
52 	uint64_t memusage;
53 
54 	/// The filter chain of this Block in human-readable form
55 	char *filter_chain;
56 
57 } block_header_info;
58 
59 #define BLOCK_HEADER_INFO_INIT { .filter_chain = NULL }
60 #define block_header_info_end(bhi) free((bhi)->filter_chain)
61 
62 
63 /// Strings ending in a colon. These are used for lines like
64 /// "  Foo:   123 MiB". These are grouped because translated strings
65 /// may have different maximum string length, and we want to pad all
66 /// strings so that the values are aligned nicely.
67 static const char *colon_strs[] = {
68 	N_("Streams:"),
69 	N_("Blocks:"),
70 	N_("Compressed size:"),
71 	N_("Uncompressed size:"),
72 	N_("Ratio:"),
73 	N_("Check:"),
74 	N_("Stream Padding:"),
75 	N_("Memory needed:"),
76 	N_("Sizes in headers:"),
77 	// This won't be aligned because it's so long:
78 	//N_("Minimum XZ Utils version:"),
79 	N_("Number of files:"),
80 };
81 
82 /// Enum matching the above strings.
83 enum {
84 	COLON_STR_STREAMS,
85 	COLON_STR_BLOCKS,
86 	COLON_STR_COMPRESSED_SIZE,
87 	COLON_STR_UNCOMPRESSED_SIZE,
88 	COLON_STR_RATIO,
89 	COLON_STR_CHECK,
90 	COLON_STR_STREAM_PADDING,
91 	COLON_STR_MEMORY_NEEDED,
92 	COLON_STR_SIZES_IN_HEADERS,
93 	//COLON_STR_MINIMUM_XZ_VERSION,
94 	COLON_STR_NUMBER_OF_FILES,
95 };
96 
97 /// Field widths to use with printf to pad the strings to use the same number
98 /// of columns on a terminal.
99 static int colon_strs_fw[ARRAY_SIZE(colon_strs)];
100 
101 /// Convenience macro to get the translated string and its field width
102 /// using a COLON_STR_foo enum.
103 #define COLON_STR(num) colon_strs_fw[num], _(colon_strs[num])
104 
105 
106 /// Column headings
107 static struct {
108 	/// Table column heading string
109 	const char *str;
110 
111 	/// Number of terminal-columns to use for this table-column.
112 	/// If a translated string is longer than the initial value,
113 	/// this value will be increased in init_headings().
114 	int columns;
115 
116 	/// Field width to use for printf() to pad "str" to use "columns"
117 	/// number of columns on a terminal. This is calculated in
118 	/// init_headings().
119 	int fw;
120 
121 } headings[] = {
122 	{ N_("Stream"), 6, 0 },
123 	{ N_("Block"), 9, 0 },
124 	{ N_("Blocks"), 9, 0 },
125 	{ N_("CompOffset"), 15, 0 },
126 	{ N_("UncompOffset"), 15, 0 },
127 	{ N_("CompSize"), 15, 0 },
128 	{ N_("UncompSize"), 15, 0 },
129 	{ N_("TotalSize"), 15, 0 },
130 	{ N_("Ratio"), 5, 0 },
131 	{ N_("Check"), 10, 0 },
132 	{ N_("CheckVal"), 1, 0 },
133 	{ N_("Padding"), 7, 0 },
134 	{ N_("Header"), 5, 0 },
135 	{ N_("Flags"), 2, 0 },
136 	{ N_("MemUsage"), 7 + 4, 0 }, // +4 is for " MiB"
137 	{ N_("Filters"), 1, 0 },
138 };
139 
140 /// Enum matching the above strings.
141 enum {
142 	HEADING_STREAM,
143 	HEADING_BLOCK,
144 	HEADING_BLOCKS,
145 	HEADING_COMPOFFSET,
146 	HEADING_UNCOMPOFFSET,
147 	HEADING_COMPSIZE,
148 	HEADING_UNCOMPSIZE,
149 	HEADING_TOTALSIZE,
150 	HEADING_RATIO,
151 	HEADING_CHECK,
152 	HEADING_CHECKVAL,
153 	HEADING_PADDING,
154 	HEADING_HEADERSIZE,
155 	HEADING_HEADERFLAGS,
156 	HEADING_MEMUSAGE,
157 	HEADING_FILTERS,
158 };
159 
160 #define HEADING_STR(num) headings[num].fw, _(headings[num].str)
161 
162 
163 /// Check ID to string mapping
164 static const char check_names[LZMA_CHECK_ID_MAX + 1][12] = {
165 	// TRANSLATORS: Indicates that there is no integrity check.
166 	// This string is used in tables. In older xz version this
167 	// string was limited to ten columns in a fixed-width font, but
168 	// nowadays there is no strict length restriction anymore.
169 	N_("None"),
170 	"CRC32",
171 	// TRANSLATORS: Indicates that integrity check name is not known,
172 	// but the Check ID is known (here 2). In older xz version these
173 	// strings were limited to ten columns in a fixed-width font, but
174 	// nowadays there is no strict length restriction anymore.
175 	N_("Unknown-2"),
176 	N_("Unknown-3"),
177 	"CRC64",
178 	N_("Unknown-5"),
179 	N_("Unknown-6"),
180 	N_("Unknown-7"),
181 	N_("Unknown-8"),
182 	N_("Unknown-9"),
183 	"SHA-256",
184 	N_("Unknown-11"),
185 	N_("Unknown-12"),
186 	N_("Unknown-13"),
187 	N_("Unknown-14"),
188 	N_("Unknown-15"),
189 };
190 
191 /// Buffer size for get_check_names(). This may be a bit ridiculous,
192 /// but at least it's enough if some language needs many multibyte chars.
193 #define CHECKS_STR_SIZE 1024
194 
195 
196 /// Value of the Check field as hexadecimal string.
197 /// This is set by parse_check_value().
198 static char check_value[2 * LZMA_CHECK_SIZE_MAX + 1];
199 
200 
201 /// Totals that are displayed if there was more than one file.
202 /// The "files" counter is also used in print_info_adv() to show
203 /// the file number.
204 static struct {
205 	uint64_t files;
206 	uint64_t streams;
207 	uint64_t blocks;
208 	uint64_t compressed_size;
209 	uint64_t uncompressed_size;
210 	uint64_t stream_padding;
211 	uint64_t memusage_max;
212 	uint32_t checks;
213 	uint32_t min_version;
214 	bool all_have_sizes;
215 } totals = { 0, 0, 0, 0, 0, 0, 0, 0, 50000002, true };
216 
217 
218 /// Initialize colon_strs_fw[].
219 static void
220 init_colon_strs(void)
221 {
222 	// Lengths of translated strings as bytes.
223 	size_t lens[ARRAY_SIZE(colon_strs)];
224 
225 	// Lengths of translated strings as columns.
226 	size_t widths[ARRAY_SIZE(colon_strs)];
227 
228 	// Maximum number of columns needed by a translated string.
229 	size_t width_max = 0;
230 
231 	for (unsigned i = 0; i < ARRAY_SIZE(colon_strs); ++i) {
232 		widths[i] = tuklib_mbstr_width(_(colon_strs[i]), &lens[i]);
233 
234 		// If debugging is enabled, catch invalid strings with
235 		// an assertion. However, when not debugging, use the
236 		// byte count as the fallback width. This shouldn't
237 		// ever happen unless there is a bad string in the
238 		// translations, but in such case I guess it's better
239 		// to try to print something useful instead of failing
240 		// completely.
241 		assert(widths[i] != (size_t)-1);
242 		if (widths[i] == (size_t)-1)
243 			widths[i] = lens[i];
244 
245 		if (widths[i] > width_max)
246 			width_max = widths[i];
247 	}
248 
249 	// Calculate the field width for printf("%*s") so that the strings
250 	// will use width_max columns on a terminal.
251 	for (unsigned i = 0; i < ARRAY_SIZE(colon_strs); ++i)
252 		colon_strs_fw[i] = (int)(lens[i] + width_max - widths[i]);
253 
254 	return;
255 }
256 
257 
258 /// Initialize headings[].
259 static void
260 init_headings(void)
261 {
262 	// Before going through the heading strings themselves, treat
263 	// the Check heading specially: Look at the widths of the various
264 	// check names and increase the width of the Check column if needed.
265 	// The width of the heading name "Check" will then be handled normally
266 	// with other heading names in the second loop in this function.
267 	for (unsigned i = 0; i < ARRAY_SIZE(check_names); ++i) {
268 		size_t len;
269 		size_t w = tuklib_mbstr_width(_(check_names[i]), &len);
270 
271 		// Error handling like in init_colon_strs().
272 		assert(w != (size_t)-1);
273 		if (w == (size_t)-1)
274 			w = len;
275 
276 		// If the translated string is wider than the minimum width
277 		// set at compile time, increase the width.
278 		if ((size_t)(headings[HEADING_CHECK].columns) < w)
279 			headings[HEADING_CHECK].columns = w;
280 	}
281 
282 	for (unsigned i = 0; i < ARRAY_SIZE(headings); ++i) {
283 		size_t len;
284 		size_t w = tuklib_mbstr_width(_(headings[i].str), &len);
285 
286 		// Error handling like in init_colon_strs().
287 		assert(w != (size_t)-1);
288 		if (w == (size_t)-1)
289 			w = len;
290 
291 		// If the translated string is wider than the minimum width
292 		// set at compile time, increase the width.
293 		if ((size_t)(headings[i].columns) < w)
294 			headings[i].columns = w;
295 
296 		// Calculate the field width for printf("%*s") so that
297 		// the string uses .columns number of columns on a terminal.
298 		headings[i].fw = (int)(len + (size_t)headings[i].columns - w);
299 	}
300 
301 	return;
302 }
303 
304 
305 /// Initialize the printf field widths that are needed to get nicely aligned
306 /// output with translated strings.
307 static void
308 init_field_widths(void)
309 {
310 	init_colon_strs();
311 	init_headings();
312 	return;
313 }
314 
315 
316 /// Convert XZ Utils version number to a string.
317 static const char *
318 xz_ver_to_str(uint32_t ver)
319 {
320 	static char buf[32];
321 
322 	unsigned int major = ver / 10000000U;
323 	ver -= major * 10000000U;
324 
325 	unsigned int minor = ver / 10000U;
326 	ver -= minor * 10000U;
327 
328 	unsigned int patch = ver / 10U;
329 	ver -= patch * 10U;
330 
331 	const char *stability = ver == 0 ? "alpha" : ver == 1 ? "beta" : "";
332 
333 	snprintf(buf, sizeof(buf), "%u.%u.%u%s",
334 			major, minor, patch, stability);
335 	return buf;
336 }
337 
338 
339 /// \brief      Parse the Index(es) from the given .xz file
340 ///
341 /// \param      xfi     Pointer to structure where the decoded information
342 ///                     is stored.
343 /// \param      pair    Input file
344 ///
345 /// \return     On success, false is returned. On error, true is returned.
346 ///
347 static bool
348 parse_indexes(xz_file_info *xfi, file_pair *pair)
349 {
350 	if (pair->src_st.st_size <= 0) {
351 		message_error(_("%s: File is empty"), pair->src_name);
352 		return true;
353 	}
354 
355 	if (pair->src_st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) {
356 		message_error(_("%s: Too small to be a valid .xz file"),
357 				pair->src_name);
358 		return true;
359 	}
360 
361 	io_buf buf;
362 	lzma_stream strm = LZMA_STREAM_INIT;
363 	lzma_index *idx = NULL;
364 
365 	lzma_ret ret = lzma_file_info_decoder(&strm, &idx,
366 			hardware_memlimit_get(MODE_LIST),
367 			(uint64_t)(pair->src_st.st_size));
368 	if (ret != LZMA_OK) {
369 		message_error("%s: %s", pair->src_name, message_strm(ret));
370 		return true;
371 	}
372 
373 	while (true) {
374 		if (strm.avail_in == 0) {
375 			strm.next_in = buf.u8;
376 			strm.avail_in = io_read(pair, &buf, IO_BUFFER_SIZE);
377 			if (strm.avail_in == SIZE_MAX)
378 				goto error;
379 		}
380 
381 		ret = lzma_code(&strm, LZMA_RUN);
382 
383 		switch (ret) {
384 		case LZMA_OK:
385 			break;
386 
387 		case LZMA_SEEK_NEEDED:
388 			// liblzma won't ask us to seek past the known size
389 			// of the input file.
390 			assert(strm.seek_pos
391 					<= (uint64_t)(pair->src_st.st_size));
392 			if (io_seek_src(pair, strm.seek_pos))
393 				goto error;
394 
395 			// avail_in must be zero so that we will read new
396 			// input.
397 			strm.avail_in = 0;
398 			break;
399 
400 		case LZMA_STREAM_END: {
401 			lzma_end(&strm);
402 			xfi->idx = idx;
403 
404 			// Calculate xfi->stream_padding.
405 			lzma_index_iter iter;
406 			lzma_index_iter_init(&iter, xfi->idx);
407 			while (!lzma_index_iter_next(&iter,
408 					LZMA_INDEX_ITER_STREAM))
409 				xfi->stream_padding += iter.stream.padding;
410 
411 			return false;
412 		}
413 
414 		default:
415 			message_error("%s: %s", pair->src_name,
416 					message_strm(ret));
417 
418 			// If the error was too low memory usage limit,
419 			// show also how much memory would have been needed.
420 			if (ret == LZMA_MEMLIMIT_ERROR)
421 				message_mem_needed(V_ERROR,
422 						lzma_memusage(&strm));
423 
424 			goto error;
425 		}
426 	}
427 
428 error:
429 	lzma_end(&strm);
430 	return true;
431 }
432 
433 
434 /// \brief      Parse the Block Header
435 ///
436 /// The result is stored into *bhi. The caller takes care of initializing it.
437 ///
438 /// \return     False on success, true on error.
439 static bool
440 parse_block_header(file_pair *pair, const lzma_index_iter *iter,
441 		block_header_info *bhi, xz_file_info *xfi)
442 {
443 #if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
444 #	error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
445 #endif
446 
447 	// Get the whole Block Header with one read, but don't read past
448 	// the end of the Block (or even its Check field).
449 	const uint32_t size = my_min(iter->block.total_size
450 				- lzma_check_size(iter->stream.flags->check),
451 			LZMA_BLOCK_HEADER_SIZE_MAX);
452 	io_buf buf;
453 	if (io_pread(pair, &buf, size, iter->block.compressed_file_offset))
454 		return true;
455 
456 	// Zero would mean Index Indicator and thus not a valid Block.
457 	if (buf.u8[0] == 0)
458 		goto data_error;
459 
460 	// Initialize the block structure and decode Block Header Size.
461 	lzma_filter filters[LZMA_FILTERS_MAX + 1];
462 	lzma_block block;
463 	block.version = 0;
464 	block.check = iter->stream.flags->check;
465 	block.filters = filters;
466 
467 	block.header_size = lzma_block_header_size_decode(buf.u8[0]);
468 	if (block.header_size > size)
469 		goto data_error;
470 
471 	// Decode the Block Header.
472 	switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
473 	case LZMA_OK:
474 		break;
475 
476 	case LZMA_OPTIONS_ERROR:
477 		message_error("%s: %s", pair->src_name,
478 				message_strm(LZMA_OPTIONS_ERROR));
479 		return true;
480 
481 	case LZMA_DATA_ERROR:
482 		goto data_error;
483 
484 	default:
485 		message_bug();
486 	}
487 
488 	// Check the Block Flags. These must be done before calling
489 	// lzma_block_compressed_size(), because it overwrites
490 	// block.compressed_size.
491 	//
492 	// NOTE: If you add new characters here, update the minimum number of
493 	// columns in headings[HEADING_HEADERFLAGS] to match the number of
494 	// characters used here.
495 	bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
496 			? 'c' : '-';
497 	bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
498 			? 'u' : '-';
499 	bhi->flags[2] = '\0';
500 
501 	// Collect information if all Blocks have both Compressed Size
502 	// and Uncompressed Size fields. They can be useful e.g. for
503 	// multi-threaded decompression so it can be useful to know it.
504 	xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
505 			&& block.uncompressed_size != LZMA_VLI_UNKNOWN;
506 
507 	// Validate or set block.compressed_size.
508 	switch (lzma_block_compressed_size(&block,
509 			iter->block.unpadded_size)) {
510 	case LZMA_OK:
511 		// Validate also block.uncompressed_size if it is present.
512 		// If it isn't present, there's no need to set it since
513 		// we aren't going to actually decompress the Block; if
514 		// we were decompressing, then we should set it so that
515 		// the Block decoder could validate the Uncompressed Size
516 		// that was stored in the Index.
517 		if (block.uncompressed_size == LZMA_VLI_UNKNOWN
518 				|| block.uncompressed_size
519 					== iter->block.uncompressed_size)
520 			break;
521 
522 		// If the above fails, the file is corrupt so
523 		// LZMA_DATA_ERROR is a good error code.
524 
525 	// Fall through
526 
527 	case LZMA_DATA_ERROR:
528 		// Free the memory allocated by lzma_block_header_decode().
529 		lzma_filters_free(filters, NULL);
530 		goto data_error;
531 
532 	default:
533 		message_bug();
534 	}
535 
536 	// Copy the known sizes.
537 	bhi->header_size = block.header_size;
538 	bhi->compressed_size = block.compressed_size;
539 
540 	// Calculate the decoder memory usage and update the maximum
541 	// memory usage of this Block.
542 	bhi->memusage = lzma_raw_decoder_memusage(filters);
543 	if (xfi->memusage_max < bhi->memusage)
544 		xfi->memusage_max = bhi->memusage;
545 
546 	// Determine the minimum XZ Utils version that supports this Block.
547 	//
548 	//   - ARM64 filter needs 5.4.0.
549 	//
550 	//   - 5.0.0 doesn't support empty LZMA2 streams and thus empty
551 	//     Blocks that use LZMA2. This decoder bug was fixed in 5.0.2.
552 	if (xfi->min_version < 50040002U) {
553 		for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
554 			if (filters[i].id == LZMA_FILTER_ARM64) {
555 				xfi->min_version = 50040002U;
556 				break;
557 			}
558 		}
559 	}
560 
561 	if (xfi->min_version < 50000022U) {
562 		size_t i = 0;
563 		while (filters[i + 1].id != LZMA_VLI_UNKNOWN)
564 			++i;
565 
566 		if (filters[i].id == LZMA_FILTER_LZMA2
567 				&& iter->block.uncompressed_size == 0)
568 			xfi->min_version = 50000022U;
569 	}
570 
571 	// Convert the filter chain to human readable form.
572 	const lzma_ret str_ret = lzma_str_from_filters(
573 			&bhi->filter_chain, filters,
574 			LZMA_STR_DECODER | LZMA_STR_GETOPT_LONG, NULL);
575 
576 	// Free the memory allocated by lzma_block_header_decode().
577 	lzma_filters_free(filters, NULL);
578 
579 	// Check if the stringification succeeded.
580 	if (str_ret != LZMA_OK) {
581 		message_error("%s: %s", pair->src_name, message_strm(str_ret));
582 		return true;
583 	}
584 
585 	return false;
586 
587 data_error:
588 	// Show the error message.
589 	message_error("%s: %s", pair->src_name,
590 			message_strm(LZMA_DATA_ERROR));
591 	return true;
592 }
593 
594 
595 /// \brief      Parse the Check field and put it into check_value[]
596 ///
597 /// \return     False on success, true on error.
598 static bool
599 parse_check_value(file_pair *pair, const lzma_index_iter *iter)
600 {
601 	// Don't read anything from the file if there is no integrity Check.
602 	if (iter->stream.flags->check == LZMA_CHECK_NONE) {
603 		snprintf(check_value, sizeof(check_value), "---");
604 		return false;
605 	}
606 
607 	// Locate and read the Check field.
608 	const uint32_t size = lzma_check_size(iter->stream.flags->check);
609 	const uint64_t offset = iter->block.compressed_file_offset
610 			+ iter->block.total_size - size;
611 	io_buf buf;
612 	if (io_pread(pair, &buf, size, offset))
613 		return true;
614 
615 	// CRC32 and CRC64 are in little endian. Guess that all the future
616 	// 32-bit and 64-bit Check values are little endian too. It shouldn't
617 	// be a too big problem if this guess is wrong.
618 	if (size == 4)
619 		snprintf(check_value, sizeof(check_value),
620 				"%08" PRIx32, conv32le(buf.u32[0]));
621 	else if (size == 8)
622 		snprintf(check_value, sizeof(check_value),
623 				"%016" PRIx64, conv64le(buf.u64[0]));
624 	else
625 		for (size_t i = 0; i < size; ++i)
626 			snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);
627 
628 	return false;
629 }
630 
631 
632 /// \brief      Parse detailed information about a Block
633 ///
634 /// Since this requires seek(s), listing information about all Blocks can
635 /// be slow.
636 ///
637 /// \param      pair    Input file
638 /// \param      iter    Location of the Block whose Check value should
639 ///                     be printed.
640 /// \param      bhi     Pointer to structure where to store the information
641 ///                     about the Block Header field.
642 ///
643 /// \return     False on success, true on error. If an error occurs,
644 ///             the error message is printed too so the caller doesn't
645 ///             need to worry about that.
646 static bool
647 parse_details(file_pair *pair, const lzma_index_iter *iter,
648 		block_header_info *bhi, xz_file_info *xfi)
649 {
650 	if (parse_block_header(pair, iter, bhi, xfi))
651 		return true;
652 
653 	if (parse_check_value(pair, iter))
654 		return true;
655 
656 	return false;
657 }
658 
659 
660 /// \brief      Get the compression ratio
661 ///
662 /// This has slightly different format than that is used in message.c.
663 static const char *
664 get_ratio(uint64_t compressed_size, uint64_t uncompressed_size)
665 {
666 	if (uncompressed_size == 0)
667 		return "---";
668 
669 	const double ratio = (double)(compressed_size)
670 			/ (double)(uncompressed_size);
671 	if (ratio > 9.999)
672 		return "---";
673 
674 	static char buf[16];
675 	snprintf(buf, sizeof(buf), "%.3f", ratio);
676 	return buf;
677 }
678 
679 
680 /// \brief      Get a comma-separated list of Check names
681 ///
682 /// The check names are translated with gettext except when in robot mode.
683 ///
684 /// \param      buf     Buffer to hold the resulting string
685 /// \param      checks  Bit mask of Checks to print
686 /// \param      space_after_comma
687 ///                     It's better to not use spaces in table-like listings,
688 ///                     but in more verbose formats a space after a comma
689 ///                     is good for readability.
690 static void
691 get_check_names(char buf[CHECKS_STR_SIZE],
692 		uint32_t checks, bool space_after_comma)
693 {
694 	// If we get called when there are no Checks to print, set checks
695 	// to 1 so that we print "None". This can happen in the robot mode
696 	// when printing the totals line if there are no valid input files.
697 	if (checks == 0)
698 		checks = 1;
699 
700 	char *pos = buf;
701 	size_t left = CHECKS_STR_SIZE;
702 
703 	const char *sep = space_after_comma ? ", " : ",";
704 	bool comma = false;
705 
706 	for (size_t i = 0; i <= LZMA_CHECK_ID_MAX; ++i) {
707 		if (checks & (UINT32_C(1) << i)) {
708 			my_snprintf(&pos, &left, "%s%s",
709 					comma ? sep : "",
710 					opt_robot ? check_names[i]
711 						: _(check_names[i]));
712 			comma = true;
713 		}
714 	}
715 
716 	return;
717 }
718 
719 
720 static bool
721 print_info_basic(const xz_file_info *xfi, file_pair *pair)
722 {
723 	static bool headings_displayed = false;
724 	if (!headings_displayed) {
725 		headings_displayed = true;
726 		// TRANSLATORS: These are column headings. From Strms (Streams)
727 		// to Ratio, the columns are right aligned. Check and Filename
728 		// are left aligned. If you need longer words, it's OK to
729 		// use two lines here. Test with "xz -l foo.xz".
730 		puts(_("Strms  Blocks   Compressed Uncompressed  Ratio  "
731 				"Check   Filename"));
732 	}
733 
734 	char checks[CHECKS_STR_SIZE];
735 	get_check_names(checks, lzma_index_checks(xfi->idx), false);
736 
737 	const char *cols[7] = {
738 		uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
739 		uint64_to_str(lzma_index_block_count(xfi->idx), 1),
740 		uint64_to_nicestr(lzma_index_file_size(xfi->idx),
741 			NICESTR_B, NICESTR_TIB, false, 2),
742 		uint64_to_nicestr(lzma_index_uncompressed_size(xfi->idx),
743 			NICESTR_B, NICESTR_TIB, false, 3),
744 		get_ratio(lzma_index_file_size(xfi->idx),
745 			lzma_index_uncompressed_size(xfi->idx)),
746 		checks,
747 		pair->src_name,
748 	};
749 	printf("%*s %*s  %*s  %*s  %*s  %-*s %s\n",
750 			tuklib_mbstr_fw(cols[0], 5), cols[0],
751 			tuklib_mbstr_fw(cols[1], 7), cols[1],
752 			tuklib_mbstr_fw(cols[2], 11), cols[2],
753 			tuklib_mbstr_fw(cols[3], 11), cols[3],
754 			tuklib_mbstr_fw(cols[4], 5), cols[4],
755 			tuklib_mbstr_fw(cols[5], 7), cols[5],
756 			cols[6]);
757 
758 	return false;
759 }
760 
761 
762 static void
763 print_adv_helper(uint64_t stream_count, uint64_t block_count,
764 		uint64_t compressed_size, uint64_t uncompressed_size,
765 		uint32_t checks, uint64_t stream_padding)
766 {
767 	char checks_str[CHECKS_STR_SIZE];
768 	get_check_names(checks_str, checks, true);
769 
770 	printf("  %-*s %s\n", COLON_STR(COLON_STR_STREAMS),
771 			uint64_to_str(stream_count, 0));
772 	printf("  %-*s %s\n", COLON_STR(COLON_STR_BLOCKS),
773 			uint64_to_str(block_count, 0));
774 	printf("  %-*s %s\n", COLON_STR(COLON_STR_COMPRESSED_SIZE),
775 			uint64_to_nicestr(compressed_size,
776 				NICESTR_B, NICESTR_TIB, true, 0));
777 	printf("  %-*s %s\n", COLON_STR(COLON_STR_UNCOMPRESSED_SIZE),
778 			uint64_to_nicestr(uncompressed_size,
779 				NICESTR_B, NICESTR_TIB, true, 0));
780 	printf("  %-*s %s\n", COLON_STR(COLON_STR_RATIO),
781 			get_ratio(compressed_size, uncompressed_size));
782 	printf("  %-*s %s\n", COLON_STR(COLON_STR_CHECK), checks_str);
783 	printf("  %-*s %s\n", COLON_STR(COLON_STR_STREAM_PADDING),
784 			uint64_to_nicestr(stream_padding,
785 				NICESTR_B, NICESTR_TIB, true, 0));
786 	return;
787 }
788 
789 
790 static bool
791 print_info_adv(xz_file_info *xfi, file_pair *pair)
792 {
793 	// Print the overall information.
794 	print_adv_helper(lzma_index_stream_count(xfi->idx),
795 			lzma_index_block_count(xfi->idx),
796 			lzma_index_file_size(xfi->idx),
797 			lzma_index_uncompressed_size(xfi->idx),
798 			lzma_index_checks(xfi->idx),
799 			xfi->stream_padding);
800 
801 	// Size of the biggest Check. This is used to calculate the width
802 	// of the CheckVal field. The table would get insanely wide if
803 	// we always reserved space for 64-byte Check (128 chars as hex).
804 	uint32_t check_max = 0;
805 
806 	// Print information about the Streams.
807 	//
808 	// All except Check are right aligned; Check is left aligned.
809 	// Test with "xz -lv foo.xz".
810 	printf("  %s\n    %*s %*s %*s %*s %*s %*s  %*s  %-*s %*s\n",
811 			_(colon_strs[COLON_STR_STREAMS]),
812 			HEADING_STR(HEADING_STREAM),
813 			HEADING_STR(HEADING_BLOCKS),
814 			HEADING_STR(HEADING_COMPOFFSET),
815 			HEADING_STR(HEADING_UNCOMPOFFSET),
816 			HEADING_STR(HEADING_COMPSIZE),
817 			HEADING_STR(HEADING_UNCOMPSIZE),
818 			HEADING_STR(HEADING_RATIO),
819 			HEADING_STR(HEADING_CHECK),
820 			HEADING_STR(HEADING_PADDING));
821 
822 	lzma_index_iter iter;
823 	lzma_index_iter_init(&iter, xfi->idx);
824 
825 	while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
826 		const char *cols1[4] = {
827 			uint64_to_str(iter.stream.number, 0),
828 			uint64_to_str(iter.stream.block_count, 1),
829 			uint64_to_str(iter.stream.compressed_offset, 2),
830 			uint64_to_str(iter.stream.uncompressed_offset, 3),
831 		};
832 		printf("    %*s %*s %*s %*s ",
833 			tuklib_mbstr_fw(cols1[0],
834 				headings[HEADING_STREAM].columns),
835 			cols1[0],
836 			tuklib_mbstr_fw(cols1[1],
837 				headings[HEADING_BLOCKS].columns),
838 			cols1[1],
839 			tuklib_mbstr_fw(cols1[2],
840 				headings[HEADING_COMPOFFSET].columns),
841 			cols1[2],
842 			tuklib_mbstr_fw(cols1[3],
843 				headings[HEADING_UNCOMPOFFSET].columns),
844 			cols1[3]);
845 
846 		const char *cols2[5] = {
847 			uint64_to_str(iter.stream.compressed_size, 0),
848 			uint64_to_str(iter.stream.uncompressed_size, 1),
849 			get_ratio(iter.stream.compressed_size,
850 				iter.stream.uncompressed_size),
851 			_(check_names[iter.stream.flags->check]),
852 			uint64_to_str(iter.stream.padding, 2),
853 		};
854 		printf("%*s %*s  %*s  %-*s %*s\n",
855 			tuklib_mbstr_fw(cols2[0],
856 				headings[HEADING_COMPSIZE].columns),
857 			cols2[0],
858 			tuklib_mbstr_fw(cols2[1],
859 				headings[HEADING_UNCOMPSIZE].columns),
860 			cols2[1],
861 			tuklib_mbstr_fw(cols2[2],
862 				headings[HEADING_RATIO].columns),
863 			cols2[2],
864 			tuklib_mbstr_fw(cols2[3],
865 				headings[HEADING_CHECK].columns),
866 			cols2[3],
867 			tuklib_mbstr_fw(cols2[4],
868 				headings[HEADING_PADDING].columns),
869 			cols2[4]);
870 
871 		// Update the maximum Check size.
872 		if (lzma_check_size(iter.stream.flags->check) > check_max)
873 			check_max = lzma_check_size(iter.stream.flags->check);
874 	}
875 
876 	// Cache the verbosity level to a local variable.
877 	const bool detailed = message_verbosity_get() >= V_DEBUG;
878 
879 	// Print information about the Blocks but only if there is
880 	// at least one Block.
881 	if (lzma_index_block_count(xfi->idx) > 0) {
882 		// Calculate the width of the CheckVal column. This can be
883 		// used as is as the field width for printf() when printing
884 		// the actual check value as it is hexadecimal. However, to
885 		// print the column heading, further calculation is needed
886 		// to handle a translated string (it's done a few lines later).
887 		assert(check_max <= LZMA_CHECK_SIZE_MAX);
888 		const int checkval_width = my_max(
889 				headings[HEADING_CHECKVAL].columns,
890 				(int)(2 * check_max));
891 
892 		// All except Check are right aligned; Check is left aligned.
893 		printf("  %s\n    %*s %*s %*s %*s %*s %*s  %*s  %-*s",
894 				_(colon_strs[COLON_STR_BLOCKS]),
895 				HEADING_STR(HEADING_STREAM),
896 				HEADING_STR(HEADING_BLOCK),
897 				HEADING_STR(HEADING_COMPOFFSET),
898 				HEADING_STR(HEADING_UNCOMPOFFSET),
899 				HEADING_STR(HEADING_TOTALSIZE),
900 				HEADING_STR(HEADING_UNCOMPSIZE),
901 				HEADING_STR(HEADING_RATIO),
902 				detailed ? headings[HEADING_CHECK].fw : 1,
903 				_(headings[HEADING_CHECK].str));
904 
905 		if (detailed) {
906 			// CheckVal (Check value), Flags, and Filters are
907 			// left aligned. Block Header Size, CompSize, and
908 			// MemUsage are right aligned. Test with
909 			// "xz -lvv foo.xz".
910 			printf(" %-*s  %*s  %-*s %*s %*s  %s",
911 				headings[HEADING_CHECKVAL].fw
912 					+ checkval_width
913 					- headings[HEADING_CHECKVAL].columns,
914 				_(headings[HEADING_CHECKVAL].str),
915 				HEADING_STR(HEADING_HEADERSIZE),
916 				HEADING_STR(HEADING_HEADERFLAGS),
917 				HEADING_STR(HEADING_COMPSIZE),
918 				HEADING_STR(HEADING_MEMUSAGE),
919 				_(headings[HEADING_FILTERS].str));
920 		}
921 
922 		putchar('\n');
923 
924 		lzma_index_iter_init(&iter, xfi->idx);
925 
926 		// Iterate over the Blocks.
927 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
928 			// If in detailed mode, collect the information from
929 			// Block Header before starting to print the next line.
930 			block_header_info bhi = BLOCK_HEADER_INFO_INIT;
931 			if (detailed && parse_details(pair, &iter, &bhi, xfi))
932 				return true;
933 
934 			const char *cols1[4] = {
935 				uint64_to_str(iter.stream.number, 0),
936 				uint64_to_str(
937 					iter.block.number_in_stream, 1),
938 				uint64_to_str(
939 					iter.block.compressed_file_offset, 2),
940 				uint64_to_str(
941 					iter.block.uncompressed_file_offset, 3)
942 			};
943 			printf("    %*s %*s %*s %*s ",
944 				tuklib_mbstr_fw(cols1[0],
945 					headings[HEADING_STREAM].columns),
946 				cols1[0],
947 				tuklib_mbstr_fw(cols1[1],
948 					headings[HEADING_BLOCK].columns),
949 				cols1[1],
950 				tuklib_mbstr_fw(cols1[2],
951 					headings[HEADING_COMPOFFSET].columns),
952 				cols1[2],
953 				tuklib_mbstr_fw(cols1[3], headings[
954 					HEADING_UNCOMPOFFSET].columns),
955 				cols1[3]);
956 
957 			const char *cols2[4] = {
958 				uint64_to_str(iter.block.total_size, 0),
959 				uint64_to_str(iter.block.uncompressed_size,
960 						1),
961 				get_ratio(iter.block.total_size,
962 					iter.block.uncompressed_size),
963 				_(check_names[iter.stream.flags->check])
964 			};
965 			printf("%*s %*s  %*s  %-*s",
966 				tuklib_mbstr_fw(cols2[0],
967 					headings[HEADING_TOTALSIZE].columns),
968 				cols2[0],
969 				tuklib_mbstr_fw(cols2[1],
970 					headings[HEADING_UNCOMPSIZE].columns),
971 				cols2[1],
972 				tuklib_mbstr_fw(cols2[2],
973 					headings[HEADING_RATIO].columns),
974 				cols2[2],
975 				tuklib_mbstr_fw(cols2[3], detailed
976 					? headings[HEADING_CHECK].columns : 1),
977 				cols2[3]);
978 
979 			if (detailed) {
980 				const lzma_vli compressed_size
981 						= iter.block.unpadded_size
982 						- bhi.header_size
983 						- lzma_check_size(
984 						iter.stream.flags->check);
985 
986 				const char *cols3[6] = {
987 					check_value,
988 					uint64_to_str(bhi.header_size, 0),
989 					bhi.flags,
990 					uint64_to_str(compressed_size, 1),
991 					uint64_to_str(
992 						round_up_to_mib(bhi.memusage),
993 						2),
994 					bhi.filter_chain
995 				};
996 				// Show MiB for memory usage, because it
997 				// is the only size which is not in bytes.
998 				printf(" %-*s  %*s  %-*s %*s %*s MiB  %s",
999 					checkval_width, cols3[0],
1000 					tuklib_mbstr_fw(cols3[1], headings[
1001 						HEADING_HEADERSIZE].columns),
1002 					cols3[1],
1003 					tuklib_mbstr_fw(cols3[2], headings[
1004 						HEADING_HEADERFLAGS].columns),
1005 					cols3[2],
1006 					tuklib_mbstr_fw(cols3[3], headings[
1007 						HEADING_COMPSIZE].columns),
1008 					cols3[3],
1009 					tuklib_mbstr_fw(cols3[4], headings[
1010 						HEADING_MEMUSAGE].columns - 4),
1011 					cols3[4],
1012 					cols3[5]);
1013 			}
1014 
1015 			putchar('\n');
1016 			block_header_info_end(&bhi);
1017 		}
1018 	}
1019 
1020 	if (detailed) {
1021 		printf("  %-*s %s MiB\n", COLON_STR(COLON_STR_MEMORY_NEEDED),
1022 				uint64_to_str(
1023 				round_up_to_mib(xfi->memusage_max), 0));
1024 		printf("  %-*s %s\n", COLON_STR(COLON_STR_SIZES_IN_HEADERS),
1025 				xfi->all_have_sizes ? _("Yes") : _("No"));
1026 		//printf("  %-*s %s\n", COLON_STR(COLON_STR_MINIMUM_XZ_VERSION),
1027 		printf(_("  Minimum XZ Utils version: %s\n"),
1028 				xz_ver_to_str(xfi->min_version));
1029 	}
1030 
1031 	return false;
1032 }
1033 
1034 
1035 static bool
1036 print_info_robot(xz_file_info *xfi, file_pair *pair)
1037 {
1038 	char checks[CHECKS_STR_SIZE];
1039 	get_check_names(checks, lzma_index_checks(xfi->idx), false);
1040 
1041 	printf("name\t%s\n", pair->src_name);
1042 
1043 	printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1044 			"\t%s\t%s\t%" PRIu64 "\n",
1045 			lzma_index_stream_count(xfi->idx),
1046 			lzma_index_block_count(xfi->idx),
1047 			lzma_index_file_size(xfi->idx),
1048 			lzma_index_uncompressed_size(xfi->idx),
1049 			get_ratio(lzma_index_file_size(xfi->idx),
1050 				lzma_index_uncompressed_size(xfi->idx)),
1051 			checks,
1052 			xfi->stream_padding);
1053 
1054 	if (message_verbosity_get() >= V_VERBOSE) {
1055 		lzma_index_iter iter;
1056 		lzma_index_iter_init(&iter, xfi->idx);
1057 
1058 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
1059 			printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1060 				"\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1061 				"\t%s\t%s\t%" PRIu64 "\n",
1062 				iter.stream.number,
1063 				iter.stream.block_count,
1064 				iter.stream.compressed_offset,
1065 				iter.stream.uncompressed_offset,
1066 				iter.stream.compressed_size,
1067 				iter.stream.uncompressed_size,
1068 				get_ratio(iter.stream.compressed_size,
1069 					iter.stream.uncompressed_size),
1070 				check_names[iter.stream.flags->check],
1071 				iter.stream.padding);
1072 
1073 		lzma_index_iter_rewind(&iter);
1074 
1075 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
1076 			block_header_info bhi = BLOCK_HEADER_INFO_INIT;
1077 			if (message_verbosity_get() >= V_DEBUG
1078 					&& parse_details(
1079 						pair, &iter, &bhi, xfi))
1080 				return true;
1081 
1082 			printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1083 					"\t%" PRIu64 "\t%" PRIu64
1084 					"\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
1085 					iter.stream.number,
1086 					iter.block.number_in_stream,
1087 					iter.block.number_in_file,
1088 					iter.block.compressed_file_offset,
1089 					iter.block.uncompressed_file_offset,
1090 					iter.block.total_size,
1091 					iter.block.uncompressed_size,
1092 					get_ratio(iter.block.total_size,
1093 						iter.block.uncompressed_size),
1094 					check_names[iter.stream.flags->check]);
1095 
1096 			if (message_verbosity_get() >= V_DEBUG)
1097 				printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
1098 						"\t%" PRIu64 "\t%s",
1099 						check_value,
1100 						bhi.header_size,
1101 						bhi.flags,
1102 						bhi.compressed_size,
1103 						bhi.memusage,
1104 						bhi.filter_chain);
1105 
1106 			putchar('\n');
1107 			block_header_info_end(&bhi);
1108 		}
1109 	}
1110 
1111 	if (message_verbosity_get() >= V_DEBUG)
1112 		printf("summary\t%" PRIu64 "\t%s\t%" PRIu32 "\n",
1113 				xfi->memusage_max,
1114 				xfi->all_have_sizes ? "yes" : "no",
1115 				xfi->min_version);
1116 
1117 	return false;
1118 }
1119 
1120 
1121 static void
1122 update_totals(const xz_file_info *xfi)
1123 {
1124 	// TODO: Integer overflow checks
1125 	++totals.files;
1126 	totals.streams += lzma_index_stream_count(xfi->idx);
1127 	totals.blocks += lzma_index_block_count(xfi->idx);
1128 	totals.compressed_size += lzma_index_file_size(xfi->idx);
1129 	totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
1130 	totals.stream_padding += xfi->stream_padding;
1131 	totals.checks |= lzma_index_checks(xfi->idx);
1132 
1133 	if (totals.memusage_max < xfi->memusage_max)
1134 		totals.memusage_max = xfi->memusage_max;
1135 
1136 	if (totals.min_version < xfi->min_version)
1137 		totals.min_version = xfi->min_version;
1138 
1139 	totals.all_have_sizes &= xfi->all_have_sizes;
1140 
1141 	return;
1142 }
1143 
1144 
1145 static void
1146 print_totals_basic(void)
1147 {
1148 	// Print a separator line.
1149 	char line[80];
1150 	memset(line, '-', sizeof(line));
1151 	line[sizeof(line) - 1] = '\0';
1152 	puts(line);
1153 
1154 	// Get the check names.
1155 	char checks[CHECKS_STR_SIZE];
1156 	get_check_names(checks, totals.checks, false);
1157 
1158 	// Print the totals except the file count, which needs
1159 	// special handling.
1160 	printf("%5s %7s  %11s  %11s  %5s  %-7s ",
1161 			uint64_to_str(totals.streams, 0),
1162 			uint64_to_str(totals.blocks, 1),
1163 			uint64_to_nicestr(totals.compressed_size,
1164 				NICESTR_B, NICESTR_TIB, false, 2),
1165 			uint64_to_nicestr(totals.uncompressed_size,
1166 				NICESTR_B, NICESTR_TIB, false, 3),
1167 			get_ratio(totals.compressed_size,
1168 				totals.uncompressed_size),
1169 			checks);
1170 
1171 	// Since we print totals only when there are at least two files,
1172 	// the English message will always use "%s files". But some other
1173 	// languages need different forms for different plurals so we
1174 	// have to translate this with ngettext().
1175 	//
1176 	// TRANSLATORS: %s is an integer. Only the plural form of this
1177 	// message is used (e.g. "2 files"). Test with "xz -l foo.xz bar.xz".
1178 	printf(ngettext("%s file\n", "%s files\n",
1179 			totals.files <= ULONG_MAX ? totals.files
1180 				: (totals.files % 1000000) + 1000000),
1181 			uint64_to_str(totals.files, 0));
1182 
1183 	return;
1184 }
1185 
1186 
1187 static void
1188 print_totals_adv(void)
1189 {
1190 	putchar('\n');
1191 	puts(_("Totals:"));
1192 	printf("  %-*s %s\n", COLON_STR(COLON_STR_NUMBER_OF_FILES),
1193 			uint64_to_str(totals.files, 0));
1194 	print_adv_helper(totals.streams, totals.blocks,
1195 			totals.compressed_size, totals.uncompressed_size,
1196 			totals.checks, totals.stream_padding);
1197 
1198 	if (message_verbosity_get() >= V_DEBUG) {
1199 		printf("  %-*s %s MiB\n", COLON_STR(COLON_STR_MEMORY_NEEDED),
1200 				uint64_to_str(
1201 				round_up_to_mib(totals.memusage_max), 0));
1202 		printf("  %-*s %s\n", COLON_STR(COLON_STR_SIZES_IN_HEADERS),
1203 				totals.all_have_sizes ? _("Yes") : _("No"));
1204 		//printf("  %-*s %s\n", COLON_STR(COLON_STR_MINIMUM_XZ_VERSION),
1205 		printf(_("  Minimum XZ Utils version: %s\n"),
1206 				xz_ver_to_str(totals.min_version));
1207 	}
1208 
1209 	return;
1210 }
1211 
1212 
1213 static void
1214 print_totals_robot(void)
1215 {
1216 	char checks[CHECKS_STR_SIZE];
1217 	get_check_names(checks, totals.checks, false);
1218 
1219 	printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1220 			"\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
1221 			totals.streams,
1222 			totals.blocks,
1223 			totals.compressed_size,
1224 			totals.uncompressed_size,
1225 			get_ratio(totals.compressed_size,
1226 				totals.uncompressed_size),
1227 			checks,
1228 			totals.stream_padding,
1229 			totals.files);
1230 
1231 	if (message_verbosity_get() >= V_DEBUG)
1232 		printf("\t%" PRIu64 "\t%s\t%" PRIu32,
1233 				totals.memusage_max,
1234 				totals.all_have_sizes ? "yes" : "no",
1235 				totals.min_version);
1236 
1237 	putchar('\n');
1238 
1239 	return;
1240 }
1241 
1242 
1243 extern void
1244 list_totals(void)
1245 {
1246 	if (opt_robot) {
1247 		// Always print totals in --robot mode. It can be convenient
1248 		// in some cases and doesn't complicate usage of the
1249 		// single-file case much.
1250 		print_totals_robot();
1251 
1252 	} else if (totals.files > 1) {
1253 		// For non-robot mode, totals are printed only if there
1254 		// is more than one file.
1255 		if (message_verbosity_get() <= V_WARNING)
1256 			print_totals_basic();
1257 		else
1258 			print_totals_adv();
1259 	}
1260 
1261 	return;
1262 }
1263 
1264 
1265 extern void
1266 list_file(const char *filename)
1267 {
1268 	if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
1269 		message_fatal(_("--list works only on .xz files "
1270 				"(--format=xz or --format=auto)"));
1271 
1272 	message_filename(filename);
1273 
1274 	if (filename == stdin_filename) {
1275 		message_error(_("--list does not support reading from "
1276 				"standard input"));
1277 		return;
1278 	}
1279 
1280 	init_field_widths();
1281 
1282 	// Unset opt_stdout so that io_open_src() won't accept special files.
1283 	// Set opt_force so that io_open_src() will follow symlinks.
1284 	opt_stdout = false;
1285 	opt_force = true;
1286 	file_pair *pair = io_open_src(filename);
1287 	if (pair == NULL)
1288 		return;
1289 
1290 	xz_file_info xfi = XZ_FILE_INFO_INIT;
1291 	if (!parse_indexes(&xfi, pair)) {
1292 		bool fail;
1293 
1294 		// We have three main modes:
1295 		//  - --robot, which has submodes if --verbose is specified
1296 		//    once or twice
1297 		//  - Normal --list without --verbose
1298 		//  - --list with one or two --verbose
1299 		if (opt_robot)
1300 			fail = print_info_robot(&xfi, pair);
1301 		else if (message_verbosity_get() <= V_WARNING)
1302 			fail = print_info_basic(&xfi, pair);
1303 		else
1304 			fail = print_info_adv(&xfi, pair);
1305 
1306 		// Update the totals that are displayed after all
1307 		// the individual files have been listed. Don't count
1308 		// broken files.
1309 		if (!fail)
1310 			update_totals(&xfi);
1311 
1312 		lzma_index_end(xfi.idx, NULL);
1313 	}
1314 
1315 	io_close(pair, false);
1316 	return;
1317 }
1318