/**@file  compress.c
 * @brief       电压数据压缩
 * @details     电压值经delta,zigzag,lzss压缩后传输
 * @author      tbh
 * @date        2023-5-8
 * @version     V1.0
 * @copyright   
********************************************************************************
 * @attention
 * 硬件平台: \n
 * @par 修改日志:
 * <table>
 * <tr><th>Date        <th>Version  <th>Author    <th>Description
 * <tr><td>2023/05/10  <td>1.0      <td>tbh       <td>创建初始版本
 * </table>
 *
********************************************************************************
*/

#include "j1939_compress.h"
//#include "rte.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdint.h>
#include <stddef.h>


#define POS_BITS 12	/* 用于编码位置的值 */
#define LEN_BITS (16 - POS_BITS) /* 用于编码长度的值 */
#define POS_SIZE (1 << POS_BITS) // 滑动窗口长度 
#define LEN_SIZE (1 << LEN_BITS) /* 匹配字符串的长度 */
#define LEN_MIN 3 /* 最小匹配字符串长度 */
#define MAX_COMPRESS_REG_NUM 600 /*最大压缩寄存器*/

#define FASTLZ_LIKELY(c) (c)
#define FASTLZ_UNLIKELY(c) (c)
#define MAX_COPY 32
#define MAX_LEN 264 /* 256 + 8 */
#define MAX_L1_DISTANCE 8192
#define MAX_L2_DISTANCE 8191
#define MAX_FARDISTANCE (65535 + MAX_L2_DISTANCE - 1)

#define HASH_LOG 5
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MASK (HASH_SIZE - 1)


typedef enum
{
    COMPRESS_TYPE_NONE,
    COMPRESS_TYPE_ZIGZAG,
    COMPRESS_TYPE_LZSS,
    COMPRESS_TYPE_BUTT
}COMPRESS_TYPE_ENUM;

typedef struct
{
    uint8_t varintbuf[5 * MAX_COMPRESS_REG_NUM];
    uint8_t lzssBuf[3 * MAX_COMPRESS_REG_NUM];
}COMPRESS_DATA_STRU;

COMPRESS_DATA_STRU *g_pCompressDataStru = NULL;

void Encode_Delta(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen); 
void Decode_Delta(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen); 
void Encode_Zigzag(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen);
void Decode_Zigzag(uint16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen); 
int32_t Encode_Varint(uint16_t zz, uint8_t* buf, int32_t size);
int32_t Decode_Varint(uint8_t* buf, int32_t* val);
int32_t fastlz_compress(const void* input, int length, void* output) ;
int32_t fastlz_decompress(const void* input, int length, void* output, int maxout); 

/*!
 * @brief       压缩与解压缩初始化
 *
 * @param[in]   void
 * @return      Std_Ret_Type
 * @retval      Std_Ret_OK:初始化成功 Std_Ret_ERR：初始化失败
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2023-5-11    jyg      Create             \n
 *
 */
Std_Ret_Type Compress_Init(void)
{
    g_pCompressDataStru = (COMPRESS_DATA_STRU *)malloc(sizeof(COMPRESS_DATA_STRU));
    if(g_pCompressDataStru == NULL)
    {
        return Std_Ret_ERR;
    }
    memset(g_pCompressDataStru, 0x00, sizeof(COMPRESS_DATA_STRU));
    return Std_Ret_OK;
}

/**@brief       delta编码，计算相邻两位原始数值的差值，首个数值不变
 * @param[in]  int16_t* data 原始数据
 * @param[in]  int32_t dataLen 原始数据长度
 * @param[out] int16_t* returnBuf delta编码后的数据
 * @param[out] int32_t* returnLen delta编码后的数据长度
 * @return      无
 * @retval      无
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 * 2023/05/11           jyg        优化栈深问题(进出使用同一片地址)     \n
 */
