source: mainline/uspace/lib/compress/gzip.c@ 38d150e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 38d150e was 38d150e, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Prefer to get memory allocation functions through the standard stdlib header.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2014 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29#include <stdint.h>
30#include <stddef.h>
31#include <errno.h>
32#include <mem.h>
33#include <byteorder.h>
34#include <stdlib.h>
35#include "gzip.h"
36#include "inflate.h"
37
38#define GZIP_ID1 UINT8_C(0x1f)
39#define GZIP_ID2 UINT8_C(0x8b)
40
41#define GZIP_METHOD_DEFLATE UINT8_C(0x08)
42
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)
48
49typedef struct {
50 uint8_t id1;
51 uint8_t id2;
52 uint8_t method;
53 uint8_t flags;
54 uint32_t mtime;
55 uint8_t extra_flags;
56 uint8_t os;
57} __attribute__((packed)) gzip_header_t;
58
59typedef struct {
60 uint32_t crc32;
61 uint32_t size;
62} __attribute__((packed)) gzip_footer_t;
63
64/** Expand GZIP compressed data
65 *
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).
71 *
72 * So far, no CRC is perfomed.
73 *
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).
78 *
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.
85 *
86 */
87int gzip_expand(void *src, size_t srclen, void **dest, size_t *destlen)
88{
89 gzip_header_t header;
90 gzip_footer_t footer;
91
92 if ((srclen < sizeof(header)) || (srclen < sizeof(footer)))
93 return EINVAL;
94
95 /* Decode header and footer */
96
97 memcpy(&header, src, sizeof(header));
98 memcpy(&footer, src + srclen - sizeof(footer), sizeof(footer));
99
100 if ((header.id1 != GZIP_ID1) ||
101 (header.id2 != GZIP_ID2) ||
102 (header.method != GZIP_METHOD_DEFLATE) ||
103 ((header.flags & (~GZIP_FLAGS_MASK)) != 0))
104 return EINVAL;
105
106 *destlen = uint32_t_le2host(footer.size);
107
108 /* Ignore extra metadata */
109
110 void *stream = src + sizeof(header);
111 size_t stream_length = srclen - sizeof(header) - sizeof(footer);
112
113 if ((header.flags & GZIP_FLAG_FEXTRA) != 0) {
114 uint16_t extra_length;
115
116 if (stream_length < sizeof(extra_length))
117 return EINVAL;
118
119 memcpy(&extra_length, stream, sizeof(extra_length));
120 stream += sizeof(extra_length);
121 stream_length -= sizeof(extra_length);
122
123 if (stream_length < extra_length)
124 return EINVAL;
125
126 stream += extra_length;
127 stream_length -= extra_length;
128 }
129
130 if ((header.flags & GZIP_FLAG_FNAME) != 0) {
131 while (*((uint8_t *) stream) != 0) {
132 if (stream_length == 0)
133 return EINVAL;
134
135 stream++;
136 stream_length--;
137 }
138
139 if (stream_length == 0)
140 return EINVAL;
141
142 stream++;
143 stream_length--;
144 }
145
146 if ((header.flags & GZIP_FLAG_FCOMMENT) != 0) {
147 while (*((uint8_t *) stream) != 0) {
148 if (stream_length == 0)
149 return EINVAL;
150
151 stream++;
152 stream_length--;
153 }
154
155 if (stream_length == 0)
156 return EINVAL;
157
158 stream++;
159 stream_length--;
160 }
161
162 if ((header.flags & GZIP_FLAG_FHCRC) != 0) {
163 if (stream_length < 2)
164 return EINVAL;
165
166 stream += 2;
167 stream_length -= 2;
168 }
169
170 /* Allocate output buffer and inflate the data */
171
172 *dest = malloc(*destlen);
173 if (*dest == NULL)
174 return ENOMEM;
175
176 int ret = inflate(stream, stream_length, *dest, *destlen);
177 if (ret != EOK) {
178 free(dest);
179 return ret;
180 }
181
182 return EOK;
183}
Note: See TracBrowser for help on using the repository browser.