lz4压缩格式-block

概述

lz4属于lz77系列的压缩算法,lz77系列压缩算法将重复的字符串(也称为匹配)表示成(offset、match length)来对数据进行压缩。lz77算法只是一种思想,寻找匹配的方式有很多中,常见的有hash chain、BST,这些算法会在介绍各个通用压缩算法的时候介绍。
本文只介绍lz4的压缩格式,详细的算法实现会放在另外文章里面讲。
lz4实现了两种格式,分别叫block、frame

lz4_Block格式

名词翻译说明:

  • sequence: 序列,lz4的block格式只包含一系列的序列,不像Frame格式会包含数据头
    |sequence|sequence|sequence|sequence|sequence|…|
  • offset,lz4的offset由2个字节组成,0没有使用,属于非法值
  • literal,未匹配的字符串
  • match,匹配的字符串,即能在前面找到一样的字符串

序列的格式如下:

高4bit低4bit0-n byte0-n byte2 byte0-n byte
未匹配的字符长度匹配的字符长度可选的未匹配的字符长度未匹配的字符offset可选的匹配长度

序列的填值规则如下:
1.“高4bit的值”等于15,则说明“可选的未匹配的字符长度”里面有值,小于15则“可选的未匹配的字符长度”字段不存在。
“可选的未匹配的字符长度”部分,如果前一个字节的值为255,表示后面一个字节也是属于该字段。
2.“低4bit值”的存储规则与“高4bit”一致。如果值等于15,则说明“可选的匹配长度”部分还有数据与“低4bit”一起组成匹配的字符长度。
3.“offset”字段为固定的2个字节,所以lz4选取的查询窗口为固定的64KB,无法配置。该字段采用小端格式存储数值。最后一个序列只包含未匹配的字符串,为了与其他序列进行区分,offset的值是0
一般匹配的字符长度都比较小,“低4bit”就存储完整的长度值,所以lz4将第一个字节拆成高低4位,最大限度的节约了数据的存储,提高了压缩率。

下面以一个具体的例子来说明lz4_Block格式。
比如输入数据为:
abcdefghijklmnoabcdefghijklmno
lz4算法会将该字符串转成三元组。
(‘abcdefghijklmno’(未匹配的字符串),15(offset),15(match length))
转成字节流如下:

高4bit低4bit1 byte15 byte2 byte1 byte
15150abcdefghijklmno150

从上面可以看到,lz4_block格式没有header字段,一般的压缩算法有许多参数可选,比如窗口大小,挡位,是否进行crc校验等。当这些参数在解压的时候需要知道,则压缩格式中会设计header部分,并将这些数据存储进去,供解压的时候使用。

int decode(char* input, int inLen, char* output, int outLen) {
    unsigned char* inp = (unsigned char*)input;
    unsigned char* outp = (unsigned char*)output;
    int decodeSize = 0;

    while (1) {
        unsigned char token = *inp;
        inp++;
        int high4Bits = (token & 0xF0) >> 4;
        int low4Bits = token & 0x0F;
        int literalLen = high4Bits;
        int matchLen = 4 + low4Bits;

        // 解码literalLen
        if (high4Bits == 15) {
            while (*inp == 255) {
                literalLen += 255;
                inp++;
            }
            literalLen += *inp;
            inp++;
        }
        decodeSize += literalLen;
        memcpy(outp, inp, literalLen);
        inp += literalLen;
        outp += literalLen;

        //解码offset
        int offset = *(inp + 1);
        offset = (offset << 8) + *inp;
        inp += 2;

        // 解码matchLen
        if (offset > 0) {
            if (low4Bits == 15) {
                while (*inp == 255) {
                    matchLen += 255;
                    inp++;
                }
                matchLen += *inp;
                inp++;
            }

            unsigned char* matchPos = (unsigned char*)(output + decodeSize) - offset;
            for (int i = 0; i < matchLen; i++) {
                outp[i] = matchPos[i];
            }
            decodeSize += matchLen;
            outp += matchLen;
        }

        if (inp - (unsigned char*)input >= inLen) {
            break;
        }
    }
    return decodeSize;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值