1 /* Gzip encoding (ENCODING_GZIP) backend */
18 #include "encoding/encoding.h"
19 #include "encoding/gzip.h"
20 #include "osdep/osdep.h"
21 #include "util/memory.h"
25 gzip_open(struct stream_encoded
*stream
, int fd
)
27 stream
->data
= (void *) gzdopen(fd
, "rb");
28 if (!stream
->data
) return -1;
34 gzip_read(struct stream_encoded
*stream
, unsigned char *data
, int len
)
36 return gzread((gzFile
*) stream
->data
, data
, len
);
39 static unsigned char *
40 gzip_decode(struct stream_encoded
*stream
, unsigned char *data
, int len
,
48 /* The following code for decoding gzip in memory is a mix of code from zlib's
49 * gzio.c file copyrighted 1995-2002 by Jean-loup Gailly and the costumized
50 * header extraction in the linux kernels lib/inflate.c file not copyrighted
51 * 1992 by Mark Adler. */
53 static int gzip_header_magic
[2] = { 0x1f, 0x8b };
55 enum gzip_header_flag
{
56 GZIP_ASCII_TEXT
= 0x01, /* File probably ascii text (unused) */
57 GZIP_HEADER_CRC
= 0x02, /* Header CRC present */
58 GZIP_EXTRA_FIELD
= 0x04, /* Extra field present */
59 GZIP_ORIG_NAME
= 0x08, /* Original file name present */
60 GZIP_COMMENT
= 0x10, /* File comment present */
61 GZIP_RESERVED
= 0xE0, /* bits 5..7: reserved */
64 /* Read a byte from a gz_stream; update next_in and avail_in. Return EOF for
67 get_gzip_byte(z_stream
*stream
)
69 if (stream
->avail_in
== 0)
74 return *(stream
->next_in
)++;
77 #define skip_gzip_bytes(stream, bytes) \
78 do { int i = bytes; while (i-- > 0) get_gzip_byte(stream); } while (0)
80 #define skip_gzip_string(stream) \
81 do { int i; while ((i = get_gzip_byte(stream)) != 0 && i != EOF) ; } while (0)
83 /* Check the gzip header of a gz_stream opened for reading. Set the stream mode
84 * to transparent if the gzip magic header is not present; set s->err to
85 * Z_DATA_ERROR if the magic header is present but the rest of the header is
88 skip_gzip_header(z_stream
*stream
)
91 int method
; /* method byte */
92 int flags
; /* flags byte */
94 /* Check the gzip magic header */
95 for (len
= 0; len
< 2; len
++) {
96 int byte
= get_gzip_byte(stream
);
98 if (byte
!= gzip_header_magic
[len
]) {
109 return stream
->avail_in
!= 0 ? Z_OK
: Z_STREAM_END
;
113 method
= get_gzip_byte(stream
);
114 flags
= get_gzip_byte(stream
);
116 if (method
!= Z_DEFLATED
|| (flags
& GZIP_RESERVED
) != 0)
119 /* Discard time, xflags and OS code: */
120 skip_gzip_bytes(stream
, 6);
122 if (flags
& GZIP_EXTRA_FIELD
) {
123 /* Skip the extra field */
124 len
= (unsigned int) get_gzip_byte(stream
);
125 len
+= ((unsigned int) get_gzip_byte(stream
)) << 8;
127 /* If EOF is encountered @len is garbage, but the loop below
128 * will quit anyway. */
129 while (len
-- > 0 && get_gzip_byte(stream
) != EOF
) ;
132 /* Skip the original file name */
133 if (flags
& GZIP_ORIG_NAME
)
134 skip_gzip_string(stream
);
136 /* Skip the .gz file comment */
137 if (flags
& GZIP_COMMENT
)
138 skip_gzip_string(stream
);
140 /* Skip the header CRC */
141 if (flags
& GZIP_HEADER_CRC
)
142 skip_gzip_bytes(stream
, 2);
148 /* Freaking dammit. This is impossible for me to get working. */
149 static unsigned char *
150 gzip_decode_buffer(unsigned char *data
, int len
, int *new_len
)
152 unsigned char *buffer
= NULL
;
156 /* This WBITS loop thing was something I got from
157 * http://lists.infradead.org/pipermail/linux-mtd/2002-March/004429.html
158 * but it doesn't fix it. :/ --jonas */
159 /* -MAX_WBITS impiles -> suppress zlib header and adler32. try first
160 * with -MAX_WBITS, if that fails, try MAX_WBITS to be backwards
164 for (tries
= 0; tries
< 2; tries
++) {
167 memset(&stream
, 0, sizeof(z_stream
));
169 /* FIXME: Use inflateInit2() to configure low memory
170 * usage for CONFIG_SMALL configurations. --jonas */
171 error
= inflateInit2(&stream
, wbits
);
172 if (error
!= Z_OK
) break;
174 stream
.next_in
= (char *)data
;
175 stream
.avail_in
= len
;
177 error
= skip_gzip_header(&stream
);
179 stream
.next_in
= (char *)data
;
180 stream
.avail_in
= len
;
184 unsigned char *new_buffer
;
185 size_t size
= stream
.total_out
+ MAX_STR_LEN
;
187 assert(stream
.total_out
>= 0);
188 assert(stream
.next_in
);
190 new_buffer
= mem_realloc(buffer
, size
);
197 stream
.next_out
= buffer
+ stream
.total_out
;
198 stream
.avail_out
= MAX_STR_LEN
;
200 error
= inflate(&stream
, Z_NO_FLUSH
);
201 if (error
== Z_STREAM_END
) {
202 /* Here gzio.c has some detection of
203 * concatenated .gz files and will do a gzip
204 * header skip and an inflateReset() call
205 * before continuing. It partly uses CRC to
207 *new_len
= stream
.total_out
;
212 } while (error
== Z_OK
&& stream
.avail_in
> 0);
216 if (error
!= Z_DATA_ERROR
)
219 /* Try again with next wbits */
224 if (buffer
) mem_free(buffer
);
234 gzip_close(struct stream_encoded
*stream
)
236 gzclose((gzFile
*) stream
->data
);
239 static unsigned char *gzip_extensions
[] = { ".gz", ".tgz", NULL
};
241 struct decoding_backend gzip_decoding_backend
= {