mirror of https://github.com/ARMmbed/mbed-os.git
Repalce compression libs for license issues
parent
4d1d1a0313
commit
6dadbd897a
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2000-2008 Marc Alexander Lehmann <schmorp@schmorp.de>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modifica-
|
|
||||||
* tion, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
|
||||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
|
||||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
|
||||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
|
||||||
* in which case the provisions of the GPL are applicable instead of
|
|
||||||
* the above. If you wish to allow the use of your version of this file
|
|
||||||
* only under the terms of the GPL and not to allow others to use your
|
|
||||||
* version of this file under the BSD license, indicate your decision
|
|
||||||
* by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL. If you do not delete the
|
|
||||||
* provisions above, a recipient may use your version of this file under
|
|
||||||
* either the BSD or the GPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LZF_H
|
|
||||||
#define LZF_H
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
**
|
|
||||||
** lzf -- an extremely fast/free compression/decompression-method
|
|
||||||
** http://liblzf.plan9.de/
|
|
||||||
**
|
|
||||||
** This algorithm is believed to be patent-free.
|
|
||||||
**
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
#define LZF_VERSION 0x0105 /* 1.5, API version */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compress in_len bytes stored at the memory block starting at
|
|
||||||
* in_data and write the result to out_data, up to a maximum length
|
|
||||||
* of out_len bytes.
|
|
||||||
*
|
|
||||||
* If the output buffer is not large enough or any error occurs return 0,
|
|
||||||
* otherwise return the number of bytes used, which might be considerably
|
|
||||||
* more than in_len (but less than 104% of the original size), so it
|
|
||||||
* makes sense to always use out_len == in_len - 1), to ensure _some_
|
|
||||||
* compression, and store the data uncompressed otherwise (with a flag, of
|
|
||||||
* course.
|
|
||||||
*
|
|
||||||
* lzf_compress might use different algorithms on different systems and
|
|
||||||
* even different runs, thus might result in different compressed strings
|
|
||||||
* depending on the phase of the moon or similar factors. However, all
|
|
||||||
* these strings are architecture-independent and will result in the
|
|
||||||
* original data when decompressed using lzf_decompress.
|
|
||||||
*
|
|
||||||
* The buffers must not be overlapping.
|
|
||||||
*
|
|
||||||
* If the option LZF_STATE_ARG is enabled, an extra argument must be
|
|
||||||
* supplied which is not reflected in this header file. Refer to lzfP.h
|
|
||||||
* and lzf_c.c.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
unsigned int
|
|
||||||
lzf_compress (const void *const in_data, unsigned int in_len,
|
|
||||||
void *out_data, unsigned int out_len,
|
|
||||||
unsigned char **htab);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decompress data compressed with some version of the lzf_compress
|
|
||||||
* function and stored at location in_data and length in_len. The result
|
|
||||||
* will be stored at out_data up to a maximum of out_len characters.
|
|
||||||
*
|
|
||||||
* If the output buffer is not large enough to hold the decompressed
|
|
||||||
* data, a 0 is returned and errno is set to E2BIG. Otherwise the number
|
|
||||||
* of decompressed bytes (i.e. the original length of the data) is
|
|
||||||
* returned.
|
|
||||||
*
|
|
||||||
* If an error in the compressed data is detected, a zero is returned and
|
|
||||||
* errno is set to EINVAL.
|
|
||||||
*
|
|
||||||
* This function is very fast, about as fast as a copying loop.
|
|
||||||
*/
|
|
||||||
unsigned int
|
|
||||||
lzf_decompress (const void *const in_data, unsigned int in_len,
|
|
||||||
void *out_data, unsigned int out_len);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2000-2007 Marc Alexander Lehmann <schmorp@schmorp.de>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modifica-
|
|
||||||
* tion, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
|
||||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
|
||||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
|
||||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
|
||||||
* in which case the provisions of the GPL are applicable instead of
|
|
||||||
* the above. If you wish to allow the use of your version of this file
|
|
||||||
* only under the terms of the GPL and not to allow others to use your
|
|
||||||
* version of this file under the BSD license, indicate your decision
|
|
||||||
* by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL. If you do not delete the
|
|
||||||
* provisions above, a recipient may use your version of this file under
|
|
||||||
* either the BSD or the GPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LZFP_h
|
|
||||||
#define LZFP_h
|
|
||||||
|
|
||||||
#define STANDALONE 1 /* at the moment, this is ok. */
|
|
||||||
|
|
||||||
#ifndef STANDALONE
|
|
||||||
# include "lzf.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Size of hashtable is (1 << HLOG) * sizeof (char *)
|
|
||||||
* decompression is independent of the hash table size
|
|
||||||
* the difference between 15 and 14 is very small
|
|
||||||
* for small blocks (and 14 is usually a bit faster).
|
|
||||||
* For a low-memory/faster configuration, use HLOG == 13;
|
|
||||||
* For best compression, use 15 or 16 (or more, up to 22).
|
|
||||||
*/
|
|
||||||
#ifndef HLOG
|
|
||||||
# define HLOG 14
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sacrifice very little compression quality in favour of compression speed.
|
|
||||||
* This gives almost the same compression as the default code, and is
|
|
||||||
* (very roughly) 15% faster. This is the preferred mode of operation.
|
|
||||||
*/
|
|
||||||
#ifndef VERY_FAST
|
|
||||||
# define VERY_FAST 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sacrifice some more compression quality in favour of compression speed.
|
|
||||||
* (roughly 1-2% worse compression for large blocks and
|
|
||||||
* 9-10% for small, redundant, blocks and >>20% better speed in both cases)
|
|
||||||
* In short: when in need for speed, enable this for binary data,
|
|
||||||
* possibly disable this for text data.
|
|
||||||
*/
|
|
||||||
#ifndef ULTRA_FAST
|
|
||||||
# define ULTRA_FAST 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unconditionally aligning does not cost very much, so do it if unsure
|
|
||||||
*/
|
|
||||||
#ifndef STRICT_ALIGN
|
|
||||||
# define STRICT_ALIGN !(defined(__i386) || defined (__amd64))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* You may choose to pre-set the hash table (might be faster on some
|
|
||||||
* modern cpus and large (>>64k) blocks, and also makes compression
|
|
||||||
* deterministic/repeatable when the configuration otherwise is the same).
|
|
||||||
*/
|
|
||||||
#ifndef INIT_HTAB
|
|
||||||
# define INIT_HTAB 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Avoid assigning values to errno variable? for some embedding purposes
|
|
||||||
* (linux kernel for example), this is necessary. NOTE: this breaks
|
|
||||||
* the documentation in lzf.h. Avoiding errno has no speed impact.
|
|
||||||
*/
|
|
||||||
#ifndef AVOID_ERRNO
|
|
||||||
# define AVOID_ERRNO 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether to pass the LZF_STATE variable as argument, or allocate it
|
|
||||||
* on the stack. For small-stack environments, define this to 1.
|
|
||||||
* NOTE: this breaks the prototype in lzf.h.
|
|
||||||
*/
|
|
||||||
#ifndef LZF_STATE_ARG
|
|
||||||
# define LZF_STATE_ARG 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether to add extra checks for input validity in lzf_decompress
|
|
||||||
* and return EINVAL if the input stream has been corrupted. This
|
|
||||||
* only shields against overflowing the input buffer and will not
|
|
||||||
* detect most corrupted streams.
|
|
||||||
* This check is not normally noticeable on modern hardware
|
|
||||||
* (<1% slowdown), but might slow down older cpus considerably.
|
|
||||||
*/
|
|
||||||
#ifndef CHECK_INPUT
|
|
||||||
# define CHECK_INPUT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether to store pointers or offsets inside the hash table. On
|
|
||||||
* 64 bit architetcures, pointers take up twice as much space,
|
|
||||||
* and might also be slower. Default is to autodetect.
|
|
||||||
*/
|
|
||||||
/*#define LZF_USER_OFFSETS autodetect */
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* nothing should be changed below */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
# include <cstring>
|
|
||||||
# include <climits>
|
|
||||||
using namespace std;
|
|
||||||
#else
|
|
||||||
# include <string.h>
|
|
||||||
# include <limits.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LZF_USE_OFFSETS
|
|
||||||
# if defined (WIN32)
|
|
||||||
# define LZF_USE_OFFSETS defined(_M_X64)
|
|
||||||
# else
|
|
||||||
# if __cplusplus > 199711L
|
|
||||||
# include <cstdint>
|
|
||||||
# else
|
|
||||||
# include <stdint.h>
|
|
||||||
# endif
|
|
||||||
# define LZF_USE_OFFSETS (UINTPTR_MAX > 0xffffffffU)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned char u8;
|
|
||||||
|
|
||||||
#if LZF_USE_OFFSETS
|
|
||||||
# define LZF_HSLOT_BIAS ((const u8 *)in_data)
|
|
||||||
typedef unsigned int LZF_HSLOT;
|
|
||||||
#else
|
|
||||||
# define LZF_HSLOT_BIAS 0
|
|
||||||
typedef const u8 *LZF_HSLOT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef LZF_HSLOT LZF_STATE[1 << (HLOG)];
|
|
||||||
|
|
||||||
#if !STRICT_ALIGN
|
|
||||||
/* for unaligned accesses we need a 16 bit datatype. */
|
|
||||||
# if USHRT_MAX == 65535
|
|
||||||
typedef unsigned short u16;
|
|
||||||
# elif UINT_MAX == 65535
|
|
||||||
typedef unsigned int u16;
|
|
||||||
# else
|
|
||||||
# undef STRICT_ALIGN
|
|
||||||
# define STRICT_ALIGN 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ULTRA_FAST
|
|
||||||
# undef VERY_FAST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,300 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2000-2010 Marc Alexander Lehmann <schmorp@schmorp.de>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modifica-
|
|
||||||
* tion, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
|
||||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
|
||||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
|
||||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
|
||||||
* in which case the provisions of the GPL are applicable instead of
|
|
||||||
* the above. If you wish to allow the use of your version of this file
|
|
||||||
* only under the terms of the GPL and not to allow others to use your
|
|
||||||
* version of this file under the BSD license, indicate your decision
|
|
||||||
* by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL. If you do not delete the
|
|
||||||
* provisions above, a recipient may use your version of this file under
|
|
||||||
* either the BSD or the GPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lzfP.h"
|
|
||||||
|
|
||||||
#define HSIZE (1 << (HLOG))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* don't play with this unless you benchmark!
|
|
||||||
* the data format is not dependent on the hash function.
|
|
||||||
* the hash function might seem strange, just believe me,
|
|
||||||
* it works ;)
|
|
||||||
*/
|
|
||||||
#ifndef FRST
|
|
||||||
# define FRST(p) (((p[0]) << 8) | p[1])
|
|
||||||
# define NEXT(v,p) (((v) << 8) | p[2])
|
|
||||||
# if ULTRA_FAST
|
|
||||||
# define IDX(h) ((( h >> (3*8 - HLOG)) - h ) & (HSIZE - 1))
|
|
||||||
# elif VERY_FAST
|
|
||||||
# define IDX(h) ((( h >> (3*8 - HLOG)) - h*5) & (HSIZE - 1))
|
|
||||||
# else
|
|
||||||
# define IDX(h) ((((h ^ (h << 5)) >> (3*8 - HLOG)) - h*5) & (HSIZE - 1))
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* IDX works because it is very similar to a multiplicative hash, e.g.
|
|
||||||
* ((h * 57321 >> (3*8 - HLOG)) & (HSIZE - 1))
|
|
||||||
* the latter is also quite fast on newer CPUs, and compresses similarly.
|
|
||||||
*
|
|
||||||
* the next one is also quite good, albeit slow ;)
|
|
||||||
* (int)(cos(h & 0xffffff) * 1e6)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* original lzv-like hash function, much worse and thus slower */
|
|
||||||
# define FRST(p) (p[0] << 5) ^ p[1]
|
|
||||||
# define NEXT(v,p) ((v) << 5) ^ p[2]
|
|
||||||
# define IDX(h) ((h) & (HSIZE - 1))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX_LIT (1 << 5)
|
|
||||||
#define MAX_OFF (1 << 13)
|
|
||||||
#define MAX_REF ((1 << 8) + (1 << 3))
|
|
||||||
|
|
||||||
#if __GNUC__ >= 3
|
|
||||||
# define expect(expr,value) __builtin_expect ((expr),(value))
|
|
||||||
# define inline inline
|
|
||||||
#else
|
|
||||||
# define expect(expr,value) (expr)
|
|
||||||
# define inline static
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define expect_false(expr) expect ((expr) != 0, 0)
|
|
||||||
#define expect_true(expr) expect ((expr) != 0, 1)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* compressed format
|
|
||||||
*
|
|
||||||
* 000LLLLL <L+1> ; literal, L+1=1..33 octets
|
|
||||||
* LLLooooo oooooooo ; backref L+1=1..7 octets, o+1=1..4096 offset
|
|
||||||
* 111ooooo LLLLLLLL oooooooo ; backref L+8 octets, o+1=1..4096 offset
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
lzf_compress (const void *const in_data, unsigned int in_len,
|
|
||||||
void *out_data, unsigned int out_len
|
|
||||||
#if LZF_STATE_ARG
|
|
||||||
, LZF_STATE htab
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#if !LZF_STATE_ARG
|
|
||||||
LZF_STATE htab;
|
|
||||||
#endif
|
|
||||||
const u8 *ip = (const u8 *)in_data;
|
|
||||||
u8 *op = (u8 *)out_data;
|
|
||||||
const u8 *in_end = ip + in_len;
|
|
||||||
u8 *out_end = op + out_len;
|
|
||||||
const u8 *ref;
|
|
||||||
|
|
||||||
/* off requires a type wide enough to hold a general pointer difference.
|
|
||||||
* ISO C doesn't have that (size_t might not be enough and ptrdiff_t only
|
|
||||||
* works for differences within a single object). We also assume that no
|
|
||||||
* no bit pattern traps. Since the only platform that is both non-POSIX
|
|
||||||
* and fails to support both assumptions is windows 64 bit, we make a
|
|
||||||
* special workaround for it.
|
|
||||||
*/
|
|
||||||
#if defined (WIN32) && defined (_M_X64)
|
|
||||||
unsigned _int64 off; /* workaround for missing POSIX compliance */
|
|
||||||
#else
|
|
||||||
unsigned long off;
|
|
||||||
#endif
|
|
||||||
unsigned int hval;
|
|
||||||
int lit;
|
|
||||||
|
|
||||||
if (!in_len || !out_len)
|
|
||||||
{ return 0; }
|
|
||||||
|
|
||||||
#if INIT_HTAB
|
|
||||||
memset (htab, 0, sizeof (htab));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lit = 0;
|
|
||||||
op++; /* start run */
|
|
||||||
|
|
||||||
hval = FRST (ip);
|
|
||||||
while (ip < in_end - 2) {
|
|
||||||
LZF_HSLOT *hslot;
|
|
||||||
|
|
||||||
hval = NEXT (hval, ip);
|
|
||||||
hslot = htab + IDX (hval);
|
|
||||||
ref = *hslot + LZF_HSLOT_BIAS;
|
|
||||||
*hslot = ip - LZF_HSLOT_BIAS;
|
|
||||||
|
|
||||||
if (1
|
|
||||||
#if INIT_HTAB
|
|
||||||
&& ref < ip /* the next test will actually take care of this, but this is faster */
|
|
||||||
#endif
|
|
||||||
&& (off = (unsigned long)(uintptr_t)(ip - ref - 1)) < MAX_OFF
|
|
||||||
&& ref > (u8 *)in_data
|
|
||||||
&& ref[2] == ip[2]
|
|
||||||
#if STRICT_ALIGN
|
|
||||||
&& ((ref[1] << 8) | ref[0]) == ((ip[1] << 8) | ip[0])
|
|
||||||
#else
|
|
||||||
&& *(u16 *)ref == *(u16 *)ip
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
/* match found at *ref++ */
|
|
||||||
unsigned int len = 2;
|
|
||||||
unsigned int maxlen = (unsigned int)((uintptr_t)in_end - (uintptr_t)ip) - len;
|
|
||||||
maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
|
|
||||||
|
|
||||||
if (expect_false (op + 3 + 1 >= out_end)) /* first a faster conservative test */
|
|
||||||
if (op - !lit + 3 + 1 >= out_end) /* second the exact but rare test */
|
|
||||||
{ return 0; }
|
|
||||||
|
|
||||||
op [- lit - 1] = lit - 1; /* stop run */
|
|
||||||
op -= !lit; /* undo run if length is zero */
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (expect_true (maxlen > 16)) {
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
len++;
|
|
||||||
if (ref [len] != ip [len]) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{ len++; }
|
|
||||||
while (len < maxlen && ref[len] == ip[len]);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
len -= 2; /* len is now #octets - 1 */
|
|
||||||
ip++;
|
|
||||||
|
|
||||||
if (len < 7) {
|
|
||||||
*op++ = (u8)((off >> 8) + (len << 5));
|
|
||||||
} else {
|
|
||||||
*op++ = (u8)((off >> 8) + ( 7 << 5));
|
|
||||||
*op++ = len - 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
*op++ = (u8)off;
|
|
||||||
|
|
||||||
lit = 0;
|
|
||||||
op++; /* start run */
|
|
||||||
|
|
||||||
ip += len + 1;
|
|
||||||
|
|
||||||
if (expect_false (ip >= in_end - 2))
|
|
||||||
{ break; }
|
|
||||||
|
|
||||||
#if ULTRA_FAST || VERY_FAST
|
|
||||||
--ip;
|
|
||||||
# if VERY_FAST && !ULTRA_FAST
|
|
||||||
--ip;
|
|
||||||
# endif
|
|
||||||
hval = FRST (ip);
|
|
||||||
|
|
||||||
hval = NEXT (hval, ip);
|
|
||||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
|
||||||
ip++;
|
|
||||||
|
|
||||||
# if VERY_FAST && !ULTRA_FAST
|
|
||||||
hval = NEXT (hval, ip);
|
|
||||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
|
||||||
ip++;
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
ip -= len + 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
hval = NEXT (hval, ip);
|
|
||||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
|
||||||
ip++;
|
|
||||||
} while (len--);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
/* one more literal byte we must copy */
|
|
||||||
if (expect_false (op >= out_end))
|
|
||||||
{ return 0; }
|
|
||||||
|
|
||||||
lit++;
|
|
||||||
*op++ = *ip++;
|
|
||||||
|
|
||||||
if (expect_false (lit == MAX_LIT)) {
|
|
||||||
op [- lit - 1] = lit - 1; /* stop run */
|
|
||||||
lit = 0;
|
|
||||||
op++; /* start run */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op + 3 > out_end) /* at most 3 bytes can be missing here */
|
|
||||||
{ return 0; }
|
|
||||||
|
|
||||||
while (ip < in_end) {
|
|
||||||
lit++;
|
|
||||||
*op++ = *ip++;
|
|
||||||
|
|
||||||
if (expect_false (lit == MAX_LIT)) {
|
|
||||||
op [- lit - 1] = lit - 1; /* stop run */
|
|
||||||
lit = 0;
|
|
||||||
op++; /* start run */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
op [- lit - 1] = lit - 1; /* end run */
|
|
||||||
op -= !lit; /* undo run if length is zero */
|
|
||||||
|
|
||||||
return (unsigned int)((uintptr_t)op - (uintptr_t)out_data);
|
|
||||||
}
|
|
||||||
|
|
|
@ -44,13 +44,9 @@
|
||||||
#include "hal/trng_api.h"
|
#include "hal/trng_api.h"
|
||||||
#include "base64b.h"
|
#include "base64b.h"
|
||||||
#include "nvstore.h"
|
#include "nvstore.h"
|
||||||
|
#include "pithy.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/*Include LZF Compressor librart */
|
|
||||||
extern "C" {
|
|
||||||
#include "lzf.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !DEVICE_TRNG
|
#if !DEVICE_TRNG
|
||||||
#error [NOT_SUPPORTED] TRNG API not supported for this target
|
#error [NOT_SUPPORTED] TRNG API not supported for this target
|
||||||
#endif
|
#endif
|
||||||
|
@ -104,11 +100,10 @@ static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len)
|
||||||
static void compress_and_compare(char *key, char *value)
|
static void compress_and_compare(char *key, char *value)
|
||||||
{
|
{
|
||||||
trng_t trng_obj;
|
trng_t trng_obj;
|
||||||
uint8_t out_comp_buf[BUFFER_LEN * 2] = {0}, buffer[BUFFER_LEN] = {0};
|
uint8_t out_comp_buf[BUFFER_LEN * 4] = {0}, buffer[BUFFER_LEN] = {0};
|
||||||
uint8_t input_buf[BUFFER_LEN * 2] = {0}, temp_buff[BUFFER_LEN * 2] = {0};
|
uint8_t input_buf[BUFFER_LEN * 2] = {0}, temp_buff[BUFFER_LEN * 2] = {0};
|
||||||
size_t out_comp_buf_len = 0;
|
size_t comp_sz = 0;
|
||||||
unsigned int comp_res = 0, result = 0;
|
unsigned int result = 0;
|
||||||
unsigned char htab[32][32] = {0};
|
|
||||||
|
|
||||||
#if NVSTORE_RESET
|
#if NVSTORE_RESET
|
||||||
NVStore& nvstore = NVStore::get_instance();
|
NVStore& nvstore = NVStore::get_instance();
|
||||||
|
@ -134,35 +129,29 @@ static void compress_and_compare(char *key, char *value)
|
||||||
result = fill_buffer_trng(buffer, &trng_obj, sizeof(buffer));
|
result = fill_buffer_trng(buffer, &trng_obj, sizeof(buffer));
|
||||||
TEST_ASSERT_EQUAL(0, result);
|
TEST_ASSERT_EQUAL(0, result);
|
||||||
|
|
||||||
/*lzf_compress will try to compress the random data, if it succeeded it means the data is not really random*/
|
/*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/
|
||||||
if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
|
if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
|
||||||
printf("\n******TRNG_TEST_STEP1*****\n");
|
printf("\n******TRNG_TEST_STEP1*****\n");
|
||||||
out_comp_buf_len = BUFFER_LEN + (BUFFER_LEN / 4);
|
|
||||||
comp_res = lzf_compress((const void *)buffer,
|
comp_sz = pithy_Compress((char *)buffer, sizeof(buffer), (char *)out_comp_buf, sizeof(out_comp_buf), 9);
|
||||||
(unsigned int)sizeof(buffer),
|
|
||||||
(void *)out_comp_buf,
|
if (comp_sz >= BUFFER_LEN) {
|
||||||
out_comp_buf_len,
|
|
||||||
(unsigned char **)htab);
|
|
||||||
if (comp_res >= BUFFER_LEN) {
|
|
||||||
printf("trng_get_bytes for buffer size %d was successful", sizeof(buffer));
|
printf("trng_get_bytes for buffer size %d was successful", sizeof(buffer));
|
||||||
} else {
|
} else {
|
||||||
printf("trng_get_bytes for buffer size %d was unsuccessful", sizeof(buffer));
|
printf("trng_get_bytes for buffer size %d was unsuccessful", sizeof(buffer));
|
||||||
TEST_ASSERT(false);
|
TEST_ASSERT(false);
|
||||||
}
|
}
|
||||||
printf("\n******FINISHED_TRNG_TEST_STEP1*****\n\n");
|
printf("\n******FINISHED_TRNG_TEST_STEP1*****\n\n");
|
||||||
|
|
||||||
} else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
|
} else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
|
||||||
|
/*pithy_Compress will try to compress the random data with a different buffer sizem*/
|
||||||
printf("\n******TRNG_TEST_STEP2*****\n");
|
printf("\n******TRNG_TEST_STEP2*****\n");
|
||||||
result = fill_buffer_trng(temp_buff, &trng_obj, sizeof(temp_buff));
|
result = fill_buffer_trng(temp_buff, &trng_obj, sizeof(temp_buff));
|
||||||
TEST_ASSERT_EQUAL(0, result);
|
TEST_ASSERT_EQUAL(0, result);
|
||||||
|
|
||||||
out_comp_buf_len = 2 * BUFFER_LEN + (BUFFER_LEN / 2);
|
comp_sz = pithy_Compress((char *)temp_buff, sizeof(temp_buff), (char *)out_comp_buf, sizeof(out_comp_buf), 9);
|
||||||
comp_res = lzf_compress((const void *)temp_buff,
|
|
||||||
(unsigned int)sizeof(temp_buff),
|
|
||||||
(void *)out_comp_buf,
|
|
||||||
out_comp_buf_len,
|
|
||||||
(unsigned char **)htab);
|
|
||||||
|
|
||||||
if (comp_res >= BUFFER_LEN) {
|
if (comp_sz >= BUFFER_LEN) {
|
||||||
printf("trng_get_bytes for buffer size %d was successful", sizeof(temp_buff));
|
printf("trng_get_bytes for buffer size %d was successful", sizeof(temp_buff));
|
||||||
} else {
|
} else {
|
||||||
printf("trng_get_bytes for buffer size %d was unsuccessful", sizeof(temp_buff));
|
printf("trng_get_bytes for buffer size %d was unsuccessful", sizeof(temp_buff));
|
||||||
|
@ -172,14 +161,10 @@ static void compress_and_compare(char *key, char *value)
|
||||||
|
|
||||||
printf("******TRNG_TEST_STEP3*****\n");
|
printf("******TRNG_TEST_STEP3*****\n");
|
||||||
|
|
||||||
memcpy(input_buf + BUFFER_LEN, buffer, BUFFER_LEN);
|
/*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/
|
||||||
comp_res = lzf_compress((const void *)input_buf,
|
comp_sz = pithy_Compress((char *)input_buf, sizeof(input_buf), (char *)out_comp_buf, sizeof(out_comp_buf), 9);
|
||||||
(unsigned int)sizeof(input_buf),
|
|
||||||
(void *)out_comp_buf,
|
|
||||||
out_comp_buf_len,
|
|
||||||
(unsigned char **)htab);
|
|
||||||
|
|
||||||
if (comp_res >= BUFFER_LEN) {
|
if (comp_sz >= BUFFER_LEN) {
|
||||||
printf("compression for concatenated buffer after reset was successful");
|
printf("compression for concatenated buffer after reset was successful");
|
||||||
} else {
|
} else {
|
||||||
printf("compression for concatenated buffer after reset was unsuccessful");
|
printf("compression for concatenated buffer after reset was unsuccessful");
|
||||||
|
|
|
@ -0,0 +1,842 @@
|
||||||
|
//
|
||||||
|
// pithy.c
|
||||||
|
// http://github.com/johnezang/pithy
|
||||||
|
// Licensed under the terms of the BSD License, as specified below.
|
||||||
|
//
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011, John Engelhart
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the Zang Industries nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(__arm__) && defined(__ARM_NEON__)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pithy.h"
|
||||||
|
|
||||||
|
#define kBlockLog 20ul
|
||||||
|
#define kBlockSize ((size_t)(1 << kBlockLog))
|
||||||
|
|
||||||
|
// The maximum size that can be compressed while still allowing for the worst case compression expansion.
|
||||||
|
#define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes.
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(__arm__)
|
||||||
|
#define PITHY_UNALIGNED_LOADS_AND_STORES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef const char *pithy_hashOffset_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PITHY_LITERAL = 0,
|
||||||
|
PITHY_COPY_1_BYTE_OFFSET = 1,
|
||||||
|
PITHY_COPY_2_BYTE_OFFSET = 2,
|
||||||
|
PITHY_COPY_3_BYTE_OFFSET = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if defined (__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
#define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
|
||||||
|
#define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect))
|
||||||
|
#define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u)
|
||||||
|
#define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u)
|
||||||
|
#define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr)
|
||||||
|
#else // defined (__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
#define PITHY_ATTRIBUTES(attr, ...)
|
||||||
|
#define PITHY_EXPECTED(cond, expect) (cond)
|
||||||
|
#define PITHY_EXPECT_T(cond) (cond)
|
||||||
|
#define PITHY_EXPECT_F(cond) (cond)
|
||||||
|
#define PITHY_PREFETCH(ptr)
|
||||||
|
#endif // defined (__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
|
||||||
|
#define PITHY_STATIC_INLINE static __inline__ PITHY_ATTRIBUTES(always_inline)
|
||||||
|
#define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x))
|
||||||
|
|
||||||
|
#if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG)
|
||||||
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define DCHECK(condition)
|
||||||
|
#else
|
||||||
|
#define DCHECK(condition) do { \
|
||||||
|
if(PITHY_EXPECT_F(!(condition))) { \
|
||||||
|
fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", \
|
||||||
|
__FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT);
|
||||||
|
PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v);
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset);
|
||||||
|
PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift);
|
||||||
|
PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit);
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path);
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len);
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len);
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PITHY_UNALIGNED_LOADS_AND_STORES
|
||||||
|
|
||||||
|
#define pithy_Load16(_p) (*((uint16_t *)(_p)))
|
||||||
|
#define pithy_Load32(_p) (*((uint32_t *)(_p)))
|
||||||
|
#define pithy_Store16(_p, _val) (*((uint16_t *)(_p)) = (_val))
|
||||||
|
#define pithy_Store32(_p, _val) (*((uint32_t *)(_p)) = (_val))
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
#if defined(__ARM_NEON__)
|
||||||
|
#define pithy_Load64(_p) ((uint64_t)vld1_u64(_p))
|
||||||
|
#define pithy_Store64(_p, _val) vst1_u64(_p, (uint64x1_t)_val)
|
||||||
|
#else
|
||||||
|
#define PITHY_32BIT_MOVE64
|
||||||
|
PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||||
|
PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else // not __arm__
|
||||||
|
#define pithy_Load64(_p) (*((uint64_t *)(_p)))
|
||||||
|
#define pithy_Store64(_p, _val) (*((uint64_t *)(_p)) = (_val))
|
||||||
|
#endif // __arm__
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||||
|
PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||||
|
PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||||
|
PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); }
|
||||||
|
PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); }
|
||||||
|
PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PITHY_32BIT_MOVE64
|
||||||
|
#define pithy_Move64(dst,src) pithy_Store32(dst, pithy_Load32(src)); \
|
||||||
|
pithy_Store32(dst + 4ul, pithy_Load32(src + 4ul));
|
||||||
|
#else
|
||||||
|
#define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__arm__) && defined(__ARM_NEON__) && defined(PITHY_UNALIGNED_LOADS_AND_STORES)
|
||||||
|
#define pithy_Move128(_dst,_src) ({ \
|
||||||
|
asm ("vld1.64 {d0-d1}, [%[src]]\n\tvst1.64 {d0-d1}, [%[dst]]" : : \
|
||||||
|
[src]"r"(_src), [dst]"r"(_dst) : "d0", "d1", "memory"); })
|
||||||
|
#else
|
||||||
|
#define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN__
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define pithy_bswap_16(x) _byteswap_ushort(x)
|
||||||
|
#define pithy_bswap_32(x) _byteswap_ulong(x)
|
||||||
|
#define pithy_bswap_64(x) _byteswap_uint64(x)
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
// Mac OS X / Darwin features
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
#define pithy_bswap_16(x) OSSwapInt16(x)
|
||||||
|
#define pithy_bswap_32(x) OSSwapInt32(x)
|
||||||
|
#define pithy_bswap_64(x) OSSwapInt64(x)
|
||||||
|
#else
|
||||||
|
#include <byteswap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __BIG_ENDIAN__
|
||||||
|
|
||||||
|
// Conversion functions.
|
||||||
|
#ifdef __BIG_ENDIAN__
|
||||||
|
#define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x))
|
||||||
|
#define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x))
|
||||||
|
#define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x))
|
||||||
|
#define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x))
|
||||||
|
#define pithy_IsLittleEndian() (0)
|
||||||
|
|
||||||
|
#else // !defined(__BIG_ENDIAN__)
|
||||||
|
#define pithy_FromHost16(x) ((uint16_t)(x))
|
||||||
|
#define pithy_ToHost16(x) ((uint16_t)(x))
|
||||||
|
#define pithy_FromHost32(x) ((uint32_t)(x))
|
||||||
|
#define pithy_ToHost32(x) ((uint32_t)(x))
|
||||||
|
#define pithy_IsLittleEndian() (1)
|
||||||
|
|
||||||
|
#endif // !defined(__BIG_ENDIAN__)
|
||||||
|
|
||||||
|
#define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p)))
|
||||||
|
#define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v))
|
||||||
|
#define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p)))
|
||||||
|
#define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v))
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v)
|
||||||
|
{
|
||||||
|
*p++ = (v & 0xffu);
|
||||||
|
*p++ = ((v >> 8) & 0xffu);
|
||||||
|
*p++ = ((v >> 16) & 0xffu);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined (__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
|
||||||
|
#define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));})
|
||||||
|
#define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n)))
|
||||||
|
#define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n)))
|
||||||
|
#define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n)))
|
||||||
|
#define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n)))
|
||||||
|
|
||||||
|
#else // Portable versions, !GNUC || GNUC < 3
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n)
|
||||||
|
{
|
||||||
|
if (n == 0u) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
int i = 0, log = 0;
|
||||||
|
uint32_t value = n;
|
||||||
|
for (i = 4; i >= 0; --i) {
|
||||||
|
int shift = (1 << i);
|
||||||
|
uint32_t x = value >> shift;
|
||||||
|
if (x != 0u) {
|
||||||
|
value = x;
|
||||||
|
log += shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DCHECK(value == 1);
|
||||||
|
return (log);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n)
|
||||||
|
{
|
||||||
|
int i = 0, rc = 31;
|
||||||
|
for (i = 4, shift = 1 << 4; i >= 0; --i) {
|
||||||
|
const uint32_t x = n << shift;
|
||||||
|
if (x != 0u) {
|
||||||
|
n = x;
|
||||||
|
rc -= shift;
|
||||||
|
}
|
||||||
|
shift >>= 1;
|
||||||
|
}
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n)
|
||||||
|
{
|
||||||
|
const uint32_t bottomBits = n;
|
||||||
|
if (bottomBits == 0u) {
|
||||||
|
return (32 + pithy_FindLSBSetNonZero32((n >> 32)));
|
||||||
|
} else {
|
||||||
|
return (pithy_FindLSBSetNonZero32(bottomBits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t x, rc = 32, shift = 1 << 4;
|
||||||
|
for (i = 3; i >= 0; --i) {
|
||||||
|
x = n >> shift;
|
||||||
|
if (x != 0) {
|
||||||
|
rc -= shift;
|
||||||
|
n = x;
|
||||||
|
}
|
||||||
|
shift >>= 1;
|
||||||
|
}
|
||||||
|
x = n >> shift;
|
||||||
|
return (rc - ((x != 0) ? 2 : n));
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n)
|
||||||
|
{
|
||||||
|
const uint32_t upperBits = n >> 32;
|
||||||
|
if (upperBits == 0u) {
|
||||||
|
return (32 + pithy_FindMSBSetNonZero32((n)));
|
||||||
|
} else {
|
||||||
|
return (pithy_FindMSBSetNonZero32(upperBits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // End portable versions.
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut)
|
||||||
|
{
|
||||||
|
const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l;
|
||||||
|
size_t resultShift = 0ul, result = 0ul;
|
||||||
|
uint32_t encodedByte = 0u;
|
||||||
|
|
||||||
|
for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) {
|
||||||
|
if (ptr >= limit) {
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
encodedByte = *(ptr++);
|
||||||
|
result |= (encodedByte & 127u) << resultShift;
|
||||||
|
if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
done:
|
||||||
|
*resultOut = result;
|
||||||
|
return ((const char *)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v)
|
||||||
|
{
|
||||||
|
unsigned char *ptr = (unsigned char *)sptr;
|
||||||
|
if (v < (1u << 7)) {
|
||||||
|
*(ptr++) = v;
|
||||||
|
} else if (v < (1u << 14)) {
|
||||||
|
*(ptr++) = v | 0x80u;
|
||||||
|
*(ptr++) = (v >> 7);
|
||||||
|
} else if (v < (1u << 21)) {
|
||||||
|
*(ptr++) = v | 0x80u;
|
||||||
|
*(ptr++) = (v >> 7) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 14);
|
||||||
|
} else if (v < (1u << 28)) {
|
||||||
|
*(ptr++) = v | 0x80u;
|
||||||
|
*(ptr++) = (v >> 7) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 14) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 21);
|
||||||
|
} else {
|
||||||
|
*(ptr++) = v | 0x80u;
|
||||||
|
*(ptr++) = (v >> 7) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 14) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 21) | 0x80u;
|
||||||
|
*(ptr++) = (v >> 28);
|
||||||
|
}
|
||||||
|
return ((char *)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset)
|
||||||
|
{
|
||||||
|
DCHECK(offset <= 4);
|
||||||
|
return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift)
|
||||||
|
{
|
||||||
|
uint32_t kMul = 0x1e35a7bdU;
|
||||||
|
return ((bytes * kMul) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit)
|
||||||
|
{
|
||||||
|
DCHECK(s2_limit >= s2);
|
||||||
|
const char *ms1 = s1, *ms2 = s2;
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) {
|
||||||
|
uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2);
|
||||||
|
if (PITHY_EXPECT_F(x == 0ul)) {
|
||||||
|
ms1 += 8ul;
|
||||||
|
ms2 += 8ul;
|
||||||
|
} else {
|
||||||
|
return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) :
|
||||||
|
(pithy_FindMSBSetNonZero64(x) >> 3))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) {
|
||||||
|
uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2);
|
||||||
|
if (PITHY_EXPECT_F(x == 0u)) {
|
||||||
|
ms1 += 4u;
|
||||||
|
ms2 += 4u;
|
||||||
|
} else {
|
||||||
|
return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ?
|
||||||
|
(pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
while (PITHY_EXPECT_T(ms2 < s2_limit)) {
|
||||||
|
if (PITHY_EXPECT_T(*ms1 == *ms2)) {
|
||||||
|
ms1++;
|
||||||
|
ms2++;
|
||||||
|
} else {
|
||||||
|
return (ms1 - s1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (ms1 - s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path)
|
||||||
|
{
|
||||||
|
ssize_t n = len - 1l;
|
||||||
|
if (PITHY_EXPECT_T(n < 60l)) {
|
||||||
|
*op++ = PITHY_LITERAL | (n << 2);
|
||||||
|
if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) {
|
||||||
|
pithy_Move128(op, literal);
|
||||||
|
return (op + len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char *base = op;
|
||||||
|
int count = 0;
|
||||||
|
op++;
|
||||||
|
while (n > 0l) {
|
||||||
|
*op++ = n & 0xff;
|
||||||
|
n >>= 8;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
DCHECK((count >= 1) && (count <= 4));
|
||||||
|
*base = PITHY_LITERAL | ((59 + count) << 2);
|
||||||
|
}
|
||||||
|
memcpy(op, literal, len);
|
||||||
|
return (op + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize));
|
||||||
|
if (PITHY_EXPECT_T(offset < 65536ul)) {
|
||||||
|
if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
|
||||||
|
*op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2);
|
||||||
|
pithy_StoreHost16(op, offset);
|
||||||
|
op += 2ul;
|
||||||
|
*op++ = (len - 63ul);
|
||||||
|
} else {
|
||||||
|
*op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2);
|
||||||
|
pithy_StoreHost16(op, offset);
|
||||||
|
op += 2ul;
|
||||||
|
pithy_StoreHost16(op, len);
|
||||||
|
op += 2ul;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
|
||||||
|
*op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2);
|
||||||
|
pithy_StoreHost24(op, offset);
|
||||||
|
op += 3ul;
|
||||||
|
*op++ = (len - 63ul);
|
||||||
|
} else {
|
||||||
|
*op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2);
|
||||||
|
pithy_StoreHost24(op, offset);
|
||||||
|
op += 3ul;
|
||||||
|
pithy_StoreHost16(op, len);
|
||||||
|
op += 2ul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (op);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize));
|
||||||
|
if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) {
|
||||||
|
ssize_t lenMinus4 = len - 4l;
|
||||||
|
DCHECK(lenMinus4 < 8l);
|
||||||
|
*op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5);
|
||||||
|
*op++ = offset & 0xff;
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_T(offset < 65536ul)) {
|
||||||
|
*op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2);
|
||||||
|
pithy_StoreHost16(op, offset);
|
||||||
|
op += 2ul;
|
||||||
|
} else {
|
||||||
|
*op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2);
|
||||||
|
pithy_StoreHost24(op, offset);
|
||||||
|
op += 3ul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (op);
|
||||||
|
}
|
||||||
|
|
||||||
|
PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
while (PITHY_EXPECT_F(len >= 63ul)) {
|
||||||
|
op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len);
|
||||||
|
len -= (len >= 65539ul) ? 65535ul : len;
|
||||||
|
}
|
||||||
|
DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1);
|
||||||
|
if ( PITHY_EXPECT_T(len > 0ul)) {
|
||||||
|
op = pithy_EmitCopyLessThan63(op, offset, len);
|
||||||
|
len -= len;
|
||||||
|
}
|
||||||
|
return (op);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pithy_MaxCompressedLength(size_t inputLength)
|
||||||
|
{
|
||||||
|
return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pithy_Compress(const char *uncompressed,
|
||||||
|
size_t uncompressedLength,
|
||||||
|
char *compressedOut,
|
||||||
|
size_t compressedOutLength,
|
||||||
|
int compressionLevel)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) ||
|
||||||
|
(uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ||
|
||||||
|
(uncompressedLength == 0ul)) {
|
||||||
|
return (0ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *compressedPtr = compressedOut;
|
||||||
|
|
||||||
|
size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 :
|
||||||
|
(compressionLevel > 9) ? 9 : compressionLevel) / 2ul));
|
||||||
|
while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) {
|
||||||
|
hashTableSize <<= 1;
|
||||||
|
}
|
||||||
|
pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable;
|
||||||
|
if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) {
|
||||||
|
if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) {
|
||||||
|
return (0ul);
|
||||||
|
}
|
||||||
|
hashTable = heapHashTable;
|
||||||
|
}
|
||||||
|
size_t x = 0ul;
|
||||||
|
for (x = 0ul; x < hashTableSize; x++) {
|
||||||
|
hashTable[x] = uncompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
char *const compressedOutEnd = compressedOut + compressedOutLength;
|
||||||
|
#endif
|
||||||
|
compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength);
|
||||||
|
DCHECK(compressedPtr <= compressedOutEnd);
|
||||||
|
{
|
||||||
|
const char *uncompressedPtr = uncompressed;
|
||||||
|
const char *uncompressedEnd = uncompressed + uncompressedLength;
|
||||||
|
const char *nextEmitUncompressedPtr = uncompressedPtr;
|
||||||
|
DCHECK((hashTableSize & (hashTableSize - 1l)) == 0);
|
||||||
|
const int shift = 32 - pithy_Log2Floor(hashTableSize);
|
||||||
|
DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l));
|
||||||
|
size_t skip = 32ul;
|
||||||
|
|
||||||
|
if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) {
|
||||||
|
const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul;
|
||||||
|
uint32_t uncompressedBytes;
|
||||||
|
uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr);
|
||||||
|
uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
DCHECK(nextEmitUncompressedPtr < uncompressedPtr);
|
||||||
|
const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL;
|
||||||
|
|
||||||
|
skip = (((skip - 32ul) * 184ul) >> 8) + 32ul;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uncompressedPtr = nextUncompressedPtr;
|
||||||
|
uncompressedBytes = nextUncompressedBytes;
|
||||||
|
uint32_t uncompressedBytesHash = nextUncompressedBytesHash;
|
||||||
|
DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift));
|
||||||
|
size_t skipBytesBetweenHashLookups = skip >> 5;
|
||||||
|
skip += ((skip * 7ul) >> 11) + 1ul;
|
||||||
|
nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups;
|
||||||
|
if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) {
|
||||||
|
goto emit_remainder;
|
||||||
|
}
|
||||||
|
nextUncompressedBytes = pithy_Load32(nextUncompressedPtr);
|
||||||
|
nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||||
|
matchCandidatePtr = hashTable[uncompressedBytesHash];
|
||||||
|
DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
|
||||||
|
hashTable[uncompressedBytesHash] = uncompressedPtr;
|
||||||
|
} while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) ||
|
||||||
|
PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((ssize_t)(kBlockSize - 2ul))));
|
||||||
|
|
||||||
|
DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd);
|
||||||
|
compressedPtr = pithy_EmitLiteral(compressedPtr,
|
||||||
|
nextEmitUncompressedPtr,
|
||||||
|
uncompressedPtr - nextEmitUncompressedPtr,
|
||||||
|
1);
|
||||||
|
DCHECK(compressedPtr <= compressedOutEnd);
|
||||||
|
uint64_t uncompressedBytes64 = 0ul;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (compressionLevel > 2) {
|
||||||
|
DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd);
|
||||||
|
uncompressedBytes64 = pithy_Load64(uncompressedPtr + 1ul);
|
||||||
|
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
|
||||||
|
uncompressedPtr + 1ul;
|
||||||
|
if (compressionLevel > 4) {
|
||||||
|
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
|
||||||
|
uncompressedPtr + 2ul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK((matchCandidatePtr >= uncompressed) &&
|
||||||
|
(matchCandidatePtr <= uncompressedPtr) &&
|
||||||
|
((matchCandidatePtr + 4ul) <= uncompressedEnd) &&
|
||||||
|
((uncompressedPtr + 4ul) <= uncompressedEnd));
|
||||||
|
|
||||||
|
size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul,
|
||||||
|
uncompressedPtr + 4ul,
|
||||||
|
uncompressedEnd);
|
||||||
|
DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) &&
|
||||||
|
((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd));
|
||||||
|
DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength));
|
||||||
|
compressedPtr = pithy_EmitCopy(compressedPtr,
|
||||||
|
uncompressedPtr - matchCandidatePtr,
|
||||||
|
matchCandidateLength);
|
||||||
|
DCHECK(compressedPtr <= compressedOutEnd);
|
||||||
|
uncompressedPtr += matchCandidateLength;
|
||||||
|
DCHECK(uncompressedPtr <= uncompressedEnd);
|
||||||
|
nextEmitUncompressedPtr = uncompressedPtr;
|
||||||
|
if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) {
|
||||||
|
goto emit_remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd));
|
||||||
|
|
||||||
|
uncompressedBytes64 = pithy_Load64(uncompressedPtr - 3ul);
|
||||||
|
|
||||||
|
if (compressionLevel > 0) {
|
||||||
|
if (compressionLevel > 8) {
|
||||||
|
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
|
||||||
|
uncompressedPtr - 3ul;
|
||||||
|
}
|
||||||
|
if (compressionLevel > 6) {
|
||||||
|
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
|
||||||
|
uncompressedPtr - 2ul;
|
||||||
|
}
|
||||||
|
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] =
|
||||||
|
uncompressedPtr - 1ul;
|
||||||
|
}
|
||||||
|
|
||||||
|
uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u);
|
||||||
|
uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift);
|
||||||
|
matchCandidatePtr = hashTable[uncompressedBytesHash];
|
||||||
|
DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
|
||||||
|
hashTable[uncompressedBytesHash] = uncompressedPtr;
|
||||||
|
} while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) &&
|
||||||
|
PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((ssize_t)(kBlockSize - 2ul))));
|
||||||
|
|
||||||
|
nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u);
|
||||||
|
nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||||
|
uncompressedPtr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_remainder:
|
||||||
|
if (nextEmitUncompressedPtr < uncompressedEnd) {
|
||||||
|
compressedPtr = pithy_EmitLiteral(compressedPtr,
|
||||||
|
nextEmitUncompressedPtr,
|
||||||
|
uncompressedEnd - nextEmitUncompressedPtr,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pithy_Store32(compressedPtr, 0);
|
||||||
|
compressedPtr += 4;
|
||||||
|
|
||||||
|
DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength);
|
||||||
|
if (heapHashTable != NULL) {
|
||||||
|
free(heapHashTable);
|
||||||
|
heapHashTable = NULL;
|
||||||
|
hashTable = NULL;
|
||||||
|
}
|
||||||
|
return (compressedPtr - compressedOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const uint32_t pithy_wordmask[] = {
|
||||||
|
0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const uint16_t pithy_charTable[256] = {
|
||||||
|
0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802,
|
||||||
|
0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804,
|
||||||
|
0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806,
|
||||||
|
0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808,
|
||||||
|
0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a,
|
||||||
|
0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c,
|
||||||
|
0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e,
|
||||||
|
0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810,
|
||||||
|
0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812,
|
||||||
|
0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814,
|
||||||
|
0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816,
|
||||||
|
0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818,
|
||||||
|
0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a,
|
||||||
|
0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c,
|
||||||
|
0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e,
|
||||||
|
0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820,
|
||||||
|
0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822,
|
||||||
|
0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824,
|
||||||
|
0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826,
|
||||||
|
0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828,
|
||||||
|
0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a,
|
||||||
|
0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c,
|
||||||
|
0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e,
|
||||||
|
0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830,
|
||||||
|
0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832,
|
||||||
|
0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834,
|
||||||
|
0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836,
|
||||||
|
0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838,
|
||||||
|
0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a,
|
||||||
|
0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c,
|
||||||
|
0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e,
|
||||||
|
0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult)
|
||||||
|
{
|
||||||
|
const char *compressedEnd = compressed + compressedLength;
|
||||||
|
size_t decompressedLength = 0ul;
|
||||||
|
if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) {
|
||||||
|
*decompressedOutLengthResult = decompressedLength;
|
||||||
|
return (1);
|
||||||
|
} else {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut,
|
||||||
|
size_t decompressedOutLength)
|
||||||
|
{
|
||||||
|
const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength);
|
||||||
|
size_t parsedDecompressedLength = 0ul;
|
||||||
|
if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) ||
|
||||||
|
(parsedDecompressedLength > decompressedOutLength)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const char *compressedPtr = nextCompressedPtr;
|
||||||
|
DCHECK(compressedPtr <= compressedEnd);
|
||||||
|
if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char c = *((const unsigned char *)(compressedPtr++));
|
||||||
|
const unsigned char cLowerBits = (c & 0x3u);
|
||||||
|
const ssize_t spaceLeft = (decompressedEnd - decompressedPtr);
|
||||||
|
|
||||||
|
if ((cLowerBits == PITHY_LITERAL)) {
|
||||||
|
size_t literalLength = (c >> 2) + 1;
|
||||||
|
if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) &&
|
||||||
|
PITHY_EXPECT_T(spaceLeft >= 16l)) {
|
||||||
|
pithy_Move128(decompressedPtr, compressedPtr);
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_F(literalLength > 60)) {
|
||||||
|
if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_t literalLengthBytes = literalLength - 60;
|
||||||
|
literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1;
|
||||||
|
compressedPtr += literalLengthBytes;
|
||||||
|
}
|
||||||
|
if (PITHY_EXPECT_F(spaceLeft < (ssize_t)literalLength) ||
|
||||||
|
PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(decompressedPtr, compressedPtr, literalLength);
|
||||||
|
}
|
||||||
|
nextCompressedPtr = compressedPtr + literalLength;
|
||||||
|
decompressedPtr += literalLength;
|
||||||
|
} else {
|
||||||
|
const uint32_t entry = pithy_charTable[c];
|
||||||
|
const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits];
|
||||||
|
size_t length = entry & 0xffu;
|
||||||
|
const size_t copyOffset = ((entry & 0x700u) + trailer);
|
||||||
|
|
||||||
|
compressedPtr += cLowerBits;
|
||||||
|
|
||||||
|
DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul));
|
||||||
|
|
||||||
|
if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((ssize_t)copyOffset - 1l))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (PITHY_EXPECT_T(length <= 16ul) &&
|
||||||
|
PITHY_EXPECT_T(copyOffset >= 16ul) &&
|
||||||
|
PITHY_EXPECT_T(spaceLeft >= 16l)) {
|
||||||
|
pithy_Move128(decompressedPtr, decompressedPtr - copyOffset);
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_F(length >= 63ul)) {
|
||||||
|
if (PITHY_EXPECT_T(length == 63ul)) {
|
||||||
|
if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length = (*((unsigned char *)compressedPtr++)) + 63ul;
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length = pithy_LoadHost16(compressedPtr);
|
||||||
|
compressedPtr += 2ul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr;
|
||||||
|
ssize_t copyLength = (ssize_t)length;
|
||||||
|
|
||||||
|
if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) {
|
||||||
|
if (PITHY_EXPECT_F(spaceLeft < copyLength)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(copyTo, copyFrom, copyLength);
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) {
|
||||||
|
while ((copyTo - copyFrom) < 16l) {
|
||||||
|
pithy_Move128(copyTo, copyFrom);
|
||||||
|
copyLength -= copyTo - copyFrom;
|
||||||
|
copyTo += copyTo - copyFrom;
|
||||||
|
}
|
||||||
|
while (copyLength > 0l) {
|
||||||
|
pithy_Move128(copyTo, copyFrom);
|
||||||
|
copyFrom += 16l;
|
||||||
|
copyTo += 16l;
|
||||||
|
copyLength -= 16l;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
*copyTo++ = *copyFrom++;
|
||||||
|
} while (--copyLength > 0l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextCompressedPtr = compressedPtr;
|
||||||
|
decompressedPtr += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (decompressedPtr == decompressedEnd);
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// pithy.h
|
||||||
|
// http://github.com/johnezang/pithy
|
||||||
|
// Licensed under the terms of the BSD License, as specified below.
|
||||||
|
//
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011, John Engelhart
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the Zang Industries nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PITHY_H_
|
||||||
|
#define _PITHY_H_
|
||||||
|
|
||||||
|
// compressionLevel >= 0 && compressionLevel <= 9. Values out side this range will be clamped to this range.
|
||||||
|
size_t pithy_Compress (const char *uncompressed, size_t uncompressedLength, char *compressedOut,
|
||||||
|
size_t compressedOutLength, int compressionLevel);
|
||||||
|
int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut,
|
||||||
|
size_t decompressedOutLength);
|
||||||
|
|
||||||
|
size_t pithy_MaxCompressedLength(size_t inputLength);
|
||||||
|
int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength,
|
||||||
|
size_t *decompressedOutLengthResult);
|
||||||
|
|
||||||
|
#endif // _PITHY_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
Loading…
Reference in New Issue