Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (trans_stream_zlib.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | ||
26 | #include <zlib.h> | |
27 | #include <string/stdstring.h> | |
28 | #include <streams/trans_stream.h> | |
29 | ||
30 | struct zlib_trans_stream | |
31 | { | |
32 | z_stream z; | |
33 | int ex; /* window_bits or level */ | |
34 | bool inited; | |
35 | }; | |
36 | ||
37 | static void *zlib_deflate_stream_new(void) | |
38 | { | |
39 | struct zlib_trans_stream *ret = (struct zlib_trans_stream*) | |
40 | malloc(sizeof(*ret)); | |
41 | if (!ret) | |
42 | return NULL; | |
43 | ret->inited = false; | |
44 | ret->ex = 9; | |
45 | ||
46 | ret->z.next_in = NULL; | |
47 | ret->z.avail_in = 0; | |
48 | ret->z.total_in = 0; | |
49 | ret->z.next_out = NULL; | |
50 | ret->z.avail_out = 0; | |
51 | ret->z.total_out = 0; | |
52 | ||
53 | ret->z.msg = NULL; | |
54 | ret->z.state = NULL; | |
55 | ||
56 | ret->z.zalloc = NULL; | |
57 | ret->z.zfree = NULL; | |
58 | ret->z.opaque = NULL; | |
59 | ||
60 | ret->z.data_type = 0; | |
61 | ret->z.adler = 0; | |
62 | ret->z.reserved = 0; | |
63 | return (void *)ret; | |
64 | } | |
65 | ||
66 | static void *zlib_inflate_stream_new(void) | |
67 | { | |
68 | struct zlib_trans_stream *ret = (struct zlib_trans_stream*) | |
69 | malloc(sizeof(*ret)); | |
70 | if (!ret) | |
71 | return NULL; | |
72 | ret->inited = false; | |
73 | ret->ex = MAX_WBITS; | |
74 | ||
75 | ret->z.next_in = NULL; | |
76 | ret->z.avail_in = 0; | |
77 | ret->z.total_in = 0; | |
78 | ret->z.next_out = NULL; | |
79 | ret->z.avail_out = 0; | |
80 | ret->z.total_out = 0; | |
81 | ||
82 | ret->z.msg = NULL; | |
83 | ret->z.state = NULL; | |
84 | ||
85 | ret->z.zalloc = NULL; | |
86 | ret->z.zfree = NULL; | |
87 | ret->z.opaque = NULL; | |
88 | ||
89 | ret->z.data_type = 0; | |
90 | ret->z.adler = 0; | |
91 | ret->z.reserved = 0; | |
92 | return (void *)ret; | |
93 | } | |
94 | ||
95 | static void zlib_deflate_stream_free(void *data) | |
96 | { | |
97 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
98 | if (!z) | |
99 | return; | |
100 | if (z->inited) | |
101 | deflateEnd(&z->z); | |
102 | free(z); | |
103 | } | |
104 | ||
105 | static void zlib_inflate_stream_free(void *data) | |
106 | { | |
107 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
108 | if (!z) | |
109 | return; | |
110 | if (z->inited) | |
111 | inflateEnd(&z->z); | |
112 | if (z) | |
113 | free(z); | |
114 | } | |
115 | ||
116 | static bool zlib_deflate_define(void *data, const char *prop, uint32_t val) | |
117 | { | |
118 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
119 | if (string_is_equal(prop, "level")) | |
120 | { | |
121 | if (z) | |
122 | z->ex = (int) val; | |
123 | return true; | |
124 | } | |
125 | return false; | |
126 | } | |
127 | ||
128 | static bool zlib_inflate_define(void *data, const char *prop, uint32_t val) | |
129 | { | |
130 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
131 | if (string_is_equal(prop, "window_bits")) | |
132 | { | |
133 | if (z) | |
134 | z->ex = (int) val; | |
135 | return true; | |
136 | } | |
137 | return false; | |
138 | } | |
139 | ||
140 | static void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size) | |
141 | { | |
142 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
143 | ||
144 | if (!z) | |
145 | return; | |
146 | ||
147 | z->z.next_in = (uint8_t *) in; | |
148 | z->z.avail_in = in_size; | |
149 | ||
150 | if (!z->inited) | |
151 | { | |
152 | deflateInit(&z->z, z->ex); | |
153 | z->inited = true; | |
154 | } | |
155 | } | |
156 | ||
157 | static void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size) | |
158 | { | |
159 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
160 | ||
161 | if (!z) | |
162 | return; | |
163 | ||
164 | z->z.next_in = (uint8_t *) in; | |
165 | z->z.avail_in = in_size; | |
166 | if (!z->inited) | |
167 | { | |
168 | inflateInit2(&z->z, z->ex); | |
169 | z->inited = true; | |
170 | } | |
171 | } | |
172 | ||
173 | static void zlib_set_out(void *data, uint8_t *out, uint32_t out_size) | |
174 | { | |
175 | struct zlib_trans_stream *z = (struct zlib_trans_stream *) data; | |
176 | ||
177 | if (!z) | |
178 | return; | |
179 | ||
180 | z->z.next_out = out; | |
181 | z->z.avail_out = out_size; | |
182 | } | |
183 | ||
184 | static bool zlib_deflate_trans( | |
185 | void *data, bool flush, | |
186 | uint32_t *rd, uint32_t *wn, | |
187 | enum trans_stream_error *error) | |
188 | { | |
189 | int zret = 0; | |
190 | bool ret = false; | |
191 | uint32_t pre_avail_in = 0; | |
192 | uint32_t pre_avail_out = 0; | |
193 | struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data; | |
194 | z_stream *z = &zt->z; | |
195 | ||
196 | if (!zt->inited) | |
197 | { | |
198 | deflateInit(z, zt->ex); | |
199 | zt->inited = true; | |
200 | } | |
201 | ||
202 | pre_avail_in = z->avail_in; | |
203 | pre_avail_out = z->avail_out; | |
204 | zret = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH); | |
205 | ||
206 | if (zret == Z_OK) | |
207 | { | |
208 | if (error) | |
209 | *error = TRANS_STREAM_ERROR_AGAIN; | |
210 | } | |
211 | else if (zret == Z_STREAM_END) | |
212 | { | |
213 | if (error) | |
214 | *error = TRANS_STREAM_ERROR_NONE; | |
215 | } | |
216 | else | |
217 | { | |
218 | if (error) | |
219 | *error = TRANS_STREAM_ERROR_OTHER; | |
220 | return false; | |
221 | } | |
222 | ret = true; | |
223 | ||
224 | if (z->avail_out == 0) | |
225 | { | |
226 | /* Filled buffer, maybe an error */ | |
227 | if (z->avail_in != 0) | |
228 | { | |
229 | ret = false; | |
230 | if (error) | |
231 | *error = TRANS_STREAM_ERROR_BUFFER_FULL; | |
232 | } | |
233 | } | |
234 | ||
235 | *rd = pre_avail_in - z->avail_in; | |
236 | *wn = pre_avail_out - z->avail_out; | |
237 | ||
238 | if (flush && zret == Z_STREAM_END) | |
239 | { | |
240 | deflateEnd(z); | |
241 | zt->inited = false; | |
242 | } | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
247 | static bool zlib_inflate_trans( | |
248 | void *data, bool flush, | |
249 | uint32_t *rd, uint32_t *wn, | |
250 | enum trans_stream_error *error) | |
251 | { | |
252 | int zret; | |
253 | bool ret = false; | |
254 | uint32_t pre_avail_in = 0; | |
255 | uint32_t pre_avail_out = 0; | |
256 | struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data; | |
257 | z_stream *z = &zt->z; | |
258 | ||
259 | if (!zt->inited) | |
260 | { | |
261 | inflateInit2(z, zt->ex); | |
262 | zt->inited = true; | |
263 | } | |
264 | ||
265 | pre_avail_in = z->avail_in; | |
266 | pre_avail_out = z->avail_out; | |
267 | zret = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH); | |
268 | ||
269 | if (zret == Z_OK) | |
270 | { | |
271 | if (error) | |
272 | *error = TRANS_STREAM_ERROR_AGAIN; | |
273 | } | |
274 | else if (zret == Z_STREAM_END) | |
275 | { | |
276 | if (error) | |
277 | *error = TRANS_STREAM_ERROR_NONE; | |
278 | } | |
279 | else | |
280 | { | |
281 | if (error) | |
282 | *error = TRANS_STREAM_ERROR_OTHER; | |
283 | return false; | |
284 | } | |
285 | ret = true; | |
286 | ||
287 | if (z->avail_out == 0) | |
288 | { | |
289 | /* Filled buffer, maybe an error */ | |
290 | if (z->avail_in != 0) | |
291 | { | |
292 | ret = false; | |
293 | if (error) | |
294 | *error = TRANS_STREAM_ERROR_BUFFER_FULL; | |
295 | } | |
296 | } | |
297 | ||
298 | *rd = pre_avail_in - z->avail_in; | |
299 | *wn = pre_avail_out - z->avail_out; | |
300 | ||
301 | if (flush && zret == Z_STREAM_END) | |
302 | { | |
303 | inflateEnd(z); | |
304 | zt->inited = false; | |
305 | } | |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
310 | const struct trans_stream_backend zlib_deflate_backend = { | |
311 | "zlib_deflate", | |
312 | &zlib_inflate_backend, | |
313 | zlib_deflate_stream_new, | |
314 | zlib_deflate_stream_free, | |
315 | zlib_deflate_define, | |
316 | zlib_deflate_set_in, | |
317 | zlib_set_out, | |
318 | zlib_deflate_trans | |
319 | }; | |
320 | ||
321 | const struct trans_stream_backend zlib_inflate_backend = { | |
322 | "zlib_inflate", | |
323 | &zlib_deflate_backend, | |
324 | zlib_inflate_stream_new, | |
325 | zlib_inflate_stream_free, | |
326 | zlib_inflate_define, | |
327 | zlib_inflate_set_in, | |
328 | zlib_set_out, | |
329 | zlib_inflate_trans | |
330 | }; |