1 // LoadCodecs.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/7zVersion.h"
6 
7 #include "../../../Common/MyCom.h"
8 #include "../../../Common/StringToInt.h"
9 #include "../../../Common/StringConvert.h"
10 
11 #include "../../../Windows/PropVariant.h"
12 
13 #include "LoadCodecs.h"
14 
15 using namespace NWindows;
16 
17 #ifdef NEW_FOLDER_INTERFACE
18 #include "../../../Common/StringToInt.h"
19 #endif
20 
21 #include "../../ICoder.h"
22 #include "../../Common/RegisterArc.h"
23 
24 #ifdef EXTERNAL_CODECS
25 
26 #include "../../../Windows/FileFind.h"
27 #include "../../../Windows/DLL.h"
28 #ifdef NEW_FOLDER_INTERFACE
29 #include "../../../Windows/ResourceString.h"
30 static const UINT kIconTypesResId = 100;
31 #endif
32 
33 #ifdef _WIN32
34 #include "../../../Windows/FileName.h"
35 #include "../../../Windows/Registry.h"
36 #endif
37 
38 using namespace NFile;
39 
40 #ifdef _WIN32
41 extern HINSTANCE g_hInstance;
42 #endif
43 
44 #define kCodecsFolderName FTEXT("Codecs")
45 #define kFormatsFolderName FTEXT("Formats")
46 static CFSTR kMainDll = FTEXT("7z.dll");
47 
48 #ifdef _WIN32
49 
50 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
51 static LPCWSTR kProgramPathValue = L"Path";
52 static LPCWSTR kProgramPath2Value = L"Path"
53   #ifdef _WIN64
54   L"64";
55   #else
56   L"32";
57   #endif
58 
ReadPathFromRegistry(HKEY baseKey,LPCWSTR value,FString & path)59 static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
60 {
61   NRegistry::CKey key;
62   if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
63   {
64     UString pathU;
65     if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
66     {
67       path = us2fs(pathU);
68       NName::NormalizeDirPathPrefix(path);
69       return NFind::DoesFileExist(path + kMainDll);
70     }
71   }
72   return false;
73 }
74 
75 #endif // _WIN32
76 
77 #endif // EXTERNAL_CODECS
78 
79 
80 static const unsigned kNumArcsMax = 48;
81 static unsigned g_NumArcs = 0;
82 static const CArcInfo *g_Arcs[kNumArcsMax];
83 
RegisterArc(const CArcInfo * arcInfo)84 void RegisterArc(const CArcInfo *arcInfo) throw()
85 {
86   if (g_NumArcs < kNumArcsMax)
87   {
88     g_Arcs[g_NumArcs] = arcInfo;
89     g_NumArcs++;
90   }
91 }
92 
SplitString(const UString & srcString,UStringVector & destStrings)93 static void SplitString(const UString &srcString, UStringVector &destStrings)
94 {
95   destStrings.Clear();
96   UString s;
97   unsigned len = srcString.Len();
98   if (len == 0)
99     return;
100   for (unsigned i = 0; i < len; i++)
101   {
102     wchar_t c = srcString[i];
103     if (c == L' ')
104     {
105       if (!s.IsEmpty())
106       {
107         destStrings.Add(s);
108         s.Empty();
109       }
110     }
111     else
112       s += c;
113   }
114   if (!s.IsEmpty())
115     destStrings.Add(s);
116 }
117 
FindExtension(const UString & ext) const118 int CArcInfoEx::FindExtension(const UString &ext) const
119 {
120   FOR_VECTOR (i, Exts)
121     if (ext.IsEqualToNoCase(Exts[i].Ext))
122       return i;
123   return -1;
124 }
125 
AddExts(const UString & ext,const UString & addExt)126 void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
127 {
128   UStringVector exts, addExts;
129   SplitString(ext, exts);
130   SplitString(addExt, addExts);
131   FOR_VECTOR (i, exts)
132   {
133     CArcExtInfo extInfo;
134     extInfo.Ext = exts[i];
135     if (i < addExts.Size())
136     {
137       extInfo.AddExt = addExts[i];
138       if (extInfo.AddExt == L"*")
139         extInfo.AddExt.Empty();
140     }
141     Exts.Add(extInfo);
142   }
143 }
144 
145 #ifndef _SFX
146 
ParseSignatures(const Byte * data,unsigned size,CObjectVector<CByteBuffer> & signatures)147 static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
148 {
149   signatures.Clear();
150   while (size > 0)
151   {
152     unsigned len = *data++;
153     size--;
154     if (len > size)
155       return false;
156     signatures.AddNew().CopyFrom(data, len);
157     data += len;
158     size -= len;
159   }
160   return true;
161 }
162 
163 #endif // _SFX
164 
165 #ifdef EXTERNAL_CODECS
166 
GetBaseFolderPrefixFromRegistry()167 static FString GetBaseFolderPrefixFromRegistry()
168 {
169   FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
170   #ifdef _WIN32
171   if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
172       !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
173       !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
174   {
175     FString path;
176     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPath2Value, path)) return path;
177     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
178     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPathValue,  path)) return path;
179     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue,  path)) return path;
180   }
181   #endif
182   return moduleFolderPrefix;
183 }
184 
GetCoderClass(Func_GetMethodProperty getMethodProperty,UInt32 index,PROPID propId,CLSID & clsId,bool & isAssigned)185 static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
186     PROPID propId, CLSID &clsId, bool &isAssigned)
187 {
188   NCOM::CPropVariant prop;
189   isAssigned = false;
190   RINOK(getMethodProperty(index, propId, &prop));
191   if (prop.vt == VT_BSTR)
192   {
193     if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
194       return E_FAIL;
195     isAssigned = true;
196     clsId = *(const GUID *)prop.bstrVal;
197   }
198   else if (prop.vt != VT_EMPTY)
199     return E_FAIL;
200   return S_OK;
201 }
202 
LoadCodecs()203 HRESULT CCodecs::LoadCodecs()
204 {
205   CCodecLib &lib = Libs.Back();
206   lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");
207   if (lib.GetMethodProperty)
208   {
209     UInt32 numMethods = 1;
210     Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods");
211     if (getNumberOfMethodsFunc)
212     {
213       RINOK(getNumberOfMethodsFunc(&numMethods));
214     }
215     for (UInt32 i = 0; i < numMethods; i++)
216     {
217       CDllCodecInfo info;
218       info.LibIndex = Libs.Size() - 1;
219       info.CodecIndex = i;
220       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
221       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
222       Codecs.Add(info);
223     }
224   }
225 
226   Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers");
227   if (getHashers)
228   {
229     RINOK(getHashers(&lib.Hashers));
230     if (lib.Hashers)
231     {
232       UInt32 numMethods = lib.Hashers->GetNumHashers();
233       for (UInt32 i = 0; i < numMethods; i++)
234       {
235         CDllHasherInfo info;
236         info.LibIndex = Libs.Size() - 1;
237         info.HasherIndex = i;
238         Hashers.Add(info);
239       }
240     }
241   }
242   return S_OK;
243 }
244 
GetProp(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,NCOM::CPropVariant & prop)245 static HRESULT GetProp(
246     Func_GetHandlerProperty getProp,
247     Func_GetHandlerProperty2 getProp2,
248     UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
249 {
250   if (getProp2)
251     return getProp2(index, propID, &prop);;
252   return getProp(propID, &prop);
253 }
254 
GetProp_Bool(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,bool & res)255 static HRESULT GetProp_Bool(
256     Func_GetHandlerProperty getProp,
257     Func_GetHandlerProperty2 getProp2,
258     UInt32 index, PROPID propID, bool &res)
259 {
260   res = false;
261   NCOM::CPropVariant prop;
262   RINOK(GetProp(getProp, getProp2, index, propID, prop));
263   if (prop.vt == VT_BOOL)
264     res = VARIANT_BOOLToBool(prop.boolVal);
265   else if (prop.vt != VT_EMPTY)
266     return E_FAIL;
267   return S_OK;
268 }
269 
GetProp_UInt32(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UInt32 & res,bool & defined)270 static HRESULT GetProp_UInt32(
271     Func_GetHandlerProperty getProp,
272     Func_GetHandlerProperty2 getProp2,
273     UInt32 index, PROPID propID, UInt32 &res, bool &defined)
274 {
275   res = 0;
276   defined = false;
277   NCOM::CPropVariant prop;
278   RINOK(GetProp(getProp, getProp2, index, propID, prop));
279   if (prop.vt == VT_UI4)
280   {
281     res = prop.ulVal;
282     defined = true;
283   }
284   else if (prop.vt != VT_EMPTY)
285     return E_FAIL;
286   return S_OK;
287 }
288 
GetProp_String(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UString & res)289 static HRESULT GetProp_String(
290     Func_GetHandlerProperty getProp,
291     Func_GetHandlerProperty2 getProp2,
292     UInt32 index, PROPID propID, UString &res)
293 {
294   res.Empty();
295   NCOM::CPropVariant prop;
296   RINOK(GetProp(getProp, getProp2, index, propID, prop));
297   if (prop.vt == VT_BSTR)
298     res = prop.bstrVal;
299   else if (prop.vt != VT_EMPTY)
300     return E_FAIL;
301   return S_OK;
302 }
303 
GetProp_RawData(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,CByteBuffer & bb)304 static HRESULT GetProp_RawData(
305     Func_GetHandlerProperty getProp,
306     Func_GetHandlerProperty2 getProp2,
307     UInt32 index, PROPID propID, CByteBuffer &bb)
308 {
309   bb.Free();
310   NCOM::CPropVariant prop;
311   RINOK(GetProp(getProp, getProp2, index, propID, prop));
312   if (prop.vt == VT_BSTR)
313   {
314     UINT len = ::SysStringByteLen(prop.bstrVal);
315     bb.CopyFrom((const Byte *)prop.bstrVal, len);
316   }
317   else if (prop.vt != VT_EMPTY)
318     return E_FAIL;
319   return S_OK;
320 }
321 
322 static const UInt32 kArcFlagsPars[] =
323 {
324   NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
325   NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
326   NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
327 };
328 
LoadFormats()329 HRESULT CCodecs::LoadFormats()
330 {
331   const NDLL::CLibrary &lib = Libs.Back().Lib;
332 
333   Func_GetHandlerProperty getProp = NULL;
334   Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2");
335   Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc");
336 
337   UInt32 numFormats = 1;
338 
339   if (getProp2)
340   {
341     Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats");
342     if (getNumberOfFormats)
343     {
344       RINOK(getNumberOfFormats(&numFormats));
345     }
346   }
347   else
348   {
349     getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty");
350     if (!getProp)
351       return S_OK;
352   }
353 
354   for (UInt32 i = 0; i < numFormats; i++)
355   {
356     CArcInfoEx item;
357     item.LibIndex = Libs.Size() - 1;
358     item.FormatIndex = i;
359 
360     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name));
361 
362     {
363       NCOM::CPropVariant prop;
364       if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
365         continue;
366       if (prop.vt != VT_BSTR)
367         continue;
368       if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
369         return E_FAIL;
370       item.ClassID = *(const GUID *)prop.bstrVal;
371       prop.Clear();
372     }
373 
374     UString ext, addExt;
375     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext));
376     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt));
377     item.AddExts(ext, addExt);
378 
379     GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
380     bool flags_Defined = false;
381     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined));
382     item.NewInterface = flags_Defined;
383     if (!flags_Defined) // && item.UpdateEnabled
384     {
385       // support for DLL version before 9.31:
386       for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2)
387       {
388         bool val = false;
389         GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
390         if (val)
391           item.Flags |= kArcFlagsPars[j + 1];
392       }
393     }
394 
395     CByteBuffer sig;
396     RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig));
397     if (sig.Size() != 0)
398       item.Signatures.Add(sig);
399     else
400     {
401       RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig));
402       ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
403     }
404 
405     bool signatureOffset_Defined;
406     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined));
407 
408     // bool version_Defined;
409     // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
410 
411     if (getIsArc)
412       getIsArc(i, &item.IsArcFunc);
413 
414     Formats.Add(item);
415   }
416   return S_OK;
417 }
418 
419 #ifdef NEW_FOLDER_INTERFACE
LoadIcons(HMODULE m)420 void CCodecIcons::LoadIcons(HMODULE m)
421 {
422   UString iconTypes;
423   MyLoadString(m, kIconTypesResId, iconTypes);
424   UStringVector pairs;
425   SplitString(iconTypes, pairs);
426   FOR_VECTOR (i, pairs)
427   {
428     const UString &s = pairs[i];
429     int pos = s.Find(L':');
430     CIconPair iconPair;
431     iconPair.IconIndex = -1;
432     if (pos < 0)
433       pos = s.Len();
434     else
435     {
436       UString num = s.Ptr(pos + 1);
437       if (!num.IsEmpty())
438       {
439         const wchar_t *end;
440         iconPair.IconIndex = ConvertStringToUInt32(num, &end);
441         if (*end != 0)
442           continue;
443       }
444     }
445     iconPair.Ext = s.Left(pos);
446     IconPairs.Add(iconPair);
447   }
448 }
449 
FindIconIndex(const UString & ext,int & iconIndex) const450 bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
451 {
452   iconIndex = -1;
453   FOR_VECTOR (i, IconPairs)
454   {
455     const CIconPair &pair = IconPairs[i];
456     if (ext.IsEqualToNoCase(pair.Ext))
457     {
458       iconIndex = pair.IconIndex;
459       return true;
460     }
461   }
462   return false;
463 }
464 
465 #endif // EXTERNAL_CODECS
466 
467 #ifdef _7ZIP_LARGE_PAGES
468 extern "C"
469 {
470   extern SIZE_T g_LargePageSize;
471 }
472 #endif
473 
LoadDll(const FString & dllPath,bool needCheckDll)474 HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll)
475 {
476   if (needCheckDll)
477   {
478     NDLL::CLibrary library;
479     if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
480       return S_OK;
481   }
482   Libs.Add(CCodecLib());
483   CCodecLib &lib = Libs.Back();
484   lib.Path = dllPath;
485   bool used = false;
486   HRESULT res = S_OK;
487   if (lib.Lib.Load(dllPath))
488   {
489     #ifdef NEW_FOLDER_INTERFACE
490     lib.LoadIcons();
491     #endif
492 
493     #ifdef _7ZIP_LARGE_PAGES
494     if (g_LargePageSize != 0)
495     {
496       Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");
497       if (setLargePageMode)
498         setLargePageMode();
499     }
500     #endif
501 
502     if (CaseSensitiveChange)
503     {
504       Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");
505       if (setCaseSensitive)
506         setCaseSensitive(CaseSensitive ? 1 : 0);
507     }
508 
509     lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");
510     if (lib.CreateObject)
511     {
512       unsigned startSize = Codecs.Size() + Hashers.Size();
513       res = LoadCodecs();
514       used = (startSize != Codecs.Size() + Hashers.Size());
515       if (res == S_OK)
516       {
517         startSize = Formats.Size();
518         res = LoadFormats();
519         if (startSize != Formats.Size())
520           used = true;
521       }
522     }
523   }
524   if (!used)
525     Libs.DeleteBack();
526   return res;
527 }
528 
LoadDllsFromFolder(const FString & folderPrefix)529 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
530 {
531   NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK);
532   NFile::NFind::CFileInfo fi;
533   while (enumerator.Next(fi))
534   {
535     if (fi.IsDir())
536       continue;
537     RINOK(LoadDll(folderPrefix + fi.Name, true));
538   }
539   return S_OK;
540 }
541 
542 #endif
543 
Load()544 HRESULT CCodecs::Load()
545 {
546   #ifdef NEW_FOLDER_INTERFACE
547     InternalIcons.LoadIcons(g_hInstance);
548   #endif
549 
550   Formats.Clear();
551 
552   #ifdef EXTERNAL_CODECS
553     Codecs.Clear();
554     Hashers.Clear();
555   #endif
556 
557   for (UInt32 i = 0; i < g_NumArcs; i++)
558   {
559     const CArcInfo &arc = *g_Arcs[i];
560     CArcInfoEx item;
561 
562     item.Name.SetFromAscii(arc.Name);
563     item.CreateInArchive = arc.CreateInArchive;
564     item.IsArcFunc = arc.IsArc;
565     item.Flags = arc.Flags;
566 
567     {
568       UString e, ae;
569       if (arc.Ext)
570         e.SetFromAscii(arc.Ext);
571       if (arc.AddExt)
572         ae.SetFromAscii(arc.AddExt);
573       item.AddExts(e, ae);
574     }
575 
576     #ifndef _SFX
577 
578     item.CreateOutArchive = arc.CreateOutArchive;
579     item.UpdateEnabled = (arc.CreateOutArchive != NULL);
580     item.SignatureOffset = arc.SignatureOffset;
581     // item.Version = MY_VER_MIX;
582     item.NewInterface = true;
583 
584     if (arc.IsMultiSignature())
585       ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
586     else
587       item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
588 
589     #endif
590 
591     Formats.Add(item);
592   }
593 
594   #ifdef EXTERNAL_CODECS
595     const FString baseFolder = GetBaseFolderPrefixFromRegistry();
596     RINOK(LoadDll(baseFolder + kMainDll, false));
597     RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
598     RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
599   #endif
600 
601   return S_OK;
602 }
603 
604 #ifndef _SFX
605 
FindFormatForArchiveName(const UString & arcPath) const606 int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
607 {
608   int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR);
609   int dotPos = arcPath.ReverseFind(L'.');
610   if (dotPos < 0 || dotPos < slashPos)
611     return -1;
612   const UString ext = arcPath.Ptr(dotPos + 1);
613   if (ext.IsEmpty())
614     return -1;
615   if (ext.IsEqualToNoCase(L"exe"))
616     return -1;
617   FOR_VECTOR (i, Formats)
618   {
619     const CArcInfoEx &arc = Formats[i];
620     /*
621     if (!arc.UpdateEnabled)
622       continue;
623     */
624     if (arc.FindExtension(ext) >= 0)
625       return i;
626   }
627   return -1;
628 }
629 
FindFormatForExtension(const UString & ext) const630 int CCodecs::FindFormatForExtension(const UString &ext) const
631 {
632   if (ext.IsEmpty())
633     return -1;
634   FOR_VECTOR (i, Formats)
635     if (Formats[i].FindExtension(ext) >= 0)
636       return i;
637   return -1;
638 }
639 
FindFormatForArchiveType(const UString & arcType) const640 int CCodecs::FindFormatForArchiveType(const UString &arcType) const
641 {
642   FOR_VECTOR (i, Formats)
643     if (Formats[i].Name.IsEqualToNoCase(arcType))
644       return i;
645   return -1;
646 }
647 
FindFormatForArchiveType(const UString & arcType,CIntVector & formatIndices) const648 bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
649 {
650   formatIndices.Clear();
651   for (unsigned pos = 0; pos < arcType.Len();)
652   {
653     int pos2 = arcType.Find('.', pos);
654     if (pos2 < 0)
655       pos2 = arcType.Len();
656     const UString name = arcType.Mid(pos, pos2 - pos);
657     if (name.IsEmpty())
658       return false;
659     int index = FindFormatForArchiveType(name);
660     if (index < 0 && name != L"*")
661     {
662       formatIndices.Clear();
663       return false;
664     }
665     formatIndices.Add(index);
666     pos = pos2 + 1;
667   }
668   return true;
669 }
670 
671 #endif // _SFX
672 
673 
674 #ifdef EXTERNAL_CODECS
675 
676 // #define EXPORT_CODECS
677 
678 #ifdef EXPORT_CODECS
679 
680 extern unsigned g_NumCodecs;
681 STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
682 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
683 #define NUM_EXPORT_CODECS g_NumCodecs
684 
685 extern unsigned g_NumHashers;
686 STDAPI CreateHasher(UInt32 index, IHasher **hasher);
687 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
688 #define NUM_EXPORT_HASHERS g_NumHashers
689 
690 #else // EXPORT_CODECS
691 
692 #define NUM_EXPORT_CODECS 0
693 #define NUM_EXPORT_HASHERS 0
694 
695 #endif // EXPORT_CODECS
696 
GetNumberOfMethods(UInt32 * numMethods)697 STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods)
698 {
699   *numMethods = NUM_EXPORT_CODECS
700     #ifdef EXTERNAL_CODECS
701     + Codecs.Size()
702     #endif
703     ;
704   return S_OK;
705 }
706 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)707 STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
708 {
709   #ifdef EXPORT_CODECS
710   if (index < g_NumCodecs)
711     return GetMethodProperty(index, propID, value);
712   #endif
713 
714   #ifdef EXTERNAL_CODECS
715   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
716 
717   if (propID == NMethodPropID::kDecoderIsAssigned ||
718       propID == NMethodPropID::kEncoderIsAssigned)
719   {
720     NCOM::CPropVariant prop;
721     prop = (propID == NMethodPropID::kDecoderIsAssigned) ?
722         ci.DecoderIsAssigned :
723         ci.EncoderIsAssigned;
724     prop.Detach(value);
725     return S_OK;
726   }
727   return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
728   #else
729   return E_FAIL;
730   #endif
731 }
732 
CreateDecoder(UInt32 index,const GUID * iid,void ** coder)733 STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
734 {
735   #ifdef EXPORT_CODECS
736   if (index < g_NumCodecs)
737     return CreateCoder2(false, index, iid, coder);
738   #endif
739   #ifdef EXTERNAL_CODECS
740   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
741   if (ci.DecoderIsAssigned)
742     return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
743   return S_OK;
744   #else
745   return E_FAIL;
746   #endif
747 }
748 
CreateEncoder(UInt32 index,const GUID * iid,void ** coder)749 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
750 {
751   #ifdef EXPORT_CODECS
752   if (index < g_NumCodecs)
753     return CreateCoder2(true, index, iid, coder);
754   #endif
755   #ifdef EXTERNAL_CODECS
756   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
757   if (ci.EncoderIsAssigned)
758     return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
759   return S_OK;
760   #else
761   return E_FAIL;
762   #endif
763 }
764 
765 
STDMETHODIMP_(UInt32)766 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
767 {
768   return NUM_EXPORT_HASHERS
769     #ifdef EXTERNAL_CODECS
770     + Hashers.Size()
771     #endif
772     ;
773 }
774 
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)775 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
776 {
777   #ifdef EXPORT_CODECS
778   if (index < g_NumHashers)
779     return ::GetHasherProp(index, propID, value);
780   #endif
781 
782   #ifdef EXTERNAL_CODECS
783   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
784   return Libs[ci.LibIndex].Hashers->GetHasherProp(ci.HasherIndex, propID, value);
785   #else
786   return E_FAIL;
787   #endif
788 }
789 
CreateHasher(UInt32 index,IHasher ** hasher)790 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
791 {
792   #ifdef EXPORT_CODECS
793   if (index < g_NumHashers)
794     return CreateHasher(index, hasher);
795   #endif
796   #ifdef EXTERNAL_CODECS
797   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
798   return Libs[ci.LibIndex].Hashers->CreateHasher(ci.HasherIndex, hasher);
799   #else
800   return E_FAIL;
801   #endif
802 }
803 
GetCodecLibIndex(UInt32 index)804 int CCodecs::GetCodecLibIndex(UInt32 index)
805 {
806   #ifdef EXPORT_CODECS
807   if (index < g_NumCodecs)
808     return -1;
809   #endif
810   #ifdef EXTERNAL_CODECS
811   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
812   return ci.LibIndex;
813   #else
814   return -1;
815   #endif
816 }
817 
GetHasherLibIndex(UInt32 index)818 int CCodecs::GetHasherLibIndex(UInt32 index)
819 {
820   #ifdef EXPORT_CODECS
821   if (index < g_NumHashers)
822     return -1;
823   #endif
824   #ifdef EXTERNAL_CODECS
825   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
826   return ci.LibIndex;
827   #else
828   return -1;
829   #endif
830 }
831 
GetCodecEncoderIsAssigned(UInt32 index)832 bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
833 {
834   #ifdef EXPORT_CODECS
835   if (index < g_NumCodecs)
836   {
837     NCOM::CPropVariant prop;
838     if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
839       if (prop.vt != VT_EMPTY)
840         return true;
841     return false;
842   }
843   #endif
844   #ifdef EXTERNAL_CODECS
845   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
846   return ci.EncoderIsAssigned;
847   #else
848   return false;
849   #endif
850 }
851 
GetCodecId(UInt32 index,UInt64 & id)852 HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
853 {
854   NCOM::CPropVariant prop;
855   RINOK(GetProperty(index, NMethodPropID::kID, &prop));
856   if (prop.vt != VT_UI8)
857     return E_INVALIDARG;
858   id = prop.uhVal.QuadPart;
859   return S_OK;
860 }
861 
GetCodecName(UInt32 index)862 UString CCodecs::GetCodecName(UInt32 index)
863 {
864   UString s;
865   NCOM::CPropVariant prop;
866   if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
867     if (prop.vt == VT_BSTR)
868       s = prop.bstrVal;
869   return s;
870 }
871 
GetHasherId(UInt32 index)872 UInt64 CCodecs::GetHasherId(UInt32 index)
873 {
874   NCOM::CPropVariant prop;
875   RINOK(GetHasherProp(index, NMethodPropID::kID, &prop));
876   if (prop.vt != VT_UI8)
877     return 0;
878   return prop.uhVal.QuadPart;
879 }
880 
GetHasherName(UInt32 index)881 UString CCodecs::GetHasherName(UInt32 index)
882 {
883   UString s;
884   NCOM::CPropVariant prop;
885   if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
886     if (prop.vt == VT_BSTR)
887       s = prop.bstrVal;
888   return s;
889 }
890 
GetHasherDigestSize(UInt32 index)891 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
892 {
893   NCOM::CPropVariant prop;
894   RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
895   if (prop.vt != VT_UI4)
896     return 0;
897   return prop.ulVal;
898 }
899 
900 #endif // EXTERNAL_CODECS
901