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 const 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 const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
95 static LPCWSTR const kProgramPathValue = L"Path";
96 static LPCWSTR const 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     {
520       unsigned startSize = Codecs.Size() + Hashers.Size();
521       res = LoadCodecs();
522       used = (startSize != Codecs.Size() + Hashers.Size());
523       if (res == S_OK && lib.CreateObject)
524       {
525         startSize = Formats.Size();
526         res = LoadFormats();
527         if (startSize != Formats.Size())
528           used = true;
529       }
530     }
531   }
532 
533   if (!used)
534     Libs.DeleteBack();
535 
536   return res;
537 }
538 
LoadDllsFromFolder(const FString & folderPrefix)539 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
540 {
541   NFile::NFind::CEnumerator enumerator;
542   enumerator.SetDirPrefix(folderPrefix);
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 = 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 = arc.Ext;
607       if (arc.AddExt)
608         ae = 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     if (lib.CreateObject)
870       return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
871   }
872   return S_OK;
873   #else
874   return E_FAIL;
875   #endif
876 }
877 
CreateEncoder(UInt32 index,const GUID * iid,void ** coder)878 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
879 {
880   #ifdef EXPORT_CODECS
881   if (index < g_NumCodecs)
882     return CreateEncoder(index, iid, coder);
883   #endif
884 
885   #ifdef EXTERNAL_CODECS
886   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
887   if (ci.EncoderIsAssigned)
888   {
889     const CCodecLib &lib = Libs[ci.LibIndex];
890     if (lib.CreateEncoder)
891       return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
892     if (lib.CreateObject)
893       return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
894   }
895   return S_OK;
896   #else
897   return E_FAIL;
898   #endif
899 }
900 
901 
STDMETHODIMP_(UInt32)902 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
903 {
904   return NUM_EXPORT_HASHERS
905     #ifdef EXTERNAL_CODECS
906     + Hashers.Size()
907     #endif
908     ;
909 }
910 
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)911 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
912 {
913   #ifdef EXPORT_CODECS
914   if (index < g_NumHashers)
915     return ::GetHasherProp(index, propID, value);
916   #endif
917 
918   #ifdef EXTERNAL_CODECS
919   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
920   return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
921   #else
922   return E_FAIL;
923   #endif
924 }
925 
CreateHasher(UInt32 index,IHasher ** hasher)926 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
927 {
928   #ifdef EXPORT_CODECS
929   if (index < g_NumHashers)
930     return CreateHasher(index, hasher);
931   #endif
932   #ifdef EXTERNAL_CODECS
933   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
934   return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
935   #else
936   return E_FAIL;
937   #endif
938 }
939 
GetCodec_LibIndex(UInt32 index) const940 int CCodecs::GetCodec_LibIndex(UInt32 index) const
941 {
942   #ifdef EXPORT_CODECS
943   if (index < g_NumCodecs)
944     return -1;
945   #endif
946 
947   #ifdef EXTERNAL_CODECS
948   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
949   return ci.LibIndex;
950   #else
951   return -1;
952   #endif
953 }
954 
GetHasherLibIndex(UInt32 index)955 int CCodecs::GetHasherLibIndex(UInt32 index)
956 {
957   #ifdef EXPORT_CODECS
958   if (index < g_NumHashers)
959     return -1;
960   #endif
961 
962   #ifdef EXTERNAL_CODECS
963   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
964   return ci.LibIndex;
965   #else
966   return -1;
967   #endif
968 }
969 
GetCodec_DecoderIsAssigned(UInt32 index) const970 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
971 {
972   #ifdef EXPORT_CODECS
973   if (index < g_NumCodecs)
974   {
975     NCOM::CPropVariant prop;
976     if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
977     {
978       if (prop.vt == VT_BOOL)
979         return VARIANT_BOOLToBool(prop.boolVal);
980     }
981     return false;
982   }
983   #endif
984 
985   #ifdef EXTERNAL_CODECS
986   return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
987   #else
988   return false;
989   #endif
990 }
991 
GetCodec_EncoderIsAssigned(UInt32 index) const992 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
993 {
994   #ifdef EXPORT_CODECS
995   if (index < g_NumCodecs)
996   {
997     NCOM::CPropVariant prop;
998     if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
999     {
1000       if (prop.vt == VT_BOOL)
1001         return VARIANT_BOOLToBool(prop.boolVal);
1002     }
1003     return false;
1004   }
1005   #endif
1006 
1007   #ifdef EXTERNAL_CODECS
1008   return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
1009   #else
1010   return false;
1011   #endif
1012 }
1013 
GetCodec_NumStreams(UInt32 index)1014 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
1015 {
1016   NCOM::CPropVariant prop;
1017   RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
1018   if (prop.vt == VT_UI4)
1019     return (UInt32)prop.ulVal;
1020   if (prop.vt == VT_EMPTY)
1021     return 1;
1022   return 0;
1023 }
1024 
GetCodec_Id(UInt32 index,UInt64 & id)1025 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
1026 {
1027   NCOM::CPropVariant prop;
1028   RINOK(GetProperty(index, NMethodPropID::kID, &prop));
1029   if (prop.vt != VT_UI8)
1030     return E_INVALIDARG;
1031   id = prop.uhVal.QuadPart;
1032   return S_OK;
1033 }
1034 
GetCodec_Name(UInt32 index)1035 AString CCodecs::GetCodec_Name(UInt32 index)
1036 {
1037   AString s;
1038   NCOM::CPropVariant prop;
1039   if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
1040     if (prop.vt == VT_BSTR)
1041       s.SetFromWStr_if_Ascii(prop.bstrVal);
1042   return s;
1043 }
1044 
GetHasherId(UInt32 index)1045 UInt64 CCodecs::GetHasherId(UInt32 index)
1046 {
1047   NCOM::CPropVariant prop;
1048   if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
1049     return 0;
1050   if (prop.vt != VT_UI8)
1051     return 0;
1052   return prop.uhVal.QuadPart;
1053 }
1054 
GetHasherName(UInt32 index)1055 AString CCodecs::GetHasherName(UInt32 index)
1056 {
1057   AString s;
1058   NCOM::CPropVariant prop;
1059   if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
1060     if (prop.vt == VT_BSTR)
1061       s.SetFromWStr_if_Ascii(prop.bstrVal);
1062   return s;
1063 }
1064 
GetHasherDigestSize(UInt32 index)1065 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
1066 {
1067   NCOM::CPropVariant prop;
1068   RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
1069   if (prop.vt != VT_UI4)
1070     return 0;
1071   return prop.ulVal;
1072 }
1073 
1074 #endif // EXTERNAL_CODECS
1075