libc/lzf: Add Marc Alexander Lehmann's LIBLZF3.6 librrary

This commit is contained in:
Boris Astardzhiev 2018-03-14 14:48:53 -06:00 committed by Gregory Nutt
parent 9c1efc7ab9
commit 25eb417c12
9 changed files with 985 additions and 0 deletions

100
include/lzf.h Normal file
View File

@ -0,0 +1,100 @@
/*
* 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);
/*
* 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

View File

@ -15,6 +15,7 @@ source libc/dllfcn/Kconfig
source libc/modlib/Kconfig
source libc/wchar/Kconfig
source libc/locale/Kconfig
source libc/lzf/Kconfig
source libc/time/Kconfig
source libc/tls/Kconfig
source libc/net/Kconfig

View File

@ -62,6 +62,7 @@ include hex2bin/Make.defs
include inttypes/Make.defs
include libgen/Make.defs
include locale/Make.defs
include lzf/Make.defs
include machine/Make.defs
include math/Make.defs
include misc/Make.defs

View File

@ -33,6 +33,7 @@ we have:
hex2bin - hex2bin.h
libgen - libgen.h
locale - locale.h
lzf - lzf.h
fixedmath - fixedmath.h
inttypes - inttypes.h
machine - Various architecture-specific implementations.

39
libc/lzf/Kconfig Normal file
View File

@ -0,0 +1,39 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config LIBC_LZF
bool "LZF compression"
default n
---help---
Enable the LZF compression library from Marc Alexander Lehmann
if LIBC_LZF
choice
prompt "Compression options"
default LIBC_LZF_SMALL
---help---
Trade-offs between faster and smaller compression. These sections
have no effect on decompression.
config LIBC_LZF_SMALL
bool "Better compression"
config LIBC_LZF_FAST
bool "Faster compression"
config LIBC_LZF_FASTEST
bool "Fastest compression"
endchoice # Compression options
config LIBC_LZF_ALIGN
bool "Strict alignment"
default y
---help---
Unconditionally aligning does not cost very much, so do it if unsure.
endif # LIBC_LZF

47
libc/lzf/Make.defs Normal file
View File

@ -0,0 +1,47 @@
############################################################################
# libc/lzf/Make.defs
#
# Copyright (C) 2018 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, 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.
# 3. Neither the name NuttX 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.
#
############################################################################
ifeq ($(CONFIG_LIBC_LZF),y)
# Add the internal C files to the build
CSRCS += lzf_c.c lzf_d.c
# Add the userfs directory to the build
DEPPATH += --dep-path lzf
VPATH += :lzf
endif

123
libc/lzf/lzfP.h Normal file
View File

@ -0,0 +1,123 @@
/****************************************************************************
* libc/lzf/lzf_c.c
*
* 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.
*
****************************************************************************/
#ifndef __LIBC_LZF_LZFP_H
#define __LIBC_LZF_LZFP_H 1
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef __cplusplus
# include <cstdint>
# include <cstring>
# include <climits>
# include <cerrno>
using namespace std;
#else
# include <stdint.h>
# include <string.h>
# include <limits.h>
# include <errno.h>
#endif
#include <lzf.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* 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 13
#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
/* 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 0
#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 architectures, pointers take up twice as much space,
* and might also be slower. Default is to autodetect.
*/
/*#define LZF_USER_OFFSETS autodetect */
#ifndef LZF_USE_OFFSETS
# define LZF_USE_OFFSETS (UINTPTR_MAX > 0xffffffffU)
#endif
/****************************************************************************
* Public Types
****************************************************************************/
#if LZF_USE_OFFSETS
# define LZF_HSLOT_BIAS ((const uint8_t *)in_data)
typedef unsigned int LZF_HSLOT;
#else
# define LZF_HSLOT_BIAS 0
typedef const uint8_t *LZF_HSLOT;
#endif
typedef LZF_HSLOT LZF_STATE[1 << (HLOG)];
#endif /* __LIBC_LZF_LZFP_H */

394
libc/lzf/lzf_c.c Normal file
View File

@ -0,0 +1,394 @@
/****************************************************************************
* libc/lzf/lzf_c.c
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "lzf/lzfP.h"
#ifdef CONFIG_LIBC_LZF
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#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 defined(CONFIG_LIBC_LZF_FASTEST)
# define IDX(h) ((( h >> (3*8 - HLOG)) - h ) & (HSIZE - 1))
# elif defined(CONFIG_LIBC_LZF_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)
/****************************************************************************
* Public Functions
****************************************************************************/
/* 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(FAR const void *const in_data, unsigned int in_len,
FAR void *out_data, unsigned int out_len
#if LZF_STATE_ARG
, LZF_STATE htab
#endif
)
{
#if !LZF_STATE_ARG
LZF_STATE htab;
#endif
FAR const uint8_t *ip = (const uint8_t *)in_data;
FAR uint8_t *op = (uint8_t *)out_data;
FAR const uint8_t *in_end = ip + in_len;
FAR uint8_t *out_end = op + out_len;
FAR const uint8_t *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.
*/
#ifdef CONFIG_HAVE_LONG_LONG
uint64_t 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; /* start run */
op++;
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 = ip - ref - 1) < MAX_OFF
&& ref > (uint8_t *)in_data
&& ref[2] == ip[2]
#ifdef CONFIG_LIBC_LZF_ALIGN
&& ((ref[1] << 8) | ref[0]) == ((ip[1] << 8) | ip[0])
#else
&& *(uin16_t *)ref == *(uin16_t *)ip
#endif
)
{
/* Match found at *ref++ */
unsigned int len = 2;
unsigned int maxlen = in_end - ip - len;
maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
/* First a faster conservative test */
if (expect_false (op + 3 + 1 >= out_end))
{
/* Second the exact but rare test */
if (op - !lit + 3 + 1 >= out_end)
{
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++ = (off >> 8) + (len << 5);
}
else
{
*op++ = (off >> 8) + ( 7 << 5);
*op++ = len - 7;
}
*op++ = off;
lit = 0; op++; /* start run */
ip += len + 1;
if (expect_false (ip >= in_end - 2))
break;
#if defined(CONFIG_LIBC_LZF_FASTEST) || defined(CONFIG_LIBC_LZF_FAST)
--ip;
# if defined(CONFIG_LIBC_LZF_FAST) && !defined(CONFIG_LIBC_LZF_FASTEST)
--ip;
# endif
hval = FRST (ip);
hval = NEXT (hval, ip);
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
ip++;
# if defined(CONFIG_LIBC_LZF_FAST) && !defined(CONFIG_LIBC_LZF_FASTEST)
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 */
}
}
}
/* At most 3 bytes can be missing here */
if (op + 3 > out_end)
{
return 0;
}
while (ip < in_end)
{
lit++; *op++ = *ip++;
if (expect_false (lit == MAX_LIT))
{
op [- lit - 1] = lit - 1; /* Stop run */
lit = 0; /* Start run */
op++;
}
}
op [- lit - 1] = lit - 1; /* End run */
op -= !lit; /* Undo run if length is zero */
return op - (uint8_t *)out_data;
}
#endif /* CONFIG_LIBC_LZF */

