GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/zlibstreams.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 169 315 53.7%
Functions: 13 29 44.8%
Branches: 53 137 38.7%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. 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 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/encode/zlibstreams.h"
30 #include "gate/memalloc.h"
31 #include "gate/atomics.h"
32 #include "gate/results.h"
33 #include "gate/debugging.h"
34
35 #if defined(GATE_EXTLIB_ZLIB)
36 # define GATE_ENCODE_ZLIBSTREAM_USE_ZLIB 1
37 #else
38 # define GATE_ENCODE_ZLIBSTREAM_NO_IMPL 1
39 #endif
40
41 #if defined(GATE_ENCODE_ZLIBSTREAM_USE_ZLIB)
42
43 #include "zlib.h"
44
45 /* output stream encoder implementation */
46
47 12 static voidpf gate_zlibstream_alloc_func(voidpf opaque, uInt items, uInt size)
48 {
49 voidpf ret;
50 12 gate_size_t const mem_sz = (gate_size_t)items * (gate_size_t)size;
51 (void)opaque;
52
53 12 ret = gate_mem_alloc(mem_sz);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!ret)
55 {
56 GATE_DEBUG_TRACE("ZLIB allocation failed");
57 }
58 else
59 {
60 12 gate_mem_clear(ret, mem_sz);
61 }
62 12 return ret;
63 }
64 12 static void gate_zlibstream_free_func(voidpf opaque, voidpf address)
65 {
66 (void)opaque;
67
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (address)
68 {
69 12 gate_mem_dealloc(address);
70 }
71 12 }
72
73 static void gate_zlibencoder_release_impl(void* self);
74 static int gate_zlibencoder_retain_impl(void* self);
75 static char const* gate_zlibencoder_interface_name_impl(void* self)
76 {
77 (void)self;
78 return GATE_INTERFACE_NAME_STREAM;
79 }
80 static gate_result_t gate_zlibencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
81 static gate_result_t gate_zlibencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
82 static gate_result_t gate_zlibencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
83 static gate_result_t gate_zlibencoder_flush_impl(void* self);
84
85 static GATE_INTERFACE_VTBL(gate_stream) gate_zlibencoder_vtbl;
86 2 static void gate_init_zlibencoder_vtbl()
87 {
88
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!gate_zlibencoder_vtbl.get_interface_name)
89 {
90 GATE_INTERFACE_VTBL(gate_stream) const local_vtbl =
91 {
92 &gate_zlibencoder_interface_name_impl,
93 &gate_zlibencoder_release_impl,
94 &gate_zlibencoder_retain_impl,
95 &gate_zlibencoder_read_impl,
96 &gate_zlibencoder_peek_impl,
97 &gate_zlibencoder_write_impl,
98 &gate_zlibencoder_flush_impl
99 };
100 1 gate_zlibencoder_vtbl = local_vtbl;
101 }
102 2 }
103
104 typedef struct gate_zlibencoder_impl
105 {
106 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
107
108 gate_atomic_int_t ref_counter;
109 gate_stream_t* dest_stream;
110 z_stream zipper;
111 char data_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH];
112 gate_size_t data_buffer_used;
113
114 } gate_zlibencoder_impl_t;
115
116 2 gate_result_t gate_zlib_encoder_create(gate_stream_t* output, gate_bool_t gzformat, gate_int16_t compression, gate_stream_t** ptr2streamptr)
117 {
118 gate_result_t ret;
119 gate_zlibencoder_impl_t* impl;
120 int zresult;
121 2 int level = Z_DEFAULT_COMPRESSION;
122 #if defined(GATE_SYS_WINCE) || defined(GATE_SYS_DOS)
123 int memlevel = MAX_MEM_LEVEL - 2;
124 int window_bits = MAX_WBITS - 1;
125 #else
126 2 int memlevel = MAX_MEM_LEVEL;
127 2 int window_bits = MAX_WBITS;
128 #endif
129 do
130 {
131
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((output == NULL) || (ptr2streamptr == NULL))
132 {
133 GATE_DEBUG_TRACE("ZLIB encoder NULL pointer");
134 ret = GATE_RESULT_NULLPOINTER;
135 break;
136 }
137 2 impl = (gate_zlibencoder_impl_t*)gate_mem_alloc(sizeof(gate_zlibencoder_impl_t));
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (impl == NULL)
139 {
140 GATE_DEBUG_TRACE("Failed to allocate ZLIB encoder");
141 ret = GATE_RESULT_OUTOFMEMORY;
142 break;
143 }
144
145 2 gate_mem_clear(impl, sizeof(gate_zlibencoder_impl_t));
146 2 gate_init_zlibencoder_vtbl();
147 2 impl->vtbl = &gate_zlibencoder_vtbl;
148 2 gate_atomic_int_init(&impl->ref_counter, 1);
149 2 impl->dest_stream = output;
150
151
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
2 switch (compression)
152 {
153 case GATE_ZLIB_COMPRESSION_MINIMUM: level = Z_BEST_SPEED; break;
154 case GATE_ZLIB_COMPRESSION_LOW: level = (Z_BEST_SPEED + (Z_BEST_SPEED + Z_BEST_COMPRESSION) / 2) / 2; break;
155 case GATE_ZLIB_COMPRESSION_MEDIUM: level = (Z_BEST_SPEED + Z_BEST_COMPRESSION) / 2; break;
156 case GATE_ZLIB_COMPRESSION_HIGH: level = (Z_BEST_COMPRESSION + (Z_BEST_SPEED + Z_BEST_COMPRESSION) / 2) / 2; break;
157 case GATE_ZLIB_COMPRESSION_MAXIMUM: level = Z_BEST_COMPRESSION; break;
158 }
159
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (gzformat)
160 {
161 1 window_bits += 16;
162 }
163
164 2 impl->zipper.zalloc = &gate_zlibstream_alloc_func;
165 2 impl->zipper.opaque = Z_NULL;
166 2 impl->zipper.zfree = &gate_zlibstream_free_func;
167
168 2 zresult = deflateInit2(&impl->zipper, level, Z_DEFLATED, window_bits, memlevel, Z_DEFAULT_STRATEGY);
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (zresult != Z_OK)
170 {
171 GATE_DEBUG_TRACE_MSG_VALUE("deflateInit2() failed", zresult);
172 gate_mem_dealloc(impl);
173 ret = GATE_RESULT_FAILED;
174 break;
175 }
176
177 2 impl->data_buffer_used = 0;
178
179 2 gate_object_retain(impl->dest_stream);
180 2 *ptr2streamptr = (gate_stream_t*)impl;
181
182 2 ret = GATE_RESULT_OK;
183 } while (0);
184
185 2 return ret;
186
187 }
188
189 2 static void gate_zlibencoder_release_impl(void* self)
190 {
191 2 gate_zlibencoder_impl_t* impl = (gate_zlibencoder_impl_t*)self;
192
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
193 {
194 2 gate_zlibencoder_flush_impl(self);
195 2 deflateEnd(&impl->zipper);
196 2 gate_object_release(impl->dest_stream);
197 2 gate_mem_dealloc(impl);
198 }
199 2 }
200 static int gate_zlibencoder_retain_impl(void* self)
201 {
202 gate_zlibencoder_impl_t* impl = (gate_zlibencoder_impl_t*)self;
203 return gate_atomic_int_inc(&impl->ref_counter);
204 }
205 static gate_result_t gate_zlibencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
206 {
207 (void)self;
208 (void)buffer;
209 (void)bufferlength;
210 (void)returned;
211 return GATE_RESULT_NOTSUPPORTED;
212 }
213 static gate_result_t gate_zlibencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
214 {
215 (void)self;
216 (void)buffer;
217 (void)bufferlength;
218 (void)returned;
219 return GATE_RESULT_NOTSUPPORTED;
220 }
221 20 static gate_result_t gate_zlibencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
222 {
223 20 gate_result_t ret = GATE_RESULT_OK;
224 20 gate_zlibencoder_impl_t* impl = (gate_zlibencoder_impl_t*)self;
225 char compressed_buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
226 20 gate_size_t bytesavailable = sizeof(impl->data_buffer) - impl->data_buffer_used;
227 20 gate_size_t bytesaccepted = bytesavailable < bufferlength ? bytesavailable : bufferlength;
228 int zresult;
229 gate_size_t bytescompressed;
230 gate_size_t byteswritten;
231 gate_size_t bytesremaining;
232
233 do
234 {
235 20 gate_mem_copy(&impl->data_buffer[impl->data_buffer_used], buffer, bytesaccepted);
236
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (written != NULL)
237 {
238 20 *written = bytesaccepted;
239 }
240 20 impl->data_buffer_used += bytesaccepted;
241
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (impl->data_buffer_used == 0)
243 {
244 GATE_DEBUG_TRACE("zlibencoder_write data_buffer_used==0");
245 ret = GATE_RESULT_INVALIDARG;
246 break;
247 }
248
249 20 impl->zipper.avail_in = (uInt)impl->data_buffer_used;
250 20 impl->zipper.next_in = (Bytef*)&impl->data_buffer[0];
251
252
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 while (impl->zipper.avail_in != 0)
253 {
254 20 impl->zipper.avail_out = sizeof(compressed_buffer);
255 20 impl->zipper.next_out = (Bytef*)&compressed_buffer[0];
256
257 20 zresult = deflate(&impl->zipper, Z_NO_FLUSH);
258
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
20 if ((zresult != Z_OK) && (zresult != Z_STREAM_END))
259 {
260 GATE_DEBUG_TRACE_MSG_VALUE("deflate() failed", zresult);
261 ret = GATE_RESULT_FAILED;
262 break;
263 }
264 20 bytescompressed = sizeof(compressed_buffer) - impl->zipper.avail_out;
265
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if (bytescompressed > 0)
266 {
267 2 ret = gate_stream_write_block(impl->dest_stream, &compressed_buffer[0], bytescompressed, &byteswritten);
268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
269 {
270 GATE_DEBUG_TRACE_MSG_VALUE("zlib_encoder_write write_block failed", ret);
271 break;
272 }
273 }
274 else
275 {
276 18 break;
277 }
278 }
279
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (impl->zipper.avail_in != 0)
281 {
282 bytesremaining = impl->zipper.avail_in;
283 gate_mem_move(&impl->data_buffer[0], &impl->data_buffer[impl->data_buffer_used - bytesremaining], bytesremaining);
284 impl->data_buffer_used = bytesremaining;
285 }
286 else
287 {
288 20 impl->data_buffer_used = 0;
289 }
290 } while (0);
291 20 return ret;
292 }
293 4 static gate_result_t gate_zlibencoder_flush_impl(void* self)
294 {
295 4 gate_result_t ret = GATE_RESULT_OK;
296 4 gate_zlibencoder_impl_t* impl = (gate_zlibencoder_impl_t*)self;
297 char compressed_buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
298 int zresult;
299 gate_size_t bytescompressed;
300 gate_size_t byteswritten;
301 gate_size_t bytesoffset;
302
303 do
304 {
305 4 impl->zipper.next_in = (Bytef*)&impl->data_buffer[0];
306 4 impl->zipper.avail_in = (uInt)impl->data_buffer_used;
307
308 4 impl->zipper.avail_out = sizeof(compressed_buffer);
309 4 impl->zipper.next_out = (Bytef*)&compressed_buffer[0];
310
311 4 zresult = deflate(&impl->zipper, Z_FINISH);
312
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if ((zresult != Z_OK) && (zresult != Z_STREAM_END))
313 {
314 GATE_DEBUG_TRACE_MSG_VALUE("deflate(FINISH) failed", zresult);
315 ret = GATE_RESULT_FAILED;
316 break;
317 }
318
319 4 bytescompressed = sizeof(compressed_buffer) - impl->zipper.avail_out;
320 4 ret = gate_stream_write_block(impl->dest_stream, compressed_buffer, bytescompressed, &byteswritten);
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
322 {
323 GATE_DEBUG_TRACE_MSG_VALUE("zlibencoder_flush write_block failed", ret);
324 break;
325 }
326
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (impl->zipper.avail_in < impl->data_buffer_used)
328 {
329 bytesoffset = impl->data_buffer_used - impl->zipper.avail_in;
330 gate_mem_move(&impl->data_buffer[0], &impl->data_buffer[bytesoffset], impl->zipper.avail_in);
331 impl->data_buffer_used = impl->zipper.avail_in;
332 }
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 } while (impl->zipper.avail_out == 0);
334
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (GATE_SUCCEEDED(ret))
335 {
336 4 ret = gate_stream_flush(impl->dest_stream);
337 }
338 4 return ret;
339 }
340
341
342
343
344 /* input stream decoder implementation */
345
346 static void gate_zlibdecoder_release_impl(void* self);
347 static int gate_zlibdecoder_retain_impl(void* self);
348 static char const* gate_zlibdecoder_interface_name_impl(void* self);
349
350 static gate_result_t gate_zlibdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
351 static gate_result_t gate_zlibdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
352 static gate_result_t gate_zlibdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
353 static gate_result_t gate_zlibdecoder_flush_impl(void* self);
354
355 static gate_result_t gate_zlibdecoder_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource);
356
357 static gate_result_t gate_zlibdecoder_can_read_impl(void* self, gate_bool_t* return_value);
358 static gate_result_t gate_zlibdecoder_can_write_impl(void* self, gate_bool_t* return_value);
359 static gate_result_t gate_zlibdecoder_get_size_impl(void* self, gate_int64_t* return_value);
360 static gate_result_t gate_zlibdecoder_get_available_impl(void* self, gate_int64_t* return_value);
361 static gate_result_t gate_zlibdecoder_seek_impl(void* self, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position);
362 static gate_result_t gate_zlibdecoder_reset_impl(void* self);
363 static gate_result_t gate_zlibdecoder_close_impl(void* self, gate_enumint_t close_type);
364
365 static GATE_INTERFACE_VTBL(gate_controlstream) gate_zlibdecoder_vtbl;
366 2 static void gate_init_zlibdecoder_vtbl()
367 {
368
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!gate_zlibdecoder_vtbl.get_interface_name)
369 {
370 static GATE_INTERFACE_VTBL(gate_controlstream) local_vtbl =
371 {
372 &gate_zlibdecoder_interface_name_impl,
373 &gate_zlibdecoder_release_impl,
374 &gate_zlibdecoder_retain_impl,
375
376 &gate_zlibdecoder_read_impl,
377 &gate_zlibdecoder_peek_impl,
378 &gate_zlibdecoder_write_impl,
379 &gate_zlibdecoder_flush_impl,
380
381 &gate_zlibdecoder_get_resource_impl,
382
383 &gate_zlibdecoder_can_read_impl,
384 &gate_zlibdecoder_can_write_impl,
385 &gate_zlibdecoder_get_size_impl,
386 &gate_zlibdecoder_get_available_impl,
387 &gate_zlibdecoder_seek_impl,
388 &gate_zlibdecoder_reset_impl,
389 &gate_zlibdecoder_close_impl
390 };
391 1 gate_zlibdecoder_vtbl = local_vtbl;
392 }
393 2 }
394
395 typedef struct gate_zlibdecoder_impl
396 {
397 GATE_INTERFACE_VTBL(gate_controlstream)* vtbl;
398
399 gate_atomic_int_t ref_counter; /* reference counter */
400 gate_stream_t* source_stream; /* source stream to deliver compressed data */
401 z_stream unzipper; /* unzip processing instance */
402 char source_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH]; /* internal source-stream input buffer */
403 char decoded_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH]; /* internal output buffer */
404 gate_size_t decoded_buffer_length; /* current amount of valid bytes in decoded_buffer */
405 gate_size_t decoded_buffer_offset; /* current start offset of valid bytes in decoded_buffer */
406 gate_uint64_t bytes_decoded_counter; /* sum of bytes that were sucessfully decompressed */
407 gate_uint64_t total_bytes_uncompressed; /* estimated total sum of bytes after decompression (incorrect if original data was greater 2^32 bytes) */
408
409 } gate_zlibdecoder_impl_t;
410
411 2 static gate_bool_t gate_zlib_decoder_get_content_length(gate_stream_t* stream, gate_uint64_t* ptr_length)
412 {
413 2 gate_bool_t ret = false;
414 2 gate_controlstream_t* ctrl = NULL;
415 gate_int64_t start_pos;
416 gate_int64_t avail;
417 gate_int64_t end_pos;
418 gate_result_t result;
419 2 char header[10] = { 0 };
420 2 char tail[8] = { 0 };
421 gate_size_t received;
422 gate_uint32_t uncompressed_size;
423
424 do
425 {
426
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (!gate_object_implements_interface((gate_object_t*)stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
427 {
428 2 break;
429 }
430
431 ctrl = (gate_controlstream_t*)stream;
432
433 result = gate_stream_peek(stream, header, sizeof(header), NULL);
434 GATE_BREAK_IF_FAILED(result);
435
436 if ((header[0] != (char)0x01f) || (header[1] != (char)0x08b) /*|| (header[0] != 8)*/)
437 {
438 break;
439 }
440
441 result = gate_stream_get_position(ctrl, &start_pos);
442 GATE_BREAK_IF_FAILED(result);
443
444 result = gate_stream_get_available(ctrl, &avail);
445 GATE_BREAK_IF_FAILED(result);
446
447 if (avail < sizeof(tail))
448 {
449 break;
450 }
451
452 end_pos = start_pos + avail;
453
454 /* jump to end of file to read tail-bytes */
455 result = gate_stream_seek(ctrl, end_pos - sizeof(tail), GATE_STREAM_SEEK_BEGIN, NULL);
456 GATE_BREAK_IF_FAILED(result);
457
458 result = gate_stream_peek(stream, tail, sizeof(tail), &received);
459
460 /* jump back to begin of stream */
461 result = gate_stream_seek(ctrl, start_pos, GATE_STREAM_SEEK_BEGIN, NULL);
462 GATE_BREAK_IF_FAILED(result);
463
464 uncompressed_size = ((gate_uint32_t)(gate_uint8_t)tail[4])
465 | (((gate_uint32_t)(gate_uint8_t)tail[5]) << 8)
466 | (((gate_uint32_t)(gate_uint8_t)tail[6]) << 16)
467 | (((gate_uint32_t)(gate_uint8_t)tail[7]) << 24)
468 ;
469 *ptr_length = uncompressed_size;
470 ret = true;
471 } while (0);
472
473 2 return ret;
474
475 }
476
477 2 gate_result_t gate_zlib_decoder_create(gate_stream_t* input, gate_bool_t gzformat, gate_stream_t** ptr2streamptr)
478 {
479 gate_result_t ret;
480 gate_zlibdecoder_impl_t* impl;
481 int zresult;
482
483 do
484 {
485
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((input == NULL) || (ptr2streamptr == NULL))
486 {
487 ret = GATE_RESULT_NULLPOINTER;
488 break;
489 }
490 2 impl = (gate_zlibdecoder_impl_t*)gate_mem_alloc(sizeof(gate_zlibdecoder_impl_t));
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (impl == NULL)
492 {
493 GATE_DEBUG_TRACE("failed to allocate zlibdecoder");
494 ret = GATE_RESULT_OUTOFMEMORY;
495 break;
496 }
497
498 2 gate_mem_clear(impl, sizeof(gate_zlibdecoder_impl_t));
499 2 gate_init_zlibdecoder_vtbl();
500 2 impl->vtbl = &gate_zlibdecoder_vtbl;
501 2 gate_atomic_int_init(&impl->ref_counter, 1);
502 2 impl->source_stream = input;
503
504 2 gate_zlib_decoder_get_content_length(input, &impl->total_bytes_uncompressed);
505
506 2 impl->unzipper.zalloc = &gate_zlibstream_alloc_func;
507 2 impl->unzipper.opaque = Z_NULL;
508 2 impl->unzipper.zfree = &gate_zlibstream_free_func;
509
510
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 zresult = inflateInit2(&impl->unzipper, (gzformat == true ? MAX_WBITS + 32 : MAX_WBITS));
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (zresult != Z_OK)
512 {
513 GATE_DEBUG_TRACE_MSG_VALUE("inflateInit2() failed", zresult);
514 gate_mem_dealloc(impl);
515 ret = GATE_RESULT_FAILED;
516 break;
517 }
518
519 2 gate_object_retain(impl->source_stream);
520 2 *ptr2streamptr = (gate_stream_t*)impl;
521
522 2 ret = GATE_RESULT_OK;
523 } while (0);
524
525 2 return ret;
526 }
527
528
529 static char const* gate_zlibdecoder_interface_name_impl(void* self)
530 {
531 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
532 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
533 {
534 return GATE_INTERFACE_NAME_CONTROLSTREAM;
535 }
536 return GATE_INTERFACE_NAME_STREAM;
537 }
538
539 2 static void gate_zlibdecoder_release_impl(void* self)
540 {
541 2 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
542
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
543 {
544 2 inflateEnd(&impl->unzipper);
545 2 gate_object_release(impl->source_stream);
546 2 gate_mem_dealloc(impl);
547 }
548 2 }
549 static int gate_zlibdecoder_retain_impl(void* self)
550 {
551 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
552 return gate_atomic_int_inc(&impl->ref_counter);
553 }
554
555 22 static gate_result_t gate_zlibdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
556 {
557 22 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
558
559 22 gate_bool_t end_of_stream = false;
560 gate_size_t bytecount;
561 gate_result_t result;
562 gate_size_t diff;
563 int zresult;
564
565
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
24 while ((impl->decoded_buffer_length == 0) && (!end_of_stream))
566 {
567
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (impl->unzipper.avail_in == 0)
568 {
569 4 result = gate_stream_read(impl->source_stream, impl->source_buffer, sizeof(impl->source_buffer), &bytecount);
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(result))
571 {
572 GATE_DEBUG_TRACE_MSG_VALUE("zlibdecoder_peek stream_read failed", result);
573 return result;
574 }
575
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (bytecount == 0)
576 {
577 2 break;
578 }
579 2 impl->unzipper.next_in = (Bytef*)&impl->source_buffer[0];
580 2 impl->unzipper.avail_in = (uInt)bytecount;
581 }
582
583
584 2 impl->unzipper.avail_out = sizeof(impl->decoded_buffer);
585 2 impl->unzipper.next_out = (Bytef*)(&impl->decoded_buffer[0]);
586
587 2 zresult = inflate(&impl->unzipper, Z_NO_FLUSH);
588
589
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 switch (zresult)
590 {
591 case Z_STREAM_ERROR:
592 case Z_NEED_DICT:
593 case Z_DATA_ERROR:
594 case Z_MEM_ERROR:
595 {
596 GATE_DEBUG_TRACE_MSG_VALUE("inflate() failed", zresult);
597 return GATE_RESULT_FAILED;
598 }
599 2 case Z_STREAM_END:
600 {
601 2 end_of_stream = true;
602 2 break;
603 }
604 case Z_BUF_ERROR:
605 {
606 /* ignore */
607 GATE_DEBUG_BREAKPOINT;
608 break;
609 }
610 case Z_OK:
611 {
612 /* success -> continue */
613 break;
614 }
615 }
616
617 2 GATE_DEBUG_ASSERT(sizeof(impl->decoded_buffer) >= impl->unzipper.avail_out);
618 2 diff = sizeof(impl->decoded_buffer) - impl->unzipper.avail_out;
619 2 impl->decoded_buffer_length = diff;
620 2 impl->decoded_buffer_offset = 0;
621 }
622
623
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (bufferlength < impl->decoded_buffer_length)
624 {
625 18 gate_mem_copy(buffer, &impl->decoded_buffer[impl->decoded_buffer_offset], bufferlength);
626
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (returned != NULL)
627 {
628 18 *returned = bufferlength;
629 }
630 }
631 else
632 {
633
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (impl->decoded_buffer_length > 0)
634 {
635 2 gate_mem_copy(buffer, &impl->decoded_buffer[impl->decoded_buffer_offset], impl->decoded_buffer_length);
636 }
637
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (returned != NULL)
638 {
639 4 *returned = impl->decoded_buffer_length;
640 }
641 }
642 22 return GATE_RESULT_OK;
643 }
644
645 22 static gate_result_t gate_zlibdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
646 {
647 22 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
648 22 gate_size_t tmp = 0;
649 22 gate_result_t ret = gate_zlibdecoder_peek_impl(self, buffer, bufferlength, &tmp);
650
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (returned != NULL)
651 {
652 22 *returned = tmp;
653 }
654
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (GATE_SUCCEEDED(ret))
655 {
656 22 impl->decoded_buffer_offset += tmp;
657 22 impl->decoded_buffer_length -= tmp;
658 22 impl->bytes_decoded_counter += tmp;
659 }
660 22 return ret;
661 }
662
663 static gate_result_t gate_zlibdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
664 {
665 GATE_UNUSED_ARG(self);
666 GATE_UNUSED_ARG(buffer);
667 GATE_UNUSED_ARG(bufferlength);
668 GATE_UNUSED_ARG(written);
669 return GATE_RESULT_NOTSUPPORTED;
670 }
671
672 static gate_result_t gate_zlibdecoder_flush_impl(void* self)
673 {
674 GATE_UNUSED_ARG(self);
675 return GATE_RESULT_NOTSUPPORTED;
676 }
677
678 static gate_result_t gate_zlibdecoder_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
679 {
680 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
681 gate_controlstream_t* ctrl;
682
683 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
684 {
685 ctrl = (gate_controlstream_t*)impl->source_stream;
686 return gate_stream_get_resource(ctrl, resource_type, resource);
687 }
688 return GATE_RESULT_NOTSUPPORTED;
689 }
690
691 static gate_result_t gate_zlibdecoder_can_read_impl(void* self, gate_bool_t* return_value)
692 {
693 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
694 gate_controlstream_t* ctrl;
695
696 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
697 {
698 ctrl = (gate_controlstream_t*)impl->source_stream;
699 return gate_stream_can_read(ctrl, return_value);
700 }
701 return GATE_RESULT_NOTSUPPORTED;
702 }
703
704 static gate_result_t gate_zlibdecoder_can_write_impl(void* self, gate_bool_t* return_value)
705 {
706 GATE_UNUSED_ARG(self);
707 if (return_value)
708 {
709 *return_value = false;
710 }
711 return GATE_RESULT_OK;
712 }
713
714 static gate_result_t gate_zlibdecoder_get_size_impl(void* self, gate_int64_t* return_value)
715 {
716 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
717 gate_controlstream_t* ctrl;
718
719 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
720 {
721 ctrl = (gate_controlstream_t*)impl->source_stream;
722 if (return_value)
723 {
724 *return_value = (gate_int64_t)impl->total_bytes_uncompressed;
725 }
726 return GATE_RESULT_OK;
727 }
728 return GATE_RESULT_NOTSUPPORTED;
729 }
730
731 static gate_result_t gate_zlibdecoder_get_available_impl(void* self, gate_int64_t* return_value)
732 {
733 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
734 gate_controlstream_t* ctrl;
735
736 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
737 {
738 ctrl = (gate_controlstream_t*)impl->source_stream;
739 if (return_value)
740 {
741 if (impl->total_bytes_uncompressed >= impl->bytes_decoded_counter)
742 {
743 *return_value = (gate_int64_t)impl->total_bytes_uncompressed - impl->bytes_decoded_counter;
744 }
745 else
746 {
747 *return_value = 0;
748 }
749 }
750 return GATE_RESULT_OK;
751 }
752 return GATE_RESULT_NOTSUPPORTED;
753 }
754
755
756 static gate_result_t gate_zlibdecoder_seek_impl(void* self, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
757 {
758 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
759 if ((origin == GATE_STREAM_SEEK_CURRENT) && (position == 0))
760 {
761 /* special case: return current position in decoded stream (no change at all) */
762 if (final_position)
763 {
764 *final_position = (gate_int64_t)impl->bytes_decoded_counter;
765 }
766 return GATE_RESULT_OK;
767 }
768 return GATE_RESULT_NOTSUPPORTED;
769 }
770
771
772 static gate_result_t gate_zlibdecoder_reset_impl(void* self)
773 {
774 GATE_UNUSED_ARG(self);
775 return GATE_RESULT_NOTSUPPORTED;
776 }
777
778
779 static gate_result_t gate_zlibdecoder_close_impl(void* self, gate_enumint_t close_type)
780 {
781 gate_zlibdecoder_impl_t* impl = (gate_zlibdecoder_impl_t*)self;
782 gate_controlstream_t* ctrl;
783
784 if (gate_object_implements_interface((gate_object_t*)impl->source_stream, GATE_INTERFACE_NAME_CONTROLSTREAM))
785 {
786 ctrl = (gate_controlstream_t*)impl->source_stream;
787 return gate_stream_close(ctrl, close_type);
788 }
789 return GATE_RESULT_NOTSUPPORTED;
790 }
791
792 #endif /* GATE_ENCODE_ZLIBSTREAM_USE_ZLIB */
793
794
795 #if defined(GATE_ENCODE_ZLIBSTREAM_NO_IMPL)
796
797 gate_result_t gate_zlib_encoder_create(gate_stream_t* output, gate_bool_t gzformat,
798 gate_int16_t compression, gate_stream_t** ptr2streamptr)
799 {
800 return GATE_RESULT_NOTIMPLEMENTED;
801 }
802
803 gate_result_t gate_zlib_decoder_create(gate_stream_t* input, gate_bool_t gzformat,
804 gate_stream_t** ptr2streamptr)
805 {
806 return GATE_RESULT_NOTIMPLEMENTED;
807 }
808
809 #endif /* GATE_ENCODE_ZLIBSTREAM_NO_IMPL */
810
811