4 * This is a collection of several routines from gzip-1.0.3
7 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
8 * puts by Nick Holloway 1993, better puts by Martin Mares 1995
9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
11 * Adapted for MEMDISK by H. Peter Anvin, April 2003
25 #define memzero(s, n) memset ((s), 0, (n))
31 #define WSIZE 0x8000 /* Window size must be at least 32k, */
32 /* and a power of two */
34 static uch
*inbuf
; /* input pointer */
35 static uch window
[WSIZE
]; /* sliding output window buffer */
37 static unsigned insize
; /* total input bytes read */
38 static unsigned inbytes
; /* valid bytes in inbuf */
39 static unsigned outcnt
; /* bytes in output buffer */
42 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
43 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
44 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
45 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
46 #define COMMENT 0x10 /* bit 4 set: file comment present */
47 #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
48 #define RESERVED 0xC0 /* bit 6,7: reserved */
50 /* Diagnostic functions */
52 # define Assert(cond,msg) {if(!(cond)) error(msg);}
53 # define Trace(x) fprintf x
54 # define Tracev(x) {if (verbose) fprintf x ;}
55 # define Tracevv(x) {if (verbose>1) fprintf x ;}
56 # define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
57 # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
59 # define Assert(cond,msg)
67 static int fill_inbuf(void);
68 static void flush_window(void);
69 static void error(char *m
);
70 static void gzip_mark(void **);
71 static void gzip_release(void **);
73 static ulg crc_32_tab
[256];
75 /* Get byte from input buffer */
76 static inline uch
get_byte(void)
83 return fill_inbuf(); /* Input buffer underrun */
87 /* Unget byte from input buffer */
88 static inline void unget_byte(void)
94 static ulg bytes_out
= 0; /* Number of bytes output */
95 static uch
*output_data
; /* Output data pointer */
96 static ulg output_size
; /* Number of output bytes expected */
98 static void *malloc(int size
);
99 static void free(void *where
);
101 static ulg free_mem_ptr
, free_mem_end_ptr
;
105 static void *malloc(int size
)
109 if (size
< 0) error("malloc error");
111 free_mem_ptr
= (free_mem_ptr
+ 3) & ~3; /* Align */
113 p
= (void *)free_mem_ptr
;
114 free_mem_ptr
+= size
;
116 if (free_mem_ptr
>= free_mem_end_ptr
)
117 error("out of memory");
122 static void free(void *where
)
128 static void gzip_mark(void **ptr
)
130 *ptr
= (void *) free_mem_ptr
;
133 static void gzip_release(void **ptr
)
135 free_mem_ptr
= (long) *ptr
;
138 /* ===========================================================================
139 * Fill the input buffer. This is called only when the buffer is empty
140 * and at least one byte is really needed.
142 static int fill_inbuf(void)
144 /* This should never happen. We have already pointed the algorithm
145 to all the data we have. */
146 printf("failed\nDecompression error: ran out of input data\n");
150 /* ===========================================================================
151 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
152 * (Used for the decompressed data only.)
154 static void flush_window(void)
156 ulg c
= crc
; /* temporary variable */
160 if ( bytes_out
+outcnt
> output_size
)
161 error("output buffer overrun");
165 for (n
= 0; n
< outcnt
; n
++) {
167 c
= crc_32_tab
[(c
^ ch
) & 0xff] ^ (c
>> 8);
171 bytes_out
+= (ulg
)outcnt
;
175 static void error(char *x
)
177 printf("failed\nDecompression error: %s\n", x
);
189 } __attribute__ ((packed
));
190 /* (followed by optional and variable length "extra", "original name",
191 and "comment" fields) */
193 struct gzip_trailer
{
196 } __attribute__ ((packed
));
199 * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>.
201 struct pkzip_header
{
206 uint16_t modified_time
;
207 uint16_t modified_date
;
211 uint16_t filename_len
;
213 } __attribute__ ((packed
));
214 /* (followed by optional and variable length "filename" and "extra"
218 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
219 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
220 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
221 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
222 #define COMMENT 0x10 /* bit 4 set: file comment present */
223 #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
224 #define RESERVED 0xC0 /* bit 6,7: reserved */
226 /* pkzip flag byte */
227 #define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */
228 #define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data
230 #define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */
233 /* Return 0 if (indata, size) points to a ZIP file, and fill in
234 compressed data size, uncompressed data size, CRC, and offset of
237 If indata is not a ZIP file, return -1. */
238 int check_zip(void *indata
, uint32_t size
, uint32_t *zbytes_p
,
239 uint32_t *dbytes_p
, uint32_t *orig_crc
, uint32_t *offset_p
) {
240 struct gzip_header
*gzh
= (struct gzip_header
*)indata
;
241 struct pkzip_header
*pkzh
= (struct pkzip_header
*)indata
;
244 if (gzh
->magic
== 0x8b1f) {
245 struct gzip_trailer
*gzt
= indata
+ size
- sizeof (struct gzip_trailer
);
246 /* We only support method #8, DEFLATED */
247 if (gzh
->method
!= 8) {
248 error("gzip file uses invalid method");
251 if (gzh
->flags
& ENCRYPTED
) {
252 error("gzip file is encrypted; not supported");
255 if (gzh
->flags
& CONTINUATION
) {
256 error("gzip file is a continuation file; not supported");
259 if (gzh
->flags
& RESERVED
) {
260 error("gzip file has unsupported flags");
263 offset
= sizeof (*gzh
);
264 if (gzh
->flags
& EXTRA_FIELD
) {
265 /* Skip extra field */
266 unsigned len
= *(unsigned *)(indata
+ offset
);
269 if (gzh
->flags
& ORIG_NAME
) {
270 /* Discard the old name */
272 while (p
[offset
] != 0 && offset
< size
) {
278 if (gzh
->flags
& COMMENT
) {
279 /* Discard the comment */
281 while (p
[offset
] != 0 && offset
< size
) {
288 error ("gzip file corrupt");
291 *zbytes_p
= size
- offset
- sizeof (struct gzip_trailer
);
292 *dbytes_p
= gzt
->dbytes
;
293 *orig_crc
= gzt
->crc
;
297 else if (pkzh
->magic
== 0x04034b50UL
) {
298 /* Magic number matches pkzip file. */
300 offset
= sizeof (*pkzh
);
301 if (pkzh
->flags
& PK_ENCRYPTED
) {
302 error("pkzip file is encrypted; not supported");
305 if (pkzh
->flags
& PK_DATADESC
) {
306 error("pkzip file uses data_descriptor field; not supported");
309 if (pkzh
->flags
& PK_UNSUPPORTED
) {
310 error("pkzip file has unsupported flags");
314 /* We only support method #8, DEFLATED */
315 if (pkzh
->method
!= 8) {
316 error("pkzip file uses invalid method");
320 offset
= sizeof (*pkzh
);
322 offset
+= pkzh
->filename_len
;
323 /* skip extra field */
324 offset
+= pkzh
->extra_len
;
326 if (offset
+ pkzh
->zbytes
> size
) {
327 error ("pkzip file corrupt");
331 *zbytes_p
= pkzh
->zbytes
;
332 *dbytes_p
= pkzh
->dbytes
;
333 *orig_crc
= pkzh
->crc
;
338 /* Magic number does not match. */
342 error ("Internal error in check_zip");
347 * Decompress the image, trying to flush the end of it as close
348 * to end_mem as possible. Return a pointer to the data block,
349 * and change datalen.
353 void *unzip(void *indata
, uint32_t zbytes
, uint32_t dbytes
,
354 uint32_t orig_crc
, void *target
)
356 /* Set up the heap; it's the 64K after the bounce buffer */
357 free_mem_ptr
= (ulg
)sys_bounce
+ 0x10000;
358 free_mem_end_ptr
= free_mem_ptr
+ 0x10000;
360 /* Set up input buffer */
362 /* Sometimes inflate() looks beyond the end of the compressed data,
363 but it always backs up before it is done. So we give it 4 bytes
365 insize
= inbytes
= zbytes
+ 4;
367 /* Set up output buffer */
369 output_data
= target
;
370 output_size
= dbytes
;
376 /* Verify that gunzip() consumed the entire input. */
378 error("compressed data length error");
380 /* Check the uncompressed data length and CRC. */
381 if ( bytes_out
!= dbytes
)
382 error("uncompressed data length error");
384 if (orig_crc
!= CRC_VALUE
)