日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

7z源码的编译与使用_markdown 格式

發布時間:2023/12/9 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 7z源码的编译与使用_markdown 格式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

7z作為開源的解壓縮項目,支持多種格式的解壓縮,由 Igor Pavlov 開發,最新的版本為 19.00 版。

源碼下載位置:https://www.7-zip.org/a/7z1900-src.7z

1、源碼結構

源碼解壓之后,是這樣的結構:

路徑備注
Asm包含主要算法的匯編實現,直接使用匯編可以提高執行效率。但是卻對跨平臺移植造成了一些困難
C主要是算法的代碼,由C語言實現
CPP相關COM接口的實現,界面,工程文件等
DOC相關文檔

對于我們編譯項目來說,最主要的就是 CPP 文件夾,編譯的項目文件在 CPP\7zip\Bundles\ 中可以找到。

路徑備注
Alone獨立的可執行程序,支持的解壓格式僅包括7z, cab, tar, zip這幾種。
Alone7z獨立的可執行程序,僅支持7z格式。FM文件管理器(File Manager),通過加載7z.dll的導出函數進行解壓。
Format7z7za.dll 7z Standalone Plugin,7z 獨立插件(僅7z格式)
Format7zF7z.dll 7z Plugin, 7z插件,包含各種格式。
SFXCon自解壓(控制臺程序)。
SFXSetup自解壓程序(安裝包)。
SFXWin自解壓程序(Windows界面)。

2、代碼的編譯

打開CPP\7zip\Bundles\Format7zF\Format7z.dsw,即可打開7z.dll工程。

我使用的編譯器是vs2008,打開dsw文件提示升級,轉換后可生成sln文件和對應的vcproj文件。

直接編譯。第一次編譯,報錯:1>LINK : 無法創建 .ILK 文件的映射;正在非增量鏈接

1>LINK : fatal error LNK1104: 無法打開文件“C:\Program Files\7-Zip\7z.dll”

解決方法:文件占用,編譯器權限不夠,不能對此文件進行修改,修改生成目標地址,生成到其他地方就可以了。

第二次編譯,報錯:

1>正在鏈接... 1>.\Debug\7zCrcOpt.obj : fatal error LNK1107: 文件無效或損壞: 無法在 0x276 處讀取

解決方法:刪除工程中的asm文件,改由對應的c文件實現,記得將這些c文件的預編譯頭選項改為“不使用預編譯頭”。

第三次編譯,成功

3、內部接口

7z.dll 中的每一種支持的格式被稱作 Archive,代碼位于CPP\7zip\Archive中。

每一種Archive包含一個Handler,Handler里包含處理每一種Archive的接口。

每一種Archive包含一個Register,用于向全局對象注冊,只有注冊后的Handler才會被調用。

Handler必須繼承IInArchive接口,表示可讀,用于解壓。(必選)

Handler可以繼承IOutArchive接口,表示可寫,用于壓縮文檔。(可選)

根據官方說明:
Packing / unpacking: 7z, XZ, BZIP2, GZIP, TAR, ZIP and WIM

僅這幾種Archive是可以被壓縮的,因此這些Archive的Handler要繼承IOutArchive接口。

如果代碼只用于解壓,而不用于壓縮,可定義EXTRACT_ONLY宏,可不生成IOutArchive,可以減少文件體積。

文件接口說明
ICoder.hICompressProgressInfo設置進度,用于向外部展示進度條
ICompressCoder解碼
ICompressCoder2同上,傳出多個Stream對象
ICompressSetCoderPropertiesOpt設置屬性
ICompressSetCoderProperties設置屬性
ICompressSetDecoderProperties2設置屬性
ICompressWriteCoderProperties將屬性寫入到Stream
ICompressGetInStreamProcessedSize獲取已經處理的大小
ICompressSetCoderMt設置進程數
ICompressSetFinishMode設置結束標志
ICompressGetInStreamProcessedSize2獲取已經處理的大小
ICompressSetMemLimit設置內存限制
ICompressGetSubStreamSize獲取內部流文件大小
ICompressSetInStream設置壓縮傳入的InStream流對象
ICompressSetInStreamSize設置壓縮傳入的InStream流對象大小
ICompressSetOutStreamSize設置壓縮傳出的InStream流對象
ICompressSetBufSize設置緩沖區大小
ICompressInitEncoder初始化編碼器
ICompressSetInStream2設置輸入流
ICompressSetOutStream2設置輸出流
ICompressSetInStreamSize2設置輸入流大小
ICompressFilter設置過濾器,只處理小于等于size的文檔
ICompressCodecsInfo獲取壓縮解碼器信息
ISetCompressCodecsInfo設置壓縮編碼器信息
ICryptoProperties加密屬性
ICryptoResetInitVector加密,重置InitVector
ICryptoSetPassword設置密碼,用戶處理加密文檔。
ICryptoSetCRC設置CRC,用于處理加密文檔的。
IHasher計算哈希接口
IHashers哈希管理器
IStream.hISequentialInStream順序可讀文件流
ISequentialOutStream順序可寫文件流
IInStream隨機可讀文件流(在ISequentialInStream基礎上增加Seek函數)
IOutStream隨機可寫文件流(在ISequentialOutStream基礎上增加Seek/SetSize函數)
IStreamGetSize獲取文件流大小
IOutStreamFinish為可寫文件流設置結束狀態
IStreamGetProps獲取文件流的屬性
IStreamGetProps2獲取文件流的屬性
IArchive.hIInArchive可讀文檔(用于輸入)
IArchiveGetRawProps文檔屬性
IArchiveGetRootProps根文檔屬性
IArchiveOpenSeq將順序流打開為文檔
IArchiveUpdateCallback設置文檔更新回調函數
IArchiveUpdateCallback2設置文檔更新回調函數
IArchiveUpdateCallbackFile設置文檔更新回調函數(到輸出流)
IOutArchive可寫文檔(用于輸出)
ISetProperties設置屬性
IArchiveKeepModeForNextOpen下次打開時保持相同模式
IArchiveAllowTail允許尾部數據

