{
unsigned char *src=inbuf;
int i;
int encSize=0;
while(src<(inbuf+inSize))
{
if((encSize+2)>onuBufSize)
{
return -1;
}
unsigned char value=*src++;
i=1;
while((*src==value)&&(i<255))
{
src++;
i++;
}
outbuf[encSize++]=i;
outbuf[encSize++]=value;
}
return encSize;
}
对于字符串“AAABBBBBCD”,用这种RLE算法Rle_Encode_N()函数压缩后的数据就是:0x03,0x41,0x05,0x42,0x01,0x43,0x01,0x44共8个字节,比原始长度10个字节少了2个字节,实现了数据长度的压缩。
解压缩的过程也很简单,就是定为到第一个块数属性字节位置,根据块数属性的值n,连续向解压缩缓冲区还原n个原始数据,原始数据就是块数属性后面一个字节的数据,然后偏移到下一个块数属性字节位置继续上述处理,直到压缩数据结束。解压缩算法的C语言实现如下:
int Rle_Decode_N(unsigned char *inbuf,int inSize,unsigned char *outbuf,int onuBufSize)
{
unsigned char *src=inbuf;
int i;
int decSize=0;
while(src<(inbuf+inSize))
{
int count=*src++;
if((decSize+count)>onuBufSize)
{
return -1;
}
unsigned char value=*src++;
for(i=0;i<count;i++)
{
outbuf[decSize++]=value;
}
}
return decSize;
}
{
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
{
if((value&0xC0)==0xC0)
{
outbuf[encSize++]=0xC1;
}
outbuf[encSize++]=value;
}
}
return encSize;
}
对于字符串“AAABBBBBCD”,用这种RLE算法的Rle_Encode_P()函数压缩后的数据就是:0xC3,0x41,0xC5,0x42,0x43,0x44共6个字节,比原始长度10个字节少了4个字节,对于原始数据都小于192的数据能够有效地抑制因插入块数属性过多导致的数据膨胀。
使用这种算法解压缩,需要判断当前数据是否有块属性标志,如果有则从低6位bit中去到重复数据的块数n,然后将下一个字节的数据重复复制n次。如果当前数据没有块属性标志,则直接使用当前数据,具体实现的C代码见Rle_Decode_P()函数:
int Rle_Decode_P(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;
value=*src++;
}
else
{
count=1;
}
if((decSize+count)>onuBufSize)
{
return -1;
}
for(i=0;i<count;i++)
{
outbuf[decSize++]=value;
}
}
return decSize;
}
上述优化后的RLE算法,在原始数据普遍大于192(0xC0)的情况下,其优化效果相对于优化前的算法没有明显改善。原因在于,原始的RLE算法和改进后的RLE算法对于连续出现的不重复数据的处理方式都是一个一个处理的,没有把不重复数据作为一个整体进行处理。现在考虑再对原始的RLE算法进行优化,主要优化思想就是对连续的不重复数据进行整理处理,用一个和处理连续重复数据一样的标志,标识后面的数据是长度为n的连续不重复数据。这样的标志字节就相当于是数据块的块头部分,描述后面跟的数据类型以及数据长度。由于标志是始终存在于数据块的前面,因此就不需要区分标志字节和原始数据,也就是说,第一个改进算法中用“高两位是连续的1”的方式区分标志字节和数据都是没有必要的,唯一需要区分的是后面跟的数据类型。区分的方法就是对标志字节的8个bit进行分工,用高位一个bit表示后面跟的数据类型,如果这个bit是1则表示后面跟的是连续重复的数据,如果这个bit是0则表示后面跟的是连续不重复的数据。标志字节的低7位bit存储一个数字(最大值是127),对于连续重复数据,这个数字表示需要重复的次数,对于连续不重复数据,这个数字表示连续不重复数据块的长度。需要注意的是,只有重复次数超过2的数据才被认为是连续重复数据,因为如果数据的重复次数是2,压缩后加上标志字节后总的长度没有变化,因此没有必要处理。
下面根据上述优化思想进行算法设计,首先是压缩算法。在这种情况下,压缩算法就比前两种RLE压缩算法复杂一些,就是要能识别连续的重复数据和连续的不重复数据。首先设置搜索起始位置,算法开始时这个搜索起始位置就是原始数据的第一个字节。每次搜索就是从起始位置开始向后搜索比较数据,根据搜索比较结果,一种情况就是后面数据重复且数据长度超过2,则设置连续重复数据的标志,然后继续向后查找,直到找到第一个与之不相同的数据为止,将这个位置记为下次搜索的起始位置,根据位置差计算重复次数,连重复标志和重复次数以及原始数据一起写入压缩数据;另一种情况是后面的数据都没有连续重复的,则继续向后查找,直到找到连续重复的数据,然后设置不重复数据标志,将新位置记为下次搜索的起始位置,最后将标志字节写入压缩数据并将原始数据复制到压缩数据。从新的搜索起始位置重复上面的过程,直到原始数据结束。函数Rle_Encode_O()就是上述算法的C语言实现(只有算法的主体部分):
int Rle_Encode_0(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;
}
现在用数据“AAABBBBBCABCDDD”检验上述算法,得到压缩后的数据:0x83,0x41,0x85,0x42,0x04,0x43,0x41,0x42,0x43,0x83,0x44,原始数据长度是15字节,压缩后是11字节,这种改进后的算法,原始数据越长,压缩的效果就越明显。
这种改进方法的解压缩算法就比较简单了,因为两种情况下的数据的首部都有标志,只要根据标志判断如何处理就可以了。首先从压缩数据中取出一个字节的标志字节,然后判断是连续重复数据的标志还是连续不重复数据的标志,如果是连续重复数据,则将标志字节后面的数据重复复制n份,;如果是连续不重复数据,则将连续复制标志字节后面的n个数据。n的值是标志字节与0x3F做与操作后得到,因为标志字节的低7位bit就是数据块数属性。
改进的解压缩算法如下:
int Rle_Decode_0(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&0x7F;
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;
}
用前面Rle_Encode_O()函数得到的压缩数据进行验证,结果正确。
参考来源:http://blog.csdn.net/orbit/article/details/7062218 (该网站有详细代码)