xref: /minix3/external/public-domain/xz/dist/doc/examples_old/xz_pipe_decomp.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*
2*0a6a1f1dSLionel Sambuc  * xz_pipe_decomp.c
3*0a6a1f1dSLionel Sambuc  * A simple example of pipe-only xz decompressor implementation.
4*0a6a1f1dSLionel Sambuc  * version: 2012-06-14 - by Daniel Mealha Cabrita
5*0a6a1f1dSLionel Sambuc  * Not copyrighted -- provided to the public domain.
6*0a6a1f1dSLionel Sambuc  *
7*0a6a1f1dSLionel Sambuc  * Compiling:
8*0a6a1f1dSLionel Sambuc  * Link with liblzma. GCC example:
9*0a6a1f1dSLionel Sambuc  * $ gcc -llzma xz_pipe_decomp.c -o xz_pipe_decomp
10*0a6a1f1dSLionel Sambuc  *
11*0a6a1f1dSLionel Sambuc  * Usage example:
12*0a6a1f1dSLionel Sambuc  * $ cat some_file.xz | ./xz_pipe_decomp > some_file
13*0a6a1f1dSLionel Sambuc  */
14*0a6a1f1dSLionel Sambuc 
15*0a6a1f1dSLionel Sambuc #include <stdio.h>
16*0a6a1f1dSLionel Sambuc #include <stdint.h>
17*0a6a1f1dSLionel Sambuc #include <inttypes.h>
18*0a6a1f1dSLionel Sambuc #include <stdbool.h>
19*0a6a1f1dSLionel Sambuc #include <lzma.h>
20*0a6a1f1dSLionel Sambuc 
21*0a6a1f1dSLionel Sambuc 
22*0a6a1f1dSLionel Sambuc /* read/write buffer sizes */
23*0a6a1f1dSLionel Sambuc #define IN_BUF_MAX	4096
24*0a6a1f1dSLionel Sambuc #define OUT_BUF_MAX	4096
25*0a6a1f1dSLionel Sambuc 
26*0a6a1f1dSLionel Sambuc /* error codes */
27*0a6a1f1dSLionel Sambuc #define RET_OK			0
28*0a6a1f1dSLionel Sambuc #define RET_ERROR_INIT		1
29*0a6a1f1dSLionel Sambuc #define RET_ERROR_INPUT		2
30*0a6a1f1dSLionel Sambuc #define RET_ERROR_OUTPUT	3
31*0a6a1f1dSLionel Sambuc #define RET_ERROR_DECOMPRESSION	4
32*0a6a1f1dSLionel Sambuc 
33*0a6a1f1dSLionel Sambuc 
34*0a6a1f1dSLionel Sambuc /* note: in_file and out_file must be open already */
xz_decompress(FILE * in_file,FILE * out_file)35*0a6a1f1dSLionel Sambuc int xz_decompress (FILE *in_file, FILE *out_file)
36*0a6a1f1dSLionel Sambuc {
37*0a6a1f1dSLionel Sambuc 	lzma_stream strm = LZMA_STREAM_INIT; /* alloc and init lzma_stream struct */
38*0a6a1f1dSLionel Sambuc 	const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED;
39*0a6a1f1dSLionel Sambuc 	const uint64_t memory_limit = UINT64_MAX; /* no memory limit */
40*0a6a1f1dSLionel Sambuc 	uint8_t in_buf [IN_BUF_MAX];
41*0a6a1f1dSLionel Sambuc 	uint8_t out_buf [OUT_BUF_MAX];
42*0a6a1f1dSLionel Sambuc 	size_t in_len;	/* length of useful data in in_buf */
43*0a6a1f1dSLionel Sambuc 	size_t out_len;	/* length of useful data in out_buf */
44*0a6a1f1dSLionel Sambuc 	bool in_finished = false;
45*0a6a1f1dSLionel Sambuc 	bool out_finished = false;
46*0a6a1f1dSLionel Sambuc 	lzma_action action;
47*0a6a1f1dSLionel Sambuc 	lzma_ret ret_xz;
48*0a6a1f1dSLionel Sambuc 	int ret;
49*0a6a1f1dSLionel Sambuc 
50*0a6a1f1dSLionel Sambuc 	ret = RET_OK;
51*0a6a1f1dSLionel Sambuc 
52*0a6a1f1dSLionel Sambuc 	/* initialize xz decoder */
53*0a6a1f1dSLionel Sambuc 	ret_xz = lzma_stream_decoder (&strm, memory_limit, flags);
54*0a6a1f1dSLionel Sambuc 	if (ret_xz != LZMA_OK) {
55*0a6a1f1dSLionel Sambuc 		fprintf (stderr, "lzma_stream_decoder error: %d\n", (int) ret_xz);
56*0a6a1f1dSLionel Sambuc 		return RET_ERROR_INIT;
57*0a6a1f1dSLionel Sambuc 	}
58*0a6a1f1dSLionel Sambuc 
59*0a6a1f1dSLionel Sambuc 	while ((! in_finished) && (! out_finished)) {
60*0a6a1f1dSLionel Sambuc 		/* read incoming data */
61*0a6a1f1dSLionel Sambuc 		in_len = fread (in_buf, 1, IN_BUF_MAX, in_file);
62*0a6a1f1dSLionel Sambuc 
63*0a6a1f1dSLionel Sambuc 		if (feof (in_file)) {
64*0a6a1f1dSLionel Sambuc 			in_finished = true;
65*0a6a1f1dSLionel Sambuc 		}
66*0a6a1f1dSLionel Sambuc 		if (ferror (in_file)) {
67*0a6a1f1dSLionel Sambuc 			in_finished = true;
68*0a6a1f1dSLionel Sambuc 			ret = RET_ERROR_INPUT;
69*0a6a1f1dSLionel Sambuc 		}
70*0a6a1f1dSLionel Sambuc 
71*0a6a1f1dSLionel Sambuc 		strm.next_in = in_buf;
72*0a6a1f1dSLionel Sambuc 		strm.avail_in = in_len;
73*0a6a1f1dSLionel Sambuc 
74*0a6a1f1dSLionel Sambuc 		/* if no more data from in_buf, flushes the
75*0a6a1f1dSLionel Sambuc 		   internal xz buffers and closes the decompressed data
76*0a6a1f1dSLionel Sambuc 		   with LZMA_FINISH */
77*0a6a1f1dSLionel Sambuc 		action = in_finished ? LZMA_FINISH : LZMA_RUN;
78*0a6a1f1dSLionel Sambuc 
79*0a6a1f1dSLionel Sambuc 		/* loop until there's no pending decompressed output */
80*0a6a1f1dSLionel Sambuc 		do {
81*0a6a1f1dSLionel Sambuc 			/* out_buf is clean at this point */
82*0a6a1f1dSLionel Sambuc 			strm.next_out = out_buf;
83*0a6a1f1dSLionel Sambuc 			strm.avail_out = OUT_BUF_MAX;
84*0a6a1f1dSLionel Sambuc 
85*0a6a1f1dSLionel Sambuc 			/* decompress data */
86*0a6a1f1dSLionel Sambuc 			ret_xz = lzma_code (&strm, action);
87*0a6a1f1dSLionel Sambuc 
88*0a6a1f1dSLionel Sambuc 			if ((ret_xz != LZMA_OK) && (ret_xz != LZMA_STREAM_END)) {
89*0a6a1f1dSLionel Sambuc 				fprintf (stderr, "lzma_code error: %d\n", (int) ret_xz);
90*0a6a1f1dSLionel Sambuc 				out_finished = true;
91*0a6a1f1dSLionel Sambuc 				ret = RET_ERROR_DECOMPRESSION;
92*0a6a1f1dSLionel Sambuc 			} else {
93*0a6a1f1dSLionel Sambuc 				/* write decompressed data */
94*0a6a1f1dSLionel Sambuc 				out_len = OUT_BUF_MAX - strm.avail_out;
95*0a6a1f1dSLionel Sambuc 				fwrite (out_buf, 1, out_len, out_file);
96*0a6a1f1dSLionel Sambuc 				if (ferror (out_file)) {
97*0a6a1f1dSLionel Sambuc 					out_finished = true;
98*0a6a1f1dSLionel Sambuc 					ret = RET_ERROR_OUTPUT;
99*0a6a1f1dSLionel Sambuc 				}
100*0a6a1f1dSLionel Sambuc 			}
101*0a6a1f1dSLionel Sambuc 		} while (strm.avail_out == 0);
102*0a6a1f1dSLionel Sambuc 	}
103*0a6a1f1dSLionel Sambuc 
104*0a6a1f1dSLionel Sambuc 	/* Bug fix (2012-06-14): If no errors were detected, check
105*0a6a1f1dSLionel Sambuc 	   that the last lzma_code() call returned LZMA_STREAM_END.
106*0a6a1f1dSLionel Sambuc 	   If not, the file is probably truncated. */
107*0a6a1f1dSLionel Sambuc 	if ((ret == RET_OK) && (ret_xz != LZMA_STREAM_END)) {
108*0a6a1f1dSLionel Sambuc 		fprintf (stderr, "Input truncated or corrupt\n");
109*0a6a1f1dSLionel Sambuc 		ret = RET_ERROR_DECOMPRESSION;
110*0a6a1f1dSLionel Sambuc 	}
111*0a6a1f1dSLionel Sambuc 
112*0a6a1f1dSLionel Sambuc 	lzma_end (&strm);
113*0a6a1f1dSLionel Sambuc 	return ret;
114*0a6a1f1dSLionel Sambuc }
115*0a6a1f1dSLionel Sambuc 
main()116*0a6a1f1dSLionel Sambuc int main ()
117*0a6a1f1dSLionel Sambuc {
118*0a6a1f1dSLionel Sambuc 	int ret;
119*0a6a1f1dSLionel Sambuc 
120*0a6a1f1dSLionel Sambuc 	ret = xz_decompress (stdin, stdout);
121*0a6a1f1dSLionel Sambuc 	return ret;
122*0a6a1f1dSLionel Sambuc }
123*0a6a1f1dSLionel Sambuc 
124