xref: /dragonfly/contrib/xz/src/xz/list.c (revision 73610d44)
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 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 
364 error:
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.
378 static bool
379 parse_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 
490 data_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.
501 static bool
502 parse_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.
549 static bool
550 parse_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.
566 static const char *
567 get_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.
593 static void
594 get_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 
619 static bool
620 print_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 
661 static void
662 print_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 
689 static bool
690 print_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 
865 static bool
866 print_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 
949 static void
950 update_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 
970 static void
971 print_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 
1012 static void
1013 print_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 
1034 static void
1035 print_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 
1063 extern void
1064 list_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 
1085 extern void
1086 list_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