2024-03-21 09:30:47 -04:00
|
|
|
// Copyright (c) 2000-2010 Marc Alexander Lehmann <schmorp@schmorp.de>
|
|
|
|
// SPDX-FileCopyrightText: 2024 Redict Contributors
|
|
|
|
// SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo <antirez at gmail dot com>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2024-03-21 15:11:44 -04:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
2009-04-02 04:00:49 -04:00
|
|
|
|
|
|
|
#include "lzfP.h"
|
|
|
|
|
|
|
|
#if AVOID_ERRNO
|
|
|
|
# define SET_ERRNO(n)
|
|
|
|
#else
|
|
|
|
# include <errno.h>
|
|
|
|
# define SET_ERRNO(n) errno = (n)
|
|
|
|
#endif
|
|
|
|
|
2014-12-23 10:10:42 -05:00
|
|
|
#if USE_REP_MOVSB /* small win on amd, big loss on intel */
|
2009-04-02 04:00:49 -04:00
|
|
|
#if (__i386 || __amd64) && __GNUC__ >= 3
|
|
|
|
# define lzf_movsb(dst, src, len) \
|
|
|
|
asm ("rep movsb" \
|
|
|
|
: "=D" (dst), "=S" (src), "=c" (len) \
|
|
|
|
: "0" (dst), "1" (src), "2" (len));
|
|
|
|
#endif
|
2014-12-23 10:10:42 -05:00
|
|
|
#endif
|
2009-04-02 04:00:49 -04:00
|
|
|
|
2020-10-23 13:49:15 -04:00
|
|
|
#if defined(__GNUC__) && __GNUC__ >= 7
|
2018-09-28 07:00:41 -04:00
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
|
|
|
#endif
|
2021-11-16 06:12:25 -05:00
|
|
|
size_t
|
|
|
|
lzf_decompress (const void *const in_data, size_t in_len,
|
|
|
|
void *out_data, size_t out_len)
|
2009-04-02 04:00:49 -04:00
|
|
|
{
|
|
|
|
u8 const *ip = (const u8 *)in_data;
|
|
|
|
u8 *op = (u8 *)out_data;
|
|
|
|
u8 const *const in_end = ip + in_len;
|
|
|
|
u8 *const out_end = op + out_len;
|
|
|
|
|
2020-08-14 09:05:34 -04:00
|
|
|
while (ip < in_end)
|
2009-04-02 04:00:49 -04:00
|
|
|
{
|
2020-08-14 09:05:34 -04:00
|
|
|
unsigned int ctrl;
|
|
|
|
ctrl = *ip++;
|
2009-04-02 04:00:49 -04:00
|
|
|
|
|
|
|
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
|
2014-12-23 10:10:42 -05:00
|
|
|
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++;
|
|
|
|
}
|
2009-04-02 04:00:49 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else /* back reference */
|
|
|
|
{
|
|
|
|
unsigned int len = ctrl >> 5;
|
|
|
|
|
|
|
|
u8 *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 < (u8 *)out_data)
|
|
|
|
{
|
|
|
|
SET_ERRNO (EINVAL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef lzf_movsb
|
|
|
|
len += 2;
|
|
|
|
lzf_movsb (op, ref, len);
|
|
|
|
#else
|
2014-12-23 10:10:42 -05:00
|
|
|
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;
|
|
|
|
|
2018-06-03 08:54:30 -04:00
|
|
|
case 9: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 8: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 7: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 6: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 5: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 4: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 3: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 2: *op++ = *ref++; /* fall-thru */
|
|
|
|
case 1: *op++ = *ref++; /* fall-thru */
|
2014-12-23 10:10:42 -05:00
|
|
|
case 0: *op++ = *ref++; /* two octets more */
|
2018-06-03 08:54:30 -04:00
|
|
|
*op++ = *ref++; /* fall-thru */
|
2014-12-23 10:10:42 -05:00
|
|
|
}
|
2009-04-02 04:00:49 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return op - (u8 *)out_data;
|
|
|
|
}
|
2018-09-28 07:00:41 -04:00
|
|
|
#if defined(__GNUC__) && __GNUC__ >= 5
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|