大概了解了存档包的处理流程,咱们就能够开始搞事了。一步一步来,让咱们先来写个虚拟存档包,也就是在代码中写死一些文件项目,每次打开该类型的存档包都固定返回这些项目。做为存档格式的识别依据,咱们就只规定一条,只要后缀名是 .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
接口,而后获取当前打开存档包的文件名,看后缀名是否是 .zzz
。code
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
注意,建立的 .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 |