279
libc/lzf/lzf_d.c Normal file
View File

@ -0,0 +1,279 @@
/****************************************************************************
* libc/lzf/lzf_c.c
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "lzf/lzfP.h"
#ifdef CONFIG_LIBC_LZF
/****************************************************************************
* Public Functions
****************************************************************************/
unsigned int lzf_decompress (FAR const void *const in_data,
unsigned int in_len, FAR void *out_data,
unsigned int out_len)
{
FAR uint8_t const *ip = (const uint8_t *)in_data;
FAR uint8_t *op = (uint8_t *)out_data;
FAR uint8_t const *const in_end = ip + in_len;
FAR uint8_t *const out_end = op + out_len;
do
{
unsigned int ctrl = *ip++;
if (ctrl < (1 << 5)) /* literal run */
{
ctrl++;
if (op + ctrl > out_end)
{
set_errno(E2BIG);
return 0;
}
#if CHECK_INPUT
if (ip + ctrl > in_end)
{
set_errno(EINVAL);
return 0;
}
#endif
#ifdef lzf_movsb
lzf_movsb(op, ip, ctrl);
#else
switch (ctrl)
{
case 32:
*op++ = *ip++;
case 31:
*op++ = *ip++;
case 30:
*op++ = *ip++;
case 29:
*op++ = *ip++;
case 28:
*op++ = *ip++;
case 27:
*op++ = *ip++;
case 26:
*op++ = *ip++;
case 25:
*op++ = *ip++;
case 24:
*op++ = *ip++;
case 23:
*op++ = *ip++;
case 22:
*op++ = *ip++;
case 21:
*op++ = *ip++;
case 20:
*op++ = *ip++;
case 19:
*op++ = *ip++;
case 18:
*op++ = *ip++;
case 17:
*op++ = *ip++;
case 16:
*op++ = *ip++;
case 15:
*op++ = *ip++;
case 14:
*op++ = *ip++;
case 13:
*op++ = *ip++;
case 12:
*op++ = *ip++;
case 11:
*op++ = *ip++;
case 10:
*op++ = *ip++;
case 9:
*op++ = *ip++;
case 8:
*op++ = *ip++;
case 7:
*op++ = *ip++;
case 6:
*op++ = *ip++;
case 5:
*op++ = *ip++;
case 4:
*op++ = *ip++;
case 3:
*op++ = *ip++;
case 2:
*op++ = *ip++;
case 1:
*op++ = *ip++;
}
#endif
}
else /* back reference */
{
unsigned int len = ctrl >> 5;
FAR uint8_t *ref = op - ((ctrl & 0x1f) << 8) - 1;
#if CHECK_INPUT
if (ip >= in_end)
{
set_errno(EINVAL);
return 0;
}
#endif
if (len == 7)
{
len += *ip++;
#if CHECK_INPUT
if (ip >= in_end)
{
set_errno(EINVAL);
return 0;
}
#endif
}
ref -= *ip++;
if (op + len + 2 > out_end)
{
set_errno(E2BIG);
return 0;
}
if (ref < (uint8_t *)out_data)
{
set_errno(EINVAL);
return 0;
}
#ifdef lzf_movsb
len += 2;
lzf_movsb (op, ref, len);
#else
switch (len)
{
default:
len += 2;
if (op >= ref + len)
{
/* Disjunct areas */
memcpy (op, ref, len);
op += len;
}
else
{
/* Overlapping, use octte by octte copying */
do
*op++ = *ref++;
while (--len);
}
break;
case 9:
*op++ = *ref++;
case 8:
*op++ = *ref++;
case 7:
*op++ = *ref++;
case 6:
*op++ = *ref++;
case 5:
*op++ = *ref++;
case 4:
*op++ = *ref++;
case 3:
*op++ = *ref++;
case 2:
*op++ = *ref++;
case 1:
case 0:
/* two octets more */
*op++ = *ref++;
*op++ = *ref++;
}
#endif
}
}
while (ip < in_end);
return op - (uint8_t *)out_data;
}
#endif /* CONFIG_LIBC_LZF */