// Fast data compression library
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
// lar@quicklz.com
//
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
// released into public must be open source) or under a commercial license if such
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
// does not cover derived or ported versions created by third parties under GPL.
// 1.5.0 final
#include "quicklz.h"
#if QLZ_VERSION_MAJOR !=
1 || QLZ_VERSION_MINOR !=
5 || QLZ_VERSION_REVISION !=
0
#error quicklz.c
and quicklz.h have different versions
#endif
#if (
defined (__X86__) ||
defined (__i386__) ||
defined (i386) ||
defined (_M_IX86) ||
defined (__
386 __) ||
defined (__x86_64__) ||
defined (_M_X64))
#define X86X64
#endif
#define MINOFFSET
2
#define UNCONDITIONAL_MATCHLEN
6
#define UNCOMPRESSED_END
4
#define CWORD_LEN
4
#if QLZ_COMPRESSION_LEVEL ==
1 &&
defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER ==
0
#define OFFSET_BASE source
#define CAST (ui32)(size_t)
#else
#define OFFSET_BASE
0
#define CAST
#endif
int qlz_get_setting(
int setting)
{
switch (setting)
{
case 0 :
return QLZ_COMPRESSION_LEVEL;
case 1 :
return sizeof (qlz_state_compress);
case 2 :
return sizeof (qlz_state_decompress);
case 3 :
return QLZ_STREAMING_BUFFER;
#ifdef QLZ_MEMORY_SAFE
case 6 :
return 1 ;
#else
case 6 :
return 0 ;
#endif
case 7 :
return QLZ_VERSION_MAJOR;
case 8 :
return QLZ_VERSION_MINOR;
case 9 :
return QLZ_VERSION_REVISION;
}
return -
1 ;
}
#if QLZ_COMPRESSION_LEVEL ==
1
static int same(
const unsigned char *src, size_t n)
{
while (n >
0 && *(src + n) == *src)
n--;
return n ==
0 ?
1 :
0 ;
}
#endif
static void reset_table_compress(qlz_state_compress *state)
{
int i;
for (i =
0 ; i < QLZ_HASH_VALUES; i++)
{
#if QLZ_COMPRESSION_LEVEL ==
1
state->hash[i].offset =
0 ;
#else
state->hash_counter[i] =
0 ;
#endif
}
}
static void reset_table_decompress(qlz_state_decompress *state)
{
int i;
(
void )state;
(
void )i;
#if QLZ_COMPRESSION_LEVEL ==
2
for (i =
0 ; i < QLZ_HASH_VALUES; i++)
{
state->hash_counter[i] =
0 ;
}
#endif
}
static __
inline ui32 hash_func(ui32 i)
{
#if QLZ_COMPRESSION_LEVEL ==
2
return ((i >>
9 ) ^ (i >>
13 ) ^ i) & (QLZ_HASH_VALUES -
1 );
#else
return ((i >>
12 ) ^ i) & (QLZ_HASH_VALUES -
1 );
#endif
}
static __
inline ui32 fast_read(
void const *src, ui32 bytes)
{
#ifndef X86X64
unsigned char *p = (
unsigned char *)src;
switch (bytes)
{
case 4 :
return (*p | *(p +
1 ) <<
8 | *(p +
2 ) <<
16 | *(p +
3 ) <<
24 );
case 3 :
return (*p | *(p +
1 ) <<
8 | *(p +
2 ) <<
16 );
case 2 :
return (*p | *(p +
1 ) <<
8 );
case 1 :
return (*p);
}
return 0 ;
#else
if (bytes >=
1 && bytes <=
4 )
return *((ui32*)src);
else
return 0 ;
#endif
}
static __
inline ui32 hashat(
const unsigned char *src)
{
ui32 fetch, hash;
fetch = fast_read(src,
3 );
hash = hash_func(fetch);
return hash;
}
static __
inline void fast_write(ui32 f,
void *dst, size_t bytes)
{
#ifndef X86X64
unsigned char *p = (
unsigned char *)dst;
switch (bytes)
{
case 4 :
*p = (
unsigned char )f;
*(p +
1 ) = (
unsigned char )(f >>
8 );
*(p +
2 ) = (
unsigned char )(f >>
16 );
*(p +
3 ) = (
unsigned char )(f >>
24 );
return ;
case 3 :
*p = (
unsigned char )f;
*(p +
1 ) = (
unsigned char )(f >>
8 );
*(p +
2 ) = (
unsigned char )(f >>
16 );
return ;
case 2 :
*p = (
unsigned char )f;
*(p +
1 ) = (
unsigned char )(f >>
8 );
return ;
case 1 :
*p = (
unsigned char )f;
return ;
}
#else
switch (bytes)
{
case 4 :
*((ui32*)dst) = f;
return ;
case 3 :
*((ui32*)dst) = f;
return ;
case 2 :
*((ui16 *)dst) = (ui16)f;
return ;
case 1 :
*((
unsigned char *)dst) = (
unsigned char )f;
return ;
}
#endif
}
size_t qlz_size_decompressed(
const char *source)
{
ui32 n, r;
n = (((*source) &
2 ) ==
2 ) ?
4 :
1 ;
r = fast_read(source +
1 + n, n);
r = r & (
0 xffffffff >> ((
4 - n)*
8 ));
return r;
}
size_t qlz_size_compressed(
const char *source)
{
ui32 n, r;
n = (((*source) &
2 ) ==
2 ) ?
4 :
1 ;
r = fast_read(source +
1 , n);
r = r & (
0 xffffffff >> ((
4 - n)*
8 ));
return r;
}
size_t qlz_size_header(
const char *source)
{
size_t n =
2 *((((*source) &
2 ) ==
2 ) ?
4 :
1 ) +
1 ;
return n;
}
static __
inline void memcpy_up(
unsigned char *dst,
const unsigned char *src, ui32 n)
{
// Caution if modifying memcpy_up! Overlap of dst and src must be special handled.
#ifndef X86X64
unsigned char *end = dst + n;
while (dst < end)
{
*dst = *src;
dst++;
src++;
}
#else
ui32 f =
0 ;
do
{
*(ui32 *)(dst + f) = *(ui32 *)(src + f);
f += MINOFFSET +
1 ;
}
while (f < n);
#endif
}
static __
inline void update_hash(qlz_state_decompress *state,
const unsigned char *s)
{
#if QLZ_COMPRESSION_LEVEL ==
1
ui32 hash;
hash = hashat(s);
state->hash[hash].offset = s;
state->hash_counter[hash] =
1 ;
#elif QLZ_COMPRESSION_LEVEL ==
2
ui32 hash;
unsigned char c;
hash = hashat(s);
c = state->hash_counter[hash];
state->hash[hash].offset[c & (QLZ_POINTERS -
1 )] = s;
c++;
state->hash_counter[hash] = c;
#endif
(
void )state;
(
void )s;
}
#if QLZ_COMPRESSION_LEVEL <=
2
static void update_hash_upto(qlz_state_decompress *state,
unsigned char **lh,
const unsigned char *max)
{
while (*lh < max)
{
(*lh)++;
update_hash(state, *lh);
}
}
#endif
static size_t qlz_compress_core(
const unsigned char *source,
unsigned char *destination,
size_t size, qlz_state_compress *state)
{
const unsigned char *last_byte = source + size - 1 ;
const unsigned char *src = source;
unsigned char *cword_ptr = destination;
unsigned char *dst = destination + CWORD_LEN;
ui32 cword_val = 1 U << 31 ;
const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
ui32 fetch = 0 ;
unsigned int lits = 0 ;
(void ) lits;
if (src <= last_matchstart)
fetch = fast_read(src, 3 );
while (src <= last_matchstart)
{
if ((cword_val & 1 ) == 1 )
{
// store uncompressed if compression ratio is too low
if (src > source + (size >> 1 ) && dst - destination > src - source - ((src - source) >> 5 ))
return 0 ;
fast_write((cword_val >> 1 ) | (1 U << 31 ), cword_ptr, CWORD_LEN);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 1 U << 31 ;
fetch = fast_read(src, 3 );
}
#if QLZ_COMPRESSION_LEVEL == 1
{
const unsigned char *o;
ui32 hash, cached;
hash = hash_func(fetch);
cached = fetch ^ state->hash[hash].cache;
state->hash[hash].cache = fetch;
o = state->hash[hash].offset + OFFSET_BASE;
state->hash[hash].offset = CAST(src - OFFSET_BASE);
#ifdef X86X64
if ((cached & 0 xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3 , 6 ))))
{
if (cached != 0 )
{
#else
if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3 , 6 ))))
{
if (*(o + 3 ) != *(src + 3 ))
{
#endif
hash <<= 4 ;
cword_val = (cword_val >> 1 ) | (1 U << 31 );
fast_write((3 - 2 ) | hash, dst, 2 );
src += 3 ;
dst += 2 ;
}
else
{
const unsigned char *old_src = src;
size_t matchlen;
hash <<= 4 ;
cword_val = (cword_val >> 1 ) | (1 U << 31 );
src += 4 ;
if (*(o + (src - old_src)) == *src)
{
src++;
if (*(o + (src - old_src)) == *src)
{
size_t q = last_byte - UNCOMPRESSED_END - (src - 5 ) + 1 ;
size_t remaining = q > 255 ? 255 : q;
src++;
while (*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining)
src++;
}
}
matchlen = src - old_src;
if (matchlen < 18 )
{
fast_write((ui32)(matchlen - 2 ) | hash, dst, 2 );
dst += 2 ;
}
else
{
fast_write((ui32)(matchlen << 16 ) | hash, dst, 3 );
dst += 3 ;
}
}
fetch = fast_read(src, 3 );
lits = 0 ;
}
else
{
lits++;
*dst = *src;
src++;
dst++;
cword_val = (cword_val >> 1 );
#ifdef X86X64
fetch = fast_read(src, 3 );
#else
fetch = (fetch >> 8 & 0 xffff) | (*(src + 2 ) << 16 );
#endif
}
}
#elif QLZ_COMPRESSION_LEVEL >= 2
{
const unsigned char *o, *offset2;
ui32 hash, matchlen, k, m, best_k = 0 ;
unsigned char c;
size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1 ) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1 );
(void )best_k;
//hash = hashat(src);
fetch = fast_read(src, 3 );
hash = hash_func(fetch);
c = state->hash_counter[hash];
offset2 = state->hash[hash].offset[0 ];
if (offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3 ) ^ fetch) & 0 xffffff) == 0 )
{
matchlen = 3 ;
if (*(offset2 + matchlen) == *(src + matchlen))
{
matchlen = 4 ;
while (*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining)
matchlen++;
}
}
else
matchlen = 0 ;
for (k = 1 ; k < QLZ_POINTERS && c > k; k++)
{
o = state->hash[hash].offset[k];
#if QLZ_COMPRESSION_LEVEL == 3
if (((fast_read(o, 3 ) ^ fetch) & 0 xffffff) == 0 && o < src - MINOFFSET)
#elif QLZ_COMPRESSION_LEVEL == 2
if (*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3 ) ^ fetch) & 0 xffffff) == 0 && o < src - MINOFFSET)
#endif
{
m = 3 ;
while (*(o + m) == *(src + m) && m < remaining)
m++;
#if QLZ_COMPRESSION_LEVEL == 3
if ((m > matchlen) || (m == matchlen && o > offset2))
#elif QLZ_COMPRESSION_LEVEL == 2
if (m > matchlen)
#endif
{
offset2 = o;
matchlen = m;
best_k = k;
}
}
}
o = offset2;
state->hash[hash].offset[c & (QLZ_POINTERS - 1 )] = src;
c++;
state->hash_counter[hash] = c;
#if QLZ_COMPRESSION_LEVEL == 3
if (matchlen > 2 && src - o < 131071 )
{
ui32 u;
size_t offset = src - o;
for (u = 1 ; u < matchlen; u++)
{
hash = hashat(src + u);
c = state->hash_counter[hash]++;
state->hash[hash].offset[c & (QLZ_POINTERS - 1 )] = src + u;
}
cword_val = (cword_val >> 1 ) | (1 U << 31 );
src += matchlen;
if (matchlen == 3 && offset <= 63 )
{
*dst = (unsigned char )(offset << 2 );
dst++;
}
else if (matchlen == 3 && offset <= 16383 )
{
ui32 f = (ui32)((offset << 2 ) | 1 );
fast_write(f, dst, 2 );
dst += 2 ;
}
else if (matchlen <= 18 && offset <= 1023 )
{
ui32 f = ((matchlen - 3 ) << 2 ) | ((ui32)offset << 6 ) | 2 ;
fast_write(f, dst, 2 );
dst += 2 ;
}
else if (matchlen <= 33 )
{
ui32 f = ((matchlen - 2 ) << 2 ) | ((ui32)offset << 7 ) | 3 ;
fast_write(f, dst, 3 );
dst += 3 ;
}
else
{
ui32 f = ((matchlen - 3 ) << 7 ) | ((ui32)offset << 15 ) | 3 ;
fast_write(f, dst, 4 );
dst += 4 ;
}
}
else
{
*dst = *src;
src++;
dst++;
cword_val = (cword_val >> 1 );
}
#elif QLZ_COMPRESSION_LEVEL == 2
if (matchlen > 2 )
{
cword_val = (cword_val >> 1 ) | (1 U << 31 );
src += matchlen;
if (matchlen < 10 )
{
ui32 f = best_k | ((matchlen - 2 ) << 2 ) | (hash << 5 );
fast_write(f, dst, 2 );
dst += 2 ;
}
else
{
ui32 f = best_k | (matchlen << 16 ) | (hash << 5 );
fast_write(f, dst, 3 );
dst += 3 ;
}
}
else
{
*dst = *src;
src++;
dst++;
cword_val = (cword_val >> 1 );
}
#endif
}
#endif
}
while (src <= last_byte)
{
if ((cword_val & 1 ) == 1 )
{
fast_write((cword_val >> 1 ) | (1 U << 31 ), cword_ptr, CWORD_LEN);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 1 U << 31 ;
}
#if QLZ_COMPRESSION_LEVEL < 3
if (src <= last_byte - 3 )
{
#if QLZ_COMPRESSION_LEVEL == 1
ui32 hash, fetch;
fetch = fast_read(src, 3 );
hash = hash_func(fetch);
state->hash[hash].offset = CAST(src - OFFSET_BASE);
state->hash[hash].cache = fetch;
#elif QLZ_COMPRESSION_LEVEL == 2
ui32 hash;
unsigned char c;
hash = hashat(src);
c = state->hash_counter[hash];
state->hash[hash].offset[c & (QLZ_POINTERS - 1 )] = src;
c++;
state->hash_counter[hash] = c;
#endif
}
#endif
*dst = *src;
src++;
dst++;
cword_val = (cword_val >> 1 );
}
while ((cword_val & 1 ) != 1 )
cword_val = (cword_val >> 1 );
fast_write((cword_val >> 1 ) | (1 U << 31 ), cword_ptr, CWORD_LEN);
// min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument
return dst - destination < 9 ? 9 : dst - destination;
}
static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history)
{
const unsigned char *src = source + qlz_size_header((const char *)source);
unsigned char *dst = destination;
const unsigned char *last_destination_byte = destination + size - 1 ;
ui32 cword_val = 1 ;
const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
unsigned char *last_hashed = destination - 1 ;
const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1 ;
static const ui32 bitlut[16 ] = {4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 };
(void ) last_source_byte;
(void ) last_hashed;
(void ) state;
(void ) history;
for (;;)
{
ui32 fetch;
if (cword_val == 1 )
{
#ifdef QLZ_MEMORY_SAFE
if (src + CWORD_LEN - 1 > last_source_byte)
return 0 ;
#endif
cword_val = fast_read(src, CWORD_LEN);
src += CWORD_LEN;
}
#ifdef QLZ_MEMORY_SAFE
if (src + 4 - 1 > last_source_byte)
return 0 ;
#endif
fetch = fast_read(src, 4 );
if ((cword_val & 1 ) == 1 )
{
ui32 matchlen;
const unsigned char *offset2;
#if QLZ_COMPRESSION_LEVEL == 1
ui32 hash;
cword_val = cword_val >> 1 ;
hash = (fetch >> 4 ) & 0 xfff;
offset2 = (const unsigned char *)(size_t)state->hash[hash].offset;
if ((fetch & 0 xf) != 0 )
{
matchlen = (fetch & 0 xf) + 2 ;
src += 2 ;
}
else
{
matchlen = *(src + 2 );
src += 3 ;
}
#elif QLZ_COMPRESSION_LEVEL == 2
ui32 hash;
unsigned char c;
cword_val = cword_val >> 1 ;
hash = (fetch >> 5 ) & 0 x7ff;
c = (unsigned char )(fetch & 0 x3);
offset2 = state->hash[hash].offset[c];
if ((fetch & (28 )) != 0 )
{
matchlen = ((fetch >> 2 ) & 0 x7) + 2 ;
src += 2 ;
}
else
{
matchlen = *(src + 2 );
src += 3 ;
}
#elif QLZ_COMPRESSION_LEVEL == 3
ui32 offset;
cword_val = cword_val >> 1 ;
if ((fetch & 3 ) == 0 )
{
offset = (fetch & 0 xff) >> 2 ;
matchlen = 3 ;
src++;
}
else if ((fetch & 2 ) == 0 )
{
offset = (fetch & 0 xffff) >> 2 ;
matchlen = 3 ;
src += 2 ;
}
else if ((fetch & 1 ) == 0 )
{
offset = (fetch & 0 xffff) >> 6 ;
matchlen = ((fetch >> 2 ) & 15 ) + 3 ;
src += 2 ;
}
else if ((fetch & 127 ) != 3 )
{
offset = (fetch >> 7 ) & 0 x1ffff;
matchlen = ((fetch >> 2 ) & 0 x1f) + 2 ;
src += 3 ;
}
else
{
offset = (fetch >> 15 );
matchlen = ((fetch >> 7 ) & 255 ) + 3 ;
src += 4 ;
}
offset2 = dst - offset;
#endif
#ifdef QLZ_MEMORY_SAFE
if (offset2 < history || offset2 > dst - MINOFFSET - 1 )
return 0 ;
if (matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1 ))
return 0 ;
#endif
memcpy_up(dst, offset2, matchlen);
dst += matchlen;
#if QLZ_COMPRESSION_LEVEL <= 2
update_hash_upto(state, &last_hashed, dst - matchlen);
last_hashed = dst - 1 ;
#endif
}
else
{
if (dst < last_matchstart)
{
unsigned int n = bitlut[cword_val & 0 xf];
#ifdef X86X64
*(ui32 *)dst = *(ui32 *)src;
#else
memcpy_up(dst, src, 4 );
#endif
cword_val = cword_val >> n;
dst += n;
src += n;
#if QLZ_COMPRESSION_LEVEL <= 2
update_hash_upto(state, &last_hashed, dst - 3 );
#endif
}
else
{
while (dst <= last_destination_byte)
{
if (cword_val == 1 )
{
src += CWORD_LEN;
cword_val = 1 U << 31 ;
}
#ifdef QLZ_MEMORY_SAFE
if (src >= last_source_byte + 1 )
return 0 ;
#endif
*dst = *src;
dst++;
src++;
cword_val = cword_val >> 1 ;
}
#if QLZ_COMPRESSION_LEVEL <= 2
update_hash_upto(state, &last_hashed, last_destination_byte - 3 ); // todo, use constant
#endif
return size;
}
}
}
}
size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state)
{
size_t r;
ui32 compressed;
size_t base;
if (size == 0 || size > 0 xffffffff - 400 )
return 0 ;
if (size < 216 )
base = 3 ;
else
base = 9 ;
#if QLZ_STREAMING_BUFFER > 0
if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER)
#endif
{
reset_table_compress(state);
r = base + qlz_compress_core((const unsigned char *)source, (unsigned char *)destination + base, size, state);
#if QLZ_STREAMING_BUFFER > 0
reset_table_compress(state);
#endif
if (r == base)
{
memcpy(destination + base, source, size);
r = size + base;
compressed = 0 ;
}
else
{
compressed = 1 ;
}
state->stream_counter = 0 ;
}
#if QLZ_STREAMING_BUFFER > 0
else
{
unsigned char *src = state->stream_buffer + state->stream_counter;
memcpy(src, source, size);
r = base + qlz_compress_core(src, (unsigned char *)destination + base, size, state);
if (r == base)
{
memcpy(destination + base, src, size);
r = size + base;
compressed = 0 ;
reset_table_compress(state);
}
else
{
compressed = 1 ;
}
state->stream_counter += size;
}
#endif
if (base == 3 )
{
*destination = (unsigned char )(0 | compressed);
*(destination + 1 ) = (unsigned char )r;
*(destination + 2 ) = (unsigned char )size;
}
else
{
*destination = (unsigned char )(2 | compressed);
fast_write((ui32)r, destination + 1 , 4 );
fast_write((ui32)size, destination + 5 , 4 );
}
*destination |= (QLZ_COMPRESSION_LEVEL << 2 );
*destination |= (1 << 6 );
*destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3 ))) << 4 );
// 76543210
// 01SSLLHC
return r;
}
size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state)
{
size_t dsiz = qlz_size_decompressed(source);
#if QLZ_STREAMING_BUFFER > 0
if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER)
#endif
{
if ((*source & 1 ) == 1 )
{
reset_table_decompress(state);
dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination);
}
else
{
memcpy(destination, source + qlz_size_header(source), dsiz);
}
state->stream_counter = 0 ;
reset_table_decompress(state);
}
#if QLZ_STREAMING_BUFFER > 0
else
{
unsigned char *dst = state->stream_buffer + state->stream_counter;
if ((*source & 1 ) == 1 )
{
dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer);
}
else
{
memcpy(dst, source + qlz_size_header(source), dsiz);
reset_table_decompress(state);
}
memcpy(destination, dst, dsiz);
state->stream_counter += dsiz;
}
#endif
return dsiz;
}
Messung V0.5 in Prozent C=99 H=92 G=95
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland