1// Fast data compression library
2// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
3// lar@quicklz.com
4//
5// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
6// released into public must be open source) or under a commercial license if such
7// has been acquired (see http://www.quicklz.com/order.html). The commercial license
8// does not cover derived or ported versions created by third parties under GPL.
9
10// 1.5.0 final
11
12#include "quicklz.h"
13
14#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0
15 #error quicklz.c and quicklz.h have different versions
16#endif
17
18#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))
19 #define X86X64
20#endif
21
22#define MINOFFSET 2
23#define UNCONDITIONAL_MATCHLEN 6
24#define UNCOMPRESSED_END 4
25#define CWORD_LEN 4
26
27#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0
28 #define OFFSET_BASE source
29 #define CAST (ui32)(size_t)
30#else
31 #define OFFSET_BASE 0
32 #define CAST
33#endif
34
35int qlz_get_setting(int setting)
36{
37 switch (setting)
38 {
39 case 0: return QLZ_COMPRESSION_LEVEL;
40 case 1: return sizeof(qlz_state_compress);
41 case 2: return sizeof(qlz_state_decompress);
42 case 3: return QLZ_STREAMING_BUFFER;
43#ifdef QLZ_MEMORY_SAFE
44 case 6: return 1;
45#else
46 case 6: return 0;
47#endif
48 case 7: return QLZ_VERSION_MAJOR;
49 case 8: return QLZ_VERSION_MINOR;
50 case 9: return QLZ_VERSION_REVISION;
51 }
52 return -1;
53}
54
55#if QLZ_COMPRESSION_LEVEL == 1
56static int same(const unsigned char *src, size_t n)
57{
58 while(n > 0 && *(src + n) == *src)
59 n--;
60 return n == 0 ? 1 : 0;
61}
62#endif
63
64static void reset_table_compress(qlz_state_compress *state)
65{
66 int i;
67 for(i = 0; i < QLZ_HASH_VALUES; i++)
68 {
69#if QLZ_COMPRESSION_LEVEL == 1
70 state->hash[i].offset = 0;
71#else
72 state->hash_counter[i] = 0;
73#endif
74 }
75}
76
77static void reset_table_decompress(qlz_state_decompress *state)
78{
79 int i;
80 (void)state;
81 (void)i;
82#if QLZ_COMPRESSION_LEVEL == 2
83 for(i = 0; i < QLZ_HASH_VALUES; i++)
84 {
85 state->hash_counter[i] = 0;
86 }
87#endif
88}
89
90static __inline ui32 hash_func(ui32 i)
91{
92#if QLZ_COMPRESSION_LEVEL == 2
93 return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1);
94#else
95 return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1);
96#endif
97}
98
99static __inline ui32 fast_read(void const *src, ui32 bytes)
100{
101#ifndef X86X64
102 unsigned char *p = (unsigned char*)src;
103 switch (bytes)
104 {
105 case 4:
106 return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24);
107 case 3:
108 return(*p | *(p + 1) << 8 | *(p + 2) << 16);
109 case 2:
110 return(*p | *(p + 1) << 8);
111 case 1:
112 return(*p);
113 }
114 return 0;
115#else
116 if (bytes >= 1 && bytes <= 4)
117 return *((ui32*)src);
118 else
119 return 0;
120#endif
121}
122
123static __inline ui32 hashat(const unsigned char *src)
124{
125 ui32 fetch, hash;
126 fetch = fast_read(src, 3);
127 hash = hash_func(fetch);
128 return hash;
129}
130
131static __inline void fast_write(ui32 f, void *dst, size_t bytes)
132{
133#ifndef X86X64
134 unsigned char *p = (unsigned char*)dst;
135
136 switch (bytes)
137 {
138 case 4:
139 *p = (unsigned char)f;
140 *(p + 1) = (unsigned char)(f >> 8);
141 *(p + 2) = (unsigned char)(f >> 16);
142 *(p + 3) = (unsigned char)(f >> 24);
143 return;
144 case 3:
145 *p = (unsigned char)f;
146 *(p + 1) = (unsigned char)(f >> 8);
147 *(p + 2) = (unsigned char)(f >> 16);
148 return;
149 case 2:
150 *p = (unsigned char)f;
151 *(p + 1) = (unsigned char)(f >> 8);
152 return;
153 case 1:
154 *p = (unsigned char)f;
155 return;
156 }
157#else
158 switch (bytes)
159 {
160 case 4:
161 *((ui32*)dst) = f;
162 return;
163 case 3:
164 *((ui32*)dst) = f;
165 return;
166 case 2:
167 *((ui16 *)dst) = (ui16)f;
168 return;
169 case 1:
170 *((unsigned char*)dst) = (unsigned char)f;
171 return;
172 }
173#endif
174}
175
176
177size_t qlz_size_decompressed(const char *source)
178{
179 ui32 n, r;
180 n = (((*source) & 2) == 2) ? 4 : 1;
181 r = fast_read(source + 1 + n, n);
182 r = r & (0xffffffff >> ((4 - n)*8));
183 return r;
184}
185
186size_t qlz_size_compressed(const char *source)
187{
188 ui32 n, r;
189 n = (((*source) & 2) == 2) ? 4 : 1;
190 r = fast_read(source + 1, n);
191 r = r & (0xffffffff >> ((4 - n)*8));
192 return r;
193}
194
195size_t qlz_size_header(const char *source)
196{
197 size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1;
198 return n;
199}
200
201
202static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n)
203{
204 // Caution if modifying memcpy_up! Overlap of dst and src must be special handled.
205#ifndef X86X64
206 unsigned char *end = dst + n;
207 while(dst < end)
208 {
209 *dst = *src;
210 dst++;
211 src++;
212 }
213#else
214 ui32 f = 0;
215 do
216 {
217 *(ui32 *)(dst + f) = *(ui32 *)(src + f);
218 f += MINOFFSET + 1;
219 }
220 while (f < n);
221#endif
222}
223
224static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s)
225{
226#if QLZ_COMPRESSION_LEVEL == 1
227 ui32 hash;
228 hash = hashat(s);
229 state->hash[hash].offset = s;
230 state->hash_counter[hash] = 1;
231#elif QLZ_COMPRESSION_LEVEL == 2
232 ui32 hash;
233 unsigned char c;
234 hash = hashat(s);
235 c = state->hash_counter[hash];
236 state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s;
237 c++;
238 state->hash_counter[hash] = c;
239#endif
240 (void)state;
241 (void)s;
242}
243
244#if QLZ_COMPRESSION_LEVEL <= 2
245static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max)
246{
247 while(*lh < max)
248 {
249 (*lh)++;
250 update_hash(state, *lh);
251 }
252}
253#endif
254
255static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state)
256{
257 const unsigned char *last_byte = source + size - 1;
258 const unsigned char *src = source;
259 unsigned char *cword_ptr = destination;
260 unsigned char *dst = destination + CWORD_LEN;
261 ui32 cword_val = 1U << 31;
262 const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
263 ui32 fetch = 0;
264 unsigned int lits = 0;
265
266 (void) lits;
267
268 if(src <= last_matchstart)
269 fetch = fast_read(src, 3);
270
271 while(src <= last_matchstart)
272 {
273 if ((cword_val & 1) == 1)
274 {
275 // store uncompressed if compression ratio is too low
276 if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5))
277 return 0;
278
279 fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
280
281 cword_ptr = dst;
282 dst += CWORD_LEN;
283 cword_val = 1U << 31;
284 fetch = fast_read(src, 3);
285 }
286#if QLZ_COMPRESSION_LEVEL == 1
287 {
288 const unsigned char *o;
289 ui32 hash, cached;
290
291 hash = hash_func(fetch);
292 cached = fetch ^ state->hash[hash].cache;
293 state->hash[hash].cache = fetch;
294
295 o = state->hash[hash].offset + OFFSET_BASE;
296 state->hash[hash].offset = CAST(src - OFFSET_BASE);
297
298#ifdef X86X64
299 if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6))))
300 {
301 if(cached != 0)
302 {
303#else
304 if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6))))
305 {
306 if (*(o + 3) != *(src + 3))
307 {
308#endif
309 hash <<= 4;
310 cword_val = (cword_val >> 1) | (1U << 31);
311 fast_write((3 - 2) | hash, dst, 2);
312 src += 3;
313 dst += 2;
314 }
315 else
316 {
317 const unsigned char *old_src = src;
318 size_t matchlen;
319 hash <<= 4;
320
321 cword_val = (cword_val >> 1) | (1U << 31);
322 src += 4;
323
324 if(*(o + (src - old_src)) == *src)
325 {
326 src++;
327 if(*(o + (src - old_src)) == *src)
328 {
329 size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1;
330 size_t remaining = q > 255 ? 255 : q;
331 src++;
332 while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining)
333 src++;
334 }
335 }
336
337 matchlen = src - old_src;
338 if (matchlen < 18)
339 {
340 fast_write((ui32)(matchlen - 2) | hash, dst, 2);
341 dst += 2;
342 }
343 else
344 {
345 fast_write((ui32)(matchlen << 16) | hash, dst, 3);
346 dst += 3;
347 }
348 }
349 fetch = fast_read(src, 3);
350 lits = 0;
351 }
352 else
353 {
354 lits++;
355 *dst = *src;
356 src++;
357 dst++;
358 cword_val = (cword_val >> 1);
359#ifdef X86X64
360 fetch = fast_read(src, 3);
361#else
362 fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16);
363#endif
364 }
365 }
366#elif QLZ_COMPRESSION_LEVEL >= 2
367 {
368 const unsigned char *o, *offset2;
369 ui32 hash, matchlen, k, m, best_k = 0;
370 unsigned char c;
371 size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1);
372 (void)best_k;
373
374
375 //hash = hashat(src);
376 fetch = fast_read(src, 3);
377 hash = hash_func(fetch);
378
379 c = state->hash_counter[hash];
380
381 offset2 = state->hash[hash].offset[0];
382 if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0)
383 {
384 matchlen = 3;
385 if(*(offset2 + matchlen) == *(src + matchlen))
386 {
387 matchlen = 4;
388 while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining)
389 matchlen++;
390 }
391 }
392 else
393 matchlen = 0;
394 for(k = 1; k < QLZ_POINTERS && c > k; k++)
395 {
396 o = state->hash[hash].offset[k];
397#if QLZ_COMPRESSION_LEVEL == 3
398 if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET)
399#elif QLZ_COMPRESSION_LEVEL == 2
400 if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET)
401#endif
402 {
403 m = 3;
404 while(*(o + m) == *(src + m) && m < remaining)
405 m++;
406#if QLZ_COMPRESSION_LEVEL == 3
407 if ((m > matchlen) || (m == matchlen && o > offset2))
408#elif QLZ_COMPRESSION_LEVEL == 2
409 if (m > matchlen)
410#endif
411 {
412 offset2 = o;
413 matchlen = m;
414 best_k = k;
415 }
416 }
417 }
418 o = offset2;
419 state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src;
420 c++;
421 state->hash_counter[hash] = c;
422
423#if QLZ_COMPRESSION_LEVEL == 3
424 if(matchlen > 2 && src - o < 131071)
425 {
426 ui32 u;
427 size_t offset = src - o;
428
429 for(u = 1; u < matchlen; u++)
430 {
431 hash = hashat(src + u);
432 c = state->hash_counter[hash]++;
433 state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u;
434 }
435
436 cword_val = (cword_val >> 1) | (1U << 31);
437 src += matchlen;
438
439 if(matchlen == 3 && offset <= 63)
440 {
441 *dst = (unsigned char)(offset << 2);
442 dst++;
443 }
444 else if (matchlen == 3 && offset <= 16383)
445 {
446 ui32 f = (ui32)((offset << 2) | 1);
447 fast_write(f, dst, 2);
448 dst += 2;
449 }
450 else if (matchlen <= 18 && offset <= 1023)
451 {
452 ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2;
453 fast_write(f, dst, 2);
454 dst += 2;
455 }
456
457 else if(matchlen <= 33)
458 {
459 ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3;
460 fast_write(f, dst, 3);
461 dst += 3;
462 }
463 else
464 {
465 ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3;
466 fast_write(f, dst, 4);
467 dst += 4;
468 }
469 }
470 else
471 {
472 *dst = *src;
473 src++;
474 dst++;
475 cword_val = (cword_val >> 1);
476 }
477#elif QLZ_COMPRESSION_LEVEL == 2
478
479 if(matchlen > 2)
480 {
481 cword_val = (cword_val >> 1) | (1U << 31);
482 src += matchlen;
483
484 if (matchlen < 10)
485 {
486 ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5);
487 fast_write(f, dst, 2);
488 dst += 2;
489 }
490 else
491 {
492 ui32 f = best_k | (matchlen << 16) | (hash << 5);
493 fast_write(f, dst, 3);
494 dst += 3;
495 }
496 }
497 else
498 {
499 *dst = *src;
500 src++;
501 dst++;
502 cword_val = (cword_val >> 1);
503 }
504#endif
505 }
506#endif
507 }
508 while (src <= last_byte)
509 {
510 if ((cword_val & 1) == 1)
511 {
512 fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
513 cword_ptr = dst;
514 dst += CWORD_LEN;
515 cword_val = 1U << 31;
516 }
517#if QLZ_COMPRESSION_LEVEL < 3
518 if (src <= last_byte - 3)
519 {
520#if QLZ_COMPRESSION_LEVEL == 1
521 ui32 hash, fetch;
522 fetch = fast_read(src, 3);
523 hash = hash_func(fetch);
524 state->hash[hash].offset = CAST(src - OFFSET_BASE);
525 state->hash[hash].cache = fetch;
526#elif QLZ_COMPRESSION_LEVEL == 2
527 ui32 hash;
528 unsigned char c;
529 hash = hashat(src);
530 c = state->hash_counter[hash];
531 state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src;
532 c++;
533 state->hash_counter[hash] = c;
534#endif
535 }
536#endif
537 *dst = *src;
538 src++;
539 dst++;
540 cword_val = (cword_val >> 1);
541 }
542
543 while((cword_val & 1) != 1)
544 cword_val = (cword_val >> 1);
545
546 fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
547
548 // min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument
549 return dst - destination < 9 ? 9 : dst - destination;
550}
551
552static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history)
553{
554 const unsigned char *src = source + qlz_size_header((const char *)source);
555 unsigned char *dst = destination;
556 const unsigned char *last_destination_byte = destination + size - 1;
557 ui32 cword_val = 1;
558 const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
559 unsigned char *last_hashed = destination - 1;
560 const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1;
561 static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
562
563 (void) last_source_byte;
564 (void) last_hashed;
565 (void) state;
566 (void) history;
567
568 for(;;)
569 {
570 ui32 fetch;
571
572 if (cword_val == 1)
573 {
574#ifdef QLZ_MEMORY_SAFE
575 if(src + CWORD_LEN - 1 > last_source_byte)
576 return 0;
577#endif
578 cword_val = fast_read(src, CWORD_LEN);
579 src += CWORD_LEN;
580 }
581
582#ifdef QLZ_MEMORY_SAFE
583 if(src + 4 - 1 > last_source_byte)
584 return 0;
585#endif
586
587 fetch = fast_read(src, 4);
588
589 if ((cword_val & 1) == 1)
590 {
591 ui32 matchlen;
592 const unsigned char *offset2;
593
594#if QLZ_COMPRESSION_LEVEL == 1
595 ui32 hash;
596 cword_val = cword_val >> 1;
597 hash = (fetch >> 4) & 0xfff;
598 offset2 = (const unsigned char *)(size_t)state->hash[hash].offset;
599
600 if((fetch & 0xf) != 0)
601 {
602 matchlen = (fetch & 0xf) + 2;
603 src += 2;
604 }
605 else
606 {
607 matchlen = *(src + 2);
608 src += 3;
609 }
610
611#elif QLZ_COMPRESSION_LEVEL == 2
612 ui32 hash;
613 unsigned char c;
614 cword_val = cword_val >> 1;
615 hash = (fetch >> 5) & 0x7ff;
616 c = (unsigned char)(fetch & 0x3);
617 offset2 = state->hash[hash].offset[c];
618
619 if((fetch & (28)) != 0)
620 {
621 matchlen = ((fetch >> 2) & 0x7) + 2;
622 src += 2;
623 }
624 else
625 {
626 matchlen = *(src + 2);
627 src += 3;
628 }
629
630#elif QLZ_COMPRESSION_LEVEL == 3
631 ui32 offset;
632 cword_val = cword_val >> 1;
633 if ((fetch & 3) == 0)
634 {
635 offset = (fetch & 0xff) >> 2;
636 matchlen = 3;
637 src++;
638 }
639 else if ((fetch & 2) == 0)
640 {
641 offset = (fetch & 0xffff) >> 2;
642 matchlen = 3;
643 src += 2;
644 }
645 else if ((fetch & 1) == 0)
646 {
647 offset = (fetch & 0xffff) >> 6;
648 matchlen = ((fetch >> 2) & 15) + 3;
649 src += 2;
650 }
651 else if ((fetch & 127) != 3)
652 {
653 offset = (fetch >> 7) & 0x1ffff;
654 matchlen = ((fetch >> 2) & 0x1f) + 2;
655 src += 3;
656 }
657 else
658 {
659 offset = (fetch >> 15);
660 matchlen = ((fetch >> 7) & 255) + 3;
661 src += 4;
662 }
663
664 offset2 = dst - offset;
665#endif
666
667#ifdef QLZ_MEMORY_SAFE
668 if(offset2 < history || offset2 > dst - MINOFFSET - 1)
669 return 0;
670
671 if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1))
672 return 0;
673#endif
674
675 memcpy_up(dst, offset2, matchlen);
676 dst += matchlen;
677
678#if QLZ_COMPRESSION_LEVEL <= 2
679 update_hash_upto(state, &last_hashed, dst - matchlen);
680 last_hashed = dst - 1;
681#endif
682 }
683 else
684 {
685 if (dst < last_matchstart)
686 {
687 unsigned int n = bitlut[cword_val & 0xf];
688#ifdef X86X64
689 *(ui32 *)dst = *(ui32 *)src;
690#else
691 memcpy_up(dst, src, 4);
692#endif
693 cword_val = cword_val >> n;
694 dst += n;
695 src += n;
696#if QLZ_COMPRESSION_LEVEL <= 2
697 update_hash_upto(state, &last_hashed, dst - 3);
698#endif
699 }
700 else
701 {
702 while(dst <= last_destination_byte)
703 {
704 if (cword_val == 1)
705 {
706 src += CWORD_LEN;
707 cword_val = 1U << 31;
708 }
709#ifdef QLZ_MEMORY_SAFE
710 if(src >= last_source_byte + 1)
711 return 0;
712#endif
713 *dst = *src;
714 dst++;
715 src++;
716 cword_val = cword_val >> 1;
717 }
718
719#if QLZ_COMPRESSION_LEVEL <= 2
720 update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant
721#endif
722 return size;
723 }
724
725 }
726 }
727}
728
729size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state)
730{
731 size_t r;
732 ui32 compressed;
733 size_t base;
734
735 if(size == 0 || size > 0xffffffff - 400)
736 return 0;
737
738 if(size < 216)
739 base = 3;
740 else
741 base = 9;
742
743#if QLZ_STREAMING_BUFFER > 0
744 if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER)
745#endif
746 {
747 reset_table_compress(state);
748 r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state);
749#if QLZ_STREAMING_BUFFER > 0
750 reset_table_compress(state);
751#endif
752 if(r == base)
753 {
754 memcpy(destination + base, source, size);
755 r = size + base;
756 compressed = 0;
757 }
758 else
759 {
760 compressed = 1;
761 }
762 state->stream_counter = 0;
763 }
764#if QLZ_STREAMING_BUFFER > 0
765 else
766 {
767 unsigned char *src = state->stream_buffer + state->stream_counter;
768
769 memcpy(src, source, size);
770 r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state);
771
772 if(r == base)
773 {
774 memcpy(destination + base, src, size);
775 r = size + base;
776 compressed = 0;
777 reset_table_compress(state);
778 }
779 else
780 {
781 compressed = 1;
782 }
783 state->stream_counter += size;
784 }
785#endif
786 if(base == 3)
787 {
788 *destination = (unsigned char)(0 | compressed);
789 *(destination + 1) = (unsigned char)r;
790 *(destination + 2) = (unsigned char)size;
791 }
792 else
793 {
794 *destination = (unsigned char)(2 | compressed);
795 fast_write((ui32)r, destination + 1, 4);
796 fast_write((ui32)size, destination + 5, 4);
797 }
798
799 *destination |= (QLZ_COMPRESSION_LEVEL << 2);
800 *destination |= (1 << 6);
801 *destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4);
802
803// 76543210
804// 01SSLLHC
805
806 return r;
807}
808
809size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state)
810{
811 size_t dsiz = qlz_size_decompressed(source);
812
813#if QLZ_STREAMING_BUFFER > 0
814 if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER)
815#endif
816 {
817 if((*source & 1) == 1)
818 {
819 reset_table_decompress(state);
820 dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination);
821 }
822 else
823 {
824 memcpy(destination, source + qlz_size_header(source), dsiz);
825 }
826 state->stream_counter = 0;
827 reset_table_decompress(state);
828 }
829#if QLZ_STREAMING_BUFFER > 0
830 else
831 {
832 unsigned char *dst = state->stream_buffer + state->stream_counter;
833 if((*source & 1) == 1)
834 {
835 dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer);
836 }
837 else
838 {
839 memcpy(dst, source + qlz_size_header(source), dsiz);
840 reset_table_decompress(state);
841 }
842 memcpy(destination, dst, dsiz);
843 state->stream_counter += dsiz;
844 }
845#endif
846 return dsiz;
847}
848
849