1 /* 2 * Simple XZ decoder command line tool 3 * 4 * Author: Lasse Collin <lasse.collin@tukaani.org> 5 * 6 * This file has been put into the public domain. 7 * You can do whatever you want with this file. 8 */ 9 10 /* 11 * This is really limited: Not all filters from .xz format are supported, 12 * only CRC32 is supported as the integrity check, and decoding of 13 * concatenated .xz streams is not supported. Thus, you may want to look 14 * at xzdec from XZ Utils if a few KiB bigger tool is not a problem. 15 */ 16 17 #include <stdbool.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include "xz.h" 21 22 static uint8_t in[BUFSIZ]; 23 static uint8_t out[BUFSIZ]; 24 25 int main(int argc, char **argv) 26 { 27 struct xz_buf b; 28 struct xz_dec *s; 29 enum xz_ret ret; 30 const char *msg; 31 32 if (argc >= 2 && strcmp(argv[1], "--help") == 0) { 33 fputs("Uncompress a .xz file from stdin to stdout.\n" 34 "Arguments other than `--help' are ignored.\n", 35 stdout); 36 return 0; 37 } 38 39 xz_crc32_init(); 40 #ifdef XZ_USE_CRC64 41 xz_crc64_init(); 42 #endif 43 44 /* 45 * Support up to 64 MiB dictionary. The actually needed memory 46 * is allocated once the headers have been parsed. 47 */ 48 s = xz_dec_init(XZ_DYNALLOC, 1 << 26); 49 if (s == NULL) { 50 msg = "Memory allocation failed\n"; 51 goto error; 52 } 53 54 b.in = in; 55 b.in_pos = 0; 56 b.in_size = 0; 57 b.out = out; 58 b.out_pos = 0; 59 b.out_size = BUFSIZ; 60 61 while (true) { 62 if (b.in_pos == b.in_size) { 63 b.in_size = fread(in, 1, sizeof(in), stdin); 64 65 if (ferror(stdin)) { 66 msg = "Read error\n"; 67 goto error; 68 } 69 70 b.in_pos = 0; 71 } 72 73 /* 74 * There are a few ways to set the "finish" (the third) 75 * argument. We could use feof(stdin) but testing in_size 76 * is fine too and may also work in applications that don't 77 * use FILEs. 78 */ 79 ret = xz_dec_catrun(s, &b, b.in_size == 0); 80 81 if (b.out_pos == sizeof(out)) { 82 if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) { 83 msg = "Write error\n"; 84 goto error; 85 } 86 87 b.out_pos = 0; 88 } 89 90 if (ret == XZ_OK) 91 continue; 92 93 #ifdef XZ_DEC_ANY_CHECK 94 if (ret == XZ_UNSUPPORTED_CHECK) { 95 fputs(argv[0], stderr); 96 fputs(": ", stderr); 97 fputs("Unsupported check; not verifying " 98 "file integrity\n", stderr); 99 continue; 100 } 101 #endif 102 103 if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos 104 || fclose(stdout)) { 105 msg = "Write error\n"; 106 goto error; 107 } 108 109 switch (ret) { 110 case XZ_STREAM_END: 111 xz_dec_end(s); 112 return 0; 113 114 case XZ_MEM_ERROR: 115 msg = "Memory allocation failed\n"; 116 goto error; 117 118 case XZ_MEMLIMIT_ERROR: 119 msg = "Memory usage limit reached\n"; 120 goto error; 121 122 case XZ_FORMAT_ERROR: 123 msg = "Not a .xz file\n"; 124 goto error; 125 126 case XZ_OPTIONS_ERROR: 127 msg = "Unsupported options in the .xz headers\n"; 128 goto error; 129 130 case XZ_DATA_ERROR: 131 case XZ_BUF_ERROR: 132 msg = "File is corrupt\n"; 133 goto error; 134 135 default: 136 msg = "Bug!\n"; 137 goto error; 138 } 139 } 140 141 error: 142 xz_dec_end(s); 143 fputs(argv[0], stderr); 144 fputs(": ", stderr); 145 fputs(msg, stderr); 146 return 1; 147 } 148