void Encode_Delta(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen) {

    int32_t i = 0, j = 0;
    int16_t lastTmpValue = 0,tmpDelta = 0;
    if((data == NULL)||(returnBuf == NULL)||(returnLen == NULL))
    {
        return;
    }
    lastTmpValue = data[0];
    returnBuf[0] = lastTmpValue;
    for (i = 1; i < dataLen; i++) 
    {
        tmpDelta = data[i] - lastTmpValue;
        lastTmpValue = data[i];
        returnBuf[++j] = tmpDelta;
    }

    *returnLen = j + 1;
}


/**@brief       delta解码，根据差值电压计算原始电压
 * @param[in]  int16_t* data 原始数据
 * @param[in]  int32_t dataLen 原始数据长度
 * @param[out] int16_t* returnBuf delta解码后的数据
 * @param[out] int32_t* returnLen delta解码后的数据长度
 * @return      无
 * @retval      无
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 */
void Decode_Delta(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen) 
{
    int32_t i = 0, j = 0;
    
    if((data == NULL)||(returnBuf == NULL)||(returnLen == NULL))
    {
        return;
    }
 
    returnBuf[0] = data[0];
    for (i = 1; i < dataLen; i++) 
    {
        returnBuf[++j] = returnBuf[i - 1] + data[i];
    }

    *returnLen = j + 1;
}


/**@brief       zigzag编码，对差值进行压缩
 * @param[in]  int16_t* data 经delta编码后的原始数据
 * @param[in]  int32_t dataLen 经delta编码后的原始数据长度
 * @param[out] int16_t* returnBuf zigzag编码后的数据
 * @param[out] int32_t* returnLen zigzag编码后的数据长度
 * @return      无
 * @retval      无
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 */
void Encode_Zigzag(int16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen) 
{
    int32_t i = 0, j = 0;

    if((data == NULL)||(returnBuf == NULL)||(returnLen == NULL))
    {
        return;
    }
    for (i = 0; i < dataLen; i++) {
        returnBuf[j++] = (data[i] << 1) ^ (data[i] >> 31);
    }
    *returnLen = j;
}

/**@brief       zigzag解码，对zigzag压缩数据进行解压缩
 * @param[in]  uint16_t* data 经字节自表示后的原始数据
 * @param[in]  int32_t dataLen 经字节自表示后的原始数据长度
 * @param[out] int16_t* returnBuf zigzag解码后的数据
 * @param[out] int32_t* returnLen zigzag解码后的数据长度
 * @return      无
 * @retval      无
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 */
void Decode_Zigzag(uint16_t* data, int32_t dataLen, int16_t* returnBuf, int32_t* returnLen) 
{
    int32_t i = 0, j = 0;
    if((data == NULL)||(returnBuf == NULL)||(returnLen == NULL))
    {
        return;
    }
    for (i = 0; i < dataLen; i++) 
    {
        returnBuf[j++] = (int16_t)((data[i] >> 1) ^ -(data[i] & 1));
    }
    *returnLen = j;
}

/**@brief      字节自表示，根据有效字节长度存放zigzag压缩数据
 * @param[in]  uint16_t zz 经zigzag编码后的原始数据
 * @param[in]  uint8_t* buf 写入数组的起始位置
 * @param[in]  int32_t size 默认为5，保证完全读取有效字节
 * @return     
 * @retval     本个数据的有效字节数
 * @par        修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 */
int32_t Encode_Varint(uint16_t zz, uint8_t* buf, int32_t size) 
{
    int32_t ret = 0,i = 0;
    if(buf == NULL)
    {
        return -1;
    }
    for (i = 0; i < size; i++) 
    {
        if ((zz & (~0x7f)) == 0) 
        {
            buf[i] = (uint8_t)zz;
            ret = i + 1;
            break;
        }
        else 
        {
            buf[i] = (uint8_t)((zz & 0x7f) | 0x80);
            zz = ((uint32_t)zz) >> 7;
        }
    }

    return ret;
}

/**@brief      将有效字节还原到能被zigzag解压缩的格式
 * @param[in]  uint8_t* buf 经varint编码后的原始数据
 * @param[in]  int32_t* val 此次解码出来的数据，用于zigzag解码
 * @return
 * @retval     本个数据的有效字节长度
 * @par        修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 */
