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