xref: /dragonfly/contrib/xz/src/xz/list.c (revision 89a89091)
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 	// Initialize the block structure and decode Block Header Size.
386 	lzma_filter filters[LZMA_FILTERS_MAX + 1];
387 	lzma_block block;
388 	block.version = 0;
389 	block.check = iter->stream.flags->check;
390 	block.filters = filters;
391 
392 	block.header_size = lzma_block_header_size_decode(buf.u8[0]);
393 	if (block.header_size > size)
394 		goto data_error;
395 
396 	// Decode the Block Header.
397 	switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
398 	case LZMA_OK:
399 		break;
400 
401 	case LZMA_OPTIONS_ERROR:
402 		message_error("%s: %s", pair->src_name,
403 				message_strm(LZMA_OPTIONS_ERROR));
404 		return true;
405 
406 	case LZMA_DATA_ERROR:
407 		goto data_error;
408 
409 	default:
410 		message_bug();
411 	}
412 
413 	// Check the Block Flags. These must be done before calling
414 	// lzma_block_compressed_size(), because it overwrites
415 	// block.compressed_size.
416 	bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
417 			? 'c' : '-';
418 	bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
419 			? 'u' : '-';
420 	bhi->flags[2] = '\0';
421 
422 	// Collect information if all Blocks have both Compressed Size
423 	// and Uncompressed Size fields. They can be useful e.g. for
424 	// multi-threaded decompression so it can be useful to know it.
425 	xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
426 			&& block.uncompressed_size != LZMA_VLI_UNKNOWN;
427 
428 	// Validate or set block.compressed_size.
429 	switch (lzma_block_compressed_size(&block,
430 			iter->block.unpadded_size)) {
431 	case LZMA_OK:
432 		break;
433 
434 	case LZMA_DATA_ERROR:
435 		// Free the memory allocated by lzma_block_header_decode().
436 		for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
437 			free(filters[i].options);
438 
439 		goto data_error;
440 
441 	default:
442 		message_bug();
443 	}
444 
445 	// Copy the known sizes.
446 	bhi->header_size = block.header_size;
447 	bhi->compressed_size = block.compressed_size;
448 
449 	// Calculate the decoder memory usage and update the maximum
450 	// memory usage of this Block.
451 	bhi->memusage = lzma_raw_decoder_memusage(filters);
452 	if (xfi->memusage_max < bhi->memusage)
453 		xfi->memusage_max = bhi->memusage;
454 
455 	// Convert the filter chain to human readable form.
456 	message_filters_to_str(bhi->filter_chain, filters, false);
457 
458 	// Free the memory allocated by lzma_block_header_decode().
459 	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
460 		free(filters[i].options);
461 
462 	return false;
463 
464 data_error:
465 	// Show the error message.
466 	message_error("%s: %s", pair->src_name,
467 			message_strm(LZMA_DATA_ERROR));
468 	return true;
469 }
470 
471 
472 /// \brief      Parse the Check field and put it into check_value[]
473 ///
474 /// \return     False on success, true on error.
475 static bool
476 parse_check_value(file_pair *pair, const lzma_index_iter *iter)
477 {
478 	// Don't read anything from the file if there is no integrity Check.
479 	if (iter->stream.flags->check == LZMA_CHECK_NONE) {
480 		snprintf(check_value, sizeof(check_value), "---");
481 		return false;
482 	}
483 
484 	// Locate and read the Check field.
485 	const uint32_t size = lzma_check_size(iter->stream.flags->check);
486 	const off_t offset = iter->block.compressed_file_offset
487 			+ iter->block.total_size - size;
488 	io_buf buf;
489 	if (io_pread(pair, &buf, size, offset))
490 		return true;
491 
492 	// CRC32 and CRC64 are in little endian. Guess that all the future
493 	// 32-bit and 64-bit Check values are little endian too. It shouldn't
494 	// be a too big problem if this guess is wrong.
495 	if (size == 4)
496 		snprintf(check_value, sizeof(check_value),
497 				"%08" PRIx32, conv32le(buf.u32[0]));
498 	else if (size == 8)
499 		snprintf(check_value, sizeof(check_value),
500 				"%016" PRIx64, conv64le(buf.u64[0]));
501 	else
502 		for (size_t i = 0; i < size; ++i)
503 			snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);
504 
505 	return false;
506 }
507 
508 
509 /// \brief      Parse detailed information about a Block
510 ///
511 /// Since this requires seek(s), listing information about all Blocks can
512 /// be slow.
513 ///
514 /// \param      pair    Input file
515 /// \param      iter    Location of the Block whose Check value should
516 ///                     be printed.
517 /// \param      bhi     Pointer to structure where to store the information
518 ///                     about the Block Header field.
519 ///
520 /// \return     False on success, true on error. If an error occurs,
521 ///             the error message is printed too so the caller doesn't
522 ///             need to worry about that.
523 static bool
524 parse_details(file_pair *pair, const lzma_index_iter *iter,
525 		block_header_info *bhi, xz_file_info *xfi)
526 {
527 	if (parse_block_header(pair, iter, bhi, xfi))
528 		return true;
529 
530 	if (parse_check_value(pair, iter))
531 		return true;
532 
533 	return false;
534 }
535 
536 
537 /// \brief      Get the compression ratio
538 ///
539 /// This has slightly different format than that is used in message.c.
540 static const char *
541 get_ratio(uint64_t compressed_size, uint64_t uncompressed_size)
542 {
543 	if (uncompressed_size == 0)
544 		return "---";
545 
546 	const double ratio = (double)(compressed_size)
547 			/ (double)(uncompressed_size);
548 	if (ratio > 9.999)
549 		return "---";
550 
551 	static char buf[16];
552 	snprintf(buf, sizeof(buf), "%.3f", ratio);
553 	return buf;
554 }
555 
556 
557 /// \brief      Get a comma-separated list of Check names
558 ///
559 /// The check names are translated with gettext except when in robot mode.
560 ///
561 /// \param      buf     Buffer to hold the resulting string
562 /// \param      checks  Bit mask of Checks to print
563 /// \param      space_after_comma
564 ///                     It's better to not use spaces in table-like listings,
565 ///                     but in more verbose formats a space after a comma
566 ///                     is good for readability.
567 static void
568 get_check_names(char buf[CHECKS_STR_SIZE],
569 		uint32_t checks, bool space_after_comma)
570 {
571 	assert(checks != 0);
572 
573 	char *pos = buf;
574 	size_t left = CHECKS_STR_SIZE;
575 
576 	const char *sep = space_after_comma ? ", " : ",";
577 	bool comma = false;
578 
579 	for (size_t i = 0; i <= LZMA_CHECK_ID_MAX; ++i) {
580 		if (checks & (UINT32_C(1) << i)) {
581 			my_snprintf(&pos, &left, "%s%s",
582 					comma ? sep : "",
583 					opt_robot ? check_names[i]
584 						: _(check_names[i]));
585 			comma = true;
586 		}
587 	}
588 
589 	return;
590 }
591 
592 
593 static bool
594 print_info_basic(const xz_file_info *xfi, file_pair *pair)
595 {
596 	static bool headings_displayed = false;
597 	if (!headings_displayed) {
598 		headings_displayed = true;
599 		// TRANSLATORS: These are column headings. From Strms (Streams)
600 		// to Ratio, the columns are right aligned. Check and Filename
601 		// are left aligned. If you need longer words, it's OK to
602 		// use two lines here. Test with "xz -l foo.xz".
603 		puts(_("Strms  Blocks   Compressed Uncompressed  Ratio  "
604 				"Check   Filename"));
605 	}
606 
607 	char checks[CHECKS_STR_SIZE];
608 	get_check_names(checks, lzma_index_checks(xfi->idx), false);
609 
610 	const char *cols[7] = {
611 		uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
612 		uint64_to_str(lzma_index_block_count(xfi->idx), 1),
613 		uint64_to_nicestr(lzma_index_file_size(xfi->idx),
614 			NICESTR_B, NICESTR_TIB, false, 2),
615 		uint64_to_nicestr(lzma_index_uncompressed_size(xfi->idx),
616 			NICESTR_B, NICESTR_TIB, false, 3),
617 		get_ratio(lzma_index_file_size(xfi->idx),
618 			lzma_index_uncompressed_size(xfi->idx)),
619 		checks,
620 		pair->src_name,
621 	};
622 	printf("%*s %*s  %*s  %*s  %*s  %-*s %s\n",
623 			tuklib_mbstr_fw(cols[0], 5), cols[0],
624 			tuklib_mbstr_fw(cols[1], 7), cols[1],
625 			tuklib_mbstr_fw(cols[2], 11), cols[2],
626 			tuklib_mbstr_fw(cols[3], 11), cols[3],
627 			tuklib_mbstr_fw(cols[4], 5), cols[4],
628 			tuklib_mbstr_fw(cols[5], 7), cols[5],
629 			cols[6]);
630 
631 	return false;
632 }
633 
634 
635 static void
636 print_adv_helper(uint64_t stream_count, uint64_t block_count,
637 		uint64_t compressed_size, uint64_t uncompressed_size,
638 		uint32_t checks, uint64_t stream_padding)
639 {
640 	char checks_str[CHECKS_STR_SIZE];
641 	get_check_names(checks_str, checks, true);
642 
643 	printf(_("  Streams:            %s\n"),
644 			uint64_to_str(stream_count, 0));
645 	printf(_("  Blocks:             %s\n"),
646 			uint64_to_str(block_count, 0));
647 	printf(_("  Compressed size:    %s\n"),
648 			uint64_to_nicestr(compressed_size,
649 				NICESTR_B, NICESTR_TIB, true, 0));
650 	printf(_("  Uncompressed size:  %s\n"),
651 			uint64_to_nicestr(uncompressed_size,
652 				NICESTR_B, NICESTR_TIB, true, 0));
653 	printf(_("  Ratio:              %s\n"),
654 			get_ratio(compressed_size, uncompressed_size));
655 	printf(_("  Check:              %s\n"), checks_str);
656 	printf(_("  Stream padding:     %s\n"),
657 			uint64_to_nicestr(stream_padding,
658 				NICESTR_B, NICESTR_TIB, true, 0));
659 	return;
660 }
661 
662 
663 static bool
664 print_info_adv(xz_file_info *xfi, file_pair *pair)
665 {
666 	// Print the overall information.
667 	print_adv_helper(lzma_index_stream_count(xfi->idx),
668 			lzma_index_block_count(xfi->idx),
669 			lzma_index_file_size(xfi->idx),
670 			lzma_index_uncompressed_size(xfi->idx),
671 			lzma_index_checks(xfi->idx),
672 			xfi->stream_padding);
673 
674 	// Size of the biggest Check. This is used to calculate the width
675 	// of the CheckVal field. The table would get insanely wide if
676 	// we always reserved space for 64-byte Check (128 chars as hex).
677 	uint32_t check_max = 0;
678 
679 	// Print information about the Streams.
680 	//
681 	// TRANSLATORS: The second line is column headings. All except
682 	// Check are right aligned; Check is left aligned. Test with
683 	// "xz -lv foo.xz".
684 	puts(_("  Streams:\n    Stream    Blocks"
685 			"      CompOffset    UncompOffset"
686 			"        CompSize      UncompSize  Ratio"
687 			"  Check      Padding"));
688 
689 	lzma_index_iter iter;
690 	lzma_index_iter_init(&iter, xfi->idx);
691 
692 	while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
693 		const char *cols1[4] = {
694 			uint64_to_str(iter.stream.number, 0),
695 			uint64_to_str(iter.stream.block_count, 1),
696 			uint64_to_str(iter.stream.compressed_offset, 2),
697 			uint64_to_str(iter.stream.uncompressed_offset, 3),
698 		};
699 		printf("    %*s %*s %*s %*s ",
700 				tuklib_mbstr_fw(cols1[0], 6), cols1[0],
701 				tuklib_mbstr_fw(cols1[1], 9), cols1[1],
702 				tuklib_mbstr_fw(cols1[2], 15), cols1[2],
703 				tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
704 
705 		const char *cols2[5] = {
706 			uint64_to_str(iter.stream.compressed_size, 0),
707 			uint64_to_str(iter.stream.uncompressed_size, 1),
708 			get_ratio(iter.stream.compressed_size,
709 				iter.stream.uncompressed_size),
710 			_(check_names[iter.stream.flags->check]),
711 			uint64_to_str(iter.stream.padding, 2),
712 		};
713 		printf("%*s %*s  %*s  %-*s %*s\n",
714 				tuklib_mbstr_fw(cols2[0], 15), cols2[0],
715 				tuklib_mbstr_fw(cols2[1], 15), cols2[1],
716 				tuklib_mbstr_fw(cols2[2], 5), cols2[2],
717 				tuklib_mbstr_fw(cols2[3], 10), cols2[3],
718 				tuklib_mbstr_fw(cols2[4], 7), cols2[4]);
719 
720 		// Update the maximum Check size.
721 		if (lzma_check_size(iter.stream.flags->check) > check_max)
722 			check_max = lzma_check_size(iter.stream.flags->check);
723 	}
724 
725 	// Cache the verbosity level to a local variable.
726 	const bool detailed = message_verbosity_get() >= V_DEBUG;
727 
728 	// Information collected from Block Headers
729 	block_header_info bhi;
730 
731 	// Print information about the Blocks but only if there is
732 	// at least one Block.
733 	if (lzma_index_block_count(xfi->idx) > 0) {
734 		// Calculate the width of the CheckVal field.
735 		const int checkval_width = my_max(8, 2 * check_max);
736 
737 		// TRANSLATORS: The second line is column headings. All
738 		// except Check are right aligned; Check is left aligned.
739 		printf(_("  Blocks:\n    Stream     Block"
740 			"      CompOffset    UncompOffset"
741 			"       TotalSize      UncompSize  Ratio  Check"));
742 
743 		if (detailed) {
744 			// TRANSLATORS: These are additional column headings
745 			// for the most verbose listing mode. CheckVal
746 			// (Check value), Flags, and Filters are left aligned.
747 			// Header (Block Header Size), CompSize, and MemUsage
748 			// are right aligned. %*s is replaced with 0-120
749 			// spaces to make the CheckVal column wide enough.
750 			// Test with "xz -lvv foo.xz".
751 			printf(_("      CheckVal %*s Header  Flags        "
752 					"CompSize    MemUsage  Filters"),
753 					checkval_width - 8, "");
754 		}
755 
756 		putchar('\n');
757 
758 		lzma_index_iter_init(&iter, xfi->idx);
759 
760 		// Iterate over the Blocks.
761 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
762 			if (detailed && parse_details(pair, &iter, &bhi, xfi))
763 					return true;
764 
765 			const char *cols1[4] = {
766 				uint64_to_str(iter.stream.number, 0),
767 				uint64_to_str(
768 					iter.block.number_in_stream, 1),
769 				uint64_to_str(
770 					iter.block.compressed_file_offset, 2),
771 				uint64_to_str(
772 					iter.block.uncompressed_file_offset, 3)
773 			};
774 			printf("    %*s %*s %*s %*s ",
775 				tuklib_mbstr_fw(cols1[0], 6), cols1[0],
776 				tuklib_mbstr_fw(cols1[1], 9), cols1[1],
777 				tuklib_mbstr_fw(cols1[2], 15), cols1[2],
778 				tuklib_mbstr_fw(cols1[3], 15), cols1[3]);
779 
780 			const char *cols2[4] = {
781 				uint64_to_str(iter.block.total_size, 0),
782 				uint64_to_str(iter.block.uncompressed_size,
783 						1),
784 				get_ratio(iter.block.total_size,
785 					iter.block.uncompressed_size),
786 				_(check_names[iter.stream.flags->check])
787 			};
788 			printf("%*s %*s  %*s  %-*s",
789 				tuklib_mbstr_fw(cols2[0], 15), cols2[0],
790 				tuklib_mbstr_fw(cols2[1], 15), cols2[1],
791 				tuklib_mbstr_fw(cols2[2], 5), cols2[2],
792 				tuklib_mbstr_fw(cols2[3], detailed ? 11 : 1),
793 					cols2[3]);
794 
795 			if (detailed) {
796 				const lzma_vli compressed_size
797 						= iter.block.unpadded_size
798 						- bhi.header_size
799 						- lzma_check_size(
800 						iter.stream.flags->check);
801 
802 				const char *cols3[6] = {
803 					check_value,
804 					uint64_to_str(bhi.header_size, 0),
805 					bhi.flags,
806 					uint64_to_str(compressed_size, 1),
807 					uint64_to_str(
808 						round_up_to_mib(bhi.memusage),
809 						2),
810 					bhi.filter_chain
811 				};
812 				// Show MiB for memory usage, because it
813 				// is the only size which is not in bytes.
814 				printf("%-*s  %*s  %-5s %*s %*s MiB  %s",
815 					checkval_width, cols3[0],
816 					tuklib_mbstr_fw(cols3[1], 6), cols3[1],
817 					cols3[2],
818 					tuklib_mbstr_fw(cols3[3], 15),
819 						cols3[3],
820 					tuklib_mbstr_fw(cols3[4], 7), cols3[4],
821 					cols3[5]);
822 			}
823 
824 			putchar('\n');
825 		}
826 	}
827 
828 	if (detailed) {
829 		printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
830 				round_up_to_mib(xfi->memusage_max), 0));
831 		printf(_("  Sizes in headers:   %s\n"),
832 				xfi->all_have_sizes ? _("Yes") : _("No"));
833 	}
834 
835 	return false;
836 }
837 
838 
839 static bool
840 print_info_robot(xz_file_info *xfi, file_pair *pair)
841 {
842 	char checks[CHECKS_STR_SIZE];
843 	get_check_names(checks, lzma_index_checks(xfi->idx), false);
844 
845 	printf("name\t%s\n", pair->src_name);
846 
847 	printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
848 			"\t%s\t%s\t%" PRIu64 "\n",
849 			lzma_index_stream_count(xfi->idx),
850 			lzma_index_block_count(xfi->idx),
851 			lzma_index_file_size(xfi->idx),
852 			lzma_index_uncompressed_size(xfi->idx),
853 			get_ratio(lzma_index_file_size(xfi->idx),
854 				lzma_index_uncompressed_size(xfi->idx)),
855 			checks,
856 			xfi->stream_padding);
857 
858 	if (message_verbosity_get() >= V_VERBOSE) {
859 		lzma_index_iter iter;
860 		lzma_index_iter_init(&iter, xfi->idx);
861 
862 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
863 			printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
864 				"\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
865 				"\t%s\t%s\t%" PRIu64 "\n",
866 				iter.stream.number,
867 				iter.stream.block_count,
868 				iter.stream.compressed_offset,
869 				iter.stream.uncompressed_offset,
870 				iter.stream.compressed_size,
871 				iter.stream.uncompressed_size,
872 				get_ratio(iter.stream.compressed_size,
873 					iter.stream.uncompressed_size),
874 				check_names[iter.stream.flags->check],
875 				iter.stream.padding);
876 
877 		lzma_index_iter_rewind(&iter);
878 		block_header_info bhi;
879 
880 		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
881 			if (message_verbosity_get() >= V_DEBUG
882 					&& parse_details(
883 						pair, &iter, &bhi, xfi))
884 				return true;
885 
886 			printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
887 					"\t%" PRIu64 "\t%" PRIu64
888 					"\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
889 					iter.stream.number,
890 					iter.block.number_in_stream,
891 					iter.block.number_in_file,
892 					iter.block.compressed_file_offset,
893 					iter.block.uncompressed_file_offset,
894 					iter.block.total_size,
895 					iter.block.uncompressed_size,
896 					get_ratio(iter.block.total_size,
897 						iter.block.uncompressed_size),
898 					check_names[iter.stream.flags->check]);
899 
900 			if (message_verbosity_get() >= V_DEBUG)
901 				printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
902 						"\t%" PRIu64 "\t%s",
903 						check_value,
904 						bhi.header_size,
905 						bhi.flags,
906 						bhi.compressed_size,
907 						bhi.memusage,
908 						bhi.filter_chain);
909 
910 			putchar('\n');
911 		}
912 	}
913 
914 	if (message_verbosity_get() >= V_DEBUG)
915 		printf("summary\t%" PRIu64 "\t%s\n",
916 				xfi->memusage_max,
917 				xfi->all_have_sizes ? "yes" : "no");
918 
919 	return false;
920 }
921 
922 
923 static void
924 update_totals(const xz_file_info *xfi)
925 {
926 	// TODO: Integer overflow checks
927 	++totals.files;
928 	totals.streams += lzma_index_stream_count(xfi->idx);
929 	totals.blocks += lzma_index_block_count(xfi->idx);
930 	totals.compressed_size += lzma_index_file_size(xfi->idx);
931 	totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
932 	totals.stream_padding += xfi->stream_padding;
933 	totals.checks |= lzma_index_checks(xfi->idx);
934 
935 	if (totals.memusage_max < xfi->memusage_max)
936 		totals.memusage_max = xfi->memusage_max;
937 
938 	totals.all_have_sizes &= xfi->all_have_sizes;
939 
940 	return;
941 }
942 
943 
944 static void
945 print_totals_basic(void)
946 {
947 	// Print a separator line.
948 	char line[80];
949 	memset(line, '-', sizeof(line));
950 	line[sizeof(line) - 1] = '\0';
951 	puts(line);
952 
953 	// Get the check names.
954 	char checks[CHECKS_STR_SIZE];
955 	get_check_names(checks, totals.checks, false);
956 
957 	// Print the totals except the file count, which needs
958 	// special handling.
959 	printf("%5s %7s  %11s  %11s  %5s  %-7s ",
960 			uint64_to_str(totals.streams, 0),
961 			uint64_to_str(totals.blocks, 1),
962 			uint64_to_nicestr(totals.compressed_size,
963 				NICESTR_B, NICESTR_TIB, false, 2),
964 			uint64_to_nicestr(totals.uncompressed_size,
965 				NICESTR_B, NICESTR_TIB, false, 3),
966 			get_ratio(totals.compressed_size,
967 				totals.uncompressed_size),
968 			checks);
969 
970 	// Since we print totals only when there are at least two files,
971 	// the English message will always use "%s files". But some other
972 	// languages need different forms for different plurals so we
973 	// have to translate this with ngettext().
974 	//
975 	// TRANSLATORS: %s is an integer. Only the plural form of this
976 	// message is used (e.g. "2 files"). Test with "xz -l foo.xz bar.xz".
977 	printf(ngettext("%s file\n", "%s files\n",
978 			totals.files <= ULONG_MAX ? totals.files
979 				: (totals.files % 1000000) + 1000000),
980 			uint64_to_str(totals.files, 0));
981 
982 	return;
983 }
984 
985 
986 static void
987 print_totals_adv(void)
988 {
989 	putchar('\n');
990 	puts(_("Totals:"));
991 	printf(_("  Number of files:    %s\n"),
992 			uint64_to_str(totals.files, 0));
993 	print_adv_helper(totals.streams, totals.blocks,
994 			totals.compressed_size, totals.uncompressed_size,
995 			totals.checks, totals.stream_padding);
996 
997 	if (message_verbosity_get() >= V_DEBUG) {
998 		printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
999 				round_up_to_mib(totals.memusage_max), 0));
1000 		printf(_("  Sizes in headers:   %s\n"),
1001 				totals.all_have_sizes ? _("Yes") : _("No"));
1002 	}
1003 
1004 	return;
1005 }
1006 
1007 
1008 static void
1009 print_totals_robot(void)
1010 {
1011 	char checks[CHECKS_STR_SIZE];
1012 	get_check_names(checks, totals.checks, false);
1013 
1014 	printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
1015 			"\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
1016 			totals.streams,
1017 			totals.blocks,
1018 			totals.compressed_size,
1019 			totals.uncompressed_size,
1020 			get_ratio(totals.compressed_size,
1021 				totals.uncompressed_size),
1022 			checks,
1023 			totals.stream_padding,
1024 			totals.files);
1025 
1026 	if (message_verbosity_get() >= V_DEBUG)
1027 		printf("\t%" PRIu64 "\t%s",
1028 				totals.memusage_max,
1029 				totals.all_have_sizes ? "yes" : "no");
1030 
1031 	putchar('\n');
1032 
1033 	return;
1034 }
1035 
1036 
1037 extern void
1038 list_totals(void)
1039 {
1040 	if (opt_robot) {
1041 		// Always print totals in --robot mode. It can be convenient
1042 		// in some cases and doesn't complicate usage of the
1043 		// single-file case much.
1044 		print_totals_robot();
1045 
1046 	} else if (totals.files > 1) {
1047 		// For non-robot mode, totals are printed only if there
1048 		// is more than one file.
1049 		if (message_verbosity_get() <= V_WARNING)
1050 			print_totals_basic();
1051 		else
1052 			print_totals_adv();
1053 	}
1054 
1055 	return;
1056 }
1057 
1058 
1059 extern void
1060 list_file(const char *filename)
1061 {
1062 	if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
1063 		message_fatal(_("--list works only on .xz files "
1064 				"(--format=xz or --format=auto)"));
1065 
1066 	message_filename(filename);
1067 
1068 	if (filename == stdin_filename) {
1069 		message_error(_("--list does not support reading from "
1070 				"standard input"));
1071 		return;
1072 	}
1073 
1074 	// Unset opt_stdout so that io_open_src() won't accept special files.
1075 	// Set opt_force so that io_open_src() will follow symlinks.
1076 	opt_stdout = false;
1077 	opt_force = true;
1078 	file_pair *pair = io_open_src(filename);
1079 	if (pair == NULL)
1080 		return;
1081 
1082 	xz_file_info xfi = XZ_FILE_INFO_INIT;
1083 	if (!parse_indexes(&xfi, pair)) {
1084 		bool fail;
1085 
1086 		// We have three main modes:
1087 		//  - --robot, which has submodes if --verbose is specified
1088 		//    once or twice
1089 		//  - Normal --list without --verbose
1090 		//  - --list with one or two --verbose
1091 		if (opt_robot)
1092 			fail = print_info_robot(&xfi, pair);
1093 		else if (message_verbosity_get() <= V_WARNING)
1094 			fail = print_info_basic(&xfi, pair);
1095 		else
1096 			fail = print_info_adv(&xfi, pair);
1097 
1098 		// Update the totals that are displayed after all
1099 		// the individual files have been listed. Don't count
1100 		// broken files.
1101 		if (!fail)
1102 			update_totals(&xfi);
1103 
1104 		lzma_index_end(xfi.idx, NULL);
1105 	}
1106 
1107 	io_close(pair, false);
1108 	return;
1109 }
1110