int32_t Decode_Varint(uint8_t* buf, int32_t* val) 
{
    int32_t size = 0,i = 0;
    if((buf == NULL)||(val == NULL))
    {
        return -1;
    }
    *val = 0;
    for (i = 0; i < 5; i++) 
    {
        uint8_t b = buf[i];
        if (b < 128) 
        {
            *val |= (b << (7 * i));
            size = i + 1;
            break;
        }
        else 
        {
            *val |= ((b & 127) << (7 * i));
        }
    }
    return size;
}

/**@brief      内存拷贝，源地址与目标地址无重叠则用memmove，否则循环逐个拷贝
 * @param[in]  uint8_t* dest 目标地址
 * @param[in]  const uint8_t* src 源地址
 * @param[in]  uint32_t count 拷贝的字节数
 * @return
 * @retval      
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) {
    if ((count > 4) && (dest >= src + count)) {
        memmove(dest, src, count);
    }
    else {
        switch (count) {
        default:
            do {
                *dest++ = *src++;
            } while (--count);
            break;
        case 3:
            *dest++ = *src++;
        case 2:
            *dest++ = *src++;
        case 1:
            *dest++ = *src++;
        case 0:
            break;
        }
    }
}

static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { memcpy(dest, src, count); }
static uint32_t flz_readu32(const void* ptr) 
{
    const uint8_t* p = (const uint8_t*)ptr;
    return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
}

static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) 
{
    const uint8_t* start = p;
    while (q < r)
        if (*p++ != *q++) break;
    return p - start;
}

/**@brief      哈希操作，将输入的32位整数进行哈希得到16位哈希值
 * @param[in]  uint32_t 输入32位整数
 * @return
 * @retval     哈希值
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static uint16_t flz_hash(uint32_t v) 
{
    uint32_t h = (v * 2654435769LL) >> (32 - HASH_LOG);
    return (uint16_t)(h & HASH_MASK);
}

/**@brief      小数据块拷贝，数据块大小分界点为4字节
 * @param[in]  uint8_t* dest 目标地址
 * @param[in]  const uint8_t* src 源地址
 * @param[in]  uint32_t count 拷贝的字节数
 * @return
 * @retval
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static void flz_smallcopy(uint8_t* dest, const uint8_t* src, uint32_t count) 
{
    fastlz_memcpy(dest, src, count);
}

/**@brief      最大数据块拷贝，正好是MAX_COPY字节
 * @param[in]  uint8_t* dest 目标地址
 * @param[in]  const uint8_t* src 源地址
 * @return
 * @retval
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static void flz_maxcopy(void* dest, const void* src) 
{
    fastlz_memcpy(dest, src, MAX_COPY);
}

/**@brief      字面量编码，将连续的字面量拷贝到目标地址中
 * @param[in]  uint32_t runs 连续的字面量数
 * @param[in]  const uint8_t* src 源地址
 * @param[out] uint8_t* dest 目标地址
 * @return
 * @retval     拷贝后的目标地址
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static uint8_t* flz_literals(uint32_t runs, const uint8_t* src, uint8_t* dest) 
{
    while (runs >= MAX_COPY) {
        *dest++ = MAX_COPY - 1;
        flz_maxcopy(dest, src);
        src += MAX_COPY;
        dest += MAX_COPY;
        runs -= MAX_COPY;
    }
    if (runs > 0) {
        *dest++ = runs - 1;
        flz_smallcopy(dest, src, runs);
        dest += runs;
    }
    return dest;
}

/**@brief      匹配编码，将匹配位置与长度编码到目标地址
 * @param[in]  uint32_t len 匹配长度
 * @param[in]  uint32_t distance 匹配距离
 * @param[out] uint8_t* op 目标地址
 * @return
 * @retval     编码后的目标地址
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static uint8_t* flz1_match(uint32_t len, uint32_t distance, uint8_t* op) 
{
    --distance;
    if (FASTLZ_UNLIKELY(len > MAX_LEN - 2))
        while (len > MAX_LEN - 2) {
            *op++ = (7 << 5) + (distance >> 8);
            *op++ = MAX_LEN - 2 - 7 - 2;
            *op++ = (distance & 255);
            len -= MAX_LEN - 2;
        }
    if (len < 7) {
        *op++ = (len << 5) + (distance >> 8);
        *op++ = (distance & 255);
    }
    else {
        *op++ = (7 << 5) + (distance >> 8);
        *op++ = len - 7;
        *op++ = (distance & 255);
    }
    return op;
}

#define FASTLZ_BOUND_CHECK(cond) \
  if (FASTLZ_UNLIKELY(!(cond))) return 0;

/**@brief      fastlz压缩，压缩级别1，将zigzag编码后的数据进一步压缩，最快，通常对短数据有用。
 * @param[in]  const void* input 输入缓冲区，用于存放要压缩的数据
 * @param[in]  int length 输入缓冲区的大小，最小输入缓冲区大小为16
 * @param[out] void* output 输出缓冲区，用于存放压缩后的数据。输出缓冲区必须至少比输入缓冲区大5%，并且不能小于66字节。
 * @return
 * @retval      压缩后的数据大小，如果输入不可压缩，则返回值可能大于长度
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz1_compress(const void* input, int length, void* output) {
    const uint8_t* ip = (const uint8_t*)input;
    const uint8_t* ip_start = ip;
    const uint8_t* ip_bound = ip + length - 4; /* because readU32 */
    const uint8_t* ip_limit = ip + length - 12 - 1;
    const uint8_t* anchor = NULL;
    const uint8_t* ref = NULL;
    uint8_t* op = (uint8_t*)output;
    uint32_t htab[HASH_SIZE] = {0u};
    uint32_t seq = 0u, hash = 0u;
    uint32_t distance = 0u, cmp = 0u;
    uint32_t len = 0u,copy = 0u;

    /* initializes hash table */
    for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0;

    /* we start with literal copy */
    anchor = ip;
    ip += 2;

    /* main loop */
    while (FASTLZ_LIKELY(ip < ip_limit)) 
    {
        /* find potential match */
        do {
            seq = flz_readu32(ip) & 0xffffff;
            hash = flz_hash(seq);
            ref = ip_start + htab[hash];
            htab[hash] = ip - ip_start;
            distance = ip - ref;
            cmp = FASTLZ_LIKELY(distance < MAX_L1_DISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000;
            if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
            ++ip;
        } while (seq != cmp);

        if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
        --ip;

        if (FASTLZ_LIKELY(ip > anchor)) {
            op = flz_literals(ip - anchor, anchor, op);
        }

        len = flz_cmp(ref + 3, ip + 3, ip_bound);
        op = flz1_match(len, distance, op);

        /* update the hash at match boundary */
        ip += len;
        seq = flz_readu32(ip);
        hash = flz_hash(seq & 0xffffff);
        htab[hash] = ip++ - ip_start;
        seq >>= 8;
        hash = flz_hash(seq);
        htab[hash] = ip++ - ip_start;
        anchor = ip;
    }

    copy = (uint8_t*)input + length - anchor;
    op = flz_literals(copy, anchor, op);

    return (int32_t )(op - (uint8_t*)output);
}


