前言

最近在研究的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 significant. Below is the 8-bit byte encoding of these digits. Note that the MSBs of 58, 111 and 26 are on.

这样,就完成了Base-128的编码过程,接下来我们介绍一下解码过程。

解码

解码就是将分割后的字节正确有序地拼接在一起,还原数值。

在拼接时,舍去最高位(MSB)之前先进行判断,若标志位为1则表示后一个字节也属于该数值的一部分,为0时则表示该字节为拼接的最后一部分,最后将之前所有部分拼接在一起就得到如下的二进制串:

10111010 | 11101111 | 10011010 | 00010101

舍去最高位(MSB)后:

0111010 | 1101111 | 0011010 | 0010101

完整二进制串:

0111010110111100110100010101 = 123456789

以上就是Base-128的解码过程,是不是很简单^ ^

代码实现

下面贴一下在Xdelta3中对Base-128编码/解码实现的相关源码(以32位操作系统为例):

Base-128编码
//参数:stream为数据流;output为输出缓冲区;num为要编码的数值
static inline int xd3_emit_uint32_t(xd3_stream *stream, xd3_output **output, uint32_t num)
{uint8_t buf[10];    //由于最长数据类型也就64位,将被分割成9.1个字节,因此buf的长度为10足矣usize_t bufi = 10;do{buf[--bufi] = (num & 127) | 128;    //低位字节存入数组的高位地址,同时将MSB置1num >>= 7U;} while (num != 0);buf[9] &= 127;  //将最后一个字节的MSB置0return xd3_emit_bytes(stream, output, buf + bufi, 10 - bufi);
}
Base-128解码
//参数:stream为数据流;inpp为输入缓冲区;maxp为输入缓冲区的尾结点;valp用于存放解码后的数值
static inline int xd3_read_uint32_t(xd3_stream *stream, const uint8_t **inpp, const uint8_t *maxp, uint32_t *valp)
{uint32_t val = 0;const uint8_t *inp = (*inpp);usize_t next;do{   //如果还未完成整数的拼接就达到了缓冲区末尾,则报错if (inp == maxp){stream->msg = "end-of-input in read_integer";return XD3_INVALID_INPUT;}//在最后一次拼接前,保证高位至少7位为0,否则超过位数限制if (val & 0xfe000000U){stream->msg = "overflow in read_intger";return XD3_INVALID_INPUT;}next = (*inp++);    //读取输入缓冲区val = (val << 7) | (next & 127);    //将val左移7位后,用next的低7位来填充val的低7位} while (next & 128);   //判断next的标志位(MSB)是否为0,不为0则继续拼接(*valp) = val;(*inpp) = inp;return 0;
}

如有疑问欢迎评论私信我~

参考文献

《RFC3284》https://www.rfc-editor.org/rfc/pdfrfc/rfc3284.txt.pdf

浅析Base-128编码约定相关推荐

  1. Qt之QML编码约定

    文章目录 概述 QML对象声明 分组属性 列表 JavaScript代码 概述 之前看到一篇Qt 官方的关于QML 开发的编码约定,这里做个简单的总结.一个良好的编码习惯可提高代码的可阅读性,并且整个 ...

  2. python 字符编码处理_浅析Python 字符编码与文件处理

    Python字符编码 目前计算机内存的字符编码都是Unicode,目前国内的windows操作系统采用的是gbk. python2默认的字符编码方式是ASCII python3默认的字符编码方式是Un ...

  3. java java编码_Java编码约定被认为是有害的

    java java编码 在Oracle网站上有Java编程语言的官方代码约定指南. 您可能希望这份超过20页的文档将是有关Java语言的最佳实践,提示和技巧的最完整,最全面和最权威的来源. 但是一旦您 ...

  4. Java编码约定被认为是有害的

    在Oracle网站上有Java编程语言指南的正式代码约定 . 您可能希望这份超过20页的文档将是有关Java语言的最佳实践,提示和技巧的最完整,最全面和最权威的来源. 但是一旦你开始阅读它,失望和愤怒 ...

  5. C# 编码约定(C# 编程指南)

    1.              命名约定 ·         在不包括 using 指令的短示例中,使用命名空间限定. 如果你知道命名空间默认导入项目中,则不必完全限定来自该命名空间的名称. 如果对于 ...

  6. base64编码_动画演示 Base 64 编码

    Base64 是一种十分流行的编码方式,仅仅使用 64 个字符加等号(=) 就可以以文本的形式表示所有的二进制数据了,因为它能够把二进制格式通过编码转换成可见字符,所有我们就可以通过的把二进制格式比如 ...

  7. Base 64 编码

    核心内容: Base64编码的思想是是采用64个基本的ASCII码字符对数据进行重新编码.它将需要编码的数据拆分成字节数组.以3个字节为一组.按顺序排列24位数据,再把这24位数据分成4组,即每组6位 ...

  8. 浅析用Base64编码的图片优化网页加载速度

    想必大家都知道网页加载的过程,从开始请求,到加载页面,开始解析和显示网页,遇到图片就再次向服务器发送请求,加载图片.如果图片很多的话,就会产生大量的http请求,从而影响页面的加载速度.所以现在有一种 ...

  9. vs2017 编码约定——.editorconfig文件

    2019独角兽企业重金招聘Python工程师标准>>> 源码来自:https://docs.microsoft.com/en-us/visualstudio/ide/editorco ...

最新文章

  1. vector机器人 WHAT DO VECTOR‘S BACK LIGHTS MEAN? 矢量背光是什么意思?
  2. junit5_在Java 8之前的项目中使用JUnit 5
  3. 用Tableau画Voronoi Treemap
  4. mysql Error Code: 1005(errorno:121)解决
  5. 稀疏数组与二维数组相互转化
  6. Ubuntu 14.10 下运行进程实时监控pidstat命令详解
  7. Python操作MySQL的封装类
  8. css 动态生成圆形区域内扇形个数_CSS实用技巧总结
  9. 自适应 幻灯片代码 app_低成本0基础开发app之开发首页幻灯片接口
  10. oracle aq hang,AQ: dequeue的时候hang住
  11. web大前端开发中一些常见的安全性问题
  12. java 打印标签 批量_如何批量打印不同数量的条码标签
  13. win10小喇叭出现红叉,解决办法(转)
  14. 计算机网络——知识点
  15. 最小割与最大流(mincut amp; maxflow)
  16. Elasticsearch 响应数据压缩功能详解
  17. 豆瓣8.0分,尺度堪比色戒,一部让人绝望的电影
  18. matlab求隐函数二阶导,求隐函数二阶导数.ppt
  19. hashmap的无序和有序
  20. 什么是DDos攻击,如何有效缓解DDos攻击?

热门文章

  1. 【文件格式-TIFF】TIFF图像格式结构
  2. 2012-07-31
  3. cpc卡内计费信息异常包括_CPC卡精确计费方案
  4. Linux 服务器安装部署Jena
  5. hp服务器重装系统按什么键,惠普重装系统按什么键|惠普u盘装系统按哪个键
  6. 修改docker daemon文件
  7. 1338_龙书笔记_001_编译器的大概结构以及工作的基本流程
  8. 自动化专业学计算机技术,自动化专业学什么?大学自动化专业主要学什么
  9. 天顶围棋 8 zenith 8_2019年第九届世界围棋巅峰对决盛大启幕,此次坐标安徽阜阳祥源文旅城!...
  10. Qt 实现的一个生产者消费者模式类