1 /*
2  * Lazy test for the case when the output size is known
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 #include <stdbool.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include "xz.h"
15 
16 static uint8_t in[1];
17 static uint8_t out[BUFSIZ];
18 
19 int main(int argc, char **argv)
20 {
21 	struct xz_buf b;
22 	struct xz_dec *s;
23 	enum xz_ret ret;
24 	const char *msg;
25 	size_t uncomp_size;
26 
27 	if (argc != 2) {
28 		fputs("Give uncompressed size as the argument", stderr);
29 		return 1;
30 	}
31 
32 	uncomp_size = atoi(argv[1]);
33 
34 	xz_crc32_init();
35 
36 	/*
37 	 * Support up to 64 MiB dictionary. The actually needed memory
38 	 * is allocated once the headers have been parsed.
39 	 */
40 	s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
41 	if (s == NULL) {
42 		msg = "Memory allocation failed\n";
43 		goto error;
44 	}
45 
46 	b.in = in;
47 	b.in_pos = 0;
48 	b.in_size = 0;
49 	b.out = out;
50 	b.out_pos = 0;
51 	b.out_size = uncomp_size < BUFSIZ ? uncomp_size : BUFSIZ;
52 
53 	while (true) {
54 		if (b.in_pos == b.in_size) {
55 			b.in_size = fread(in, 1, sizeof(in), stdin);
56 			b.in_pos = 0;
57 		}
58 
59 		ret = xz_dec_run(s, &b);
60 
61 		if (b.out_pos == sizeof(out)) {
62 			if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
63 				msg = "Write error\n";
64 				goto error;
65 			}
66 
67 			uncomp_size -= b.out_pos;
68 			b.out_pos = 0;
69 			b.out_size = uncomp_size < BUFSIZ
70 					? uncomp_size : BUFSIZ;
71 		}
72 
73 		if (ret == XZ_OK)
74 			continue;
75 
76 #ifdef XZ_DEC_ANY_CHECK
77 		if (ret == XZ_UNSUPPORTED_CHECK) {
78 			fputs(argv[0], stderr);
79 			fputs(": ", stderr);
80 			fputs("Unsupported check; not verifying "
81 					"file integrity\n", stderr);
82 			continue;
83 		}
84 #endif
85 
86 		if (uncomp_size != b.out_pos) {
87 			msg = "Uncompressed size doesn't match\n";
88 			goto error;
89 		}
90 
91 		if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
92 				|| fclose(stdout)) {
93 			msg = "Write error\n";
94 			goto error;
95 		}
96 
97 		switch (ret) {
98 		case XZ_STREAM_END:
99 			xz_dec_end(s);
100 			return 0;
101 
102 		case XZ_MEM_ERROR:
103 			msg = "Memory allocation failed\n";
104 			goto error;
105 
106 		case XZ_MEMLIMIT_ERROR:
107 			msg = "Memory usage limit reached\n";
108 			goto error;
109 
110 		case XZ_FORMAT_ERROR:
111 			msg = "Not a .xz file\n";
112 			goto error;
113 
114 		case XZ_OPTIONS_ERROR:
115 			msg = "Unsupported options in the .xz headers\n";
116 			goto error;
117 
118 		case XZ_DATA_ERROR:
119 		case XZ_BUF_ERROR:
120 			msg = "File is corrupt\n";
121 			goto error;
122 
123 		default:
124 			msg = "Bug!\n";
125 			goto error;
126 		}
127 	}
128 
129 error:
130 	xz_dec_end(s);
131 	fputs(argv[0], stderr);
132 	fputs(": ", stderr);
133 	fputs(msg, stderr);
134 	return 1;
135 }
136