/**@brief      fastlz解压缩，解压缩级别1，对应fastlz1_compress。
 * @param[in]  const void* input 输入缓冲区，用于存放要解压的数据
 * @param[in]  int length 输入缓冲区的长度
 * @param[out] void* output 输出缓冲区，用于存放解压缩后的数据
 * @param[out] int maxout 输出缓冲区的所能容纳的最大长度。解压时会保证输出缓冲区的写入量不会超过maxout中指定的值。
 * @return
 * @retval      解压缩后的数据大小，如果发生错误，例如压缩数据损坏或输出缓冲区不够大，则将返回0
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz1_decompress(const void* input, int length, void* output, int maxout) 
{
    const uint8_t* ip = (const uint8_t*)input;
    const uint8_t* ip_limit = ip + length;
    const uint8_t* ip_bound = ip_limit - 2;
    const uint8_t* ref = NULL;
    uint8_t* op = (uint8_t*)output;
    uint8_t* op_limit = op + maxout;
    uint32_t ctrl = (*ip++) & 31;
    uint32_t len = 0u,ofs = 0u;

    while (1) 
    {
        if (ctrl >= 32) {
            len = (ctrl >> 5) - 1;
            ofs = (ctrl & 31) << 8;
            ref = op - ofs - 1;
            if (len == 7 - 1) {
                FASTLZ_BOUND_CHECK(ip <= ip_bound);
                len += *ip++;
            }
            ref -= *ip++;
            len += 3;
            FASTLZ_BOUND_CHECK(op + len <= op_limit);
            FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output);
            fastlz_memmove(op, ref, len);
            op += len;
        }
        else {
            ctrl++;
            FASTLZ_BOUND_CHECK(op + ctrl <= op_limit);
            FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit);
            fastlz_memcpy(op, ip, ctrl);
            ip += ctrl;
            op += ctrl;
        }

        if (FASTLZ_UNLIKELY(ip > ip_bound)) break;
        ctrl = *ip++;
    }

    return op - (uint8_t*)output;
}


/**@brief      匹配编码，将匹配位置与长度编码到目标地址
 * @param[in]  uint32_t len 匹配长度
 * @param[in]  uint32_t distance 匹配距离
 * @param[out] uint8_t* op 目标地址
 * @return
 * @retval     编码后的目标地址
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
static uint8_t* flz2_match(uint32_t len, uint32_t distance, uint8_t* op) 
{
    --distance;
    if (distance < MAX_L2_DISTANCE) {
        if (len < 7) {
            *op++ = (len << 5) + (distance >> 8);
            *op++ = (distance & 255);
        }
        else {
            *op++ = (7 << 5) + (distance >> 8);
            for (len -= 7; len >= 255; len -= 255) *op++ = 255;
            *op++ = len;
            *op++ = (distance & 255);
        }
    }
    else {
        /* far away, but not yet in the another galaxy... */
        if (len < 7) {
            distance -= MAX_L2_DISTANCE;
            *op++ = (len << 5) + 31;
            *op++ = 255;
            *op++ = distance >> 8;
            *op++ = distance & 255;
        }
        else {
            distance -= MAX_L2_DISTANCE;
            *op++ = (7 << 5) + 31;
            for (len -= 7; len >= 255; len -= 255) *op++ = 255;
            *op++ = len;
            *op++ = 255;
            *op++ = distance >> 8;
            *op++ = distance & 255;
        }
    }
    return op;
}


