7z文件格式及其源码的分析(六)-完结篇
7z文件格式及其源码的分析(六)-完结篇
2条回复
上一篇在这里 7z文件格式及其源码的分析(五)
这一篇主要介绍7z的流式压缩和解压原理.
对于流式处理来讲, 主要问题是要处理好文件头的问题. 因为是流式的, 所以,不可能走回头路. 也就不可能说压缩完了之后回到开头来修改头的信息.
7z文件的文件头其实是分为两部分的, 这两部分文件头在前面的几篇分析中都有介绍:
头Header
, 就是写在文件前面的 Header. 这个头比较小, 主要记录了文件的版本信息, 以及尾header的位置偏移和校验和等等. 其主要作用是文件类型识别和查找到尾Header尾Header
, 就是写在文件末尾的 Header. 这里记录了 7z 文件的全部压缩信息, 解压主要就靠这里面的信息了.
7z 常见的压缩过程是: 先把 头Header
的一些位置保留, 然后压缩数据. 压缩完之后, 尾Header
写完之后, 再把 尾Header
的大小,偏移,校验和写回到 头Header
中去.
在流式环境下, 最后一步回头写 头Header
的过程显然不可能完成. 因为已经流过了.
那 7z 是怎么处理这个问题的呢? 7z 支持流式压缩吗?
7z 的文档里,并没有明确的回答这个问题. 我们还是让它的代码回答吧.
我们找到 7z 的解压代码, 7zIn.cpp
文件. 找到 HRESULT CInArchive::ReadDatabase2()
函数. 大概在 1136
行.
这个函数就是在读取 头Header
信息, 并查找 尾Header
位置.
我们截取它开头的一部分代码片段:
HRESULT CInArchive::ReadDatabase2(DECL_EXTERNAL_CODECS_LOC_VARSCArchiveDatabaseEx &db#ifndef _NO_CRYPTO, ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined#endif)
{db.Clear();db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;db.ArchiveInfo.Version.Major = _header[6];db.ArchiveInfo.Version.Minor = _header[7];if (db.ArchiveInfo.Version.Major != kMajorVersion)ThrowUnsupportedVersion();UInt32 crcFromArchive = Get32(_header + 8);UInt64 nextHeaderOffset = Get64(_header + 0xC);UInt64 nextHeaderSize = Get64(_header + 0x14);UInt32 nextHeaderCRC = Get32(_header + 0x1C);UInt32 crc = CrcCalc(_header + 0xC, 20);#ifdef FORMAT_7Z_RECOVERYif (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0){UInt64 cur, cur2;RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));const int kCheckSize = 500;Byte buf[kCheckSize];RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));int checkSize = kCheckSize;if (cur2 - cur < kCheckSize)checkSize = (int)(cur2 - cur);RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));int i;for (i = (int)checkSize - 2; i >= 0; i--)if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)break;if (i < 0)return S_FALSE;nextHeaderSize = checkSize - i;nextHeaderOffset = cur2 - cur + i;nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));}else#endif{if (crc != crcFromArchive)ThrowIncorrect();}db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;(...)}
可以看到, 下面这几句是在从 头Header
上读取 尾Header
信息.
UInt32 crcFromArchive = Get32(_header + 8);UInt64 nextHeaderOffset = Get64(_header + 0xC);UInt64 nextHeaderSize = Get64(_header + 0x14);UInt32 nextHeaderCRC = Get32(_header + 0x1C);UInt32 crc = CrcCalc(_header + 0xC, 20);
紧接着, 后面又有一句判断:
if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
如果这几个都读不到怎么办.
看代码, 接下来, 它会从文件末尾开始, 倒着向前查找特征字符:
if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
这就是在找 0x17 0x06
或者 0x01 0x04
这两个特征串.
代码已经很明确了:
如果找到这其中之一, 就算是找到 尾Header
了.
为什么能这么做呢, 这两个串代表什么呢?
通过查看7z的文档(事实上, 前面讲的 尾Header
的结构的时候也能发现)知道.
0x17
是代表压缩Header的标记kEncodedHeader
. 后面的0x06
是 packstream 的标记kPackInfo
.0x01
是代表普通Header的标记kHeader
. 而0x04
是 mainstream 的标记kMainStreamsInfo
.
这正是 7z 的两种 尾Header
的格式.
到这里, 可以总结一下了:
7z 流式压缩
压缩时可以把头Header
中的 偏移量和 crc 和等 留空.
在解压时, 如果检测到这些留空了, 则会从文件末尾开始查找尾Header
特征串.
这种方法可以一定程度实现 流式压缩. 虽然 7z 的文件结构本身,限制它不适合流式压缩的.
欢迎大家讨论交流: Neil 的博客
byNeil
byNeil.com
From Blog by Neil, post 7z文件格式及其源码的分析(六)-完结篇
原文来自 Blog by Neil, post 7z文件格式及其源码的分析(六)-完结篇 转载请注明出处。本站保留一切权力
7z文件格式及其源码的分析(六)-完结篇相关推荐
- 7z文件格式及其源码的分析
本文是一个系列. 主要是分享我最近一年做7z文件开发的经验. 主要包括7z官方源码的结构分析, 以及7z文件格式的分析. 其中涉及到7z源码结构的各个细节, 以及7z文件格式的具体细节. 本文适合对象 ...
- 【Java 虚拟机原理】Class 字节码二进制文件分析 六 ( 属性类型 | Code 属性 | 属性名称索引 | 属性长度 | 操作数栈最大深度 | 局部变量存储空间 | 字节码长度 )
文章目录 前言 一.属性类型 二.Code 属性表数据结构 三.属性名称索引 四.属性长度 五.操作数栈最大深度 六.局部变量存储空间 七.字节码长度 八.存储字节码指令的一系列字节流 前言 上一篇博 ...
- FPGA解析B码----连载7(完结篇)
前言 上篇完结篇介绍了程序的整体架构和B码错误保护程序,这篇主要介绍下1PPS的产生. 写到这里想先聊聊现在的软件,用的是QII,不知道这个软件还能免费用多久.现在国外的软件慢慢的都不能用了,只能用国 ...
- FPGA解析B码----连载8(完结篇)
前言 前两个完结篇介绍了B码的结构,B码保护程序和B码的1PPS产生程序,下面介绍B码的UTC时间产生.当然B码中含有UTC时间和UTC时间的关键信息.程序的整体思路是差不多的,翻过来调过去也就是那点 ...
- Fabric源码流程分析之Orderer篇
导言: 本文使用fabric1.1版本,此时有小朋友会问了,fabric都出1.4.2了你怎么还在看1.1呢!首先fabric自1.0以后大的架构基本没有变化,小版本升级只是功能性上更加丰满了,当然最 ...
- Python-LBM(格子玻尔兹曼)程序源码实例分析—圆柱绕流篇
初次学习LBM计算方法,找到一个比较优秀的用python语言编写的圆柱绕流的实例,对每段代码详细添加了注释,帮助自己总结,也为初学的朋友们提供一点帮助(全部代码在文章最后). 先放一张结果图像: 1. ...
- Foxdisk-代码仓库介绍暨完结篇
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) Foxdisk之代码仓库介绍暨完结篇 1 Foxdisk1 2 Foxdisk2 3 Foxdi ...
- UPX源码分析——加壳篇
0x00 前言 UPX作为一个跨平台的著名开源压缩壳,随着Android的兴起,许多开发者和公司将其和其变种应用在.so库的加密防护中.虽然针对UPX及其变种的使用和脱壳都有教程可查,但是至少在中文网 ...
- <2021SC@SDUSC>【Overload游戏引擎】OvCore源码模块分析(六)——SceneSystem
<2021SC@SDUSC>[Overload游戏引擎]OvCore源码模块分析(六)--SceneSystem 前言 SceneSystem Scene SceneManager 总结 ...
- <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(六)——Widgets
<2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(六)--Widgets Button Button namespace OvUI::Widgets::Butt ...
最新文章
- msflexgrid允许大选择_工程中要用多大的电线电缆?一文教你怎么算
- 尊重个体多样性,科学人文终统一
- 【NLP】使用BERT完成NLP任务
- QT学习:字符串类QString
- 从服务器上的数据库备份到本地
- 从ACL2021看对比学习在NLP中的应用
- 7-3 方格取数 (15 分)
- css几个居中的方法
- python学习:用两种思路计算质数与合数
- 智能车摄像头组怎么在OLED屏画出中线
- QUIC 技术创新 让视频和图片分发再提速
- 微信小游戏《飞机打方块》源码分享
- GNU通用公共许可协议--GPLV3中文翻译
- html 样式重叠问题,css怎么解决网页重叠问题
- 基于STM32的汇编程序
- 论文复现:模拟风电不确定性——拉丁超立方抽样生成及缩减场景(Matlab全代码)
- 亚马逊 Amazon Kindle Book 代购 英文原版 正版书 图书 电 子 书-淘宝网
- 日本人骑着22的自行车就上了高速!
- 【小白】学深度学习 发现一个褥百度GPU羊毛的机会
- Spring学习笔记09 - 对象的生命周期
热门文章
- linux热迁移137error VMware vCenter Converter 问题小结
- P3369 (Splay树模板)
- LCOI出题组加团规则
- 计算机科学的拉丁文,拉丁字母A-Z在计算机中对应的二进制编码
- Xcode 8 过滤系统输出
- 辩证法——自然观、自然科学方法论和科学观
- unity与Android交互的currentActivity和入口Activity
- 《正在爆发的互联网革命》作者个人出资10000美金,面向全球征召六度分割理论实验对象!...
- SSM框架-Spring(一)
- [OCCT] OCC官方示例介绍