| /* |
| * Simple XZ decoder command line tool |
| * |
| * Author: Lasse Collin <[email protected]> |
| * |
| * This file has been put into the public domain. |
| * You can do whatever you want with this file. |
| */ |
| |
| /* |
| * This is really limited: Not all filters from .xz format are supported, |
| * only CRC32 is supported as the integrity check, and decoding of |
| * concatenated .xz streams is not supported. Thus, you may want to look |
| * at xzdec from XZ Utils if a few KiB bigger tool is not a problem. |
| */ |
| |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "xz.h" |
| |
| static uint8_t in[BUFSIZ]; |
| static uint8_t out[BUFSIZ]; |
| |
| int main(int argc, char **argv) |
| { |
| struct xz_buf b; |
| struct xz_dec *s; |
| enum xz_ret ret; |
| const char *msg; |
| |
| if (argc >= 2 && strcmp(argv[1], "--help") == 0) { |
| fputs("Uncompress a .xz file from stdin to stdout.\n" |
| "Arguments other than `--help' are ignored.\n", |
| stdout); |
| return 0; |
| } |
| |
| xz_crc32_init(); |
| #ifdef XZ_USE_CRC64 |
| xz_crc64_init(); |
| #endif |
| |
| /* |
| * Support up to 64 MiB dictionary. The actually needed memory |
| * is allocated once the headers have been parsed. |
| */ |
| s = xz_dec_init(XZ_DYNALLOC, 1 << 26); |
| if (s == NULL) { |
| msg = "Memory allocation failed\n"; |
| goto error; |
| } |
| |
| b.in = in; |
| b.in_pos = 0; |
| b.in_size = 0; |
| b.out = out; |
| b.out_pos = 0; |
| b.out_size = BUFSIZ; |
| |
| while (true) { |
| if (b.in_pos == b.in_size) { |
| b.in_size = fread(in, 1, sizeof(in), stdin); |
| b.in_pos = 0; |
| } |
| |
| ret = xz_dec_run(s, &b); |
| |
| if (b.out_pos == sizeof(out)) { |
| if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) { |
| msg = "Write error\n"; |
| goto error; |
| } |
| |
| b.out_pos = 0; |
| } |
| |
| if (ret == XZ_OK) |
| continue; |
| |
| #ifdef XZ_DEC_ANY_CHECK |
| if (ret == XZ_UNSUPPORTED_CHECK) { |
| fputs(argv[0], stderr); |
| fputs(": ", stderr); |
| fputs("Unsupported check; not verifying " |
| "file integrity\n", stderr); |
| continue; |
| } |
| #endif |
| |
| if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos |
| || fclose(stdout)) { |
| msg = "Write error\n"; |
| goto error; |
| } |
| |
| switch (ret) { |
| case XZ_STREAM_END: |
| xz_dec_end(s); |
| return 0; |
| |
| case XZ_MEM_ERROR: |
| msg = "Memory allocation failed\n"; |
| goto error; |
| |
| case XZ_MEMLIMIT_ERROR: |
| msg = "Memory usage limit reached\n"; |
| goto error; |
| |
| case XZ_FORMAT_ERROR: |
| msg = "Not a .xz file\n"; |
| goto error; |
| |
| case XZ_OPTIONS_ERROR: |
| msg = "Unsupported options in the .xz headers\n"; |
| goto error; |
| |
| case XZ_DATA_ERROR: |
| case XZ_BUF_ERROR: |
| msg = "File is corrupt\n"; |
| goto error; |
| |
| default: |
| msg = "Bug!\n"; |
| goto error; |
| } |
| } |
| |
| error: |
| xz_dec_end(s); |
| fputs(argv[0], stderr); |
| fputs(": ", stderr); |
| fputs(msg, stderr); |
| return 1; |
| } |