/**@brief      fastlz压缩，压缩级别2，将zigzag编码后的数据进一步压缩，较级别1稍微慢一点，但提供了更好的压缩比
 * @param[in]  const void* input 输入缓冲区，用于存放要压缩的数据
 * @param[in]  int length 输入缓冲区的大小
 * @param[out] void* output 输出缓冲区，用于存放压缩后的数据。
 * @return
 * @retval      压缩后的数据大小，如果输入不可压缩，则返回值可能大于长度
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz2_compress(const void* input, int length, void* output) {
    const uint8_t* ip = (const uint8_t*)input;
    const uint8_t* ip_start = ip;
    const uint8_t* ip_bound = ip + length - 4; /* because readU32 */
    const uint8_t* ip_limit = ip + length - 12 - 1;
    const uint8_t* anchor = ip;
    const uint8_t* ref;
    uint8_t* op = (uint8_t*)output;
    uint32_t htab[HASH_SIZE] = {0u};
    uint32_t seq = 0u, hash = 0u;
    uint32_t copy = 0u,len = 0u;
    uint32_t distance = 0u, cmp = 0u;

    /* initializes hash table */
    for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0;

    /* we start with literal copy */
    ip += 2;
    /* main loop */
    while (FASTLZ_LIKELY(ip < ip_limit)) 
    {
        /* find potential match */
        do {
            seq = flz_readu32(ip) & 0xffffff;
            hash = flz_hash(seq);
            ref = ip_start + htab[hash];
            htab[hash] = ip - ip_start;
            distance = ip - ref;
            cmp = FASTLZ_LIKELY(distance < MAX_FARDISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000;
            if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
            ++ip;
        } while (seq != cmp);

        if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;

        --ip;

        /* far, needs at least 5-byte match */
        if (distance >= MAX_L2_DISTANCE) {
            if (ref[3] != ip[3] || ref[4] != ip[4]) {
                ++ip;
                continue;
            }
        }

        if (FASTLZ_LIKELY(ip > anchor)) {
            op = flz_literals(ip - anchor, anchor, op);
        }

        len = flz_cmp(ref + 3, ip + 3, ip_bound);
        op = flz2_match(len, distance, op);

        /* update the hash at match boundary */
        ip += len;
        seq = flz_readu32(ip);
        hash = flz_hash(seq & 0xffffff);
        htab[hash] = ip++ - ip_start;
        seq >>= 8;
        hash = flz_hash(seq);
        htab[hash] = ip++ - ip_start;

        anchor = ip;
    }

    copy = (uint8_t*)input + length - anchor;
    op = flz_literals(copy, anchor, op);

    /* marker for fastlz2 */
    *(uint8_t*)output |= (1 << 5);

    return (int32_t)(op - (uint8_t*)output);
}