4、外部接口

調用通過IDA打開7z.dll可發現其導出函數。

函數說明
CreateDecoder創建解碼器
CreateEncoder創建編碼器
CreateObject創建對象
GetHandlerProperty2獲取Handler屬性
GetHandlerProperty獲取Handler屬性
GetHashers獲取IHasher對象
GetIsArc獲取IsArc函數地址
GetMethodProperty獲取解碼器屬性。傳入codecIndex和PROPID,傳出PROPVARIANT*
GetNumberOfFormats獲取文件格式的數量。(指:7z,zip,rar等文件格式)
GetNumberOfMethods獲取解碼器的數量。(指:BCJ2,LZMA,Deflate等格式編碼)
SetCaseSensitive設置當前文件系統是否大小寫敏感,WINDOWS默認不敏感,其他系統默認敏感。
SetCodecs傳入ICompressCodecsInfo對象,設置外部解碼器。
SetLargePageMode設置大內存頁模式,這種模式可申請更多的內存。

5、解碼器

解碼器通過【注冊】的方式,注冊到全局變量g_Arcs中。

@ CPP\7zip\UI\Common\LoadCodecs.cpp

static const unsigned kNumArcsMax = 64; static unsigned g_NumArcs = 0; static const CArcInfo *g_Arcs[kNumArcsMax];

根據定義g_Arcs最多可以容納64種不同的解碼器。

CArcInfo的定義如下:

struct CArcInfo {UInt16 Flags;Byte Id;Byte SignatureSize;UInt16 SignatureOffset;const Byte *Signature;const char *Name;const char *Ext;const char *AddExt;Func_CreateInArchive CreateInArchive;Func_CreateOutArchive CreateOutArchive;Func_IsArc IsArc;bool IsMultiSignature() const{ return (Flags & NArcInfoFlags::kMultiSignature) != 0; } };

CArcInfo各主要成員的含義:

