xref: /freebsd/sys/contrib/xz-embedded/userspace/xzminidec.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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 
41 	/*
42 	 * Support up to 64 MiB dictionary. The actually needed memory
43 	 * is allocated once the headers have been parsed.
44 	 */
45 	s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
46 	if (s == NULL) {
47 		msg = "Memory allocation failed\n";
48 		goto error;
49 	}
50 
51 	b.in = in;
52 	b.in_pos = 0;
53 	b.in_size = 0;
54 	b.out = out;
55 	b.out_pos = 0;
56 	b.out_size = BUFSIZ;
57 
58 	while (true) {
59 		if (b.in_pos == b.in_size) {
60 			b.in_size = fread(in, 1, sizeof(in), stdin);
61 			b.in_pos = 0;
62 		}
63 
64 		ret = xz_dec_run(s, &b);
65 
66 		if (b.out_pos == sizeof(out)) {
67 			if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
68 				msg = "Write error\n";
69 				goto error;
70 			}
71 
72 			b.out_pos = 0;
73 		}
74 
75 		if (ret == XZ_OK)
76 			continue;
77 
78 #ifdef XZ_DEC_ANY_CHECK
79 		if (ret == XZ_UNSUPPORTED_CHECK) {
80 			fputs(argv[0], stderr);
81 			fputs(": ", stderr);
82 			fputs("Unsupported check; not verifying "
83 					"file integrity\n", stderr);
84 			continue;
85 		}
86 #endif
87 
88 		if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
89 				|| fclose(stdout)) {
90 			msg = "Write error\n";
91 			goto error;
92 		}
93 
94 		switch (ret) {
95 		case XZ_STREAM_END:
96 			xz_dec_end(s);
97 			return 0;
98 
99 		case XZ_MEM_ERROR:
100 			msg = "Memory allocation failed\n";
101 			goto error;
102 
103 		case XZ_MEMLIMIT_ERROR:
104 			msg = "Memory usage limit reached\n";
105 			goto error;
106 
107 		case XZ_FORMAT_ERROR:
108 			msg = "Not a .xz file\n";
109 			goto error;
110 
111 		case XZ_OPTIONS_ERROR:
112 			msg = "Unsupported options in the .xz headers\n";
113 			goto error;
114 
115 		case XZ_DATA_ERROR:
116 		case XZ_BUF_ERROR:
117 			msg = "File is corrupt\n";
118 			goto error;
119 
120 		default:
121 			msg = "Bug!\n";
122 			goto error;
123 		}
124 	}
125 
126 error:
127 	xz_dec_end(s);
128 	fputs(argv[0], stderr);
129 	fputs(": ", stderr);
130 	fputs(msg, stderr);
131 	return 1;
132 }
133