/**@brief      fastlz解压缩，解压缩级别2，对应fastlz2_compress。
 * @param[in]  const void* input 输入缓冲区，用于存放要解压的数据
 * @param[in]  int length 输入缓冲区的长度
 * @param[out] void* output 输出缓冲区，用于存放解压缩后的数据
 * @param[out] int maxout 输出缓冲区的所能容纳的最大长度。
 * @return
 * @retval      解压缩后的数据大小
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz2_decompress(const void* input, int length, void* output, int maxout) {
    const uint8_t* ip = (const uint8_t*)input;
    const uint8_t* ip_limit = ip + length;
    const uint8_t* ip_bound = ip_limit - 2;
    const uint8_t* ref = NULL;
    uint8_t code = 0u;
    uint8_t* op = (uint8_t*)output;
    uint8_t* op_limit = op + maxout;
    uint32_t len = 0u,ofs = 0u;
    uint32_t ctrl = (*ip++) & 31;

    while (1) 
    {
        if (ctrl >= 32) 
        {
            ref = op - ofs - 1;
            len = (ctrl >> 5) - 1;
            ofs = (ctrl & 31) << 8;
            if (len == 7 - 1) do {
                FASTLZ_BOUND_CHECK(ip <= ip_bound);
                code = *ip++;
                len += code;
            } while (code == 255);
            code = *ip++;
            ref -= code;
            len += 3;

            /* match from 16-bit distance */
            if (FASTLZ_UNLIKELY(code == 255))
                if (FASTLZ_LIKELY(ofs == (31 << 8))) {
                    FASTLZ_BOUND_CHECK(ip < ip_bound);
                    ofs = (*ip++) << 8;
                    ofs += *ip++;
                    ref = op - ofs - MAX_L2_DISTANCE - 1;
                }

            FASTLZ_BOUND_CHECK(op + len <= op_limit);
            FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output);
            fastlz_memmove(op, ref, len);
            op += len;
        }
        else {
            ctrl++;
            FASTLZ_BOUND_CHECK(op + ctrl <= op_limit);
            FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit);
            fastlz_memcpy(op, ip, ctrl);
            ip += ctrl;
            op += ctrl;
        }

        if (FASTLZ_UNLIKELY(ip >= ip_limit)) break;
        ctrl = *ip++;
    }

    return (int32_t)(op - (uint8_t*)output);
}

