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