[POWERPC] bootwrapper: Make compression of the kernel image optional.
[linux-2.6] / arch / powerpc / boot / gunzip_util.c
1 /*
2  * Copyright 2007 David Gibson, IBM Corporation.
3  * Based on earlier work, Copyright (C) Paul Mackerras 1997.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version
8  * 2 of the License, or (at your option) any later version.
9  */
10
11 #include <stddef.h>
12 #include "string.h"
13 #include "stdio.h"
14 #include "ops.h"
15 #include "gunzip_util.h"
16
17 #define HEAD_CRC        2
18 #define EXTRA_FIELD     4
19 #define ORIG_NAME       8
20 #define COMMENT         0x10
21 #define RESERVED        0xe0
22
23 /**
24  * gunzip_start - prepare to decompress gzip data
25  * @state:     decompressor state structure to be initialized
26  * @src:       buffer containing gzip compressed or uncompressed data
27  * @srclen:    size in bytes of the buffer at src
28  *
29  * If the buffer at @src contains a gzip header, this function
30  * initializes zlib to decompress the data, storing the decompression
31  * state in @state.  The other functions in this file can then be used
32  * to decompress data from the gzipped stream.
33  *
34  * If the buffer at @src does not contain a gzip header, it is assumed
35  * to contain uncompressed data.  The buffer information is recorded
36  * in @state and the other functions in this file will simply copy
37  * data from the uncompressed data stream at @src.
38  *
39  * Any errors, such as bad compressed data, cause an error to be
40  * printed an the platform's exit() function to be called.
41  */
42 void gunzip_start(struct gunzip_state *state, void *src, int srclen)
43 {
44         char *hdr = src;
45         int hdrlen = 0;
46
47         memset(state, 0, sizeof(*state));
48
49         /* Check for gzip magic number */
50         if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
51                 /* gzip data, initialize zlib parameters */
52                 int r, flags;
53
54                 state->s.workspace = state->scratch;
55                 if (zlib_inflate_workspacesize() > sizeof(state->scratch)) {
56                         printf("insufficient scratch space for gunzip\n\r");
57                         exit();
58                 }
59
60                 /* skip header */
61                 hdrlen = 10;
62                 flags = hdr[3];
63                 if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
64                         printf("bad gzipped data\n\r");
65                         exit();
66                 }
67                 if ((flags & EXTRA_FIELD) != 0)
68                         hdrlen = 12 + hdr[10] + (hdr[11] << 8);
69                 if ((flags & ORIG_NAME) != 0)
70                         while (hdr[hdrlen++] != 0)
71                                 ;
72                 if ((flags & COMMENT) != 0)
73                         while (hdr[hdrlen++] != 0)
74                                 ;
75                 if ((flags & HEAD_CRC) != 0)
76                         hdrlen += 2;
77                 if (hdrlen >= srclen) {
78                         printf("gunzip_start: ran out of data in header\n\r");
79                         exit();
80                 }
81
82                 r = zlib_inflateInit2(&state->s, -MAX_WBITS);
83                 if (r != Z_OK) {
84                         printf("inflateInit2 returned %d\n\r", r);
85                         exit();
86                 }
87         }
88
89         state->s.next_in = src + hdrlen;
90         state->s.avail_in = srclen - hdrlen;
91 }
92
93 /**
94  * gunzip_partial - extract bytes from a gzip data stream
95  * @state:     gzip state structure previously initialized by gunzip_start()
96  * @dst:       buffer to store extracted data
97  * @dstlen:    maximum number of bytes to extract
98  *
99  * This function extracts at most @dstlen bytes from the data stream
100  * previously associated with @state by gunzip_start(), decompressing
101  * if necessary.  Exactly @dstlen bytes are extracted unless the data
102  * stream doesn't contain enough bytes, in which case the entire
103  * remainder of the stream is decompressed.
104  *
105  * Returns the actual number of bytes extracted.  If any errors occur,
106  * such as a corrupted compressed stream, an error is printed an the
107  * platform's exit() function is called.
108  */
109 int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
110 {
111         int len;
112
113         if (state->s.workspace) {
114                 /* gunzipping */
115                 int r;
116
117                 state->s.next_out = dst;
118                 state->s.avail_out = dstlen;
119                 r = zlib_inflate(&state->s, Z_FULL_FLUSH);
120                 if (r != Z_OK && r != Z_STREAM_END) {
121                         printf("inflate returned %d msg: %s\n\r", r, state->s.msg);
122                         exit();
123                 }
124                 len = state->s.next_out - (unsigned char *)dst;
125         } else {
126                 /* uncompressed image */
127                 len = min(state->s.avail_in, (unsigned)dstlen);
128                 memcpy(dst, state->s.next_in, len);
129                 state->s.next_in += len;
130                 state->s.avail_in -= len;
131         }
132         return len;
133 }
134
135 /**
136  * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
137  * @state:     gzip state structure previously initialized by gunzip_start()
138  * @dst:       buffer to store extracted data
139  * @dstlen:    number of bytes to extract
140  *
141  * This function extracts exactly @dstlen bytes from the data stream
142  * previously associated with @state by gunzip_start(), decompressing
143  * if necessary.
144  *
145  * If there are less @dstlen bytes available in the data stream, or if
146  * any other errors occur, such as a corrupted compressed stream, an
147  * error is printed an the platform's exit() function is called.
148  */
149 void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
150 {
151         int len;
152
153         len  = gunzip_partial(state, dst, dstlen);
154         if (len < dstlen) {
155                 printf("gunzip_block: ran out of data\n\r");
156                 exit();
157         }
158 }
159
160 /**
161  * gunzip_discard - discard bytes from a gzip data stream
162  * @state:     gzip state structure previously initialized by gunzip_start()
163  * @len:       number of bytes to discard
164  *
165  * This function extracts, then discards exactly @len bytes from the
166  * data stream previously associated with @state by gunzip_start().
167  * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
168  * calls will extract the data following the discarded bytes in the
169  * data stream.
170  *
171  * If there are less @len bytes available in the data stream, or if
172  * any other errors occur, such as a corrupted compressed stream, an
173  * error is printed an the platform's exit() function is called.
174  */
175 void gunzip_discard(struct gunzip_state *state, int len)
176 {
177         static char discard_buf[128];
178
179         while (len > sizeof(discard_buf)) {
180                 gunzip_exactly(state, discard_buf, sizeof(discard_buf));
181                 len -= sizeof(discard_buf);
182         }
183
184         if (len > 0)
185                 gunzip_exactly(state, discard_buf, len);
186 }
187
188 /**
189  * gunzip_finish - extract all remaining bytes from a gzip data stream
190  * @state:     gzip state structure previously initialized by gunzip_start()
191  * @dst:       buffer to store extracted data
192  * @dstlen:    maximum number of bytes to extract
193  *
194  * This function extracts all remaining data, or at most @dstlen
195  * bytes, from the stream previously associated with @state by
196  * gunzip_start().  zlib is then shut down, so it is an error to use
197  * any of the functions in this file on @state until it is
198  * re-initialized with another call to gunzip_start().
199  *
200  * If any errors occur, such as a corrupted compressed stream, an
201  * error is printed an the platform's exit() function is called.
202  */
203 int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
204 {
205         int len;
206
207         if (state->s.workspace) {
208                 len = gunzip_partial(state, dst, dstlen);
209                 zlib_inflateEnd(&state->s);
210         } else {
211                 /* uncompressed image */
212                 len = min(state->s.avail_in, (unsigned)dstlen);
213                 memcpy(dst, state->s.next_in, len);
214         }
215
216         return len;
217 }