/**@brief      fastlz压缩，根据输入自动选择压缩级别
 * @param[in]  const void* input 输入缓冲区，用于存放要压缩的数据
 * @param[in]  int length 输入缓冲区的大小
 * @param[out] void* output 输出缓冲区，用于存放压缩后的数据。
 * @return
 * @retval      压缩后的数据大小
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz_compress(const void* input, int length, void* output) 
{
    /* for short block, choose fastlz1 */
    if (length < 65536) 
    {
        return fastlz1_compress(input, length, output);
    }
    else
    {
        /* else... */
        return fastlz2_compress(input, length, output);
    }
}

/**@brief      fastlz解压缩，无论级别如何，都可以使用该函数进行解压缩
 * @param[in]  const void* input 输入缓冲区，用于存放要解压的数据
 * @param[in]  int length 输入缓冲区的长度
 * @param[out] void* output 输出缓冲区，用于存放解压缩后的数据
 * @param[out] int maxout 输出缓冲区的所能容纳的最大长度。
 * @return
 * @retval      解压缩后的数据大小，发生错误返回0
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz_decompress(const void* input, int length, void* output, int maxout) 
{
    /* magic identifier for compression level */
    int level = ((*(const uint8_t*)input) >> 5) + 1;

    if (level == 1) return fastlz1_decompress(input, length, output, maxout);
    if (level == 2) return fastlz2_decompress(input, length, output, maxout);

    /* unknown level, trigger error */
    return 0;
}


/**@brief      fastlz压缩，将zigzag编码后的数据进一步压缩
 * @param[in]  int level 选择的压缩级别
 * @param[in]  const void* input 输入缓冲区，用于存放要压缩的数据
 * @param[in]  int length 输入缓冲区的大小
 * @param[out] void* output 输出缓冲区，用于存放压缩后的数据。
 * @return
 * @retval      压缩后的数据大小
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/19           tbh        创建初始版本     \n
 */
int32_t fastlz_compress_level(int level, const void* input, int length, void* output)
{
    if (level == 1) return fastlz1_compress(input, length, output);
    if (level == 2) return fastlz2_compress(input, length, output);

    return 0;
}

/**@brief      数据压缩
 * @param[in]  int16_t* src 原始电压
 * @param[in]  int32_t srcLen 原始电压数量
 * @param[out] uint8_t* dst 压缩后存放的数组(含压缩数据及压缩类型)
 * @param[out] int32_t* dstLen 压缩后的长度（含压缩数据长度及压缩类型长度）
 * @return
 * @retval
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 * 2023/05/19           tbh        更换压缩算法\n
 */
void Compress_EnCode(int16_t* src, int32_t srcLen, uint8_t* dst, int32_t* dstLen) 
{
    int16_t *deltaEnVol = NULL;
    int16_t *zigzagEnVol = NULL;
    int32_t deltaVolLen = 0, zigzagVolLen = 0;
    int32_t zigzagTotalSize = 0;
    int32_t lzssEnVolLen = 0,i = 0;;

    if(g_pCompressDataStru == NULL)
    {
        return ;
    }
    if((src == NULL)||(dst == NULL)||(dstLen == NULL))
    {
        return ;
    }
    memset(g_pCompressDataStru->varintbuf,0,sizeof(g_pCompressDataStru->varintbuf));
    memset(g_pCompressDataStru->lzssBuf,0,sizeof(g_pCompressDataStru->lzssBuf));
    deltaEnVol = src;
    Encode_Delta(src, srcLen, deltaEnVol, &deltaVolLen);
    zigzagEnVol = src;
    Encode_Zigzag(deltaEnVol, deltaVolLen, zigzagEnVol, &zigzagVolLen);
    for (i = 0; i < zigzagVolLen; i++)
    {
        zigzagTotalSize += Encode_Varint(zigzagEnVol[i], g_pCompressDataStru->varintbuf + zigzagTotalSize, 5);
    }
    
    lzssEnVolLen = fastlz_compress_level(1, g_pCompressDataStru->varintbuf, zigzagTotalSize, g_pCompressDataStru->lzssBuf);
    if (lzssEnVolLen > zigzagTotalSize) 
    {//不采用lzss传1，否则传2
        dst[0] = COMPRESS_TYPE_ZIGZAG;
        for (i = 0; i < zigzagTotalSize; i++)
        {
            dst[i + 1] = g_pCompressDataStru->varintbuf[i];
        }
        *dstLen = (zigzagTotalSize + 1);
    }
    else 
    {
        dst[0] = COMPRESS_TYPE_LZSS;
        for (i = 0; i < lzssEnVolLen; i++)
        {
            dst[i + 1] = g_pCompressDataStru->lzssBuf[i];
        }
        *dstLen = (lzssEnVolLen + 1);
    }
}

