原文地址:https://xuzx.github.io/2020/05/31/Xdelta3-Header/
背景
最近开发 APP 的增量更新功能,根据之前调研分析(详见《Android 增量更新方案调研》一文)使用到了 Xdelta3 算法。在这过程中,不乏遇到各种各样问题,诸如:
-
编译不通过,提示
error: expected declaration specifiers or '...' before numeric constant
,还没开始呢就这样了,内心很崩溃! -
差分合成时,提示
unavailable secondary compressor: LZMA: XD3_INTERNAL
,这又啥问题? -
差分生成时,同一个新/旧版本文件每次修改文件名称会导致差分生成的增量文件 MD5 值不一致,啊这又是什么鬼?
......
而在之前调研时,Google 搜索了关于 Xdelta3 介绍、使用、问题等文章少之又少,除官网外,唯一介绍完整非 RFC3284 VCDIFF 一文莫属,于是只能结合官网 Github 项目和 RFC3284 VCDIFF 一文下手解惑,并记录在此。
从 Xdelta 官网介绍中,可以得知 Xdelta3 所生成的增量文件(Delta File)格式是遵循 RFC3284 VCDIFF 数据格式。其中, 《The VCDIFF Generic Differencing and Compression Data Format》一文中,给出增量文件文件头如图1所示:
图1 增量文件的文件头(注:方括号项目为可选项)下面根据上图结合源码及具体 Xdelta3 工具所生成的增量文件文件头进行说明:
Magic
文件头前三个字节为 VCDIFF 的魔数,识别为 VCDIFF 文件格式,其值为 0xD6C3C4,如图2所示。
图2 增量文件二进制魔数值其代表着高位为1(1字节8位),且 ASCLL 码字母‘V’,‘C’,‘D’,如图3所示。
即分别为:
'V' = 01010110,D6 = 11010110
'C' = 01000011,C3 = 11000011
'D' = 01000100,C4 = 11000100
图3 ASCLL 码而在 Xdelta3 源码中,可以发现魔数相关宏定义,如图4所示。
图4 VCDIFF Magic 宏定义Version
文件头第四字节为 VCDIFF 的版本号,目前固定为 0。
图5 增量文件二进制版本号而在 Xdelta3 源码中,可以发现版本宏定义,如图6所示。
图6 VCDIFF Version 宏定义同时,在源码解码函数 int xd3_decode_input (xd3_stream *stream)
中,也发现当其版本号值大于0,将提示不支持并解码失败,如图7所示。
Hdr_Indicator
文件头第五字节为 VCDIFF 的头部指示符,默认为 04(00000100)。
图8 增量文件二进制头部指示符在该字节8位中,其中前三位代表具体意义。
1)低位第一位为 VCD_DECOMPRESS
,表示是否开启了二次压缩(因为 Xdelta 支持二次压缩)。当开启二次压缩,其值为1(即为 00000001),并在该字节其后的一个字节附带二次压缩算法 ID,如下图所示。
Xdelta3 内置两种压缩算法 DJW(二次压缩算法 ID=1) 和 FGK(二次压缩算法 ID=2),以及外依赖一种 LZMA(二次压缩算法 ID=16) 压缩算法。
图12 可执行文件命令选项(注:需包含支持压缩算法编译) 图13 不支持二次压缩(可执行没编译具体压缩算法) 图14 差分合成不支持二次压缩(可执行没编译具体压缩算法)编译可执行文件命令选项:-S [lzma | djw | fgk]
2)低位第二位为 VCD_CODETABLE
,其值为1(即为 00000010),具体意义待补充。
3)低位第三位表示是否包含应用程序头信息,当包含应用程序头信息,其值为1(即为 00000100 = 04),并在该字节其后字节包含应用程序头信息长度+应用程序头信息,这也说明图8为什么默认值为04,下一小节具体分析。
Application Header
上一节分析到 Hdr_Indicator(VCDIFF 的头部指示符)低位第三位为1时,其后字节包含应用程序头信息长度 + 应用程序头信息。从 Xdelta3 源码得知,由函数static int main_set_appheader (xd3_stream *stream, main_file *input, main_file *sfile)
进行设置。
其中,当用户不进行自定义应用程序头信息,将使用默认应用程序头信息,如图15所示:
1)当源文件名称为空时,应用程序头信息为输入文件名称/扩展压缩标识;
2)当源文件名称不为空时,应用程序头信息为源文件名称/扩展压缩标识/输入文件名称/扩展压缩标识。
图15 函数设置默认应用程序头信息注:这里的源文件指进行差分时的旧文件,输入文件指进行差分时的新文件。
一般扩展压缩标识都为空,应用程序头信息就为经常见到的:新文件名称//旧文件名称/,如version2.txt//version1.txt/,如图16所示。
图16 默认应用程序头信息同时,到这里也解答我们之前的疑惑,同一文件不同文件名导致差分生成的增量文件 MD5 值出现不一致问题。
图17 可执行文件自定义应用程序头信息命令选项其编译可执行文件提供自定义应用程序头信息命令选项:-A [apphead]
下面进行实际测试来验证以上的分析:
1)自定义应用程序头信息‘xuzx’(长度4字节), -A xuzx ,实验结果如图18和图19所示。
2)关闭包含应用程序头信息(文件头第五字节 VCDIFF 的头部指示符为 00 = 00000000),-A 不带任何参数,实验结果如图20和图21所示。
图20 关闭应用程序头信息 图21 增量文件二进制到这里,关于 Xdelta3 增量文件文件头相关信息分析完毕!
提示:本文为博主原创文章,如发现文中有误,欢迎批评指正,谢谢您支持!
参考文章
RFC3284 VCDIFF:https://tools.ietf.org/rfc/rfc3284.txt
网友评论