前言
最近在研究的Xdelta3源码中使用了一种叫做VCDIFF的编码格式,为了可移植性,VCDIFF使用了Base-128的编码约定,下面我们就来简单介绍一下Base-128编码约定。
Base-128
它是一种可移植的、可变大小的编码格式,适用于所有8位字节的系统;所谓Base-128编码就是使用一个字节中的低7位进行编码,因为最高有效位(第7位)的值为128,故而得名Base-128。
编码
打个比方,一个32位的unsigned int类型的数值123456789
,它的二进制表示为00000111010110111100110100010101
,将其按7个二进制单位来分割,如下所示:
0000 | 0111010 | 1101111 | 0011010 | 0010101
由于第一部分的位数全为0,可以舍弃:
0111010 | 1101111 | 0011010 | 0010101
由上可知,一个32位的数值123456789
被分割成了4个部分,将这4个部分分别存入4个字节中的低7位,由于一个字节占8位,还剩余一个最高位(MSB)未使用,将其作为标志位,标志位的作用我们后面会说。
我们用一个char*
的数组buff[4]
来依次接收这4个字节,每个数组成员就是一个字节,buff[0]
中存放数值的第一部分'0111010'
,其占了一个字节中的低7位,剩余1位默认以0
填充——'00111010'
。以此类推,最终数组buff
中所存的内容如下(加粗部分为自动填充的位数):
- buff[0]:‘00111010’
- buff[1]:‘01101111’
- buff[2]:‘00011010’
- buff[3]:‘00010101’
由于分割后的每个字节中的最高位(MSB)都被自动填充为0
,这破坏了数值的完整性和正确性,我们想要获得原本的数值123456789
就需要在拼接时舍去最高位(MSB)以保证拼接后得到正确的数值。
同时还有一个问题,那就是在机器码中,这个数值可能是存在于一连串的二进制码中,就如下所示:
…00111010011011110001101000010101…
那正确判断一个数值是由哪几个字节拼接后得到的呢?这就是将每个字节最高位(MSB)用作标志位的作用了,我们将除了最后一个字节的最高位(MSB)都置为1,修改后的数组buff
如下:
- buff[0]:‘10111010’
- buff[1]:‘11101111’
- buff[2]:‘10011010’
- buff[3]:‘00010101’
《RFC3284》的原文如下:
For example, consider the value 123456789, which can be represented with four 7-bit digits whose values are 58, 111, 26, 21 in order from most to least