首页
社区
课程
招聘
[求助]遇到一个没见过的压缩算法
发表于: 2020-2-3 03:28 3019

[求助]遇到一个没见过的压缩算法

2020-2-3 03:28
3019
压缩数据前面有两个DWORD。
第一个是signature:“ZLC2” ,但在网络上搜不到有关的信息。
第二个是数据解压后的长度。

解压代码我稍微整理了一下,如下:
#include <cstdio>
#include <cstdlib>

typedef unsigned char BYTE;
typedef BYTE* LPBYTE;

typedef int INT;

//------------------------------------------------------------
// File    : test.bin
// Address : 0 (0x0)
// Size    : 154 (0x9A)
//------------------------------------------------------------
unsigned char comprData[154] = {
	0x00, 0x54, 0x49, 0x54, 0x4C, 0x45, 0x3D, 0x4B, 0x41, 0x00, 0x4D, 0x49, 0x53, 0x48, 0x49, 0x50,
	0x50, 0x4F, 0x00, 0x0D, 0x0A, 0x4D, 0x4F, 0x44, 0x45, 0x3D, 0x52, 0x00, 0x45, 0x54, 0x41, 0x49,
	0x4E, 0x0D, 0x0A, 0x56, 0x00, 0x45, 0x52, 0x3D, 0x31, 0x2E, 0x30, 0x30, 0x0D, 0x00, 0x0A, 0x52,
	0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x00, 0x59, 0x3D, 0x44, 0x45, 0x53, 0x53, 0x45, 0x52, 0x02,
	0x54, 0x53, 0x4F, 0x46, 0x54, 0x5C, 0x38, 0x09, 0x53, 0x03, 0x41, 0x56, 0x45, 0x44, 0x49, 0x52,
	0x20, 0x0F, 0x58, 0x04, 0x00, 0x44, 0x49, 0x53, 0x50, 0x4C, 0x41, 0x59, 0x3D, 0x00, 0xE7, 0xA5,
	0x9E, 0xE6, 0xA7, 0x98, 0xE3, 0x81, 0x00, 0xAE, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA3, 0xE3, 0x00,
	0x81, 0xBD, 0xEF, 0xBD, 0x9E, 0xE5, 0xB9, 0xB2, 0x10, 0xE6, 0x94, 0xAF, 0x1B, 0x00, 0xE3, 0x81,
	0x95, 0xE3, 0x00, 0x81, 0xBE, 0xE3, 0x81, 0x9F, 0xE3, 0x81, 0xA1, 0x81, 0x24, 0x00, 0xE6, 0x81,
	0xA9, 0xE8, 0xBF, 0x94, 0x2A, 0x00, 0x00, 0xEF, 0xBD, 0x9E
};


int main()
{
	LPBYTE comprBuf = comprData;
	INT comprPos = 0;

	LPBYTE decomprBuf = (LPBYTE)malloc(0x10000);
	INT decomprPos = 0;

	// 读取第一个FLAG
	BYTE flag1 = comprBuf[comprPos++];
	BYTE flag2 = 0xff;

	while (1)
	{
		// 0xAB 是解压后的长度
		// 也可以通过判断 comprPos 来跳出循环
		if (decomprPos == 0xAB)
			break;

		// 判断FLAG的每个位
		if ((flag1 & 0x80) == 0)
		{
			// 为0则直接输出
			decomprBuf[decomprPos++] = comprBuf[comprPos++];
		}
		else
		{
			BYTE v7 = comprBuf[comprPos++];
			BYTE v8 = comprBuf[comprPos++];	// match count

			int offset = v7 | 0x10 * (v8 & 0xf0);
			int length = (v8 & 0xf) + 3;

			if (!offset)
				offset = 0x1000;

			int copy_pos = decomprPos - offset;

			for (int i = 0; i < length; i++)
				decomprBuf[decomprPos++] = decomprBuf[copy_pos++];
		}

		flag1 <<= 1;
		flag2 <<= 1;

		if (!flag2)
		{
			// 读取下一个FLAG
			flag1 = comprBuf[comprPos++];
			flag2 = 0xff;
		}
	}

	auto fp = fopen("out.txt", "wb");
	fwrite(decomprBuf, decomprPos, 1, fp);
	fclose(fp);

	return 0;
}

想问一下有没有大佬见过这种压缩算法。
目的是写一个压缩函数。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 83
活跃值: (1087)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
压缩代码有吗
2020-2-3 14:16
0
雪    币: 215
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
killpy 压缩代码有吗
找不到压缩代码,只有解压代码。
2020-2-3 14:32
0
雪    币: 6525
活跃值: (3398)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
日本某公司的压缩吧 
2020-2-3 15:07
0
雪    币: 215
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
Kisesy 日本某公司的压缩吧 [em_41]
所以……
2020-2-3 20:25
0
雪    币: 6525
活跃值: (3398)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6

可能是这种,和你写的这个几乎一样,不过也只有解压
https://github.com/shangjiaxuan/Crass-source/blob/4aff113b98fc39fb85f64501ab47c580df779a3d/cui-1.0.4/SystemC/SystemC.cpp#L85

 

看代码应该是个简单的 rle 压缩,而且稍微有规律,压缩完的数据,前面几段,每隔8位是一个0,不过靠后的数据就不一样了,比如这个2,很可能是判断出有重复文本了,不过你给的数据太少了,看不出多少规律来

 

