为 7-Zip 写一个存档格式插件 (5):实战

大概了解了存档包的处理流程,咱们就能够开始搞事了。一步一步来,让咱们先来写个虚拟存档包,也就是在代码中写死一些文件项目,每次打开该类型的存档包都固定返回这些项目。做为存档格式的识别依据,咱们就只规定一条,只要后缀名是 .zzz,就认为它是咱们要的虚拟存档包。git

大概写一下结构:github

namespace NArchive {
namespace NZzz {

static const Byte kProps[] =
{
    kpidPath,
    kpidSize,
    kpidPackSize
};

struct MyVirtualItem
{
    const wchar_t* name;
    const char* text;
} items[] =
{
    {L"文件1.txt", "内容1"},
    {L"文件2.txt", "内容2"},
    {L"递归调用测试.zzz", "111"}
};

class CHandler :
    public IInArchive,
    public IInArchiveGetStream,
    public CMyUnknownImp
{
public:
    MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
    INTERFACE_IInArchive(;)
    STDMETHOD(GetStream)(UInt32 index, ISequentialInStream** stream);
};

IMP_IInArchive_Props
IMP_IInArchive_ArcProps_NO_Table

// 省略 CHandler 类实现

REGISTER_ARC_I_NO_SIG(
    "Zzz", "zzz", 0, 0xAA,
    0,
    0,
    NULL)
}}

这里为了省事,使用了 IMP_IInArchive_ArcProps_NO_Table 宏,即该存档包不含任何额外的属性。数组

最后注册时,有一个格式 ID 参数,该参数理论上应该是惟一的,但。。你应该也猜到了,官方一样没有文档!因此随便写一个吧。我在最后附录中整理出了当前官方代码中已使用的全部 ID,不跟它们撞在一块儿就行。测试

虚拟文件项目数组中,最后一项我故意写了一个后缀名为 .zzz 的文件,目的就是为了测试它可否被递归调用。spa

STDMETHODIMP CHandler::Open(IInStream* stream, const UInt64*, IArchiveOpenCallback* callback)
{
    CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
    callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void**)& volumeCallback);

    UString name;
    {
        NCOM::CPropVariant prop;
        RINOK(volumeCallback->GetProperty(kpidName, &prop));
        name = prop.bstrVal;
    }

    int dotPos = name.ReverseFind_Dot();
    const UString ext = name.Ptr(dotPos + 1);

    return StringsAreEqualNoCase_Ascii(ext, "zzz") ? S_OK : S_FALSE;
}

Open 方法,我删掉了全部错误处理代码,剩下就是这些,经过 callback->QueryInterface() 查询到 IArchiveOpenVolumeCallback 接口,而后获取当前打开存档包的文件名,看后缀名是否是 .zzzcode

STDMETHODIMP CHandler::Close()
{
    return S_OK;
}

STDMETHODIMP CHandler::GetNumberOfItems(UInt32* numItems)
{
    *numItems = _countof(items);
    return S_OK;
}

这两个方法没什么好说的,咱们没有实际打开任何文件,也不须要释放资源,Close 直接返回就行。orm

STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
    Int32 testMode, IArchiveExtractCallback* extractCallback)
{
    bool allFilesMode = (numItems == (UInt32)(Int32)-1);
    if (allFilesMode)
        numItems = _countof(items);
    if (numItems == 0)
        return S_OK;

    for (UINT i = 0; i < numItems; i++)
    {
        CMyComPtr<ISequentialOutStream> realOutStream;
        Int32 askMode = testMode ?
            NExtract::NAskMode::kTest :
            NExtract::NAskMode::kExtract;

        UINT32 index = allFilesMode ? i : indices[i];
        auto& item = items[index];

        RINOK(extractCallback->GetStream(index, &realOutStream, askMode));

        if (!testMode && !realOutStream)
            continue;

        RINOK(extractCallback->PrepareOperation(askMode));

        RINOK(realOutStream->Write(item.text, (UINT32)strlen(item.text), NULL));
        realOutStream.Release();

        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
    }

    return S_OK;
}

一样,这里展现的 Extract 我也删掉了错误处理,还删掉了进度回调,只说明一下核心逻辑。递归

STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT* value)
{
    NCOM::CPropVariant prop;
    switch (propID)
    {
    case kpidPhySize:
        prop = (UInt64)1;
        break;
    }
    prop.Detach(value);
    return S_OK;
}

STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT* value)
{
    NCOM::CPropVariant prop;
    switch (propID)
    {
    case kpidPath:
        prop = items[index].name;
        break;
    case kpidSize:
        prop = strlen(items[index].text);
        break;
    case kpidPackSize:
        prop = strlen(items[index].text) * 2;
        break;
    }
    prop.Detach(value);
    return S_OK;
}

随便返回一些属性信息,注意文件项目属性中,为了与解包大小区分,打包后的大小我故意写成了实际大小的两倍,哈哈,若是有这样的打包格式,估计做者会被锤死。接口

到此为止,咱们已经实现出了一个能稳定工做的虚拟存档包格式。只要建立任意文件,把它的后缀名改成 .zzz,而后用 7z 打开这个文件,就能显示出咱们写死的这些文件项目。ip

clipboard.png

注意,建立的 .zzz 文件大小必定不能为 0,不然 7z 不会打开。

最后,完整代码在这里:https://github.com/wzv5/7z-formatzzz

附录 - 格式 ID

格式 ID
zip 0x01
bzip2 0x02
Rar 0x03
Arj 0x04
Z 0x05
Lzh 0x06
7z 0x07
Cab 0x08
Nsis 0x09
lzma 0x0A
lzma86 0x0B
xz 0x0C
Ppmd 0x0D
COFF 0xC6
Ext 0xC7
VMDK 0xC8
VDI 0xC9
QCOW 0xCA
GPT 0xCB
Rar5 0xCC
IHex 0xCD
Hxs 0xCE
TE 0xCF
UEFIc 0xD0
UEFIf 0xD1
SquashFS 0xD2
CramFS 0xD3
APM 0xD4
MsLZ 0xD5
FLV 0xD6
SWF 0xD7
SWFc 0xD8
NTFS 0xD9
FAT 0xDA
MBR 0xDB
VHD 0xDC
PE 0xDD
ELF 0xDE
MachO 0xDF
Udf 0xE0
Xar 0xE1
Mub 0xE2
HFS 0xE3
Dmg 0xE4
Compound 0xE5
wim 0xE6
Iso 0xE7
Chm 0xE9
Split 0xEA
Rpm 0xEB
Ar 0xEC
Cpio 0xED
tar 0xEE
gzip 0xEF
相关文章
相关标签/搜索