SevenZipCodecs.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. {
  2. Double Commander
  3. -------------------------------------------------------------------------
  4. SevenZip archiver plugin
  5. Copyright (C) 2017-2025 Alexander Koblov ([email protected])
  6. Based on Far Manager arclite plugin
  7. Copyright © 2000 Far Group
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. 1. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. 2. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. 3. The name of the authors may not be used to endorse or promote products
  18. derived from this software without specific prior written permission.
  19. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. }
  30. unit SevenZipCodecs;
  31. {$mode delphi}
  32. interface
  33. uses
  34. Classes, SysUtils, SevenZip, fgl, ActiveX, Windows, JclCompression;
  35. const
  36. cmMaximum = PtrInt(Ord(High(TJclCompressionMethod)));
  37. type
  38. { TLibraryInfo }
  39. TLibraryInfo = class
  40. public
  41. Handle: TLibHandle;
  42. CreateObject: TCreateObjectFunc;
  43. GetHandlerProperty2: TGetHandlerProperty2;
  44. GetHandlerProperty: TGetHandlerProperty;
  45. GetMethodProperty: TGetMethodProperty;
  46. GetNumberOfFormats: TGetNumberOfFormatsFunc;
  47. GetNumberOfMethods: TGetNumberOfMethodsFunc;
  48. SetLargePageMode: TSetLargePageMode;
  49. SetCodecs: function(compressCodecsInfo: ICompressCodecsInfo): HRESULT; winapi;
  50. CreateDecoder: function(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; winapi;
  51. CreateEncoder: function(Index: Cardinal; IID: PGUID; out Coder): HRESULT; winapi;
  52. end;
  53. { TCodecInfo }
  54. TCodecInfo = class
  55. LibraryIndex: Integer;
  56. CodecIndex: Integer;
  57. EncoderIsAssigned: LongBool;
  58. DecoderIsAssigned: LongBool;
  59. Encoder: CLSID;
  60. Decoder: CLSID;
  61. ID: Cardinal;
  62. Name: UnicodeString;
  63. end;
  64. { TCompressCodecsInfo }
  65. TCompressCodecsInfo = class(TInterfacedObject, ICompressCodecsInfo, IUnknown)
  66. private
  67. FCodecs: TFPGObjectList<TCodecInfo>;
  68. FLibraries: TFPGObjectList<TLibraryInfo>;
  69. public
  70. constructor Create(ACodecs: TFPGObjectList<TCodecInfo>; ALibraries: TFPGObjectList<TLibraryInfo>);
  71. public
  72. function GetNumberOfMethods(NumMethods: PCardinal): HRESULT; winapi;
  73. function GetProperty(Index: Cardinal; PropID: TPropID; out Value: TPropVariant): HRESULT; winapi;
  74. function CreateDecoder(Index: Cardinal; IID: PGUID; out Decoder): HRESULT; winapi;
  75. function CreateEncoder(Index: Cardinal; IID: PGUID; out Coder): HRESULT; winapi;
  76. end;
  77. procedure LoadLibraries;
  78. function GetCodecName(AMethod: Cardinal): WideString;
  79. var
  80. ACodecs: TFPGObjectList<TCodecInfo> = nil;
  81. implementation
  82. uses
  83. LazUTF8, FileUtil, DCOSUtils, SevenZipHlp;
  84. { TCompressCodecsInfo }
  85. constructor TCompressCodecsInfo.Create(ACodecs: TFPGObjectList<TCodecInfo>;
  86. ALibraries: TFPGObjectList<TLibraryInfo>);
  87. begin
  88. FCodecs:= ACodecs;
  89. FLibraries:= ALibraries;
  90. end;
  91. function TCompressCodecsInfo.GetNumberOfMethods(NumMethods: PCardinal): HRESULT; winapi;
  92. begin
  93. NumMethods^:= FCodecs.Count;
  94. Result:= S_OK;
  95. end;
  96. function TCompressCodecsInfo.GetProperty(Index: Cardinal; PropID: TPropID; out
  97. Value: TPropVariant): HRESULT; winapi;
  98. var
  99. ACodecInfo: TCodecInfo;
  100. begin
  101. ACodecInfo:= FCodecs[Index];
  102. if (PropID = kDecoderIsAssigned) then
  103. begin
  104. Value.vt:= VT_BOOL;
  105. Value.bool:= ACodecInfo.DecoderIsAssigned;
  106. Exit(S_OK);
  107. end
  108. else if (PropID = kEncoderIsAssigned) then
  109. begin
  110. Value.vt:= VT_BOOL;
  111. Value.bool:= ACodecInfo.EncoderIsAssigned;
  112. Exit(S_OK);
  113. end;
  114. Result:= FLibraries[ACodecInfo.LibraryIndex].GetMethodProperty(ACodecInfo.CodecIndex, PropID, Value);
  115. end;
  116. function TCompressCodecsInfo.CreateDecoder(Index: Cardinal; IID: PGUID; out
  117. Decoder): HRESULT; winapi;
  118. var
  119. ACodecInfo: TCodecInfo;
  120. ALibraryInfo: TLibraryInfo;
  121. begin
  122. Result:= S_OK;
  123. ACodecInfo:= FCodecs[Index];
  124. if (ACodecInfo.DecoderIsAssigned) then
  125. begin
  126. ALibraryInfo:= FLibraries[ACodecInfo.LibraryIndex];
  127. if Assigned(ALibraryInfo.CreateDecoder) then
  128. Result:= ALibraryInfo.CreateDecoder(ACodecInfo.CodecIndex, IID, Decoder)
  129. else
  130. Result:= ALibraryInfo.CreateObject(@ACodecInfo.Decoder, IID, Decoder);
  131. end;
  132. end;
  133. function TCompressCodecsInfo.CreateEncoder(Index: Cardinal; IID: PGUID; out
  134. Coder): HRESULT; winapi;
  135. var
  136. ACodecInfo: TCodecInfo;
  137. ALibraryInfo: TLibraryInfo;
  138. begin
  139. Result:= S_OK;
  140. ACodecInfo:= FCodecs[Index];
  141. if (ACodecInfo.EncoderIsAssigned) then
  142. begin
  143. ALibraryInfo:= FLibraries[ACodecInfo.LibraryIndex];
  144. if Assigned(ALibraryInfo.CreateEncoder) then
  145. Result:= ALibraryInfo.CreateEncoder(ACodecInfo.CodecIndex, IID, Coder)
  146. else
  147. Result:= ALibraryInfo.CreateObject(@ACodecInfo.Encoder, IID, Coder);
  148. end;
  149. end;
  150. function GetCoderInfo(GetMethodProperty: TGetMethodProperty; Index: UInt32; var AInfo: TCodecInfo): Boolean;
  151. var
  152. Value: TPropVariant;
  153. begin
  154. Value.vt:= VT_EMPTY;
  155. if (GetMethodProperty(Index, kDecoder, Value) <> S_OK) then
  156. Exit(False);
  157. if (Value.vt <> VT_EMPTY) then
  158. begin
  159. if (Value.vt <> VT_BSTR) then Exit(False);
  160. try
  161. if (SysStringByteLen(Value.bstrVal) < SizeOf(CLSID)) then
  162. begin
  163. Exit(False);
  164. end;
  165. AInfo.Decoder:= PGUID(Value.bstrVal)^;
  166. AInfo.DecoderIsAssigned:= True;
  167. finally
  168. VarStringClear(Value);
  169. end;
  170. end;
  171. if (GetMethodProperty(Index, kEncoder, Value) <> S_OK) then
  172. Exit(False);
  173. if (Value.vt <> VT_EMPTY) then
  174. begin
  175. if (Value.vt <> VT_BSTR) then Exit(False);
  176. try
  177. if (SysStringByteLen(Value.bstrVal) < SizeOf(CLSID)) then
  178. begin
  179. Exit(False);
  180. end;
  181. AInfo.Encoder:= PGUID(Value.bstrVal)^;
  182. AInfo.EncoderIsAssigned:= True;
  183. finally
  184. VarStringClear(Value);
  185. end;
  186. end;
  187. if (GetMethodProperty(Index, kID, Value) <> S_OK) then
  188. Exit(False);
  189. if (Value.vt <> VT_UI8) then
  190. Exit(False);
  191. AInfo.ID:= Value.uhVal.QuadPart;
  192. Value.vt:= VT_EMPTY;
  193. if (GetMethodProperty(Index, kName, Value) <> S_OK) then
  194. Exit(False);
  195. if (Value.vt = VT_BSTR) then
  196. try
  197. AInfo.Name:= BinaryToUnicode(Value.bstrVal);
  198. finally
  199. VarStringClear(Value);
  200. end;
  201. Result:= AInfo.DecoderIsAssigned or AInfo.EncoderIsAssigned;
  202. end;
  203. var
  204. ALibraries: TFPGObjectList<TLibraryInfo> = nil;
  205. procedure LoadCodecs;
  206. var
  207. Handle: TLibHandle;
  208. Index, J: Integer;
  209. AFiles: TStringList;
  210. ACodecCount: Integer;
  211. NumMethods: UInt32 = 1;
  212. ACodecInfo: TCodecInfo;
  213. ALibraryInfo: TLibraryInfo;
  214. GetModuleProp: TGetModuleProp;
  215. ACompressInfo: ICompressCodecsInfo;
  216. begin
  217. AFiles:= FindAllFiles(ExtractFilePath(SevenzipLibraryName) + 'Codecs', '*.' + SharedSuffix);
  218. for Index:= 0 to AFiles.Count - 1 do
  219. begin
  220. Handle:= mbLoadLibrary(AFiles[Index]);
  221. if Handle <> 0 then
  222. begin
  223. GetModuleProp:= GetProcAddress(Handle, 'GetModuleProp');
  224. if not CheckModule(GetModuleProp) then
  225. begin
  226. FreeLibrary(Handle);
  227. Continue;
  228. end;
  229. ALibraryInfo:= TLibraryInfo.Create;
  230. ALibraryInfo.Handle:= Handle;
  231. ALibraryInfo.CreateObject:= GetProcAddress(Handle, 'CreateObject');
  232. ALibraryInfo.CreateDecoder:= GetProcAddress(Handle, 'CreateDecoder');
  233. ALibraryInfo.CreateEncoder:= GetProcAddress(Handle, 'CreateEncoder');
  234. ALibraryInfo.GetNumberOfMethods:= GetProcAddress(Handle, 'GetNumberOfMethods');
  235. ALibraryInfo.GetMethodProperty:= GetProcAddress(Handle, 'GetMethodProperty');
  236. if (Assigned(ALibraryInfo.CreateObject) or Assigned(ALibraryInfo.CreateDecoder) or
  237. Assigned(ALibraryInfo.CreateEncoder)) and Assigned(ALibraryInfo.GetMethodProperty) then
  238. begin
  239. ACodecCount:= ACodecs.Count;
  240. if Assigned(ALibraryInfo.GetNumberOfMethods) then
  241. begin
  242. if ALibraryInfo.GetNumberOfMethods(@NumMethods) = S_OK then
  243. begin
  244. for J := 0 to Int32(NumMethods) - 1 do
  245. begin
  246. ACodecInfo:= TCodecInfo.Create;
  247. ACodecInfo.LibraryIndex:= ALibraries.Count;
  248. ACodecInfo.CodecIndex:= J;
  249. if (GetCoderInfo(ALibraryInfo.GetMethodProperty, J, ACodecInfo)) then
  250. ACodecs.Add(ACodecInfo)
  251. else
  252. ACodecInfo.Free;
  253. end;
  254. end;
  255. end; // GetNumberOfMethods
  256. if (ACodecCount < ACodecs.Count) then
  257. ALibraries.Add(ALibraryInfo)
  258. else begin
  259. ALibraryInfo.Free;
  260. FreeLibrary(Handle);
  261. end;
  262. end;
  263. end;
  264. end;
  265. AFiles.Free;
  266. if (ACodecs.Count > 0) then
  267. begin
  268. ACompressInfo:= TCompressCodecsInfo.Create(ACodecs, ALibraries);
  269. for Index:= 0 to ALibraries.Count - 1 do
  270. begin
  271. if Assigned(ALibraries[Index].SetCodecs) then
  272. ALibraries[Index].SetCodecs(ACompressInfo);
  273. end;
  274. end;
  275. end;
  276. procedure LoadLibraries;
  277. var
  278. ALibraryInfo: TLibraryInfo;
  279. begin
  280. ACodecs:= TFPGObjectList<TCodecInfo>.Create;
  281. ALibraries:= TFPGObjectList<TLibraryInfo>.Create;
  282. // Add default library
  283. ALibraryInfo:= TLibraryInfo.Create;
  284. ALibraryInfo.Handle:= SevenzipLibraryHandle;
  285. ALibraryInfo.CreateObject:= SevenZip.CreateObject;
  286. ALibraryInfo.GetHandlerProperty2:= SevenZip.GetHandlerProperty2;
  287. ALibraryInfo.GetHandlerProperty:= SevenZip.GetHandlerProperty;
  288. ALibraryInfo.GetMethodProperty:= SevenZip.GetMethodProperty;
  289. ALibraryInfo.GetNumberOfFormats:= SevenZip.GetNumberOfFormats;
  290. ALibraryInfo.GetNumberOfMethods:= SevenZip.GetNumberOfMethods;
  291. ALibraryInfo.SetLargePageMode:= SevenZip.SetLargePageMode;
  292. ALibraryInfo.SetCodecs:= GetProcAddress(SevenzipLibraryHandle, 'SetCodecs');
  293. ALibraryInfo.CreateDecoder:= GetProcAddress(SevenzipLibraryHandle, 'CreateDecoder');
  294. ALibraryInfo.CreateEncoder:= GetProcAddress(SevenzipLibraryHandle, 'CreateEncoder');
  295. ALibraries.Add(ALibraryInfo);
  296. // Load external codecs
  297. LoadCodecs;
  298. end;
  299. function GetCodecName(AMethod: Cardinal): WideString;
  300. var
  301. Index: Integer;
  302. begin
  303. if Assigned(ACodecs) then begin
  304. for Index:= 0 to ACodecs.Count - 1 do
  305. begin
  306. if (ACodecs[Index].ID = AMethod) then
  307. Exit(ACodecs[Index].Name);
  308. end;
  309. end;
  310. Result:= EmptyWideStr;
  311. end;
  312. procedure Finish;
  313. var
  314. Index: Integer;
  315. begin
  316. if Assigned(ALibraries) then
  317. begin
  318. for Index:= 0 to ALibraries.Count - 1 do
  319. begin
  320. if Assigned(ALibraries[Index].SetCodecs) then
  321. ALibraries[Index].SetCodecs(nil);
  322. FreeLibrary(ALibraries[Index].Handle);
  323. end;
  324. ALibraries.Free;
  325. end;
  326. ACodecs.Free;
  327. end;
  328. finalization
  329. Finish;
  330. end.