GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/xzstreams.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 162 187 86.6%
Functions: 13 14 92.9%
Branches: 64 100 64.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, 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_LZMASDK) && !defined(GATE_ENCODE_NO_ADVANCED_COMPRESSION)
36 # define GATE_ENCODE_XZSTREAM_USE_LZMASDK 1
37 #elif defined(GATE_EXTLIB_XZUTILS) && !defined(GATE_ENCODE_NO_ADVANCED_COMPRESSION)
38 # define GATE_ENCODE_XZSTREAM_USE_LIBLZMA 1
39 # if defined(GATE_EXTLIB_XZUTILS_STATIC)
40 # define GATE_ENCODE_XZSTREAM_USE_LIBLZMA_STATIC 1
41 # endif
42 #else
43 # define GATE_ENCODE_XZSTREAM_NO_IMPL
44 #endif
45
46
47 #if defined(GATE_ENCODE_XZSTREAM_USE_LZMASDK)
48
49 #include "Xz.h"
50 #include "XzEnc.h"
51 #include "7zCrc.h"
52 #include "XzCrc64.h"
53 #include "Lzma2Dec.h"
54 #include "Lzma2Enc.h"
55
56 static void gate_xz_init_impl(void)
57 {
58 CrcGenerateTable();
59 Crc64GenerateTable();
60 }
61
62 static void gate_xz_init()
63 {
64 static gate_atomic_flag_t is_initialized = GATE_ATOMIC_FLAG_INIT;
65
66 gate_atomic_call_once_exclusive(&is_initialized, &gate_xz_init_impl);
67 }
68
69 static void* gate_xz_alloc(ISzAllocPtr p, size_t sz)
70 {
71 (void)p;
72 if (sz == 0)
73 {
74 return NULL;
75 }
76 else
77 {
78 return gate_mem_alloc(sz);
79 }
80 }
81 static void gate_xz_free(ISzAllocPtr p, void* ptrAddress)
82 {
83 (void)p;
84 if (ptrAddress != NULL)
85 {
86 gate_mem_dealloc(ptrAddress);
87 }
88 }
89
90 static ISzAlloc gate_xz_allocator =
91 {
92 &gate_xz_alloc, &gate_xz_free
93 };
94
95
96
97 typedef struct gate_xz_read_stream_class
98 {
99 ISeqInStream seqinstream;
100 gate_stream_t* gatestream;
101 } gate_xz_read_stream_t;
102
103 static SRes gate_xz_stream_read(ISeqInStream const* p, void* buf, size_t* size)
104 {
105 gate_xz_read_stream_t const* reader = (gate_xz_read_stream_t const*)(p);
106 gate_size_t bytesreturned = 0;
107 gate_result_t result = gate_stream_read_block(reader->gatestream, (char*)buf, *size, &bytesreturned);
108 if (GATE_FAILED(result))
109 {
110 return SZ_ERROR_READ;
111 }
112 else
113 {
114 *size = bytesreturned;
115 return SZ_OK;
116 }
117 }
118
119 typedef struct gate_xz_write_stream_class
120 {
121 ISeqOutStream seqoutstream;
122 gate_stream_t* gatestream;
123 } gate_xz_write_stream_t;
124
125 static size_t gate_xz_stream_write(ISeqOutStream const* p, const void* buf, size_t size)
126 {
127 gate_xz_write_stream_t const* writer = (gate_xz_write_stream_t const*)(p);
128 gate_size_t byteswritten;
129 gate_result_t result;
130 if (size == 0)
131 {
132 return 0;
133 }
134
135 result = gate_stream_write_block(writer->gatestream, (char const*)buf, size, &byteswritten);
136 if (GATE_FAILED(result))
137 {
138 return 0;
139 }
140 else
141 {
142 return byteswritten;
143 }
144 }
145
146 static SRes gate_xz_stream_progress(ICompressProgress const* p, UInt64 inSize, UInt64 outSize)
147 {
148 return SZ_OK;
149 }
150
151
152 gate_result_t gate_xz_encode(gate_stream_t* input, gate_uint64_t const* ptrInputSize, gate_int16_t compression, gate_stream_t* output)
153 {
154 gate_xz_read_stream_t reader;
155 gate_xz_write_stream_t writer;
156 ICompressProgress progress;
157 gate_result_t result;
158 SRes xzresult;
159 CLzma2EncProps lzma2props;
160 CXzProps xzprops;
161
162 gate_xz_init();
163
164 reader.seqinstream.Read = &gate_xz_stream_read;
165 reader.gatestream = input;
166
167 writer.seqoutstream.Write = &gate_xz_stream_write;
168 writer.gatestream = output;
169
170 progress.Progress = &gate_xz_stream_progress;
171
172 Lzma2EncProps_Init(&lzma2props);
173 lzma2props.numTotalThreads = 1;
174
175 switch (compression)
176 {
177 case GATE_XZ_COMPRESSION_MINIMUM: { lzma2props.lzmaProps.level = 1; lzma2props.lzmaProps.dictSize = (1 << 16); break; }
178 case GATE_XZ_COMPRESSION_LOW: { lzma2props.lzmaProps.level = 3; lzma2props.lzmaProps.dictSize = (1 << 20); break; }
179 case GATE_XZ_COMPRESSION_MEDIUM: { lzma2props.lzmaProps.level = 5; lzma2props.lzmaProps.dictSize = (1 << 22); break; }
180 case GATE_XZ_COMPRESSION_HIGH: { lzma2props.lzmaProps.level = 7; lzma2props.lzmaProps.dictSize = (1 << 24); break; }
181 case GATE_XZ_COMPRESSION_MAXIMUM: { lzma2props.lzmaProps.level = 9; lzma2props.lzmaProps.dictSize = (1 << 25); break; }
182 default: { return GATE_RESULT_INVALIDARG; }
183 }
184
185 Lzma2EncProps_Normalize(&lzma2props);
186 XzProps_Init(&xzprops);
187 xzprops.lzma2Props = lzma2props;
188
189 xzresult = Xz_Encode(&writer.seqoutstream, &reader.seqinstream, &xzprops, &progress);
190 if (xzresult == SZ_OK)
191 {
192 result = GATE_RESULT_OK;
193 }
194 else
195 {
196 result = GATE_RESULT_FAILED;
197 }
198
199 return result;
200 }
201
202
203 /* output stream encoder implementation */
204
205 static void gate_xzencoder_release_impl(void* self);
206 static int gate_xzencoder_retain_impl(void* self);
207 static char const* gate_xzencoder_interface_name_impl(void* self)
208 {
209 GATE_UNUSED_ARG(self);
210 return GATE_INTERFACE_NAME_STREAM;
211 }
212 static gate_result_t gate_xzencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
213 static gate_result_t gate_xzencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
214 static gate_result_t gate_xzencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
215 static gate_result_t gate_xzencoder_flush_impl(void* self);
216
217 static GATE_INTERFACE_VTBL(gate_stream) gate_xzencoder_vtbl;
218 static void gate_init_xzencoder_vtbl()
219 {
220 if (!gate_xzencoder_vtbl.get_interface_name)
221 {
222 GATE_INTERFACE_VTBL(gate_stream) local_vtbl =
223 {
224 &gate_xzencoder_interface_name_impl,
225 &gate_xzencoder_release_impl,
226 &gate_xzencoder_retain_impl,
227 &gate_xzencoder_read_impl,
228 &gate_xzencoder_peek_impl,
229 &gate_xzencoder_write_impl,
230 &gate_xzencoder_flush_impl
231 };
232 gate_xzencoder_vtbl = local_vtbl;
233 }
234 }
235
236 typedef struct gate_xzencoder_impl
237 {
238 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
239
240 gate_atomic_int_t ref_counter;
241 gate_stream_t* dest_stream;
242 gate_memstream_t* mem_stream;
243 gate_int16_t compression;
244 gate_bool_t is_flushed;
245
246 } gate_xzencoder_impl_t;
247
248 gate_result_t gate_xz_encoder_create(gate_stream_t* output, gate_int16_t compression, gate_stream_t** ptr2streamptr)
249 {
250 gate_result_t ret;
251 gate_xzencoder_impl_t* impl;
252
253 gate_xz_init();
254
255 do
256 {
257 if ((output == NULL) || (ptr2streamptr == NULL))
258 {
259 ret = GATE_RESULT_NULLPOINTER;
260 break;
261 }
262 impl = (gate_xzencoder_impl_t*)gate_mem_alloc(sizeof(gate_xzencoder_impl_t));
263 if (impl == NULL)
264 {
265 ret = GATE_RESULT_OUTOFMEMORY;
266 break;
267 }
268
269 gate_mem_clear(impl, sizeof(gate_xzencoder_impl_t));
270 gate_init_xzencoder_vtbl();
271 impl->vtbl = &gate_xzencoder_vtbl;
272 gate_atomic_int_init(&impl->ref_counter, 1);
273 impl->dest_stream = output;
274
275 impl->compression = compression;
276
277 impl->mem_stream = gate_memstream_create(GATE_MAX_BLOCK_COPYBUFFER_LENGTH);
278 if (impl->mem_stream == NULL)
279 {
280 ret = GATE_RESULT_OUTOFMEMORY;
281 break;
282 }
283
284 gate_object_retain(impl->dest_stream);
285 *ptr2streamptr = (gate_stream_t*)impl;
286
287 ret = GATE_RESULT_OK;
288 } while (0);
289 return ret;
290 }
291
292 static void gate_xzencoder_release_impl(void* self)
293 {
294 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
295 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
296 {
297 gate_xzencoder_flush_impl(self);
298 gate_object_release(impl->mem_stream);
299 gate_object_release(impl->dest_stream);
300 gate_mem_dealloc(impl);
301 }
302 }
303 static int gate_xzencoder_retain_impl(void* self)
304 {
305 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
306 return gate_atomic_int_inc(&impl->ref_counter);
307 }
308 static gate_result_t gate_xzencoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
309 {
310 GATE_UNUSED_ARG(self);
311 GATE_UNUSED_ARG(buffer);
312 GATE_UNUSED_ARG(bufferlength);
313 GATE_UNUSED_ARG(returned);
314 return GATE_RESULT_NOTSUPPORTED;
315 }
316 static gate_result_t gate_xzencoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
317 {
318 GATE_UNUSED_ARG(self);
319 GATE_UNUSED_ARG(buffer);
320 GATE_UNUSED_ARG(bufferlength);
321 GATE_UNUSED_ARG(returned);
322 return GATE_RESULT_NOTSUPPORTED;
323 }
324 static gate_result_t gate_xzencoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
325 {
326 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
327 return gate_stream_write_block((gate_stream_t*)impl->mem_stream, buffer, bufferlength, written);
328 }
329 static gate_result_t gate_xzencoder_flush_impl(void* self)
330 {
331 gate_result_t ret = GATE_RESULT_OK;
332 gate_xzencoder_impl_t* impl = (gate_xzencoder_impl_t*)self;
333 gate_uint64_t source_size;
334
335 if (!impl->is_flushed)
336 {
337 source_size = gate_memstream_size(impl->mem_stream);
338 ret = gate_xz_encode((gate_stream_t*)impl->mem_stream, &source_size, impl->compression, impl->dest_stream);
339 impl->is_flushed = true;
340 }
341 return ret;
342 }
343
344
345
346
347 /* input stream decoder implementation */
348
349 static void gate_xzdecoder_release_impl(void* self);
350 static int gate_xzdecoder_retain_impl(void* self);
351 static char const* gate_xzdecoder_interface_name_impl(void* self)
352 {
353 GATE_UNUSED_ARG(self);
354 return GATE_INTERFACE_NAME_STREAM;
355 }
356 static gate_result_t gate_xzdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
357 static gate_result_t gate_xzdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
358 static gate_result_t gate_xzdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
359 static gate_result_t gate_xzdecoder_flush_impl(void* self);
360
361 static GATE_INTERFACE_VTBL(gate_stream) gate_xzdecoder_vtbl;
362 static void gate_init_xzdecoder_vtbl()
363 {
364 if (!gate_xzdecoder_vtbl.get_interface_name)
365 {
366 GATE_INTERFACE_VTBL(gate_stream) const local_vtbl =
367 {
368 &gate_xzdecoder_interface_name_impl,
369 &gate_xzdecoder_release_impl,
370 &gate_xzdecoder_retain_impl,
371 &gate_xzdecoder_read_impl,
372 &gate_xzdecoder_peek_impl,
373 &gate_xzdecoder_write_impl,
374 &gate_xzdecoder_flush_impl
375 };
376 gate_xzdecoder_vtbl = local_vtbl;
377 }
378 }
379
380 typedef struct gate_xzdecoder_impl
381 {
382 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
383
384 gate_atomic_int_t ref_counter;
385 gate_stream_t* source_stream;
386 CXzUnpacker decoder;
387 char source_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH];
388 gate_size_t source_buffer_offset;
389 gate_size_t source_buffer_length;
390 char decoded_buffer[GATE_MAX_BLOCK_COPYBUFFER_LENGTH];
391 gate_size_t decoded_buffer_offset;
392 gate_size_t decoded_buffer_length;
393 gate_bool_t finished;
394
395 } gate_xzdecoder_impl_t;
396
397 gate_result_t gate_xz_decoder_create(gate_stream_t* input, gate_stream_t** ptr2streamptr)
398 {
399 gate_result_t ret;
400 gate_xzdecoder_impl_t* impl;
401
402 gate_xz_init();
403
404 do
405 {
406 if ((input == NULL) || (ptr2streamptr == NULL))
407 {
408 ret = GATE_RESULT_NULLPOINTER;
409 break;
410 }
411 impl = (gate_xzdecoder_impl_t*)gate_mem_alloc(sizeof(gate_xzdecoder_impl_t));
412 if (impl == NULL)
413 {
414 ret = GATE_RESULT_OUTOFMEMORY;
415 break;
416 }
417
418 gate_mem_clear(impl, sizeof(gate_xzdecoder_impl_t));
419 gate_init_xzdecoder_vtbl();
420 impl->vtbl = &gate_xzdecoder_vtbl;
421 gate_atomic_int_init(&impl->ref_counter, 1);
422 impl->source_stream = input;
423
424 XzUnpacker_Construct(&impl->decoder, &gate_xz_allocator);
425 XzUnpacker_Init(&impl->decoder);
426
427 gate_object_retain(impl->source_stream);
428 *ptr2streamptr = (gate_stream_t*)impl;
429
430 ret = GATE_RESULT_OK;
431 } while (0);
432
433 return ret;
434 }
435
436
437 void gate_xzdecoder_release_impl(void* self)
438 {
439 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
440 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
441 {
442 XzUnpacker_Free(&impl->decoder);
443 gate_object_release(impl->source_stream);
444 gate_mem_dealloc(impl);
445 }
446 }
447 int gate_xzdecoder_retain_impl(void* self)
448 {
449 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
450 return gate_atomic_int_inc(&impl->ref_counter);
451 }
452
453 gate_result_t gate_xzdecoder_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
454 {
455 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
456 gate_size_t bytecount;
457 gate_result_t result;
458 SizeT inbytecount, outbytecount;
459 int xzresult;
460 ECoderStatus status;
461
462 while ((!impl->finished) && (impl->decoded_buffer_length == 0))
463 {
464 if (impl->source_buffer_length != sizeof(impl->source_buffer))
465 {
466 if (impl->source_buffer_offset != 0)
467 {
468 if (impl->source_buffer_length != 0)
469 {
470 gate_mem_move(&impl->source_buffer[0], &impl->source_buffer[impl->source_buffer_offset], impl->source_buffer_length);
471 }
472 impl->source_buffer_offset = 0;
473 }
474 result = gate_stream_read_block(impl->source_stream, &impl->source_buffer[impl->source_buffer_length],
475 sizeof(impl->source_buffer) - impl->source_buffer_length, &bytecount);
476 if (GATE_FAILED(result))
477 {
478 return result;
479 }
480 impl->source_buffer_length += bytecount;
481 }
482
483 outbytecount = sizeof(impl->decoded_buffer);
484 inbytecount = impl->source_buffer_length;
485 xzresult = XzUnpacker_Code(&impl->decoder, (Byte*)&impl->decoded_buffer[0], &outbytecount,
486 (Byte const*)&impl->source_buffer[impl->source_buffer_offset], &inbytecount, True, CODER_FINISH_ANY, &status);
487
488 if (xzresult != SZ_OK)
489 {
490 if (xzresult == SZ_ERROR_INPUT_EOF)
491 {
492 outbytecount = 0;
493 }
494 else
495 {
496 return GATE_RESULT_FAILED;
497 }
498 }
499
500 GATE_DEBUG_ASSERT(inbytecount <= impl->source_buffer_length);
501 impl->source_buffer_offset += inbytecount;
502 impl->source_buffer_length -= inbytecount;
503
504 impl->decoded_buffer_offset = 0;
505 impl->decoded_buffer_length = outbytecount;
506
507 if (status == CODER_STATUS_FINISHED_WITH_MARK)
508 {
509 impl->finished = true;
510 }
511 if ((inbytecount == 0) && (outbytecount == 0))
512 {
513 /* no data could be read and nothing was decoded ... this my lead to endless loops */
514 impl->finished = true;
515 }
516 if (impl->finished)
517 {
518 XzUnpacker_IsStreamWasFinished(&impl->decoder);
519 }
520
521 }
522
523 bytecount = bufferlength < impl->decoded_buffer_length ? bufferlength : impl->decoded_buffer_length;
524 if (bytecount > 0)
525 {
526 gate_mem_copy(buffer, &impl->decoded_buffer[impl->decoded_buffer_offset], bytecount);
527 }
528 if (returned != NULL)
529 {
530 *returned = bytecount;
531 }
532 return GATE_RESULT_OK;
533 }
534
535 gate_result_t gate_xzdecoder_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
536 {
537 gate_xzdecoder_impl_t* impl = (gate_xzdecoder_impl_t*)self;
538 gate_size_t tmp = 0;
539 gate_result_t ret = gate_xzdecoder_peek_impl(self, buffer, bufferlength, &tmp);
540 if (returned != NULL)
541 {
542 *returned = tmp;
543 }
544 if (GATE_SUCCEEDED(ret))
545 {
546 impl->decoded_buffer_offset += tmp;
547 impl->decoded_buffer_length -= tmp;
548 }
549 return ret;
550 }
551 gate_result_t gate_xzdecoder_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
552 {
553 GATE_UNUSED_ARG(self);
554 GATE_UNUSED_ARG(buffer);
555 GATE_UNUSED_ARG(bufferlength);
556 GATE_UNUSED_ARG(written);
557 return GATE_RESULT_NOTSUPPORTED;
558 }
559 gate_result_t gate_xzdecoder_flush_impl(void* self)
560 {
561 GATE_UNUSED_ARG(self);
562 return GATE_RESULT_NOTSUPPORTED;
563 }
564
565 #endif /* GATE_ENCODE_XZSTREAM_USE_LZMASDK */
566
567
568 #if defined(GATE_ENCODE_XZSTREAM_USE_LIBLZMA)
569
570 #include <lzma.h>
571 #include "gate/libraries.h"
572
573 gate_result_t gate_xz_encode(gate_stream_t* input, gate_uint64_t const* ptrInputSize, gate_int16_t compression, gate_stream_t* output)
574 {
575 return GATE_RESULT_NOTIMPLEMENTED;
576 }
577
578 typedef struct gate_lzma_functions
579 {
580 lzma_ret (*easy_encoder)(lzma_stream *strm, uint32_t preset, lzma_check check);
581 lzma_ret (*stream_decoder)(lzma_stream *strm, uint64_t memlimit, uint32_t flags);
582 lzma_ret (*code)(lzma_stream *strm, lzma_action action);
583 void (*end)(lzma_stream *strm);
584 } gate_lzma_functions_t;
585
586 static gate_lzma_functions_t lzma;
587
588 #if defined(GATE_ENCODE_XZSTREAM_USE_LIBLZMA_STATIC)
589
590 3 static gate_result_t load_lzma_functions()
591 {
592
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(lzma.easy_encoder == NULL)
593 {
594 1 lzma.easy_encoder = &lzma_easy_encoder;
595 1 lzma.stream_decoder = &lzma_stream_decoder;
596 1 lzma.code = &lzma_code;
597 1 lzma.end = &lzma_end;
598 }
599 3 return GATE_RESULT_OK;
600 }
601
602 #else
603
604 static gate_result_t load_lzma_functions()
605 {
606 static gate_string_t const lzma_libname = GATE_STRING_INIT_STATIC("liblzma.so");
607 static gate_library_t lzma_lib = NULL;
608 gate_result_t ret;
609
610 if(lzma_lib == NULL)
611 {
612 gate_library_t lib = NULL;
613 do
614 {
615 ret = gate_library_open(&lzma_libname, &lib, GATE_LIBRARY_FLAG_DEFAULT);
616 GATE_BREAK_IF_FAILED(ret);
617
618 ret = gate_library_get_function_name(lib, "lzma_easy_encoder", &lzma.easy_encoder);
619 GATE_BREAK_IF_FAILED(ret);
620 ret = gate_library_get_function_name(lib, "lzma_stream_decoder", &lzma.stream_decoder);
621 GATE_BREAK_IF_FAILED(ret);
622 ret = gate_library_get_function_name(lib, "lzma_code", &lzma.code);
623 GATE_BREAK_IF_FAILED(ret);
624 ret = gate_library_get_function_name(lib, "lzma_end", &lzma.end);
625 GATE_BREAK_IF_FAILED(ret);
626
627 lzma_lib = lib;
628 lib = NULL;
629 ret = GATE_RESULT_OK;
630 } while (0);
631
632 if(lib)
633 {
634 gate_library_close(lib);
635 }
636 return ret;
637 }
638 return GATE_RESULT_OK;
639 }
640
641 #endif
642
643 typedef struct lzmacodec_class
644 {
645 GATE_INTERFACE_VTBL(gate_stream) const* vtbl;
646
647 gate_atomic_int_t ref_counter;
648 gate_bool_t encoder;
649 gate_stream_t* target;
650 char inputbuf[GATE_MAX_COPYBUFFER_LENGTH];
651 gate_size_t inputbuf_used;
652 char peekbuf[GATE_MAX_COPYBUFFER_LENGTH];
653 gate_size_t peekbuf_used;
654 lzma_stream codec;
655 } lzmacodec_t;
656
657 3 static char const* lzmacodec_get_interface_name(void* obj)
658 {
659 3 lzmacodec_t* const self = (lzmacodec_t*)obj;
660 3 return GATE_INTERFACE_NAME_STREAM;
661 }
662
663 5 static void lzmacodec_release(void* obj)
664 {
665 5 lzmacodec_t* const self = (lzmacodec_t*)obj;
666
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
5 if (gate_atomic_int_dec(&self->ref_counter) == 0)
667 {
668 3 lzma.end(&self->codec);
669
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(self->target)
670 {
671 1 gate_object_release(self->target);
672 }
673 3 gate_mem_dealloc(self);
674 }
675 5 }
676
677 2 static int lzmacodec_retain(void* obj)
678 {
679 2 lzmacodec_t* const self = (lzmacodec_t*)obj;
680 2 return gate_atomic_int_inc(&self->ref_counter);
681 }
682
683 2 static gate_result_t lzmacodec_load_peek_buffer(lzmacodec_t* self)
684 {
685 gate_result_t ret;
686 2 gate_size_t bytes_returned = 0;
687
688
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 while(self->peekbuf_used == 0)
689 {
690 lzma_ret result;
691
692 2 gate_size_t free_inputbuf_bytes = sizeof(self->inputbuf) - self->inputbuf_used;
693
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (free_inputbuf_bytes > 0)
694 {
695 2 ret = gate_stream_read(self->target, &self->inputbuf[self->inputbuf_used], free_inputbuf_bytes, &bytes_returned);
696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
697 2 self->inputbuf_used += bytes_returned;
698 }
699
700 2 self->codec.next_in = &self->inputbuf[0];
701 2 self->codec.avail_in = self->inputbuf_used;
702 2 self->codec.next_out = &self->peekbuf[0];
703 2 self->codec.avail_out = sizeof(self->peekbuf);
704
705 2 result = lzma.code(&self->codec, LZMA_RUN);
706
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((result != LZMA_OK) && (result != LZMA_STREAM_END))
707 {
708 ret = GATE_RESULT_FAILED;
709 break;
710 }
711
712
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(self->codec.avail_in < self->inputbuf_used)
713 {
714 /* input bytes were processed, remove them */
715 1 gate_size_t bytes_processed = self->inputbuf_used - self->codec.avail_in;
716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->codec.avail_in > 0)
717 {
718 gate_mem_move(&self->inputbuf[0], &self->inputbuf[bytes_processed], self->codec.avail_in);
719 }
720 1 self->inputbuf_used = self->codec.avail_in;
721 }
722 /* mark filled peek-buffer bytes */
723 2 self->peekbuf_used = sizeof(self->peekbuf) - self->codec.avail_out;
724
725
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(result == LZMA_STREAM_END)
726 {
727 /* we exit, even if no output bytes are in our buffer */
728 2 break;
729 }
730 2 } while (0);
731 2 return ret;
732 }
733
734 13 static gate_result_t lzmacodec_peek(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t * returned)
735 {
736 13 lzmacodec_t* const self = (lzmacodec_t*)obj;
737 gate_size_t copy_bytes;
738
739
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13 if (self->encoder)
740 {
741 2 return GATE_RESULT_INVALIDSTATE;
742 }
743
744
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if (self->peekbuf_used == 0)
745 {
746 2 gate_result_t result = lzmacodec_load_peek_buffer(self);
747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_RETURN_IF_FAILED(result);
748 }
749
750 11 copy_bytes = bufferlength > self->peekbuf_used ? self->peekbuf_used : bufferlength;
751
752
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
11 if (copy_bytes > 0)
753 {
754 10 gate_mem_copy(buffer, &self->peekbuf[0], copy_bytes);
755 }
756
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (returned != NULL)
757 {
758 11 *returned = copy_bytes;
759 }
760 11 return GATE_RESULT_OK;
761 }
762
763 12 static gate_result_t lzmacodec_read(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t * returned)
764 {
765 12 lzmacodec_t* const self = (lzmacodec_t*)obj;
766 gate_result_t ret;
767 12 gate_size_t bytes_copied = 0;
768
769 12 ret = lzmacodec_peek(self, buffer, bufferlength, &bytes_copied);
770
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (GATE_SUCCEEDED(ret))
771 {
772
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if(bytes_copied == self->peekbuf_used)
773 {
774 2 self->peekbuf_used = 0;
775 }
776 else
777 {
778 9 gate_mem_move(&self->peekbuf[0], &self->peekbuf[bytes_copied], self->peekbuf_used - bytes_copied);
779 9 self->peekbuf_used -= bytes_copied;
780 }
781 }
782
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (returned)
783 {
784 12 *returned = bytes_copied;
785 }
786 12 return ret;
787 }
788
789
790 12 static gate_result_t lzmacodec_write(void* obj, char const* buffer, gate_size_t bufferlength, gate_size_t * written)
791 {
792 gate_result_t ret;
793 12 lzmacodec_t* const self = (lzmacodec_t*)obj;
794
795 do
796 {
797 lzma_ret result;
798 char encoded_data[GATE_MAX_COPYBUFFER_LENGTH];
799
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
12 if(!self->encoder || (self->target == NULL))
800 {
801 1 ret = GATE_RESULT_INVALIDSTATE;
802 1 break;
803 }
804
805 11 self->codec.next_in = buffer;
806 11 self->codec.avail_in = bufferlength;
807
808 11 ret = GATE_RESULT_OK;
809
3/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 11 times.
22 while(GATE_SUCCEEDED(ret) && (self->codec.avail_in > 0))
810 {
811 gate_size_t bytes_to_write, bytes_written;
812
813 11 self->codec.next_out = &encoded_data[0];
814 11 self->codec.avail_out = sizeof(encoded_data);
815 11 result = lzma.code(&self->codec, LZMA_RUN);
816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if(result != LZMA_OK)
817 {
818 ret = GATE_RESULT_FAILED;
819 break;
820 }
821 11 bytes_to_write = sizeof(encoded_data) - self->codec.avail_out;
822 11 ret = gate_stream_write_block(self->target, &encoded_data[0], bytes_to_write, &bytes_written);
823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 GATE_BREAK_IF_FAILED(ret);
824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if(bytes_written < bytes_to_write)
825 {
826 ret = GATE_RESULT_FAILED;
827 break;
828 }
829 }
830
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 GATE_BREAK_IF_FAILED(ret);
832
833 /* success case */
834
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (written)
835 {
836 11 *written = bufferlength;
837 }
838 } while (0);
839
840 12 return ret;
841 }
842
843 3 static gate_result_t lzmacodec_flush(void* obj)
844 {
845 gate_result_t ret;
846 3 lzmacodec_t* const self = (lzmacodec_t*)obj;
847
848 do
849 {
850 3 lzma_ret result = LZMA_OK;
851 char encoded_data[GATE_MAX_COPYBUFFER_LENGTH];
852
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
3 if(!self->encoder || (self->target == NULL))
853 {
854 1 ret = GATE_RESULT_INVALIDSTATE;
855 1 break;
856 }
857
858 2 self->codec.next_in = NULL;
859 2 self->codec.avail_in = 0;
860
861 2 ret = GATE_RESULT_OK;
862
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while(result != LZMA_STREAM_END)
863 {
864 gate_size_t bytes_to_write, bytes_written;
865
866 2 self->codec.next_out = &encoded_data[0];
867 2 self->codec.avail_out = sizeof(encoded_data);
868 2 result = lzma.code(&self->codec, LZMA_FINISH);
869
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((result != LZMA_OK) && (result != LZMA_STREAM_END))
870 {
871 /* encoding/buffer error */
872 ret = GATE_RESULT_FAILED;
873 break;
874 }
875
876 2 bytes_to_write = sizeof(encoded_data) - self->codec.avail_out;
877 2 ret = gate_stream_write_block(self->target, &encoded_data[0], bytes_to_write, &bytes_written);
878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(bytes_written < bytes_to_write)
880 {
881 ret = GATE_RESULT_FAILED;
882 break;
883 }
884 }
885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
886
887 /* success case, stream encoding completed, release output stream */
888 2 gate_object_release(self->target);
889 2 self->target = NULL;
890 } while (0);
891 3 return ret;
892 }
893
894
895 3 static GATE_INTERFACE_VTBL(gate_stream) const* init_lzmacodec_vtbl()
896 {
897 static GATE_INTERFACE_VTBL(gate_stream) lzmacodec_vtbl;
898
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(lzmacodec_vtbl.get_interface_name == NULL)
899 {
900 GATE_INTERFACE_VTBL(gate_stream) const vtbl = {
901 lzmacodec_get_interface_name,
902 lzmacodec_release,
903 lzmacodec_retain,
904
905 lzmacodec_read,
906 lzmacodec_peek,
907 lzmacodec_write,
908 lzmacodec_flush
909 };
910 1 lzmacodec_vtbl = vtbl;
911 }
912 3 return &lzmacodec_vtbl;
913 }
914
915 3 static lzmacodec_t* create_instance()
916 {
917 3 lzmacodec_t* ret = NULL;
918 3 lzmacodec_t* ptr = NULL;
919 do
920 {
921 3 gate_result_t result = load_lzma_functions();
922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(result);
923
924 3 ptr = gate_mem_alloc(sizeof(lzmacodec_t));
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(NULL == ptr)
926 {
927 break;
928 }
929 3 gate_mem_clear(ptr, sizeof(lzmacodec_t));
930
931 3 ptr->vtbl = init_lzmacodec_vtbl();
932 3 gate_atomic_int_init(&ptr->ref_counter, 1);
933
934 3 ret = ptr;
935 3 ptr = NULL;
936 } while (0);
937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(ptr)
938 {
939 gate_mem_dealloc(ptr);
940 }
941 3 return ret;
942 }
943
944 2 gate_result_t gate_xz_encoder_create(gate_stream_t* output, gate_int16_t compression, gate_stream_t** ptr2streamptr)
945 {
946 2 lzmacodec_t* codec = NULL;
947 gate_result_t result;
948
949 do
950 {
951 lzma_ret lzmaret;
952
953 2 codec = create_instance();
954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (codec == NULL)
955 {
956 result = GATE_RESULT_NOTAVAILABLE;
957 break;
958 }
959
960 2 lzmaret = lzma.easy_encoder(&codec->codec, 6, LZMA_CHECK_CRC64);
961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (LZMA_OK != lzmaret)
962 {
963 result = GATE_RESULT_FAILED;
964 break;
965 }
966
967 2 codec->encoder = true;
968 2 codec->target = output;
969
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (codec->target)
970 {
971 2 gate_object_retain(codec->target);
972 }
973
974 /* success case reached */
975
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr2streamptr)
976 {
977 2 *ptr2streamptr = (gate_stream_t*)codec;
978 2 codec = NULL;
979 }
980 2 result = GATE_RESULT_OK;
981 } while (0);
982
983 /* cleanup */
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (codec != NULL)
985 {
986 gate_object_release(codec);
987 }
988 2 return result;
989 }
990
991 1 gate_result_t gate_xz_decoder_create(gate_stream_t* input, gate_stream_t** ptr2streamptr)
992 {
993 1 lzmacodec_t* codec = NULL;
994 gate_result_t result;
995
996 do
997 {
998 lzma_ret lzmaret;
999
1000 1 codec = create_instance();
1001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (codec == NULL)
1002 {
1003 result = GATE_RESULT_NOTAVAILABLE;
1004 break;
1005 }
1006
1007 1 lzmaret = lzma.stream_decoder(&codec->codec, 1024 * 1024 * 1024, 0);
1008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (LZMA_OK != lzmaret)
1009 {
1010 result = GATE_RESULT_FAILED;
1011 break;
1012 }
1013
1014 1 codec->encoder = false;
1015 1 codec->target = input;
1016
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (codec->target)
1017 {
1018 1 gate_object_retain(codec->target);
1019 }
1020
1021 /* success case reached */
1022
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr2streamptr)
1023 {
1024 1 *ptr2streamptr = (gate_stream_t*)codec;
1025 1 codec = NULL;
1026 }
1027 1 result = GATE_RESULT_OK;
1028 } while (0);
1029
1030 /* cleanup */
1031
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (codec != NULL)
1032 {
1033 gate_object_release(codec);
1034 }
1035 1 return result;
1036
1037 lzma_stream decoder = LZMA_STREAM_INIT;
1038 lzma_ret ret;
1039 }
1040
1041 #endif /* GATE_ENCODE_XZSTREAM_USE_LIBLZMA */
1042
1043
1044 #if defined(GATE_ENCODE_XZSTREAM_NO_IMPL)
1045
1046 gate_result_t gate_xz_encode(gate_stream_t* input, gate_uint64_t const* ptrInputSize, gate_int16_t compression, gate_stream_t* output)
1047 {
1048 (void)input;
1049 (void)ptrInputSize;
1050 (void)compression;
1051 (void)output;
1052 return GATE_RESULT_NOTSUPPORTED;
1053 }
1054 gate_result_t gate_xz_encoder_create(gate_stream_t* output, gate_int16_t compression, gate_stream_t** ptr2streamptr)
1055 {
1056 (void)output;
1057 (void)compression;
1058 (void)ptr2streamptr;
1059 return GATE_RESULT_NOTSUPPORTED;
1060 }
1061
1062 gate_result_t gate_xz_decoder_create(gate_stream_t* input, gate_stream_t** ptr2streamptr)
1063 {
1064 (void)input;
1065 (void)ptr2streamptr;
1066 return GATE_RESULT_NOTSUPPORTED;
1067 }
1068
1069 #endif /* GATE_ENCODE_XZSTREAM_NO_IMPL */
1070
1071