成員說明
CArcInfo::Flags定義在@CPP\7zip\Archive\IArchive.h中,NArcInfoFlags有詳細說明。
CArcInfo::IdArchive的ID標識符,例如:7z=7, Rar=3。
CArcInfo::SignatureSize解碼器標識的長度。
CArcInfo::Signature解碼器標識符,例如:zip={0x50, 0x4B, 0x03, 0x04},7z={'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}。等。
CArcInfo::Name解碼器名稱。
CArcInfo::Ext解碼器擴展名。
CArcInfo::CreateInArchive函數指針,創建解碼器InArchive對象,用于打開文件用于解壓。
CArcInfo::CreateOutArchive函數指針,創建解碼器OutArchive對象,用于創建文件用于壓縮。
CArcInfo::IsArc函數指針,判斷文件格式是否合法。
CArcInfo::IsMultiSignature判斷是否有多個Signature。

各解碼器通過RegisterArc.h中封裝的宏進行注冊。
如:ZIP 的注冊代碼位于CPP\7zip\Archive\Zip\ZipRegister.cpp中,我將代碼貼出來。

#include "StdAfx.h"#include "../../Common/RegisterArc.h"#include "ZipHandler.h"namespace NArchive { namespace NZip {static const Byte k_Signature[] = {4, 0x50, 0x4B, 0x03, 0x04, // Local4, 0x50, 0x4B, 0x05, 0x06, // Ecd4, 0x50, 0x4B, 0x06, 0x06, // Ecd646, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpanREGISTER_ARC_IO("zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1,k_Signature,0,NArcInfoFlags::kFindSignature |NArcInfoFlags::kMultiSignature |NArcInfoFlags::kUseGlobalOffset,IsArc_Zip)}}

6、相關宏開關

宏作用
_7ZIP_STSingle-Thread單線程,默認未定義,開啟后將不編譯多線程相關邏輯
_7ZIP_LARGE_PAGES開啟大內存頁,默認未開啟
_SZ_ALLOC_DEBUG默認不開啟,開啟后可輸出內存申請與釋放的Log
USE_MIXER_MTMultiple_Thread 多線程解碼器,不可與USE_MIXER_ST同時開啟。
USE_MIXER_STSingle_Thread 單線程解碼器,不可與USE_MIXER_MT同時開啟。
EXTRACT_ONLY開啟后只包含解壓邏輯,不包含壓縮邏輯。
NSIS_SCRIPT是否將NSIS腳本解壓,默認關閉,需要手動修改CPP\7zip\Archive\Nsis\Nsis.h開啟
EXTERNAL_CODECS是否使用外部解碼器,全局變量g_ExternalCodecs負責加載外部解碼器。CPP\7zip\UI\Agent\Agent.cpp@LoadGlobalCodecs()中包含g_ExternalCodecs相關初始化邏輯。
NEW_FOLDER_INTERFACE使用新文件夾操作接口:IFolderOperations和IFolderSetFlatMode
NO_READ_FROM_CODER禁止從解碼器讀取數據,默認未定義
USE_WIN_FILE默認開啟,開啟后使用Windows API處理文件(CreateFile/CloseHandle等),否則使用C函數處理文件(如open,close等)。

7、接口的調用

1. 模塊加載

使用LoadLibrary/GetProcAddress(Windows)或dlopen/dlsym(Linux)獲取函數地址。

2. 獲取文件格式數量

DWORD dwFormat; HRESULT hr = GetNumberOfFormats(&dwFormat);

3. 獲取每種格式的GUID

for(DWORD i=0;i<dwFormat;++i) {PROPVARIANT propvar;propvar.vt = VT_EMPTY;HRESULT hr = GetHandlerProperty2(i, NArchive::NHandlerPropID::kClassID, &propvar)GUID clsid = *(const GUID *)propvar.bstrVal;SysFreeString(propvar.bstrVal);// todo...... }

在GetHandlerProperty2內部,是通過SetPropGUID()函數將classid的值傳遞給PROPVARIANT的。
內部調用了SysAllocStringByteLen(),為避免內存泄漏,獲取成功后應當調用SysFreeString()釋放

static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value) {if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)value->vt = VT_BSTR;return S_OK; }static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) {return SetPropStrFromBin((const char *)&guid, sizeof(guid), value); }

注:文檔CPP\7zip\Archive\Guid.txt中有一段描述,是關于格式classid的。
返回的classid都應當符合這種格式{23170F69-40C1-278A-1000-000110xx0000}
中間兩位xx在下表中可以找到對應關系,如果只是希望打開指定格式的文檔,直接指定classid即可,不需要通過GetHandlerProperty2來獲取。

Handler GUIDs:{23170F69-40C1-278A-1000-000110xx0000}01 Zip02 BZip203 Rar04 Arj05 Z06 Lzh07 7z08 Cab09 Nsis0A lzma0B lzma860C xz0D ppmd......

4. 創建IInArchive對象

CMyComPtr<IInArchive> parc; HRESULt hr = CreateObject(&clsid, &IID_IInArchive, (void**)&parc));

注:我在Linux版本調試時,遇到了崩潰的問題,調試之后發現,7z中的IUnknown接口在Linux中使用了虛析構函數。
這與我代碼中已有的IUnknown定義不一致,創建的對象會有虛表地址,因此調用的函數地址錯位導致崩潰。

DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); struct IUnknown {STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;STDMETHOD_(ULONG, AddRef)() PURE;STDMETHOD_(ULONG, Release)() PURE;#ifndef _WIN32virtual ~IUnknown() {}#endif };

5. 獲取包中文件數量

在IInArchive->Open返回成功之后。可通過調用IInArchive->GetNumberOfItems()獲取文檔中包含的文件數量。

UInt32 dwItems; HRESULT hr = parc->GetNumberOfItems(&dwItems);

6. 解壓

IInArchive->Extract負責文檔的解壓。

DWORD dw; // dw 為要解壓的文檔ID,從0開始 C7zArchiveOpenCB opencb(); // 自定義一個CallBack類,繼承自IArchiveExtractCallBack接口 CMyComPtr<IArchiveExtractCallback> pcb = &opencb(); HRESULT hr = parc->Extract(&dw, 1, 0/*TestMode*/, pcb)); CMyComPtr<ISequentialOutStream> pSeqOutStm; hr = pcb->GetStream(0, &pSeqOutStm, 0); // pSeqOutStm 為解壓文件流,只支持順序寫入 // 需要調用者對pSeqOutStm進行包裝,使其支持Read/Seek/Tell等操作

7. 關閉IInArchive

解壓完畢后,調用IInArchive->Close關閉IInArchive對象,以便回收內存防止泄漏。

parc->Close();

------先寫這么多,后續更------

總結

以上是生活随笔為你收集整理的7z源码的编译与使用_markdown 格式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。