1/* 2 * xz_pipe_decomp.c 3 * A simple example of pipe-only xz decompressor implementation. 4 * version: 2010-07-12 - 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 */ 35int 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 lzma_end (&strm); 105 return ret; 106} 107 108int main () 109{ 110 int ret; 111 112 ret = xz_decompress (stdin, stdout); 113 return ret; 114} 115 116