• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // LoadCodecs.cpp
2 
3 /*
4 EXTERNAL_CODECS
5 ---------------
6   CCodecs::Load() tries to detect the directory with plugins.
7   It stops the checking, if it can find any of the following items:
8     - 7z.dll file
9     - "Formats" subdir
10     - "Codecs"  subdir
11   The order of check:
12     1) directory of client executable
13     2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**]
14        The order for HKEY_* : Path** :
15          - HKEY_CURRENT_USER  : PathXX
16          - HKEY_LOCAL_MACHINE : PathXX
17          - HKEY_CURRENT_USER  : Path
18          - HKEY_LOCAL_MACHINE : Path
19        PathXX is Path32 in 32-bit code
20        PathXX is Path64 in 64-bit code
21 
22 
23 EXPORT_CODECS
24 -------------
25   if (EXTERNAL_CODECS) is defined, then the code exports internal
26   codecs of client from CCodecs object to external plugins.
27   7-Zip doesn't use that feature. 7-Zip uses the scheme:
28     - client application without internal plugins.
29     - 7z.dll module contains all (or almost all) plugins.
30       7z.dll can use codecs from another plugins, if required.
31 */
32 
33 
34 #include "StdAfx.h"
35 
36 #include "../../../../C/7zVersion.h"
37 
38 #include "../../../Common/MyCom.h"
39 #include "../../../Common/StringToInt.h"
40 #include "../../../Common/StringConvert.h"
41 
42 #include "../../../Windows/PropVariant.h"
43 
44 #include "LoadCodecs.h"
45 
46 using namespace NWindows;
47 
48 #ifdef NEW_FOLDER_INTERFACE
49 #include "../../../Common/StringToInt.h"
50 #endif
51 
52 #include "../../ICoder.h"
53 #include "../../Common/RegisterArc.h"
54 
55 #ifdef EXTERNAL_CODECS
56 
57 // #define EXPORT_CODECS
58 
59 #endif
60 
61 #ifdef NEW_FOLDER_INTERFACE
62 extern HINSTANCE g_hInstance;
63 #include "../../../Windows/ResourceString.h"
64 static const UINT kIconTypesResId = 100;
65 #endif
66 
67 #ifdef EXTERNAL_CODECS
68 
69 #include "../../../Windows/FileFind.h"
70 #include "../../../Windows/DLL.h"
71 
72 #ifdef _WIN32
73 #include "../../../Windows/FileName.h"
74 #include "../../../Windows/Registry.h"
75 #endif
76 
77 using namespace NFile;
78 
79 
80 #define kCodecsFolderName FTEXT("Codecs")
81 #define kFormatsFolderName FTEXT("Formats")
82 
83 
84 static CFSTR kMainDll =
85   // #ifdef _WIN32
86     FTEXT("7z.dll");
87   // #else
88   // FTEXT("7z.so");
89   // #endif
90 
91 
92 #ifdef _WIN32
93 
94 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
95 static LPCWSTR kProgramPathValue = L"Path";
96 static LPCWSTR kProgramPath2Value = L"Path"
97   #ifdef _WIN64
98   L"64";
99   #else
100   L"32";
101   #endif
102 
ReadPathFromRegistry(HKEY baseKey,LPCWSTR value,FString & path)103 static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
104 {
105   NRegistry::CKey key;
106   if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
107   {
108     UString pathU;
109     if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
110     {
111       path = us2fs(pathU);
112       NName::NormalizeDirPathPrefix(path);
113       return NFind::DoesFileExist(path + kMainDll);
114     }
115   }
116   return false;
117 }
118 
119 #endif // _WIN32
120 
121 #endif // EXTERNAL_CODECS
122 
123 
124 static const unsigned kNumArcsMax = 64;
125 static unsigned g_NumArcs = 0;
126 static const CArcInfo *g_Arcs[kNumArcsMax];
127 
RegisterArc(const CArcInfo * arcInfo)128 void RegisterArc(const CArcInfo *arcInfo) throw()
129 {
130   if (g_NumArcs < kNumArcsMax)
131   {
132     g_Arcs[g_NumArcs] = arcInfo;
133     g_NumArcs++;
134   }
135 }
136 
SplitString(const UString & srcString,UStringVector & destStrings)137 static void SplitString(const UString &srcString, UStringVector &destStrings)
138 {
139   destStrings.Clear();
140   UString s;
141   unsigned len = srcString.Len();
142   if (len == 0)
143     return;
144   for (unsigned i = 0; i < len; i++)
145   {
146     wchar_t c = srcString[i];
147     if (c == L' ')
148     {
149       if (!s.IsEmpty())
150       {
151         destStrings.Add(s);
152         s.Empty();
153       }
154     }
155     else
156       s += c;
157   }
158   if (!s.IsEmpty())
159     destStrings.Add(s);
160 }
161 
FindExtension(const UString & ext) const162 int CArcInfoEx::FindExtension(const UString &ext) const
163 {
164   FOR_VECTOR (i, Exts)
165     if (ext.IsEqualTo_NoCase(Exts[i].Ext))
166       return i;
167   return -1;
168 }
169 
AddExts(const UString & ext,const UString & addExt)170 void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
171 {
172   UStringVector exts, addExts;
173   SplitString(ext, exts);
174   SplitString(addExt, addExts);
175   FOR_VECTOR (i, exts)
176   {
177     CArcExtInfo extInfo;
178     extInfo.Ext = exts[i];
179     if (i < addExts.Size())
180     {
181       extInfo.AddExt = addExts[i];
182       if (extInfo.AddExt == L"*")
183         extInfo.AddExt.Empty();
184     }
185     Exts.Add(extInfo);
186   }
187 }
188 
189 #ifndef _SFX
190 
ParseSignatures(const Byte * data,unsigned size,CObjectVector<CByteBuffer> & signatures)191 static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
192 {
193   signatures.Clear();
194   while (size > 0)
195   {
196     unsigned len = *data++;
197     size--;
198     if (len > size)
199       return false;
200     signatures.AddNew().CopyFrom(data, len);
201     data += len;
202     size -= len;
203   }
204   return true;
205 }
206 
207 #endif // _SFX
208 
209 #ifdef EXTERNAL_CODECS
210 
GetBaseFolderPrefixFromRegistry()211 static FString GetBaseFolderPrefixFromRegistry()
212 {
213   FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
214   #ifdef _WIN32
215   if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
216       !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
217       !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
218   {
219     FString path;
220     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPath2Value, path)) return path;
221     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
222     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPathValue,  path)) return path;
223     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue,  path)) return path;
224   }
225   #endif
226   return moduleFolderPrefix;
227 }
228 
229 
GetCoderClass(Func_GetMethodProperty getMethodProperty,UInt32 index,PROPID propId,CLSID & clsId,bool & isAssigned)230 static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
231     PROPID propId, CLSID &clsId, bool &isAssigned)
232 {
233   NCOM::CPropVariant prop;
234   isAssigned = false;
235   RINOK(getMethodProperty(index, propId, &prop));
236   if (prop.vt == VT_BSTR)
237   {
238     if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
239       return E_FAIL;
240     isAssigned = true;
241     clsId = *(const GUID *)prop.bstrVal;
242   }
243   else if (prop.vt != VT_EMPTY)
244     return E_FAIL;
245   return S_OK;
246 }
247 
LoadCodecs()248 HRESULT CCodecs::LoadCodecs()
249 {
250   CCodecLib &lib = Libs.Back();
251 
252   lib.CreateDecoder = (Func_CreateDecoder)lib.Lib.GetProc("CreateDecoder");
253   lib.CreateEncoder = (Func_CreateEncoder)lib.Lib.GetProc("CreateEncoder");
254   lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");
255 
256   if (lib.GetMethodProperty)
257   {
258     UInt32 numMethods = 1;
259     Func_GetNumberOfMethods getNumberOfMethods = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods");
260     if (getNumberOfMethods)
261     {
262       RINOK(getNumberOfMethods(&numMethods));
263     }
264     for (UInt32 i = 0; i < numMethods; i++)
265     {
266       CDllCodecInfo info;
267       info.LibIndex = Libs.Size() - 1;
268       info.CodecIndex = i;
269       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
270       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
271       Codecs.Add(info);
272     }
273   }
274 
275   Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers");
276   if (getHashers)
277   {
278     RINOK(getHashers(&lib.ComHashers));
279     if (lib.ComHashers)
280     {
281       UInt32 numMethods = lib.ComHashers->GetNumHashers();
282       for (UInt32 i = 0; i < numMethods; i++)
283       {
284         CDllHasherInfo info;
285         info.LibIndex = Libs.Size() - 1;
286         info.HasherIndex = i;
287         Hashers.Add(info);
288       }
289     }
290   }
291 
292   return S_OK;
293 }
294 
GetProp(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,NCOM::CPropVariant & prop)295 static HRESULT GetProp(
296     Func_GetHandlerProperty getProp,
297     Func_GetHandlerProperty2 getProp2,
298     UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
299 {
300   if (getProp2)
301     return getProp2(index, propID, &prop);;
302   return getProp(propID, &prop);
303 }
304 
GetProp_Bool(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,bool & res)305 static HRESULT GetProp_Bool(
306     Func_GetHandlerProperty getProp,
307     Func_GetHandlerProperty2 getProp2,
308     UInt32 index, PROPID propID, bool &res)
309 {
310   res = false;
311   NCOM::CPropVariant prop;
312   RINOK(GetProp(getProp, getProp2, index, propID, prop));
313   if (prop.vt == VT_BOOL)
314     res = VARIANT_BOOLToBool(prop.boolVal);
315   else if (prop.vt != VT_EMPTY)
316     return E_FAIL;
317   return S_OK;
318 }
319 
GetProp_UInt32(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UInt32 & res,bool & defined)320 static HRESULT GetProp_UInt32(
321     Func_GetHandlerProperty getProp,
322     Func_GetHandlerProperty2 getProp2,
323     UInt32 index, PROPID propID, UInt32 &res, bool &defined)
324 {
325   res = 0;
326   defined = false;
327   NCOM::CPropVariant prop;
328   RINOK(GetProp(getProp, getProp2, index, propID, prop));
329   if (prop.vt == VT_UI4)
330   {
331     res = prop.ulVal;
332     defined = true;
333   }
334   else if (prop.vt != VT_EMPTY)
335     return E_FAIL;
336   return S_OK;
337 }
338 
GetProp_String(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UString & res)339 static HRESULT GetProp_String(
340     Func_GetHandlerProperty getProp,
341     Func_GetHandlerProperty2 getProp2,
342     UInt32 index, PROPID propID, UString &res)
343 {
344   res.Empty();
345   NCOM::CPropVariant prop;
346   RINOK(GetProp(getProp, getProp2, index, propID, prop));
347   if (prop.vt == VT_BSTR)
348     res.SetFromBstr(prop.bstrVal);
349   else if (prop.vt != VT_EMPTY)
350     return E_FAIL;
351   return S_OK;
352 }
353 
GetProp_RawData(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,CByteBuffer & bb)354 static HRESULT GetProp_RawData(
355     Func_GetHandlerProperty getProp,
356     Func_GetHandlerProperty2 getProp2,
357     UInt32 index, PROPID propID, CByteBuffer &bb)
358 {
359   bb.Free();
360   NCOM::CPropVariant prop;
361   RINOK(GetProp(getProp, getProp2, index, propID, prop));
362   if (prop.vt == VT_BSTR)
363   {
364     UINT len = ::SysStringByteLen(prop.bstrVal);
365     bb.CopyFrom((const Byte *)prop.bstrVal, len);
366   }
367   else if (prop.vt != VT_EMPTY)
368     return E_FAIL;
369   return S_OK;
370 }
371 
372 static const UInt32 kArcFlagsPars[] =
373 {
374   NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
375   NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
376   NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
377 };
378 
LoadFormats()379 HRESULT CCodecs::LoadFormats()
380 {
381   const NDLL::CLibrary &lib = Libs.Back().Lib;
382 
383   Func_GetHandlerProperty getProp = NULL;
384   Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2");
385   Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc");
386 
387   UInt32 numFormats = 1;
388 
389   if (getProp2)
390   {
391     Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats");
392     if (getNumberOfFormats)
393     {
394       RINOK(getNumberOfFormats(&numFormats));
395     }
396   }
397   else
398   {
399     getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty");
400     if (!getProp)
401       return S_OK;
402   }
403 
404   for (UInt32 i = 0; i < numFormats; i++)
405   {
406     CArcInfoEx item;
407     item.LibIndex = Libs.Size() - 1;
408     item.FormatIndex = i;
409 
410     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name));
411 
412     {
413       NCOM::CPropVariant prop;
414       if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
415         continue;
416       if (prop.vt != VT_BSTR)
417         continue;
418       if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
419         return E_FAIL;
420       item.ClassID = *(const GUID *)prop.bstrVal;
421       prop.Clear();
422     }
423 
424     UString ext, addExt;
425     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext));
426     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt));
427     item.AddExts(ext, addExt);
428 
429     GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
430     bool flags_Defined = false;
431     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined));
432     item.NewInterface = flags_Defined;
433     if (!flags_Defined) // && item.UpdateEnabled
434     {
435       // support for DLL version before 9.31:
436       for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2)
437       {
438         bool val = false;
439         GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
440         if (val)
441           item.Flags |= kArcFlagsPars[j + 1];
442       }
443     }
444 
445     CByteBuffer sig;
446     RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig));
447     if (sig.Size() != 0)
448       item.Signatures.Add(sig);
449     else
450     {
451       RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig));
452       ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
453     }
454 
455     bool signatureOffset_Defined;
456     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined));
457 
458     // bool version_Defined;
459     // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
460 
461     if (getIsArc)
462       getIsArc(i, &item.IsArcFunc);
463 
464     Formats.Add(item);
465   }
466   return S_OK;
467 }
468 
469 #ifdef _7ZIP_LARGE_PAGES
470 extern "C"
471 {
472   extern SIZE_T g_LargePageSize;
473 }
474 #endif
475 
LoadDll(const FString & dllPath,bool needCheckDll,bool * loadedOK)476 HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
477 {
478   if (loadedOK)
479     *loadedOK = false;
480 
481   if (needCheckDll)
482   {
483     NDLL::CLibrary lib;
484     if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
485       return S_OK;
486   }
487 
488   Libs.AddNew();
489   CCodecLib &lib = Libs.Back();
490   lib.Path = dllPath;
491   bool used = false;
492   HRESULT res = S_OK;
493 
494   if (lib.Lib.Load(dllPath))
495   {
496     if (loadedOK)
497       *loadedOK = true;
498     #ifdef NEW_FOLDER_INTERFACE
499     lib.LoadIcons();
500     #endif
501 
502     #ifdef _7ZIP_LARGE_PAGES
503     if (g_LargePageSize != 0)
504     {
505       Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");
506       if (setLargePageMode)
507         setLargePageMode();
508     }
509     #endif
510 
511     if (CaseSensitiveChange)
512     {
513       Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");
514       if (setCaseSensitive)
515         setCaseSensitive(CaseSensitive ? 1 : 0);
516     }
517 
518     lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");
519     if (lib.CreateObject)
520     {
521       unsigned startSize = Codecs.Size() + Hashers.Size();
522       res = LoadCodecs();
523       used = (startSize != Codecs.Size() + Hashers.Size());
524       if (res == S_OK)
525       {
526         startSize = Formats.Size();
527         res = LoadFormats();
528         if (startSize != Formats.Size())
529           used = true;
530       }
531     }
532   }
533 
534   if (!used)
535     Libs.DeleteBack();
536 
537   return res;
538 }
539 
LoadDllsFromFolder(const FString & folderPrefix)540 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
541 {
542   NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK);
543   NFile::NFind::CFileInfo fi;
544   while (enumerator.Next(fi))
545   {
546     if (fi.IsDir())
547       continue;
548     RINOK(LoadDll(folderPrefix + fi.Name, true));
549   }
550   return S_OK;
551 }
552 
CloseLibs()553 void CCodecs::CloseLibs()
554 {
555   // OutputDebugStringA("~CloseLibs start");
556   /*
557   WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected,
558   if it's called from another FreeLibrary() call.
559   So we need to call FreeLibrary() before global destructors.
560 
561   Also we free global links from DLLs to object of this module before CLibrary::Free() call.
562   */
563 
564   FOR_VECTOR(i, Libs)
565   {
566     const CCodecLib &lib = Libs[i];
567     if (lib.SetCodecs)
568       lib.SetCodecs(NULL);
569   }
570 
571   // OutputDebugStringA("~CloseLibs after SetCodecs");
572   Libs.Clear();
573   // OutputDebugStringA("~CloseLibs end");
574 }
575 
576 #endif // EXTERNAL_CODECS
577 
578 
Load()579 HRESULT CCodecs::Load()
580 {
581   #ifdef NEW_FOLDER_INTERFACE
582   InternalIcons.LoadIcons(g_hInstance);
583   #endif
584 
585   Formats.Clear();
586 
587   #ifdef EXTERNAL_CODECS
588     MainDll_ErrorPath.Empty();
589     Codecs.Clear();
590     Hashers.Clear();
591   #endif
592 
593   for (UInt32 i = 0; i < g_NumArcs; i++)
594   {
595     const CArcInfo &arc = *g_Arcs[i];
596     CArcInfoEx item;
597 
598     item.Name.SetFromAscii(arc.Name);
599     item.CreateInArchive = arc.CreateInArchive;
600     item.IsArcFunc = arc.IsArc;
601     item.Flags = arc.Flags;
602 
603     {
604       UString e, ae;
605       if (arc.Ext)
606         e.SetFromAscii(arc.Ext);
607       if (arc.AddExt)
608         ae.SetFromAscii(arc.AddExt);
609       item.AddExts(e, ae);
610     }
611 
612     #ifndef _SFX
613 
614     item.CreateOutArchive = arc.CreateOutArchive;
615     item.UpdateEnabled = (arc.CreateOutArchive != NULL);
616     item.SignatureOffset = arc.SignatureOffset;
617     // item.Version = MY_VER_MIX;
618     item.NewInterface = true;
619 
620     if (arc.IsMultiSignature())
621       ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
622     else
623       item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
624 
625     #endif
626 
627     Formats.Add(item);
628   }
629 
630   #ifdef EXTERNAL_CODECS
631     const FString baseFolder = GetBaseFolderPrefixFromRegistry();
632     {
633       bool loadedOK;
634       RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK));
635       if (!loadedOK)
636         MainDll_ErrorPath = kMainDll;
637     }
638     RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
639     RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
640 
641   NeedSetLibCodecs = true;
642 
643   if (Libs.Size() == 0)
644     NeedSetLibCodecs = false;
645   else if (Libs.Size() == 1)
646   {
647     // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
648     #ifndef EXPORT_CODECS
649     if (g_NumArcs == 0)
650       NeedSetLibCodecs = false;
651     #endif
652   }
653 
654   if (NeedSetLibCodecs)
655   {
656     /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
657        old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
658 
659     FOR_VECTOR(i, Libs)
660     {
661       CCodecLib &lib = Libs[i];
662       lib.SetCodecs = (Func_SetCodecs)lib.Lib.GetProc("SetCodecs");
663       if (lib.SetCodecs)
664       {
665         RINOK(lib.SetCodecs(this));
666       }
667     }
668   }
669 
670   #endif
671 
672   return S_OK;
673 }
674 
675 #ifndef _SFX
676 
FindFormatForArchiveName(const UString & arcPath) const677 int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
678 {
679   int dotPos = arcPath.ReverseFind_Dot();
680   if (dotPos <= arcPath.ReverseFind_PathSepar())
681     return -1;
682   const UString ext = arcPath.Ptr(dotPos + 1);
683   if (ext.IsEmpty())
684     return -1;
685   if (ext.IsEqualTo_Ascii_NoCase("exe"))
686     return -1;
687   FOR_VECTOR (i, Formats)
688   {
689     const CArcInfoEx &arc = Formats[i];
690     /*
691     if (!arc.UpdateEnabled)
692       continue;
693     */
694     if (arc.FindExtension(ext) >= 0)
695       return i;
696   }
697   return -1;
698 }
699 
FindFormatForExtension(const UString & ext) const700 int CCodecs::FindFormatForExtension(const UString &ext) const
701 {
702   if (ext.IsEmpty())
703     return -1;
704   FOR_VECTOR (i, Formats)
705     if (Formats[i].FindExtension(ext) >= 0)
706       return i;
707   return -1;
708 }
709 
FindFormatForArchiveType(const UString & arcType) const710 int CCodecs::FindFormatForArchiveType(const UString &arcType) const
711 {
712   FOR_VECTOR (i, Formats)
713     if (Formats[i].Name.IsEqualTo_NoCase(arcType))
714       return i;
715   return -1;
716 }
717 
FindFormatForArchiveType(const UString & arcType,CIntVector & formatIndices) const718 bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
719 {
720   formatIndices.Clear();
721   for (unsigned pos = 0; pos < arcType.Len();)
722   {
723     int pos2 = arcType.Find(L'.', pos);
724     if (pos2 < 0)
725       pos2 = arcType.Len();
726     const UString name = arcType.Mid(pos, pos2 - pos);
727     if (name.IsEmpty())
728       return false;
729     int index = FindFormatForArchiveType(name);
730     if (index < 0 && name != L"*")
731     {
732       formatIndices.Clear();
733       return false;
734     }
735     formatIndices.Add(index);
736     pos = pos2 + 1;
737   }
738   return true;
739 }
740 
741 #endif // _SFX
742 
743 
744 #ifdef NEW_FOLDER_INTERFACE
745 
LoadIcons(HMODULE m)746 void CCodecIcons::LoadIcons(HMODULE m)
747 {
748   UString iconTypes;
749   MyLoadString(m, kIconTypesResId, iconTypes);
750   UStringVector pairs;
751   SplitString(iconTypes, pairs);
752   FOR_VECTOR (i, pairs)
753   {
754     const UString &s = pairs[i];
755     int pos = s.Find(L':');
756     CIconPair iconPair;
757     iconPair.IconIndex = -1;
758     if (pos < 0)
759       pos = s.Len();
760     else
761     {
762       UString num = s.Ptr(pos + 1);
763       if (!num.IsEmpty())
764       {
765         const wchar_t *end;
766         iconPair.IconIndex = ConvertStringToUInt32(num, &end);
767         if (*end != 0)
768           continue;
769       }
770     }
771     iconPair.Ext = s.Left(pos);
772     IconPairs.Add(iconPair);
773   }
774 }
775 
FindIconIndex(const UString & ext,int & iconIndex) const776 bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
777 {
778   iconIndex = -1;
779   FOR_VECTOR (i, IconPairs)
780   {
781     const CIconPair &pair = IconPairs[i];
782     if (ext.IsEqualTo_NoCase(pair.Ext))
783     {
784       iconIndex = pair.IconIndex;
785       return true;
786     }
787   }
788   return false;
789 }
790 
791 #endif // NEW_FOLDER_INTERFACE
792 
793 
794 #ifdef EXTERNAL_CODECS
795 
796 // #define EXPORT_CODECS
797 
798 #ifdef EXPORT_CODECS
799 
800 extern unsigned g_NumCodecs;
801 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
802 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
803 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
804 #define NUM_EXPORT_CODECS g_NumCodecs
805 
806 extern unsigned g_NumHashers;
807 STDAPI CreateHasher(UInt32 index, IHasher **hasher);
808 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
809 #define NUM_EXPORT_HASHERS g_NumHashers
810 
811 #else // EXPORT_CODECS
812 
813 #define NUM_EXPORT_CODECS 0
814 #define NUM_EXPORT_HASHERS 0
815 
816 #endif // EXPORT_CODECS
817 
GetNumMethods(UInt32 * numMethods)818 STDMETHODIMP CCodecs::GetNumMethods(UInt32 *numMethods)
819 {
820   *numMethods = NUM_EXPORT_CODECS
821     #ifdef EXTERNAL_CODECS
822     + Codecs.Size()
823     #endif
824     ;
825   return S_OK;
826 }
827 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)828 STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
829 {
830   #ifdef EXPORT_CODECS
831   if (index < g_NumCodecs)
832     return GetMethodProperty(index, propID, value);
833   #endif
834 
835   #ifdef EXTERNAL_CODECS
836   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
837 
838   if (propID == NMethodPropID::kDecoderIsAssigned ||
839       propID == NMethodPropID::kEncoderIsAssigned)
840   {
841     NCOM::CPropVariant prop;
842     prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ?
843         ci.DecoderIsAssigned :
844         ci.EncoderIsAssigned);
845     prop.Detach(value);
846     return S_OK;
847   }
848   const CCodecLib &lib = Libs[ci.LibIndex];
849   return lib.GetMethodProperty(ci.CodecIndex, propID, value);
850   #else
851   return E_FAIL;
852   #endif
853 }
854 
CreateDecoder(UInt32 index,const GUID * iid,void ** coder)855 STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
856 {
857   #ifdef EXPORT_CODECS
858   if (index < g_NumCodecs)
859     return CreateDecoder(index, iid, coder);
860   #endif
861 
862   #ifdef EXTERNAL_CODECS
863   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
864   if (ci.DecoderIsAssigned)
865   {
866     const CCodecLib &lib = Libs[ci.LibIndex];
867     if (lib.CreateDecoder)
868       return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
869     return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
870   }
871   return S_OK;
872   #else
873   return E_FAIL;
874   #endif
875 }
876 
CreateEncoder(UInt32 index,const GUID * iid,void ** coder)877 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
878 {
879   #ifdef EXPORT_CODECS
880   if (index < g_NumCodecs)
881     return CreateEncoder(index, iid, coder);
882   #endif
883 
884   #ifdef EXTERNAL_CODECS
885   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
886   if (ci.EncoderIsAssigned)
887   {
888     const CCodecLib &lib = Libs[ci.LibIndex];
889     if (lib.CreateEncoder)
890       return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
891     return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
892   }
893   return S_OK;
894   #else
895   return E_FAIL;
896   #endif
897 }
898 
899 
STDMETHODIMP_(UInt32)900 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
901 {
902   return NUM_EXPORT_HASHERS
903     #ifdef EXTERNAL_CODECS
904     + Hashers.Size()
905     #endif
906     ;
907 }
908 
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)909 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
910 {
911   #ifdef EXPORT_CODECS
912   if (index < g_NumHashers)
913     return ::GetHasherProp(index, propID, value);
914   #endif
915 
916   #ifdef EXTERNAL_CODECS
917   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
918   return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
919   #else
920   return E_FAIL;
921   #endif
922 }
923 
CreateHasher(UInt32 index,IHasher ** hasher)924 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
925 {
926   #ifdef EXPORT_CODECS
927   if (index < g_NumHashers)
928     return CreateHasher(index, hasher);
929   #endif
930   #ifdef EXTERNAL_CODECS
931   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
932   return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
933   #else
934   return E_FAIL;
935   #endif
936 }
937 
GetCodec_LibIndex(UInt32 index) const938 int CCodecs::GetCodec_LibIndex(UInt32 index) const
939 {
940   #ifdef EXPORT_CODECS
941   if (index < g_NumCodecs)
942     return -1;
943   #endif
944 
945   #ifdef EXTERNAL_CODECS
946   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
947   return ci.LibIndex;
948   #else
949   return -1;
950   #endif
951 }
952 
GetHasherLibIndex(UInt32 index)953 int CCodecs::GetHasherLibIndex(UInt32 index)
954 {
955   #ifdef EXPORT_CODECS
956   if (index < g_NumHashers)
957     return -1;
958   #endif
959 
960   #ifdef EXTERNAL_CODECS
961   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
962   return ci.LibIndex;
963   #else
964   return -1;
965   #endif
966 }
967 
GetCodec_DecoderIsAssigned(UInt32 index) const968 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
969 {
970   #ifdef EXPORT_CODECS
971   if (index < g_NumCodecs)
972   {
973     NCOM::CPropVariant prop;
974     if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
975     {
976       if (prop.vt == VT_BOOL)
977         return VARIANT_BOOLToBool(prop.boolVal);
978     }
979     return false;
980   }
981   #endif
982 
983   #ifdef EXTERNAL_CODECS
984   return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
985   #else
986   return false;
987   #endif
988 }
989 
GetCodec_EncoderIsAssigned(UInt32 index) const990 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
991 {
992   #ifdef EXPORT_CODECS
993   if (index < g_NumCodecs)
994   {
995     NCOM::CPropVariant prop;
996     if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
997     {
998       if (prop.vt == VT_BOOL)
999         return VARIANT_BOOLToBool(prop.boolVal);
1000     }
1001     return false;
1002   }
1003   #endif
1004 
1005   #ifdef EXTERNAL_CODECS
1006   return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
1007   #else
1008   return false;
1009   #endif
1010 }
1011 
GetCodec_NumStreams(UInt32 index)1012 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
1013 {
1014   NCOM::CPropVariant prop;
1015   RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
1016   if (prop.vt == VT_UI4)
1017     return (UInt32)prop.ulVal;
1018   if (prop.vt == VT_EMPTY)
1019     return 1;
1020   return 0;
1021 }
1022 
GetCodec_Id(UInt32 index,UInt64 & id)1023 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
1024 {
1025   NCOM::CPropVariant prop;
1026   RINOK(GetProperty(index, NMethodPropID::kID, &prop));
1027   if (prop.vt != VT_UI8)
1028     return E_INVALIDARG;
1029   id = prop.uhVal.QuadPart;
1030   return S_OK;
1031 }
1032 
GetCodec_Name(UInt32 index)1033 AString CCodecs::GetCodec_Name(UInt32 index)
1034 {
1035   AString s;
1036   NCOM::CPropVariant prop;
1037   if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
1038     if (prop.vt == VT_BSTR)
1039       s.SetFromWStr_if_Ascii(prop.bstrVal);
1040   return s;
1041 }
1042 
GetHasherId(UInt32 index)1043 UInt64 CCodecs::GetHasherId(UInt32 index)
1044 {
1045   NCOM::CPropVariant prop;
1046   if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
1047     return 0;
1048   if (prop.vt != VT_UI8)
1049     return 0;
1050   return prop.uhVal.QuadPart;
1051 }
1052 
GetHasherName(UInt32 index)1053 AString CCodecs::GetHasherName(UInt32 index)
1054 {
1055   AString s;
1056   NCOM::CPropVariant prop;
1057   if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
1058     if (prop.vt == VT_BSTR)
1059       s.SetFromWStr_if_Ascii(prop.bstrVal);
1060   return s;
1061 }
1062 
GetHasherDigestSize(UInt32 index)1063 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
1064 {
1065   NCOM::CPropVariant prop;
1066   RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
1067   if (prop.vt != VT_UI4)
1068     return 0;
1069   return prop.ulVal;
1070 }
1071 
1072 #endif // EXTERNAL_CODECS
1073