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