lzmainfo.c revision 207753
1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file lzmainfo.c 4207753Smm/// \brief lzmainfo tool for compatibility with LZMA Utils 5207753Smm// 6207753Smm// Author: Lasse Collin 7207753Smm// 8207753Smm// This file has been put into the public domain. 9207753Smm// You can do whatever you want with this file. 10207753Smm// 11207753Smm/////////////////////////////////////////////////////////////////////////////// 12207753Smm 13207753Smm#include "sysdefs.h" 14207753Smm#include <stdio.h> 15207753Smm#include <errno.h> 16207753Smm 17207753Smm#include "lzma.h" 18207753Smm#include "getopt.h" 19207753Smm#include "tuklib_gettext.h" 20207753Smm#include "tuklib_progname.h" 21207753Smm#include "tuklib_exit.h" 22207753Smm 23207753Smm 24207753Smmstatic void lzma_attribute((noreturn)) 25207753Smmhelp(void) 26207753Smm{ 27207753Smm printf( 28207753Smm_("Usage: %s [--help] [--version] [FILE]...\n" 29207753Smm"Show information stored in the .lzma file header"), progname); 30207753Smm 31207753Smm printf(_( 32207753Smm"\nWith no FILE, or when FILE is -, read standard input.\n")); 33207753Smm printf("\n"); 34207753Smm 35207753Smm printf(_("Report bugs to <%s> (in English or Finnish).\n"), 36207753Smm PACKAGE_BUGREPORT); 37207753Smm printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); 38207753Smm 39207753Smm tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true); 40207753Smm} 41207753Smm 42207753Smm 43207753Smmstatic void lzma_attribute((noreturn)) 44207753Smmversion(void) 45207753Smm{ 46207753Smm puts("lzmainfo (" PACKAGE_NAME ") " PACKAGE_VERSION); 47207753Smm tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true); 48207753Smm} 49207753Smm 50207753Smm 51207753Smm/// Parse command line options. 52207753Smmstatic void 53207753Smmparse_args(int argc, char **argv) 54207753Smm{ 55207753Smm enum { 56207753Smm OPT_HELP, 57207753Smm OPT_VERSION, 58207753Smm }; 59207753Smm 60207753Smm static const struct option long_opts[] = { 61207753Smm { "help", no_argument, NULL, OPT_HELP }, 62207753Smm { "version", no_argument, NULL, OPT_VERSION }, 63207753Smm { NULL, 0, NULL, 0 } 64207753Smm }; 65207753Smm 66207753Smm int c; 67207753Smm while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 68207753Smm switch (c) { 69207753Smm case OPT_HELP: 70207753Smm help(); 71207753Smm 72207753Smm case OPT_VERSION: 73207753Smm version(); 74207753Smm 75207753Smm default: 76207753Smm exit(EXIT_FAILURE); 77207753Smm } 78207753Smm } 79207753Smm 80207753Smm return; 81207753Smm} 82207753Smm 83207753Smm 84207753Smm/// Primitive base-2 logarithm for integers 85207753Smmstatic uint32_t 86207753Smmmy_log2(uint32_t n) 87207753Smm{ 88207753Smm uint32_t e; 89207753Smm for (e = 0; n > 1; ++e, n /= 2) ; 90207753Smm return e; 91207753Smm} 92207753Smm 93207753Smm 94207753Smm/// Parse the .lzma header and display information about it. 95207753Smmstatic bool 96207753Smmlzmainfo(const char *name, FILE *f) 97207753Smm{ 98207753Smm uint8_t buf[13]; 99207753Smm const size_t size = fread(buf, 1, sizeof(buf), f); 100207753Smm if (size != 13) { 101207753Smm fprintf(stderr, "%s: %s: %s\n", progname, name, 102207753Smm ferror(f) ? strerror(errno) 103207753Smm : _("File is too small to be a .lzma file")); 104207753Smm return true; 105207753Smm } 106207753Smm 107207753Smm lzma_filter filter = { .id = LZMA_FILTER_LZMA1 }; 108207753Smm 109207753Smm // Parse the first five bytes. 110207753Smm switch (lzma_properties_decode(&filter, NULL, buf, 5)) { 111207753Smm case LZMA_OK: 112207753Smm break; 113207753Smm 114207753Smm case LZMA_OPTIONS_ERROR: 115207753Smm fprintf(stderr, "%s: %s: %s\n", progname, name, 116207753Smm _("Not a .lzma file")); 117207753Smm return true; 118207753Smm 119207753Smm case LZMA_MEM_ERROR: 120207753Smm fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM)); 121207753Smm exit(EXIT_FAILURE); 122207753Smm 123207753Smm default: 124207753Smm fprintf(stderr, "%s: %s\n", progname, 125207753Smm _("Internal error (bug)")); 126207753Smm exit(EXIT_FAILURE); 127207753Smm } 128207753Smm 129207753Smm // Uncompressed size 130207753Smm uint64_t uncompressed_size = 0; 131207753Smm for (size_t i = 0; i < 8; ++i) 132207753Smm uncompressed_size |= (uint64_t)(buf[5 + i]) << (i * 8); 133207753Smm 134207753Smm // Display the results. We don't want to translate these and also 135207753Smm // will use MB instead of MiB, because someone could be parsing 136207753Smm // this output and we don't want to break that when people move 137207753Smm // from LZMA Utils to XZ Utils. 138207753Smm if (f != stdin) 139207753Smm printf("%s\n", name); 140207753Smm 141207753Smm printf("Uncompressed size: "); 142207753Smm if (uncompressed_size == UINT64_MAX) 143207753Smm printf("Unknown"); 144207753Smm else 145207753Smm printf("%" PRIu64 " MB (%" PRIu64 " bytes)", 146207753Smm (uncompressed_size + 512 * 1024) 147207753Smm / (1024 * 1024), 148207753Smm uncompressed_size); 149207753Smm 150207753Smm lzma_options_lzma *opt = filter.options; 151207753Smm 152207753Smm printf("\nDictionary size: " 153207753Smm "%u MB (2^%u bytes)\n" 154207753Smm "Literal context bits (lc): %" PRIu32 "\n" 155207753Smm "Literal pos bits (lp): %" PRIu32 "\n" 156207753Smm "Number of pos bits (pb): %" PRIu32 "\n", 157207753Smm (opt->dict_size + 512 * 1024) / (1024 * 1024), 158207753Smm my_log2(opt->dict_size), opt->lc, opt->lp, opt->pb); 159207753Smm 160207753Smm free(opt); 161207753Smm 162207753Smm return false; 163207753Smm} 164207753Smm 165207753Smm 166207753Smmextern int 167207753Smmmain(int argc, char **argv) 168207753Smm{ 169207753Smm tuklib_progname_init(argv); 170207753Smm tuklib_gettext_init(PACKAGE, LOCALEDIR); 171207753Smm 172207753Smm parse_args(argc, argv); 173207753Smm 174207753Smm int ret = EXIT_SUCCESS; 175207753Smm 176207753Smm // We print empty lines around the output only when reading from 177207753Smm // files specified on the command line. This is due to how 178207753Smm // LZMA Utils did it. 179207753Smm if (optind == argc) { 180207753Smm if (lzmainfo("(stdin)", stdin)) 181207753Smm ret = EXIT_FAILURE; 182207753Smm } else { 183207753Smm printf("\n"); 184207753Smm 185207753Smm do { 186207753Smm if (strcmp(argv[optind], "-") == 0) { 187207753Smm if (lzmainfo("(stdin)", stdin)) 188207753Smm ret = EXIT_FAILURE; 189207753Smm } else { 190207753Smm FILE *f = fopen(argv[optind], "r"); 191207753Smm if (f == NULL) { 192207753Smm ret = EXIT_FAILURE; 193207753Smm fprintf(stderr, "%s: %s: %s\n", 194207753Smm progname, 195207753Smm argv[optind], 196207753Smm strerror(errno)); 197207753Smm continue; 198207753Smm } 199207753Smm 200207753Smm if (lzmainfo(argv[optind], f)) 201207753Smm ret = EXIT_FAILURE; 202207753Smm 203207753Smm printf("\n"); 204207753Smm fclose(f); 205207753Smm } 206207753Smm } while (++optind < argc); 207207753Smm } 208207753Smm 209207753Smm tuklib_exit(ret, EXIT_FAILURE, true); 210207753Smm} 211