以前只知道 7z 的做者是 Windows 用户,7z 是在 Windows 上开发出来的。如今看了源码才知道,做者深受 Windows 影响,代码中大量依赖 COM 接口,但并无使用 ATL 库,实际上是做者本身修改简化后的 COM 接口实现。若是你没有 COM 组件开发经验,那么这里会比较难受了,推荐赶忙先去补一补 COM 技术细节。数组
7z 中的这套 COM 接口简化了大部分细节,甚至引用计数都没加锁,这个操做其实有点迷。。估计做者本身在代码中能保证线程同步吧。因为有大量辅助宏,实际写接口实现类时仍是比较容易的。测试
仍是有针对性的读源码,咱们要增长新存档格式,重点就要看 CPP/7zip/Archive/IArchive.h
文件,这个文件中包含了十几个接口定义,和一些用于注册存档格式的宏,下面我把重要的几个接口和宏摘出来,如今能够不用懂它们的具体含义,以后遇到时回来查就行。线程
如下全部接口方法的返回值均为 HRESULT
,且不能抛出异常。code
如下全部注释均以存档包实现者的角度来写,而不是库使用者。对象
进度回调接口,是多个接口的父类。排序
// 若是 SetTotal 被调用,则: // 对于 xz、gz、bz二、lzma、z、ppmd 格式,SetCompleted 为打包大小 // 对于其余格式,SetCompleted 为解包大小 // 若是 SetTotal 没有被调用,则 SetCompleted 为打包大小 SetTotal(UInt64 total); SetCompleted(const UInt64 *completeValue);
打开存档的进度回调,在存档包处理对象的 Open()
方法中做为参数传入,其自己还用做其余用途,如能够经过该接口 QueryInterface
到 IArchiveOpenVolumeCallback
接口,从而获知当前打开的存档文件的相关信息。继承
SetTotal(const UInt64 *files, const UInt64 *bytes); SetCompleted(const UInt64 *files, const UInt64 *bytes);
继承自 IProgress
。解压回调,在存档包处理对象的 Extract()
方法中做为参数传入,除了用做报告解压进度外,其 GetStream()
方法仍是重要的用来获取输入流的方法。索引
GetStream( UInt32 index, // 要解压的项目索引 ISequentialOutStream **outStream, Int32 askExtractMode // 可用值为 NExtract::NAskMode 枚举,若是不为 kExtract,则不能实际解压 ); PrepareOperation(Int32 askExtractMode); // opRes 的可用值为 NExtract::NOperationResult 枚举 SetOperationResult(Int32 opRes);
用来获取当前打开卷的相关信息。对于分卷打包格式,还可用来打开后续的其余卷。接口
GetProperty(PROPID propID, PROPVARIANT *value); GetStream(const wchar_t *name, IInStream **inStream);
用来对外提供一个指定项目的顺序输入流,可能用于流式操做,无缝打开包内的其余存档包。ip
GetStream(UInt32 index, ISequentialInStream **stream);
支持读取的存档包的核心接口,存档包对象必须实现的接口之一。
// 若是 kUseGlobalOffset,stream 当前位置能够为非零 // 若是 !kUseGlobalOffset,stream 当前位置为 0 // 若是 maxCheckStartPosition == NULL,则 handler 可以在 stream 中寻找存档起点 // 若是 *maxCheckStartPosition == 0,则 handler 必须只把当前位置做为存档起点 Open( IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback ); Close(); GetNumberOfItems(UInt32 *numItems); // 写出步骤: // 1. 调用 extractCallback->GetStream(index, &outStream, askMode) 来获取写出流 // 2. 调用 extractCallback->PrepareOperation(askMode) 来让 7z 作好准备 // 3. 建立须要的 Coder 来写入 outStream // 4. 写入完成后,释放 outStream,调用 extractCallback->SetOperationResult() 设置解压结果 Extract( const UInt32* indices, // 要解压的全部索引数组,必须是已排序的 UInt32 numItems, // -1 为解压全部文件,注意这里类型为 Uint32 Int32 testMode, // 非零时,仅测试不写出文件 IArchiveExtractCallback *extractCallback ); GetNumberOfProperties(UInt32 *numProps); GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType); GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value); GetNumberOfArchiveProperties(UInt32 *numProps); GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType); // kpidOffset:存档数据的起点,VT_EMPTY 表示起点为 0,可为 VT_UI四、VT_UI八、VT_I8 类型 // kpidPhySize:存档数据的实际大小,VT_EMPTY 表示未知,可以大于文件大小 // kpidIsDeleted、kpidIsAltStream、kpidIsAux、kpidINode:若是 GetProperty 支持这些属性,则必须返回 VARIANT_TRUE (VT_BOOL) GetArchiveProperty(PROPID propID, PROPVARIANT *value);
若是存档包支持从顺序输入流中打开,能够实现该接口。
OpenSeq(ISequentialInStream *stream);