GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/xzstreams.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 6 0.0%
Functions: 0 3 0.0%
Branches: 0 0 -%

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/xzstreams.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_LZMA) && !defined(GATE_ENCODE_NO_ADVANCED_COMPRESSION)
36 # define GATE_ENCODE_XZSTREAM_USE_LZMA
37 #else
38 # define GATE_ENCODE_XZSTREAM_NO_IMPL
39 #endif
40
41 #if defined(GATE_ENCODE_XZSTREAM_USE_LZMA)
42
43 #include "Xz.h"
44 #include "XzEnc.h"
45 #include "7zCrc.h"
46 #include "XzCrc64.h"
47 #include "Lzma2Dec.h"
48 #include "Lzma2Enc.h"
49
50 static void gate_xz_init_impl(void)
51 {
52 CrcGenerateTable();
53 Crc64GenerateTable();
54 }
55
56 static void gate_xz_init()
57 {
58 static gate_atomic_flag_t is_initialized = GATE_ATOMIC_FLAG_INIT;
59
60 gate_atomic_call_once_exclusive(&is_initialized, &gate_xz_init_impl);
61 }
62
63 static void* gate_xz_alloc(ISzAllocPtr p, size_t sz)
64 {
65 (void)p;
66 if (sz == 0)
67 {
68 return NULL;
69 }
70 else
71 {
72 return gate_mem_alloc(sz);
73 }
74 }
75 static void gate_xz_free(ISzAllocPtr p, void* ptrAddress)
76 {
77 (void)p;
78 if (ptrAddress != NULL)
79 {
80 gate_mem_dealloc(ptrAddress);
81 }
82 }
83
84 static ISzAlloc gate_xz_allocator =
85 {
86 &gate_xz_alloc, &gate_xz_free
87 };
88
89
90
91 typedef struct gate_xz_read_stream_class
92 {
93 ISeqInStream seqinstream;
94 gate_stream_t* gatestream;
95 } gate_xz_read_stream_t;
96
97 static SRes gate_xz_stream_read(ISeqInStream const* p, void* buf, size_t* size)
98 {
99 gate_xz_read_stream_t const* reader = (gate_xz_read_stream_t const*)(p);
100 gate_size_t bytesreturned = 0;
101 gate_result_t result = gate_stream_read_block(reader->gatestream, (char*)buf, *size, &bytesreturned);
102 if (GATE_FAILED(result))
103 {
104 return SZ_ERROR_READ;
105 }
106 else
107 {
108 *size = bytesreturned;
109 return SZ_OK;
110 }
111 }
112
113 typedef struct gate_xz_write_stream_class
114 {
115 ISeqOutStream seqoutstream;
116 gate_stream_t* gatestream;
117 } gate_xz_write_stream_t;
118
119 static size_t gate_xz_stream_write(ISeqOutStream const* p, const void* buf, size_t size)
120 {
121 gate_xz_write_stream_t const* writer = (gate_xz_write_stream_t const*)(p);
122 gate_size_t byteswritten;
123 gate_result_t result;
124 if (size == 0)
125 {
126 return 0;
127 }
128
129 result = gate_stream_write_block(writer->gatestream, (char const*)buf, size, &byteswritten);
130 if (GATE_FAILED(result))
131 {
132 return 0;
133 }
134 else
135 {
136 return byteswritten;
137 }
138 }
139
140 static SRes gate_xz_stream_progress(ICompressProgress const* p, UInt64 inSize, UInt64 outSize)
141 {
142 return SZ_OK;
143 }
144
145
146 gate_result_t gate_xz_encode(gate_stream_t* input, gate_uint64_t const* ptrInputSize, gate_int16_t compression, gate_stream_t* output)
147 {
148 gate_xz_read_stream_t reader;
149 gate_xz_write_stream_t writer;
150 ICompressProgress progress;
151 gate_result_t result;
152 SRes xzresult;
153 CLzma2EncProps lzma2props;
154 CXzProps xzprops;
155
156 gate_xz_init();
157
158 reader.seqinstream.Read = &gate_xz_stream_read;
159 reader.gatestream = input;
160
161 writer.seqoutstream.Write = &gate_xz_stream_write;
162 writer.gatestream = output;
163
164 progress.Progress = &gate_xz_stream_progress;
165
166 Lzma2EncProps_Init(&lzma2props);
167 lzma2props.numTotalThreads = 1;
168
169 switch (compression)
170 {
171 case GATE_XZ_COMPRESSION_MINIMUM: { lzma2props.lzmaProps.level = 1; lzma2props.lzmaProps.dictSize = (1 << 16); break; }
172 case GATE_XZ_COMPRESSION_LOW: { lzma2props.lzmaProps.level = 3; lzma2props.lzmaProps.dictSize = (1 << 20); break; }
173 case GATE_XZ_COMPRESSION_MEDIUM: { lzma2props.lzmaProps.level = 5; lzma2props.lzmaProps.dictSize = (1 << 22); break; }
174 case GATE_XZ_COMPRESSION_HIGH: { lzma2props.lzmaProps.level = 7; lzma2props.lzmaProps.dictSize = (1 << 24); break; }
175 case GATE_XZ_COMPRESSION_MAXIMUM: { lzma2props.lzmaProps.level = 9; lzma2props.lzmaProps.dictSize = (1 << 25); break; }
176 default: { return GATE_RESULT_INVALIDARG; }
177 }
178
179 Lzma2EncProps_Normalize(&lzma2props);
180 XzProps_Init(&xzprops);
181 xzprops.lzma2Props = lzma2props;
182
183 xzresult = Xz_Encode(&writer.seqoutstream, &reader.seqinstream, &xzprops, &progress);
184 if (xzresult == SZ_OK)
185 {
186 result = GATE_RESULT_OK;
187 }
188 else
189 {
190 result = GATE_RESULT_FAILED;
191 }
192
193 return result;
194 }
195
196
197 /* output stream encoder implementation */
198
199 static void gate_xzencoder_release_impl(void* self);
200 static int gate_xzencoder_retain_impl(void* self);
201 static char const* gate_xzencoder_interface_name_impl(void* self)
202 {
203 GATE_UNUSED_ARG(self);
204 return GATE_INTERFACE_NAME_STREAM;
205 }
206 static gate_result_t gate_xzencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
207 static gate_result_t gate_xzencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
208 static gate_result_t gate_xzencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
209 static gate_result_t gate_xzencoder_flush_impl(void* self);
210
211 static GATE_INTERFACE_VTBL(gate_stream) gate_xzencoder_vtbl;
212 static void gate_init_xzencoder_vtbl()
213 {
214 if (!gate_xzencoder_vtbl.get_interface_name)
215 {
216 GATE_INTERFACE_VTBL(gate_stream) local_vtbl =
217 {
218 &gate_xzencoder_interface_name_impl,
219 &gate_xzencoder_release_impl,
220 &gate_xzencoder_retain_impl,
221 &gate_xzencoder_read_impl,
222 &gate_xzencoder_peek_impl,
223 &gate_xzencoder_write_impl,
224 &gate_xzencoder_flush_impl
225 };
226 gate_xzencoder_vtbl = local_vtbl;
227 }
228 }
229
230 typedef struct gate_xzencoder_impl
231 {
232 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
233
234 gate_atomic_int_t ref_counter;
235 gate_stream_t* dest_stream;
236 gate_memstream_t* mem_stream;
237 gate_int16_t compression;
238 gate_bool_t is_flushed;
239
240 } gate_xzencoder_impl_t;
241
242 gate_result_t gate_xz_encoder_create(gate_stream_t* output, gate_int16_t compression, gate_stream_t** ptr2streamptr)
243 {
244 gate_result_t ret;
245 gate_xzencoder_impl_t* impl;
246
247 gate_xz_init();
248
249 do
250 {
251 if ((output == NULL) || (ptr2streamptr == NULL))
252 {
253 ret = GATE_RESULT_NULLPOINTER;
254 break;
255 }
256 impl = (gate_xzencoder_impl_t*)gate_mem_alloc(sizeof(gate_xzencoder_impl_t));
257 if (impl == NULL)
258 {
259 ret = GATE_RESULT_OUTOFMEMORY;
260 break;
261 }
262
263 gate_mem_clear(impl, sizeof(gate_xzencoder_impl_t));
264 gate_init_xzencoder_vtbl();
265 impl->vtbl = &gate_xzencoder_vtbl;
266 gate_atomic_int_init(&impl->ref_counter, 1);
267 impl->dest_stream = output;
268
269 impl->compression = compression;
270
271 impl->mem_stream = gate_memstream_create(GATE_MAX_BLOCK_COPYBUFFER_LENGTH);
272 if (impl->mem_stream == NULL)
273 {
274 ret = GATE_RESULT_OUTOFMEMORY;
275 break;
276 }
277
278 gate_object_retain(impl->dest_stream);
279 *ptr2streamptr = (gate_stream_t*)impl;
280
281 ret = GATE_RESULT_OK;
282 } while (0);
283 return ret;
284 }
285
286 static void gate_xzencoder_release_impl(void* self)
287 {
288 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
289 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
290 {
291 gate_xzencoder_flush_impl(self);
292 gate_object_release(impl->mem_stream);
293 gate_object_release(impl->dest_stream);
294 gate_mem_dealloc(impl);
295 }
296 }
297 static int gate_xzencoder_retain_impl(void* self)
298 {
299 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
300 return gate_atomic_int_inc(&impl->ref_counter);
301 }
302 static gate_result_t gate_xzencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
303 {
304 GATE_UNUSED_ARG(self);
305 GATE_UNUSED_ARG(buffer);
306 GATE_UNUSED_ARG(bufferlength);
307 GATE_UNUSED_ARG(returned);
308 return GATE_RESULT_NOTSUPPORTED;
309 }
310 static gate_result_t gate_xzencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
311 {
312 GATE_UNUSED_ARG(self);
313 GATE_UNUSED_ARG(buffer);
314 GATE_UNUSED_ARG(bufferlength);
315 GATE_UNUSED_ARG(returned);
316 return GATE_RESULT_NOTSUPPORTED;
317 }
318 static gate_result_t gate_xzencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
319 {
320 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
321 return gate_stream_write_block((gate_stream_t*)impl->mem_stream, buffer, bufferlength, written);
322 }
323 static gate_result_t gate_xzencoder_flush_impl(void* self)
324 {
325 gate_result_t ret = GATE_RESULT_OK;
326 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
327 gate_uint64_t source_size;
328
329 if (!impl->is_flushed)
330 {
331 source_size = gate_memstream_size(impl->mem_stream);
332 ret = gate_xz_encode((gate_stream_t*)impl->mem_stream, &source_size, impl->compression, impl->dest_stream);
333 impl->is_flushed = true;
334 }
335 return ret;
336 }
337
338
339
340
341 /* input stream decoder implementation */
342
343 static void gate_xzdecoder_release_impl(void* self);
344 static int gate_xzdecoder_retain_impl(void* self);
345 static char const* gate_xzdecoder_interface_name_impl(void* self)
346 {
347 GATE_UNUSED_ARG(self);
348 return GATE_INTERFACE_NAME_STREAM;
349 }
350 static gate_result_t gate_xzdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
351 static gate_result_t gate_xzdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
352 static gate_result_t gate_xzdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
353 static gate_result_t gate_xzdecoder_flush_impl(void* self);
354
355 static GATE_INTERFACE_VTBL(gate_stream) gate_xzdecoder_vtbl;
356 static void gate_init_xzdecoder_vtbl()
357 {
358 if (!gate_xzdecoder_vtbl.get_interface_name)
359 {
360 GATE_INTERFACE_VTBL(gate_stream) const local_vtbl =
361 {
362 &gate_xzdecoder_interface_name_impl,
363 &gate_xzdecoder_release_impl,
364 &gate_xzdecoder_retain_impl,
365 &gate_xzdecoder_read_impl,
366 &gate_xzdecoder_peek_impl,
367 &gate_xzdecoder_write_impl,
368 &gate_xzdecoder_flush_impl
369 };
370 gate_xzdecoder_vtbl = local_vtbl;
371 }
372 }
373
374 typedef struct gate_xzdecoder_impl
375 {
376 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
377
378 gate_atomic_int_t ref_counter;
379 gate_stream_t* source_stream;
380 CXzUnpacker decoder;
381 char source_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH];
382 gate_size_t source_buffer_offset;
383 gate_size_t source_buffer_length;
384 char decoded_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH];
385 gate_size_t decoded_buffer_offset;
386 gate_size_t decoded_buffer_length;
387 gate_bool_t finished;
388
389 } gate_xzdecoder_impl_t;
390
391 gate_result_t gate_xz_decoder_create(gate_stream_t* input, gate_stream_t** ptr2streamptr)
392 {
393 gate_result_t ret;
394 gate_xzdecoder_impl_t* impl;
395
396 gate_xz_init();
397
398 do
399 {
400 if ((input == NULL) || (ptr2streamptr == NULL))
401 {
402 ret = GATE_RESULT_NULLPOINTER;
403 break;
404 }
405 impl = (gate_xzdecoder_impl_t*)gate_mem_alloc(sizeof(gate_xzdecoder_impl_t));
406 if (impl == NULL)
407 {
408 ret = GATE_RESULT_OUTOFMEMORY;
409 break;
410 }
411
412 gate_mem_clear(impl, sizeof(gate_xzdecoder_impl_t));
413 gate_init_xzdecoder_vtbl();
414 impl->vtbl = &gate_xzdecoder_vtbl;
415 gate_atomic_int_init(&impl->ref_counter, 1);
416 impl->source_stream = input;
417
418 XzUnpacker_Construct(&impl->decoder, &gate_xz_allocator);
419 XzUnpacker_Init(&impl->decoder);
420
421 gate_object_retain(impl->source_stream);
422 *ptr2streamptr = (gate_stream_t*)impl;
423
424 ret = GATE_RESULT_OK;
425 } while (0);
426
427 return ret;
428 }
429
430
431 void gate_xzdecoder_release_impl(void* self)
432 {
433 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
434 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
435 {
436 XzUnpacker_Free(&impl->decoder);
437 gate_object_release(impl->source_stream);
438 gate_mem_dealloc(impl);
439 }
440 }
441 int gate_xzdecoder_retain_impl(void* self)
442 {
443 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
444 return gate_atomic_int_inc(&impl->ref_counter);
445 }
446
447 gate_result_t gate_xzdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
448 {
449 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
450 gate_size_t bytecount;
451 gate_result_t result;
452 SizeT inbytecount, outbytecount;
453 int xzresult;
454 ECoderStatus status;
455
456 while ((!impl->finished) && (impl->decoded_buffer_length == 0))
457 {
458 if (impl->source_buffer_length != sizeof(impl->source_buffer))
459 {
460 if (impl->source_buffer_offset != 0)
461 {
462 if (impl->source_buffer_length != 0)
463 {
464 gate_mem_move(&impl->source_buffer[0], &impl->source_buffer[impl->source_buffer_offset], impl->source_buffer_length);
465 }
466 impl->source_buffer_offset = 0;
467 }
468 result = gate_stream_read_block(impl->source_stream, &impl->source_buffer[impl->source_buffer_length],
469 sizeof(impl->source_buffer) - impl->source_buffer_length, &bytecount);
470 if (GATE_FAILED(result))
471 {
472 return result;
473 }
474 impl->source_buffer_length += bytecount;
475 }
476
477 outbytecount = sizeof(impl->decoded_buffer);
478 inbytecount = impl->source_buffer_length;
479 xzresult = XzUnpacker_Code(&impl->decoder, (Byte*)&impl->decoded_buffer[0], &outbytecount,
480 (Byte const*)&impl->source_buffer[impl->source_buffer_offset], &inbytecount, True, CODER_FINISH_ANY, &status);
481
482 if (xzresult != SZ_OK)
483 {
484 if (xzresult == SZ_ERROR_INPUT_EOF)
485 {
486 outbytecount = 0;
487 }
488 else
489 {
490 return GATE_RESULT_FAILED;
491 }
492 }
493
494 GATE_DEBUG_ASSERT(inbytecount <= impl->source_buffer_length);
495 impl->source_buffer_offset += inbytecount;
496 impl->source_buffer_length -= inbytecount;
497
498 impl->decoded_buffer_offset = 0;
499 impl->decoded_buffer_length = outbytecount;
500
501 if (status == CODER_STATUS_FINISHED_WITH_MARK)
502 {
503 impl->finished = true;
504 }
505 if ((inbytecount == 0) && (outbytecount == 0))
506 {
507 /* no data could be read and nothing was decoded ... this my lead to endless loops */
508 impl->finished = true;
509 }
510 if (impl->finished)
511 {
512 XzUnpacker_IsStreamWasFinished(&impl->decoder);
513 }
514
515 }
516
517 bytecount = bufferlength < impl->decoded_buffer_length ? bufferlength : impl->decoded_buffer_length;
518 if (bytecount > 0)
519 {
520 gate_mem_copy(buffer, &impl->decoded_buffer[impl->decoded_buffer_offset], bytecount);
521 }
522 if (returned != NULL)
523 {
524 *returned = bytecount;
525 }
526 return GATE_RESULT_OK;
527 }
528
529 gate_result_t gate_xzdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
530 {
531 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
532 gate_size_t tmp = 0;
533 gate_result_t ret = gate_xzdecoder_peek_impl(self, buffer, bufferlength, &tmp);
534 if (returned != NULL)
535 {
536 *returned = tmp;
537 }
538 if (GATE_SUCCEEDED(ret))
539 {
540 impl->decoded_buffer_offset += tmp;
541 impl->decoded_buffer_length -= tmp;
542 }
543 return ret;
544 }
545 gate_result_t gate_xzdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
546 {
547 GATE_UNUSED_ARG(self);
548 GATE_UNUSED_ARG(buffer);
549 GATE_UNUSED_ARG(bufferlength);
550 GATE_UNUSED_ARG(written);
551 return GATE_RESULT_NOTSUPPORTED;
552 }
553 gate_result_t gate_xzdecoder_flush_impl(void* self)
554 {
555 GATE_UNUSED_ARG(self);
556 return GATE_RESULT_NOTSUPPORTED;
557 }
558
559 #endif /* GATE_ENCODE_XZSTREAM_USE_LZMA */
560
561
562 #if defined(GATE_ENCODE_XZSTREAM_NO_IMPL)
563
564 gate_result_t gate_xz_encode(gate_stream_t* input, gate_uint64_t const* ptrInputSize, gate_int16_t compression, gate_stream_t* output)
565 {
566 (void)input;
567 (void)ptrInputSize;
568 (void)compression;
569 (void)output;
570 return GATE_RESULT_NOTSUPPORTED;
571 }
572 gate_result_t gate_xz_encoder_create(gate_stream_t* output, gate_int16_t compression, gate_stream_t** ptr2streamptr)
573 {
574 (void)output;
575 (void)compression;
576 (void)ptr2streamptr;
577 return GATE_RESULT_NOTSUPPORTED;
578 }
579
580 gate_result_t gate_xz_decoder_create(gate_stream_t* input, gate_stream_t** ptr2streamptr)
581 {
582 (void)input;
583 (void)ptr2streamptr;
584 return GATE_RESULT_NOTSUPPORTED;
585 }
586
587 #endif /* GATE_ENCODE_XZSTREAM_NO_IMPL */
588
589