2 * Copyright (c) 2014 Martin Decky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <byteorder.h>
38 #define GZIP_ID1 UINT8_C(0x1f)
39 #define GZIP_ID2 UINT8_C(0x8b)
41 #define GZIP_METHOD_DEFLATE UINT8_C(0x08)
43 #define GZIP_FLAGS_MASK UINT8_C(0x1f)
44 #define GZIP_FLAG_FHCRC UINT8_C(1 << 1)
45 #define GZIP_FLAG_FEXTRA UINT8_C(1 << 2)
46 #define GZIP_FLAG_FNAME UINT8_C(1 << 3)
47 #define GZIP_FLAG_FCOMMENT UINT8_C(1 << 4)
57 } __attribute__((packed
)) gzip_header_t
;
62 } __attribute__((packed
)) gzip_footer_t
;
64 /** Expand GZIP compressed data
66 * The routine allocates the output buffer based
67 * on the size encoded in the input stream. This
68 * effectively limits the size of the uncompressed
69 * data to 4 GiB (expanding input streams that actually
70 * encode more data will always fail).
72 * So far, no CRC is perfomed.
74 * @param[in] src Source data buffer.
75 * @param[in] srclen Source buffer size (bytes).
76 * @param[out] dest Destination data buffer.
77 * @param[out] destlen Destination buffer size (bytes).
79 * @return EOK on success.
80 * @return ENOENT on distance too large.
81 * @return EINVAL on invalid Huffman code, invalid deflate data,
82 * invalid compression method or invalid stream.
83 * @return ELIMIT on input buffer overrun.
84 * @return ENOMEM on output buffer overrun.
87 errno_t
gzip_expand(void *src
, size_t srclen
, void **dest
, size_t *destlen
)
92 if ((srclen
< sizeof(header
)) || (srclen
< sizeof(footer
)))
95 /* Decode header and footer */
97 memcpy(&header
, src
, sizeof(header
));
98 memcpy(&footer
, src
+ srclen
- sizeof(footer
), sizeof(footer
));
100 if ((header
.id1
!= GZIP_ID1
) ||
101 (header
.id2
!= GZIP_ID2
) ||
102 (header
.method
!= GZIP_METHOD_DEFLATE
) ||
103 ((header
.flags
& (~GZIP_FLAGS_MASK
)) != 0))
106 *destlen
= uint32_t_le2host(footer
.size
);
108 /* Ignore extra metadata */
110 void *stream
= src
+ sizeof(header
);
111 size_t stream_length
= srclen
- sizeof(header
) - sizeof(footer
);
113 if ((header
.flags
& GZIP_FLAG_FEXTRA
) != 0) {
114 uint16_t extra_length
;
116 if (stream_length
< sizeof(extra_length
))
119 memcpy(&extra_length
, stream
, sizeof(extra_length
));
120 stream
+= sizeof(extra_length
);
121 stream_length
-= sizeof(extra_length
);
123 if (stream_length
< extra_length
)
126 stream
+= extra_length
;
127 stream_length
-= extra_length
;
130 if ((header
.flags
& GZIP_FLAG_FNAME
) != 0) {
131 while (*((uint8_t *) stream
) != 0) {
132 if (stream_length
== 0)
139 if (stream_length
== 0)
146 if ((header
.flags
& GZIP_FLAG_FCOMMENT
) != 0) {
147 while (*((uint8_t *) stream
) != 0) {
148 if (stream_length
== 0)
155 if (stream_length
== 0)
162 if ((header
.flags
& GZIP_FLAG_FHCRC
) != 0) {
163 if (stream_length
< 2)
170 /* Allocate output buffer and inflate the data */
172 *dest
= malloc(*destlen
);
176 errno_t ret
= inflate(stream
, stream_length
, *dest
, *destlen
);