/**@brief      数据解压缩
 * @param[in]  uint8_t* src 压缩后的数据（含压缩类型）
 * @param[in]  int32_t srcLen 压缩后的数据长度(剔除第一个字节(压缩类型)长度)
 * @param[out] uint8_t* dst 还原后存放原始电压的数组
 * @param[out] int32_t* dstLen 原始电压数量
 * @return
 * @retval
 * @par         修改日志:
 * Date                Author      Description           \n
 * 2023/05/10           tbh        创建初始版本     \n
 * 2023/05/19           tbh        更换解压算法\n
 * 2023/07/21           jyg        zigzag解压缩时，防止数组越界\n
 */
void Compress_DeCode(uint8_t* src, int32_t srcLen, int16_t* dst, int32_t* dstLen) 
{
    int32_t lzss_decoded_len = 0; 
    int16_t *varintDecoded = NULL;
    int16_t *zigzagDecoded = NULL;
    int16_t *deltaDecoded = NULL;
    int32_t zigzagDecodedLen = 0, deltaDecodedLen = 0,varintDecodedLen = 0;
    int32_t index = 0,i = 0,val = 0,size = 0;

    if(g_pCompressDataStru == NULL)
    {
        return ;
    }
    if((src == NULL)||(dst == NULL)||(dstLen == NULL))
    {
        return ;
    }
    lzss_decoded_len = sizeof(g_pCompressDataStru->lzssBuf);
    memset(g_pCompressDataStru->lzssBuf,0,lzss_decoded_len);
    varintDecoded = dst;
    if(src[0] == COMPRESS_TYPE_LZSS) 
    {   /*经过lzss*/
        lzss_decoded_len = fastlz_decompress(src + 1, srcLen, g_pCompressDataStru->lzssBuf, 1024);
        for (i = 0; i < lzss_decoded_len; i++) 
        {            
            val = 0;
            if(index >= lzss_decoded_len)
            {
                break;
            }
            size = Decode_Varint(g_pCompressDataStru->lzssBuf + index, &val);
            index += size;
            varintDecoded[i] = val;
            if((size == 2)||(size == 3))
            {
                ++varintDecodedLen;
            }
            else
            {
                varintDecodedLen += size;
            }
            if(index >= lzss_decoded_len)
            {
                break;
            }
        }
    }
    else 
    {   /*不经过lzss*/
        for (i = 0; i < srcLen; i++) 
        {
            val = 0;
            if(index >= srcLen)
            {
                break;
            }
            size = Decode_Varint(src + index + 1, &val);
            index += size;
            varintDecoded[i] = val;
            if((size == 2)||(size == 3))
            {
                ++varintDecodedLen;
            }
            else
            {
                varintDecodedLen += size;
            }
        }
    }
    zigzagDecoded = (int16_t *)dst;
    Decode_Zigzag((uint16_t *)varintDecoded, varintDecodedLen, zigzagDecoded, &zigzagDecodedLen);
    deltaDecoded = (int16_t *)dst;
    Decode_Delta(zigzagDecoded, zigzagDecodedLen, deltaDecoded, &deltaDecodedLen);
    dst = deltaDecoded;
    *dstLen = deltaDecodedLen;
}

