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