********************lzf.h*************************************************************************************************
#include "lzfP.h"
#if AVOID_ERRNO
# define SET_ERRNO(n)
#else
# include <errno.h>
# define SET_ERRNO(n) errno = (n)
#endif
#if USE_REP_MOVSB /* small win on amd, big loss on intel */
#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
#endif
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
unsigned int
lzf_decompress (const void *const in_data, unsigned int in_len,
void *out_data, unsigned int out_len)
{
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; 输出缓冲区结束位置
do
{
unsigned int ctrl = *ip++; 获取标志位
if (ctrl < (1 << 5)) /* literal run */ 原文表示,因为值小于2^5,所以是原文表示
{
ctrl++; 长度加1
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; 首先获取长度或者控制字符
u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; 偏移量的高5位 再减去1,进行回退(真正的偏移量还差低字节)
#if CHECK_INPUT
if (ip >= in_end) 如果已经到或者超过结束了,那么解压出错
{
SET_ERRNO (EINVAL);
return 0;
}
#endif
if (len == 7) 如果是长序列压缩 7就是111就是长序列
{
len += *ip++; 下一个字节就是长度
#if CHECK_INPUT
if (ip >= in_end)
{
SET_ERRNO (EINVAL);
return 0;
}
#endif
}
ref -= *ip++; 低字节的偏移量也要回退
if (op + len + 2 > out_end) 当前位置加解压长度加2超过 输出缓冲区结尾,解压出错
{
SET_ERRNO (E2BIG);
return 0;
}
if (ref < (u8 *)out_data) 如果引用值小于原字符序列开始值,解压也出错
{
SET_ERRNO (EINVAL);
return 0;
}
#ifdef lzf_movsb
len += 2; 长度值需要加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
{
重合区域,一个字节一个字节的拷贝,就是压缩的时候引用了自身,例如
a123123123123abc,这里123123123就会被自身引用,导致数据
/* overlapping, use octte by octte copying */
do
*op++ = *ref++;
while (--len);
}
break;
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 */
case 0: *op++ = *ref++; /* two octets more */ 这里的两个字节就是加2的效果
*op++ = *ref++; /* fall-thru */
}
#endif
}
}
while (ip < in_end);
return op - (u8 *)out_data;
}
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic pop
#endif
*********************************************************************************************************************