bzip2/lzma: library support for gzip, bzip2 and lzma decompression
[safe/jmp/linux-2.6] / lib / decompress_inflate.c
1 #ifdef STATIC
2 /* Pre-boot environment: included */
3
4 /* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
5  * errors about console_printk etc... on ARM */
6 #define _LINUX_KERNEL_H
7
8 #include "zlib_inflate/inftrees.c"
9 #include "zlib_inflate/inffast.c"
10 #include "zlib_inflate/inflate.c"
11
12 #else /* STATIC */
13 /* initramfs et al: linked */
14
15 #include <linux/zutil.h>
16
17 #include "zlib_inflate/inftrees.h"
18 #include "zlib_inflate/inffast.h"
19 #include "zlib_inflate/inflate.h"
20
21 #include "zlib_inflate/infutil.h"
22
23 #endif /* STATIC */
24
25 #include <linux/decompress/mm.h>
26
27 #define INBUF_LEN (16*1024)
28
29 /* Included from initramfs et al code */
30 STATIC int INIT gunzip(unsigned char *buf, int len,
31                        int(*fill)(void*, unsigned int),
32                        int(*flush)(void*, unsigned int),
33                        unsigned char *out_buf,
34                        int *pos,
35                        void(*error_fn)(char *x)) {
36         u8 *zbuf;
37         struct z_stream_s *strm;
38         int rc;
39         size_t out_len;
40
41         set_error_fn(error_fn);
42         rc = -1;
43         if (flush) {
44                 out_len = 0x8100; /* 32 K */
45                 out_buf = malloc(out_len);
46         } else {
47                 out_len = 0x7fffffff; /* no limit */
48         }
49         if (!out_buf) {
50                 error("Out of memory while allocating output buffer");
51                 goto gunzip_nomem1;
52         }
53
54         if (buf)
55                 zbuf = buf;
56         else {
57                 zbuf = malloc(INBUF_LEN);
58                 len = 0;
59         }
60         if (!zbuf) {
61                 error("Out of memory while allocating input buffer");
62                 goto gunzip_nomem2;
63         }
64
65         strm = malloc(sizeof(*strm));
66         if (strm == NULL) {
67                 error("Out of memory while allocating z_stream");
68                 goto gunzip_nomem3;
69         }
70
71         strm->workspace = malloc(flush ? zlib_inflate_workspacesize() :
72                                  sizeof(struct inflate_state));
73         if (strm->workspace == NULL) {
74                 error("Out of memory while allocating workspace");
75                 goto gunzip_nomem4;
76         }
77
78         if (len == 0)
79                 len = fill(zbuf, INBUF_LEN);
80
81         /* verify the gzip header */
82         if (len < 10 ||
83            zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
84                 if (pos)
85                         *pos = 0;
86                 error("Not a gzip file");
87                 goto gunzip_5;
88         }
89
90         /* skip over gzip header (1f,8b,08... 10 bytes total +
91          * possible asciz filename)
92          */
93         strm->next_in = zbuf + 10;
94         /* skip over asciz filename */
95         if (zbuf[3] & 0x8) {
96                 while (strm->next_in[0])
97                         strm->next_in++;
98                 strm->next_in++;
99         }
100         strm->avail_in = len - 10;
101
102         strm->next_out = out_buf;
103         strm->avail_out = out_len;
104
105         rc = zlib_inflateInit2(strm, -MAX_WBITS);
106
107         if (!flush) {
108                 WS(strm)->inflate_state.wsize = 0;
109                 WS(strm)->inflate_state.window = NULL;
110         }
111
112         while (rc == Z_OK) {
113                 if (strm->avail_in == 0) {
114                         /* TODO: handle case where both pos and fill are set */
115                         len = fill(zbuf, INBUF_LEN);
116                         if (len < 0) {
117                                 rc = -1;
118                                 error("read error");
119                                 break;
120                         }
121                         strm->next_in = zbuf;
122                         strm->avail_in = len;
123                 }
124                 rc = zlib_inflate(strm, 0);
125
126                 /* Write any data generated */
127                 if (flush && strm->next_out > out_buf) {
128                         int l = strm->next_out - out_buf;
129                         if (l != flush(out_buf, l)) {
130                                 rc = -1;
131                                 error("write error");
132                                 break;
133                         }
134                         strm->next_out = out_buf;
135                         strm->avail_out = out_len;
136                 }
137
138                 /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
139                 if (rc == Z_STREAM_END) {
140                         rc = 0;
141                         break;
142                 } else if (rc != Z_OK) {
143                         error("uncompression error");
144                         rc = -1;
145                 }
146         }
147
148         zlib_inflateEnd(strm);
149         if (pos)
150                 /* add + 8 to skip over trailer */
151                 *pos = strm->next_in - zbuf+8;
152
153 gunzip_5:
154         free(strm->workspace);
155 gunzip_nomem4:
156         free(strm);
157 gunzip_nomem3:
158         if (!buf)
159                 free(zbuf);
160 gunzip_nomem2:
161         if (flush)
162                 free(out_buf);
163 gunzip_nomem1:
164         return rc; /* returns Z_OK (0) if successful */
165 }
166
167 #define decompress gunzip