From 25eb417c126fa9eb648abc3ad9ae8cdacba5ef71 Mon Sep 17 00:00:00 2001 From: Boris Astardzhiev Date: Wed, 14 Mar 2018 14:48:53 -0600 Subject: [PATCH] libc/lzf: Add Marc Alexander Lehmann's LIBLZF3.6 librrary --- include/lzf.h | 100 ++++++++++++ libc/Kconfig | 1 + libc/Makefile | 1 + libc/README.txt | 1 + libc/lzf/Kconfig | 39 +++++ libc/lzf/Make.defs | 47 ++++++ libc/lzf/lzfP.h | 123 ++++++++++++++ libc/lzf/lzf_c.c | 394 +++++++++++++++++++++++++++++++++++++++++++++ libc/lzf/lzf_d.c | 279 ++++++++++++++++++++++++++++++++ 9 files changed, 985 insertions(+) create mode 100644 include/lzf.h create mode 100644 libc/lzf/Kconfig create mode 100644 libc/lzf/Make.defs create mode 100644 libc/lzf/lzfP.h create mode 100644 libc/lzf/lzf_c.c create mode 100644 libc/lzf/lzf_d.c diff --git a/include/lzf.h b/include/lzf.h new file mode 100644 index 0000000000..919b6e6be2 --- /dev/null +++ b/include/lzf.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2000-2008 Marc Alexander Lehmann + * + * 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 + diff --git a/libc/Kconfig b/libc/Kconfig index 0e558863db..14201c1814 100644 --- a/libc/Kconfig +++ b/libc/Kconfig @@ -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 diff --git a/libc/Makefile b/libc/Makefile index 09e3cbd81b..bf866203b0 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -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 diff --git a/libc/README.txt b/libc/README.txt index b80438c9b9..7e93ee8fb4 100644 --- a/libc/README.txt +++ b/libc/README.txt @@ -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. diff --git a/libc/lzf/Kconfig b/libc/lzf/Kconfig new file mode 100644 index 0000000000..3b27143ddf --- /dev/null +++ b/libc/lzf/Kconfig @@ -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 + diff --git a/libc/lzf/Make.defs b/libc/lzf/Make.defs new file mode 100644 index 0000000000..e5b95f5293 --- /dev/null +++ b/libc/lzf/Make.defs @@ -0,0 +1,47 @@ +############################################################################ +# libc/lzf/Make.defs +# +# Copyright (C) 2018 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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 diff --git a/libc/lzf/lzfP.h b/libc/lzf/lzfP.h new file mode 100644 index 0000000000..0b5c470cba --- /dev/null +++ b/libc/lzf/lzfP.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * libc/lzf/lzf_c.c + * + * Copyright (c) 2000-2007 Marc Alexander Lehmann + * + * 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 + +#ifdef __cplusplus +# include +# include +# include +# include +using namespace std; +#else +# include +# include +# include +# include +#endif + +#include + +/**************************************************************************** + * 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 */ diff --git a/libc/lzf/lzf_c.c b/libc/lzf/lzf_c.c new file mode 100644 index 0000000000..28af584e64 --- /dev/null +++ b/libc/lzf/lzf_c.c @@ -0,0 +1,394 @@ +/**************************************************************************** + * libc/lzf/lzf_c.c + * + * Copyright (c) 2000-2010 Marc Alexander Lehmann + * + * 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 ; 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 */ diff --git a/libc/lzf/lzf_d.c b/libc/lzf/lzf_d.c new file mode 100644 index 0000000000..fe29f2accc --- /dev/null +++ b/libc/lzf/lzf_d.c @@ -0,0 +1,279 @@ +/**************************************************************************** + * libc/lzf/lzf_c.c + * + * Copyright (c) 2000-2010 Marc Alexander Lehmann + * + * 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 */