在上一篇文中,咱們講了 SplitHandler 中的總體結構,剩下的就是實現存檔包的操做邏輯,也就是實現 CHandler
類。數組
再次明確一下,咱們的目標是實現一個只讀的存檔包格式插件,因此這裏只討論 IInArchive
接口的實現。性能
IInArchive
接口中還剩下這些方法須要討論:測試
Close
、GetNumberOfItems
顧名思義,關閉文件和獲取存檔包內的文件項目數量,沒什麼好說的,直接跳過,講講剩下這幾個。插件
STDMETHODIMP CHandler::Open( IInStream* stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback* callback )
參數1 stream
就是要打開的存檔包的流對象,流對象應該不用多說,7z 中的流接口比 STL 中的流簡單多了,一目瞭然。調試
參數2 maxCheckStartPosition
,IArchive.h
的註釋中有講,本系列第 2 篇文中也有說。code
參數3 callback
表面上看是打開進度回調,但別忘了它實現了 IUnknown
接口,是能夠查詢關聯的其餘接口的。對象
CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
好比 Split 就經過 callback
查詢到了 IArchiveOpenVolumeCallback
接口,從而獲取了當前打開的存檔包的文件名。排序
對於 Split 這樣的多卷存檔格式,打開剩餘的其餘卷也是經過 IArchiveOpenVolumeCallback
接口,調用其 GetStream
方法,傳入其餘卷的文件名,就能得到其餘卷的輸入流。索引
說回 callback
的本質,用它報告打開進度就是調用 SetCompleted
方法。若是存檔格式支持直接獲取全部文件項目數,還能夠先調用 SetTotal
設置總數,這是可選的,不設置總數也行,就像 Split 這樣。接口
STDMETHODIMP CHandler::Extract( const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback )
參數1 indices
爲要解壓的全部索引的數組,7z 強制要求,該數組傳入時必須是已排序的。排序後的索引應該可以提升解壓性能,由於順序讀入一次就好了。
參數2 numItems
爲參數 indices
數組的成員數。若是要解壓全部項目,該參數爲 -1。注意,該參數的類型爲 UInt32,因此 -1 這個值實際爲 0xffffffff,官方源碼中是這樣寫的:(UInt32)(Int32)-1
。
參數3 testMode
能夠認爲是個 bool 類型,表示本次解壓是否爲測試模式,測試模式下不會實際寫出文件。
參數4 extractCallback
爲解壓進度回調。可是像 IArchiveOpenCallback
打開回調同樣,該參數也不單單隻有解壓進度回調這一個功能。它還用於獲取寫出流,即調用 GetStream
方法。有了這個寫出流,咱們才能寫出數據。
該方法的實現流程大概是這樣:
indices
和 numItems
是否合理extractCallback->SetTotal()
設置總進度,這個總數爲要解壓的總字節數extractCallback->GetStream()
獲取寫出流extractCallback->PrepareOperation()
讓 7z 作好準備extractCallback->SetOperationResult()
設置當前項目的解壓結果上一篇文中講到,對於存檔包總體的全部屬性,應該在全局 kArcProps
數組中寫出來。經過 IMP_IInArchive_ArcProps
宏,咱們就只須要本身實現一下 GetArchiveProperty
方法。
照葫蘆畫瓢就好了。
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidMainSubfile: prop = (UInt32)0; break; case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; case kpidTotalPhySize: prop = _totalSize; break; case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; } prop.Detach(value); return S_OK; }
每一個屬性的含義,看它的名字就知道,看不出來怎麼辦呢?猜唄,否則還能如何。。這裏官方源碼中徹底沒有註釋!什麼都沒有講!咱們知道的就只有屬性名字是什麼,它的數據類型是什麼。
據個人調試觀察,即便以前調用 IMP_IInArchive_ArcProps_NO_Table
,即定義存檔包不含任何屬性,7z 仍然會嘗試獲取如下這些屬性:
與 GetArchiveProperty
相似,這裏是獲取每一個文件項目的屬性。
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidPath: prop = _subName; break; case kpidSize: case kpidPackSize: prop = _totalSize; break; } prop.Detach(value); return S_OK; }
一樣,屬性的含義只能靠猜。。
如下屬性是必定會嘗試獲取的: