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