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