为 7-Zip 写一个存档格式插件 (2):IArchive.h

以前只知道 7z 的做者是 Windows 用户,7z 是在 Windows 上开发出来的。如今看了源码才知道,做者深受 Windows 影响,代码中大量依赖 COM 接口,但并无使用 ATL 库,实际上是做者本身修改简化后的 COM 接口实现。若是你没有 COM 组件开发经验,那么这里会比较难受了,推荐赶忙先去补一补 COM 技术细节。数组

7z 中的这套 COM 接口简化了大部分细节,甚至引用计数都没加锁,这个操做其实有点迷。。估计做者本身在代码中能保证线程同步吧。因为有大量辅助宏,实际写接口实现类时仍是比较容易的。测试

仍是有针对性的读源码,咱们要增长新存档格式,重点就要看 CPP/7zip/Archive/IArchive.h 文件,这个文件中包含了十几个接口定义,和一些用于注册存档格式的宏,下面我把重要的几个接口和宏摘出来,如今能够不用懂它们的具体含义,以后遇到时回来查就行。线程

重要接口

如下全部接口方法的返回值均为 HRESULT,且不能抛出异常。code

如下全部注释均以存档包实现者的角度来写,而不是库使用者。对象

IProgress

进度回调接口,是多个接口的父类。排序

// 若是 SetTotal 被调用,则:
//     对于 xz、gz、bz二、lzma、z、ppmd 格式,SetCompleted 为打包大小
//     对于其余格式,SetCompleted 为解包大小
// 若是 SetTotal 没有被调用,则 SetCompleted 为打包大小
SetTotal(UInt64 total);
SetCompleted(const UInt64 *completeValue);

IArchiveOpenCallback

打开存档的进度回调,在存档包处理对象的 Open() 方法中做为参数传入,其自己还用做其余用途,如能够经过该接口 QueryInterfaceIArchiveOpenVolumeCallback 接口,从而获知当前打开的存档文件的相关信息。继承

SetTotal(const UInt64 *files, const UInt64 *bytes);
SetCompleted(const UInt64 *files, const UInt64 *bytes);

IArchiveExtractCallback

继承自 IProgress。解压回调,在存档包处理对象的 Extract() 方法中做为参数传入,除了用做报告解压进度外,其 GetStream() 方法仍是重要的用来获取输入流的方法。索引

GetStream(
    UInt32 index,                        // 要解压的项目索引
    ISequentialOutStream **outStream,
    Int32 askExtractMode                 // 可用值为 NExtract::NAskMode 枚举,若是不为 kExtract,则不能实际解压
);

PrepareOperation(Int32 askExtractMode);

// opRes 的可用值为 NExtract::NOperationResult 枚举
SetOperationResult(Int32 opRes);

IArchiveOpenVolumeCallback

用来获取当前打开卷的相关信息。对于分卷打包格式,还可用来打开后续的其余卷。接口

GetProperty(PROPID propID, PROPVARIANT *value);
GetStream(const wchar_t *name, IInStream **inStream);

IInArchiveGetStream

用来对外提供一个指定项目的顺序输入流,可能用于流式操做,无缝打开包内的其余存档包。ip

GetStream(UInt32 index, ISequentialInStream **stream);

IInArchive

支持读取的存档包的核心接口,存档包对象必须实现的接口之一。

// 若是 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);

IArchiveOpenSeq

若是存档包支持从顺序输入流中打开,能够实现该接口。

OpenSeq(ISequentialInStream *stream);

辅助宏

  • IMP_IInArchive_Props:重要,用来实现获取包内项目属性的相关方法
  • IMP_IInArchive_Props_WITH_NAME:同上,同时返回属性名
  • IMP_IInArchive_ArcProps:重要,用来实现获取存档包总体属性的相关方法
  • IMP_IInArchive_ArcProps_WITH_NAME:同上,同时返回属性名
  • IMP_IInArchive_ArcProps_NO_Table:存档包总体不含任何额外属性,但可获取如文件大小这样的基本信息
  • IMP_IInArchive_ArcProps_NO:存档包总体不含任何属性,包括文件大小也不能获取
相关文章
相关标签/搜索