大概瞭解了存檔包的處理流程,咱們就能夠開始搞事了。一步一步來,讓咱們先來寫個虛擬存檔包,也就是在代碼中寫死一些文件項目,每次打開該類型的存檔包都固定返回這些項目。做爲存檔格式的識別依據,咱們就只規定一條,只要後綴名是 .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 |