1229159Sadrian/*
2229159Sadrian * Simple XZ decoder command line tool
3229159Sadrian *
4229159Sadrian * Author: Lasse Collin <lasse.collin@tukaani.org>
5229159Sadrian *
6229159Sadrian * This file has been put into the public domain.
7229159Sadrian * You can do whatever you want with this file.
8229159Sadrian */
9229159Sadrian
10229159Sadrian/*
11229159Sadrian * This is really limited: Not all filters from .xz format are supported,
12229159Sadrian * only CRC32 is supported as the integrity check, and decoding of
13229159Sadrian * concatenated .xz streams is not supported. Thus, you may want to look
14229159Sadrian * at xzdec from XZ Utils if a few KiB bigger tool is not a problem.
15229159Sadrian */
16229159Sadrian
17229159Sadrian#include <stdbool.h>
18229159Sadrian#include <stdio.h>
19229159Sadrian#include <string.h>
20229159Sadrian#include "xz.h"
21229159Sadrian
22229159Sadrianstatic uint8_t in[BUFSIZ];
23229159Sadrianstatic uint8_t out[BUFSIZ];
24229159Sadrian
25229159Sadrianint main(int argc, char **argv)
26229159Sadrian{
27229159Sadrian	struct xz_buf b;
28229159Sadrian	struct xz_dec *s;
29229159Sadrian	enum xz_ret ret;
30229159Sadrian	const char *msg;
31229159Sadrian
32229159Sadrian	if (argc >= 2 && strcmp(argv[1], "--help") == 0) {
33229159Sadrian		fputs("Uncompress a .xz file from stdin to stdout.\n"
34229159Sadrian				"Arguments other than `--help' are ignored.\n",
35229159Sadrian				stdout);
36229159Sadrian		return 0;
37229159Sadrian	}
38229159Sadrian
39229159Sadrian	xz_crc32_init();
40262764Sdelphij#ifdef XZ_USE_CRC64
41262764Sdelphij	xz_crc64_init();
42262764Sdelphij#endif
43229159Sadrian
44229159Sadrian	/*
45229159Sadrian	 * Support up to 64 MiB dictionary. The actually needed memory
46229159Sadrian	 * is allocated once the headers have been parsed.
47229159Sadrian	 */
48229159Sadrian	s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
49229159Sadrian	if (s == NULL) {
50229159Sadrian		msg = "Memory allocation failed\n";
51229159Sadrian		goto error;
52229159Sadrian	}
53229159Sadrian
54229159Sadrian	b.in = in;
55229159Sadrian	b.in_pos = 0;
56229159Sadrian	b.in_size = 0;
57229159Sadrian	b.out = out;
58229159Sadrian	b.out_pos = 0;
59229159Sadrian	b.out_size = BUFSIZ;
60229159Sadrian
61229159Sadrian	while (true) {
62229159Sadrian		if (b.in_pos == b.in_size) {
63229159Sadrian			b.in_size = fread(in, 1, sizeof(in), stdin);
64229159Sadrian			b.in_pos = 0;
65229159Sadrian		}
66229159Sadrian
67229159Sadrian		ret = xz_dec_run(s, &b);
68229159Sadrian
69229159Sadrian		if (b.out_pos == sizeof(out)) {
70229159Sadrian			if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
71229159Sadrian				msg = "Write error\n";
72229159Sadrian				goto error;
73229159Sadrian			}
74229159Sadrian
75229159Sadrian			b.out_pos = 0;
76229159Sadrian		}
77229159Sadrian
78229159Sadrian		if (ret == XZ_OK)
79229159Sadrian			continue;
80229159Sadrian
81229159Sadrian#ifdef XZ_DEC_ANY_CHECK
82229159Sadrian		if (ret == XZ_UNSUPPORTED_CHECK) {
83229159Sadrian			fputs(argv[0], stderr);
84229159Sadrian			fputs(": ", stderr);
85229159Sadrian			fputs("Unsupported check; not verifying "
86229159Sadrian					"file integrity\n", stderr);
87229159Sadrian			continue;
88229159Sadrian		}
89229159Sadrian#endif
90229159Sadrian
91229159Sadrian		if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
92229159Sadrian				|| fclose(stdout)) {
93229159Sadrian			msg = "Write error\n";
94229159Sadrian			goto error;
95229159Sadrian		}
96229159Sadrian
97229159Sadrian		switch (ret) {
98229159Sadrian		case XZ_STREAM_END:
99229159Sadrian			xz_dec_end(s);
100229159Sadrian			return 0;
101229159Sadrian
102229159Sadrian		case XZ_MEM_ERROR:
103229159Sadrian			msg = "Memory allocation failed\n";
104229159Sadrian			goto error;
105229159Sadrian
106229159Sadrian		case XZ_MEMLIMIT_ERROR:
107229159Sadrian			msg = "Memory usage limit reached\n";
108229159Sadrian			goto error;
109229159Sadrian
110229159Sadrian		case XZ_FORMAT_ERROR:
111229159Sadrian			msg = "Not a .xz file\n";
112229159Sadrian			goto error;
113229159Sadrian
114229159Sadrian		case XZ_OPTIONS_ERROR:
115229159Sadrian			msg = "Unsupported options in the .xz headers\n";
116229159Sadrian			goto error;
117229159Sadrian
118229159Sadrian		case XZ_DATA_ERROR:
119229159Sadrian		case XZ_BUF_ERROR:
120229159Sadrian			msg = "File is corrupt\n";
121229159Sadrian			goto error;
122229159Sadrian
123229159Sadrian		default:
124229159Sadrian			msg = "Bug!\n";
125229159Sadrian			goto error;
126229159Sadrian		}
127229159Sadrian	}
128229159Sadrian
129229159Sadrianerror:
130229159Sadrian	xz_dec_end(s);
131229159Sadrian	fputs(argv[0], stderr);
132229159Sadrian	fputs(": ", stderr);
133229159Sadrian	fputs(msg, stderr);
134229159Sadrian	return 1;
135229159Sadrian}
136