不过其实根据解压代码写压缩应该不难,不过反正我实在是不想写。。。以前写过

 

这个是算法的乐趣上的代码,有 Rle 和 PcxRle 两种
他这个 Rle 压缩是只有3个或以上的重复的才会当作重复数据,你看着改改看吧

int PcxRle_Encode(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)
{
    unsigned char *src = inbuf;
    int i;
    int encSize = 0;

    while(src < (inbuf + inSize))
    {
        unsigned char value = *src++;
        i = 1;
        while((*src == value) && (i < 63))
        {
            src++;
            i++;
        }

        if((encSize + i + 1) > onuBufSize) /*输出缓冲区空间不够了*/
        {
            return -1;
        }
        if(i > 1)
        {
            outbuf[encSize++] = i | 0xC0;
            outbuf[encSize++] = value;
        }
        else
        {
            /*如果非重复数据最高两位是1,插入标识字节*/
            if((value & 0xC0) == 0xC0) 
            {
                outbuf[encSize++] = 0xC1;
            }
            outbuf[encSize++] = value;
        }
    }

    return encSize;
}

int PcxRle_Decode(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)
{
    unsigned char *src = inbuf;
    int i;
    int decSize = 0;
    int count = 0;

    while(src < (inbuf + inSize))
    {
        unsigned char value = *src++;
        int count = 1;
        if((value & 0xC0) == 0xC0) /*是否有块属性标志*/
        {
            count = value & 0x3F; /*低6位是count*/
            value = *src++;
        }
        else
        {
            count = 1;
        }
        if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/
        {
            return -1;
        }
        for(i = 0; i < count; i++)
        {
            outbuf[decSize++] = value;
        }
    }

    return decSize;
}

bool IsRepetitionStart(unsigned char *start, int length)
{
    if(length <= 2)
        return false;

    if( (*(start + 1) == *start) && (*(start + 2) == *start) )
    {
        return true;
    }

    return false;
}

/*限制返回长度不超过127*/
int GetRepetitionCount(unsigned char *start, int length)
{
    if(length <= 1)
        return length;

    unsigned char value = *start;
    unsigned char *src = start + 1;
    int i = 1;
    while( (src < (start + length)) && (i < 127) )
    {
        if(*src != value)
        {
            break;
        }

        i++;
        src++;
    }

    return i;
}

/*限制返回长度不超过127*/
int GetNonRepetitionCount(unsigned char *start, int length)
{
    if(length <= 1)
        return length;

    unsigned char value = *start;
    unsigned char *src = start;
    int i = 0;
    while( (src < (start + length)) && (i < 127) )
    {
        if(IsRepetitionStart(src, length - i))
        {
            break;
        }

        i++;
        src++;
    }

    return i;
}

int Rle_Encode(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)
{
    unsigned char *src = inbuf;
    int i;
    int encSize = 0;
    int srcLeft = inSize;

    while(srcLeft > 0)
    {
        int count = 0;
        if(IsRepetitionStart(src, srcLeft)) /*是否连续三个字节数据相同?*/
        {
            if((encSize + 2) > onuBufSize) /*输出缓冲区空间不够了*/
            {
                return -1;
            }
            count = GetRepetitionCount(src, srcLeft);
            outbuf[encSize++] = count | 0x80;
            outbuf[encSize++] = *src;
            src += count;
            srcLeft -= count;
        }
        else
        {
            count = GetNonRepetitionCount(src, srcLeft);
            if((encSize + count + 1) > onuBufSize) /*输出缓冲区空间不够了*/
            {
                return -1;
            }
            outbuf[encSize++] = count;
            for(i = 0; i < count; i++) /*逐个复制这些数据*/
            {
                outbuf[encSize++] = *src++;;
            }
            srcLeft -= count;
        }
    }
    return encSize;
}

int Rle_Decode(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)
{
    unsigned char *src = inbuf;
    int i;
    int decSize = 0;
    int count = 0;

    while(src < (inbuf + inSize))
    {
        unsigned char sign = *src++;
        int count = sign & 0x3F;
        if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/
        {
            return -1;
        }
        if((sign & 0x80) == 0x80) /*连续重复数据标志*/
        {
            for(i = 0; i < count; i++)
            {
                outbuf[decSize++] = *src;
            }
            src++;
        }
        else
        {
            for(i = 0; i < count; i++)
            {
                outbuf[decSize++] = *src++;
            }
        }
    }

    return decSize;
}
2020-2-3 21:04
0
雪    币: 215
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
Kisesy 可能是这种,和你写的这个几乎一样,不过也只有解压 https://github.com/shangjiaxuan/Crass-source/blob/4aff113b98fc39fb85f64501 ...
我看它似乎有个滑动窗口的操作,就是那个 win_offset 所以有可能是 lzss 那系列的魔改?
2020-2-3 21:57
0
雪    币: 215
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
crskyii 所以……[em_86]
谢了老哥。最后我还是自己把算法撸出来了。算法是LZ77系列的没错,不过是被程序员瞎改过的,还原出压缩算法之后,发现还有BUG的,简直瞎搞。
2020-2-5 23:01
0
游客
登录 | 注册 方可回帖
返回
//