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
16static uint8_t in[1];
17static uint8_t out[BUFSIZ];
18
19int 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
129error:
130	xz_dec_end(s);
131	fputs(argv[0], stderr);
132	fputs(": ", stderr);
133	fputs(msg, stderr);
134	return 1;
135}
136