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