1 | #include "wandio.h" |
---|
2 | #include <bzlib.h> |
---|
3 | #include <sys/types.h> |
---|
4 | #include <sys/stat.h> |
---|
5 | #include <fcntl.h> |
---|
6 | #include <stdlib.h> |
---|
7 | #include <string.h> |
---|
8 | |
---|
9 | enum err_t { |
---|
10 | ERR_OK = 1, |
---|
11 | ERR_EOF = 0, |
---|
12 | ERR_ERROR = -1 |
---|
13 | }; |
---|
14 | |
---|
15 | struct bz_t { |
---|
16 | bz_stream strm; |
---|
17 | char inbuff[1024*1024]; |
---|
18 | int outoffset; |
---|
19 | io_t *parent; |
---|
20 | enum err_t err; |
---|
21 | }; |
---|
22 | |
---|
23 | |
---|
24 | extern io_source_t bz_source; |
---|
25 | |
---|
26 | #define DATA(io) ((struct bz_t *)((io)->data)) |
---|
27 | #define min(a,b) ((a)<(b) ? (a) : (b)) |
---|
28 | |
---|
29 | io_t *bz_open(io_t *parent) |
---|
30 | { |
---|
31 | io_t *io; |
---|
32 | if (!parent) |
---|
33 | return NULL; |
---|
34 | io = malloc(sizeof(io_t)); |
---|
35 | io->source = &bz_source; |
---|
36 | io->data = malloc(sizeof(struct bz_t)); |
---|
37 | |
---|
38 | DATA(io)->parent = parent; |
---|
39 | |
---|
40 | DATA(io)->strm.next_in = NULL; |
---|
41 | DATA(io)->strm.avail_in = 0; |
---|
42 | DATA(io)->strm.next_out = NULL; |
---|
43 | DATA(io)->strm.avail_out = 0; |
---|
44 | DATA(io)->strm.bzalloc = NULL; |
---|
45 | DATA(io)->strm.bzfree = NULL; |
---|
46 | DATA(io)->strm.opaque = NULL; |
---|
47 | DATA(io)->err = ERR_OK; |
---|
48 | |
---|
49 | BZ2_bzDecompressInit(&DATA(io)->strm, |
---|
50 | 0, /* Verbosity */ |
---|
51 | 0); /* small */ |
---|
52 | |
---|
53 | return io; |
---|
54 | } |
---|
55 | |
---|
56 | |
---|
57 | static off_t bz_read(io_t *io, char *buffer, off_t len) |
---|
58 | { |
---|
59 | if (DATA(io)->err == ERR_EOF) |
---|
60 | return 0; /* EOF */ |
---|
61 | if (DATA(io)->err == ERR_ERROR) |
---|
62 | return -1; /* ERROR! */ |
---|
63 | |
---|
64 | DATA(io)->strm.avail_out = len; |
---|
65 | DATA(io)->strm.next_out = buffer; |
---|
66 | |
---|
67 | while (DATA(io)->err == ERR_OK && DATA(io)->strm.avail_out > 0) { |
---|
68 | while (DATA(io)->strm.avail_in <= 0) { |
---|
69 | int bytes_read = wandio_read(DATA(io)->parent, |
---|
70 | DATA(io)->inbuff, |
---|
71 | sizeof(DATA(io)->inbuff)); |
---|
72 | if (bytes_read == 0) /* EOF */ |
---|
73 | return len-DATA(io)->strm.avail_out; |
---|
74 | if (bytes_read < 0) { /* Error */ |
---|
75 | DATA(io)->err = ERR_ERROR; |
---|
76 | /* Return how much data we managed to read ok */ |
---|
77 | if (DATA(io)->strm.avail_out != len) { |
---|
78 | return len-DATA(io)->strm.avail_out; |
---|
79 | } |
---|
80 | /* Now return error */ |
---|
81 | return -1; |
---|
82 | } |
---|
83 | DATA(io)->strm.next_in = DATA(io)->inbuff; |
---|
84 | DATA(io)->strm.avail_in = bytes_read; |
---|
85 | } |
---|
86 | /* Decompress some data into the output buffer */ |
---|
87 | int err=BZ2_bzDecompress(&DATA(io)->strm); |
---|
88 | switch(err) { |
---|
89 | case BZ_OK: |
---|
90 | DATA(io)->err = ERR_OK; |
---|
91 | break; |
---|
92 | case BZ_STREAM_END: |
---|
93 | DATA(io)->err = ERR_EOF; |
---|
94 | break; |
---|
95 | default: |
---|
96 | DATA(io)->err = ERR_ERROR; |
---|
97 | } |
---|
98 | } |
---|
99 | /* Return the number of bytes decompressed */ |
---|
100 | return len-DATA(io)->strm.avail_out; |
---|
101 | } |
---|
102 | |
---|
103 | static void bz_close(io_t *io) |
---|
104 | { |
---|
105 | BZ2_bzDecompressEnd(&DATA(io)->strm); |
---|
106 | wandio_destroy(DATA(io)->parent); |
---|
107 | free(io->data); |
---|
108 | free(io); |
---|
109 | } |
---|
110 | |
---|
111 | io_source_t bz_source = { |
---|
112 | "bzip", |
---|
113 | bz_read, |
---|
114 | NULL, /* peek */ |
---|
115 | NULL, /* tell */ |
---|
116 | NULL, /* seek */ |
---|
117 | bz_close |
---|
118 | }; |
---|
119 | |
---|