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();
40229159Sadrian
41229159Sadrian	/*
42229159Sadrian	 * Support up to 64 MiB dictionary. The actually needed memory
43229159Sadrian	 * is allocated once the headers have been parsed.
44229159Sadrian	 */
45229159Sadrian	s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
46229159Sadrian	if (s == NULL) {
47229159Sadrian		msg = "Memory allocation failed\n";
48229159Sadrian		goto error;
49229159Sadrian	}
50229159Sadrian
51229159Sadrian	b.in = in;
52229159Sadrian	b.in_pos = 0;
53229159Sadrian	b.in_size = 0;
54229159Sadrian	b.out = out;
55229159Sadrian	b.out_pos = 0;
56229159Sadrian	b.out_size = BUFSIZ;
57229159Sadrian
58229159Sadrian	while (true) {
59229159Sadrian		if (b.in_pos == b.in_size) {
60229159Sadrian			b.in_size = fread(in, 1, sizeof(in), stdin);
61229159Sadrian			b.in_pos = 0;
62229159Sadrian		}
63229159Sadrian
64229159Sadrian		ret = xz_dec_run(s, &b);
65229159Sadrian
66229159Sadrian		if (b.out_pos == sizeof(out)) {
67229159Sadrian			if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
68229159Sadrian				msg = "Write error\n";
69229159Sadrian				goto error;
70229159Sadrian			}
71229159Sadrian
72229159Sadrian			b.out_pos = 0;
73229159Sadrian		}
74229159Sadrian
75229159Sadrian		if (ret == XZ_OK)
76229159Sadrian			continue;
77229159Sadrian
78229159Sadrian#ifdef XZ_DEC_ANY_CHECK
79229159Sadrian		if (ret == XZ_UNSUPPORTED_CHECK) {
80229159Sadrian			fputs(argv[0], stderr);
81229159Sadrian			fputs(": ", stderr);
82229159Sadrian			fputs("Unsupported check; not verifying "
83229159Sadrian					"file integrity\n", stderr);
84229159Sadrian			continue;
85229159Sadrian		}
86229159Sadrian#endif
87229159Sadrian
88229159Sadrian		if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
89229159Sadrian				|| fclose(stdout)) {
90229159Sadrian			msg = "Write error\n";
91229159Sadrian			goto error;
92229159Sadrian		}
93229159Sadrian
94229159Sadrian		switch (ret) {
95229159Sadrian		case XZ_STREAM_END:
96229159Sadrian			xz_dec_end(s);
97229159Sadrian			return 0;
98229159Sadrian
99229159Sadrian		case XZ_MEM_ERROR:
100229159Sadrian			msg = "Memory allocation failed\n";
101229159Sadrian			goto error;
102229159Sadrian
103229159Sadrian		case XZ_MEMLIMIT_ERROR:
104229159Sadrian			msg = "Memory usage limit reached\n";
105229159Sadrian			goto error;
106229159Sadrian
107229159Sadrian		case XZ_FORMAT_ERROR:
108229159Sadrian			msg = "Not a .xz file\n";
109229159Sadrian			goto error;
110229159Sadrian
111229159Sadrian		case XZ_OPTIONS_ERROR:
112229159Sadrian			msg = "Unsupported options in the .xz headers\n";
113229159Sadrian			goto error;
114229159Sadrian
115229159Sadrian		case XZ_DATA_ERROR:
116229159Sadrian		case XZ_BUF_ERROR:
117229159Sadrian			msg = "File is corrupt\n";
118229159Sadrian			goto error;
119229159Sadrian
120229159Sadrian		default:
121229159Sadrian			msg = "Bug!\n";
122229159Sadrian			goto error;
123229159Sadrian		}
124229159Sadrian	}
125229159Sadrian
126229159Sadrianerror:
127229159Sadrian	xz_dec_end(s);
128229159Sadrian	fputs(argv[0], stderr);
129229159Sadrian	fputs(": ", stderr);
130229159Sadrian	fputs(msg, stderr);
131229159Sadrian	return 1;
132229159Sadrian}
133