xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // LoadCodecs.cpp
2 
3 /*
4 Z7_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 (Z7_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 "../../../Common/MyCom.h"
37 #include "../../../Common/StringToInt.h"
38 #include "../../../Common/StringConvert.h"
39 
40 #include "../../../Windows/ErrorMsg.h"
41 #include "../../../Windows/FileIO.h"
42 #include "../../../Windows/PropVariant.h"
43 
44 #include "LoadCodecs.h"
45 
46 #include "../../ICoder.h"
47 #include "../../Common/RegisterArc.h"
48 #include "../../Common/RegisterCodec.h"
49 
50 #ifdef Z7_EXTERNAL_CODECS
51 // #define EXPORT_CODECS
52 #endif
53 
54 #ifdef Z7_EXTERNAL_CODECS
55 
56 #include "../../../Windows/FileFind.h"
57 #include "../../../Windows/DLL.h"
58 
59 #ifdef _WIN32
60 #include "../../../Windows/FileName.h"
61 #include "../../../Windows/Registry.h"
62 #endif
63 
64 using namespace NWindows;
65 using namespace NFile;
66 
67 
68 #define kCodecsFolderName FTEXT("Codecs")
69 #define kFormatsFolderName FTEXT("Formats")
70 
71 
72 static CFSTR const kMainDll =
73   #ifdef _WIN32
74     FTEXT("7z.dll");
75   #else
76     FTEXT("7z.so");
77   #endif
78 
79 
80 #ifdef _WIN32
81 
82 static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
83 static LPCWSTR const kProgramPathValue = L"Path";
84 static LPCWSTR const kProgramPath2Value = L"Path"
85   #ifdef _WIN64
86   L"64";
87   #else
88   L"32";
89   #endif
90 
ReadPathFromRegistry(HKEY baseKey,LPCWSTR value,FString & path)91 static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
92 {
93   NRegistry::CKey key;
94   if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
95   {
96     UString pathU;
97     if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
98     {
99       path = us2fs(pathU);
100       NName::NormalizeDirPathPrefix(path);
101       return NFind::DoesFileExist_Raw(path + kMainDll);
102     }
103   }
104   return false;
105 }
106 
107 #endif // _WIN32
108 
109 #endif // Z7_EXTERNAL_CODECS
110 
111 
112 static const unsigned kNumArcsMax = 72;
113 static unsigned g_NumArcs = 0;
114 static const CArcInfo *g_Arcs[kNumArcsMax];
115 
RegisterArc(const CArcInfo * arcInfo)116 void RegisterArc(const CArcInfo *arcInfo) throw()
117 {
118   if (g_NumArcs < kNumArcsMax)
119   {
120     g_Arcs[g_NumArcs] = arcInfo;
121     g_NumArcs++;
122   }
123   // else throw 1;
124 }
125 
126 /*
127 static void SplitString(const UString &srcString, UStringVector &destStrings)
128 {
129   destStrings.Clear();
130   UString s;
131   unsigned len = srcString.Len();
132   if (len == 0)
133     return;
134   for (unsigned i = 0; i < len; i++)
135   {
136     wchar_t c = srcString[i];
137     if (c == L' ')
138     {
139       if (!s.IsEmpty())
140       {
141         destStrings.Add(s);
142         s.Empty();
143       }
144     }
145     else
146       s += c;
147   }
148   if (!s.IsEmpty())
149     destStrings.Add(s);
150 }
151 */
152 
FindExtension(const UString & ext) const153 int CArcInfoEx::FindExtension(const UString &ext) const
154 {
155   FOR_VECTOR (i, Exts)
156     if (ext.IsEqualTo_NoCase(Exts[i].Ext))
157       return (int)i;
158   return -1;
159 }
160 
AddExts(const UString & ext,const UString & addExt)161 void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
162 {
163   UStringVector exts, addExts;
164   SplitString(ext, exts);
165   SplitString(addExt, addExts);
166   FOR_VECTOR (i, exts)
167   {
168     CArcExtInfo extInfo;
169     extInfo.Ext = exts[i];
170     if (i < addExts.Size())
171     {
172       extInfo.AddExt = addExts[i];
173       if (extInfo.AddExt == L"*")
174         extInfo.AddExt.Empty();
175     }
176     Exts.Add(extInfo);
177   }
178 }
179 
180 #ifndef Z7_SFX
181 
ParseSignatures(const Byte * data,unsigned size,CObjectVector<CByteBuffer> & signatures)182 static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
183 {
184   signatures.Clear();
185   while (size != 0)
186   {
187     const unsigned len = *data++;
188     size--;
189     if (len > size)
190       return false;
191     signatures.AddNew().CopyFrom(data, len);
192     data += len;
193     size -= len;
194   }
195   return true;
196 }
197 
198 #endif // Z7_SFX
199 
200 // #include <stdio.h>
201 
202 #ifdef Z7_EXTERNAL_CODECS
203 
GetBaseFolderPrefixFromRegistry()204 static FString GetBaseFolderPrefixFromRegistry()
205 {
206   FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
207 
208   #ifdef _WIN32
209   if (   !NFind::DoesFileOrDirExist(moduleFolderPrefix + kMainDll)
210       && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kCodecsFolderName)
211       && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kFormatsFolderName))
212   {
213     FString path;
214     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPath2Value, path)) return path;
215     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
216     if (ReadPathFromRegistry(HKEY_CURRENT_USER,  kProgramPathValue,  path)) return path;
217     if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue,  path)) return path;
218   }
219   #endif
220 
221   // printf("\nmoduleFolderPrefix = %s\n", (const char *)GetAnsiString(moduleFolderPrefix));
222   return moduleFolderPrefix;
223 }
224 
225 
GetCoderClass(Func_GetMethodProperty getMethodProperty,UInt32 index,PROPID propId,CLSID & clsId,bool & isAssigned)226 static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
227     PROPID propId, CLSID &clsId, bool &isAssigned)
228 {
229   NCOM::CPropVariant prop;
230   isAssigned = false;
231   RINOK(getMethodProperty(index, propId, &prop))
232   if (prop.vt == VT_BSTR)
233   {
234     if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
235       return E_FAIL;
236     isAssigned = true;
237     clsId = *(const GUID *)(const void *)prop.bstrVal;
238   }
239   else if (prop.vt != VT_EMPTY)
240     return E_FAIL;
241   return S_OK;
242 }
243 
244 
GetMethodBoolProp(Func_GetMethodProperty getMethodProperty,UInt32 index,PROPID propId,bool & resVal,bool & isAssigned)245 static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt32 index,
246     PROPID propId, bool &resVal, bool &isAssigned)
247 {
248   NCOM::CPropVariant prop;
249   resVal = false;
250   isAssigned = false;
251   RINOK(getMethodProperty(index, propId, &prop))
252   if (prop.vt == VT_BOOL)
253   {
254     isAssigned = true;
255     resVal = VARIANT_BOOLToBool(prop.boolVal);
256   }
257   else if (prop.vt != VT_EMPTY)
258     return E_FAIL;
259   return S_OK;
260 }
261 
262 #if defined(__clang__)
263 #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
264 #endif
265 
266 #ifdef _WIN32
267 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
268 #endif
269 
270 #define MY_GET_FUNC(dest, type, lib, func)  \
271   dest = Z7_GET_PROC_ADDRESS(type, lib.Get_HMODULE(), func);
272 // #define MY_GET_FUNC(dest, type, func)  dest = (type)(func);
273 
274 #define MY_GET_FUNC_LOC(dest, type, lib, func) \
275   type dest;  MY_GET_FUNC(dest, type, lib, func)
276 
LoadCodecs()277 HRESULT CCodecs::LoadCodecs()
278 {
279   CCodecLib &lib = Libs.Back();
280 
281   MY_GET_FUNC (lib.CreateDecoder,     Func_CreateDecoder,     lib.Lib, "CreateDecoder")
282   MY_GET_FUNC (lib.CreateEncoder,     Func_CreateEncoder,     lib.Lib, "CreateEncoder")
283   MY_GET_FUNC (lib.GetMethodProperty, Func_GetMethodProperty, lib.Lib, "GetMethodProperty")
284 
285   if (lib.GetMethodProperty)
286   {
287     UInt32 numMethods = 1;
288     MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib, "GetNumberOfMethods")
289     if (getNumberOfMethods)
290     {
291       RINOK(getNumberOfMethods(&numMethods))
292     }
293     for (UInt32 i = 0; i < numMethods; i++)
294     {
295       CDllCodecInfo info;
296       info.LibIndex = Libs.Size() - 1;
297       info.CodecIndex = i;
298       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned))
299       RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned))
300       RINOK(GetMethodBoolProp(lib.GetMethodProperty, i, NMethodPropID::kIsFilter, info.IsFilter, info.IsFilter_Assigned))
301       Codecs.Add(info);
302     }
303   }
304 
305   MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib, "GetHashers")
306   if (getHashers)
307   {
308     RINOK(getHashers(&lib.ComHashers))
309     if (lib.ComHashers)
310     {
311       UInt32 numMethods = lib.ComHashers->GetNumHashers();
312       for (UInt32 i = 0; i < numMethods; i++)
313       {
314         CDllHasherInfo info;
315         info.LibIndex = Libs.Size() - 1;
316         info.HasherIndex = i;
317         Hashers.Add(info);
318       }
319     }
320   }
321 
322   return S_OK;
323 }
324 
GetProp(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,NCOM::CPropVariant & prop)325 static HRESULT GetProp(
326     Func_GetHandlerProperty getProp,
327     Func_GetHandlerProperty2 getProp2,
328     UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
329 {
330   if (getProp2)
331     return getProp2(index, propID, &prop);
332   return getProp(propID, &prop);
333 }
334 
GetProp_Bool(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,bool & res)335 static HRESULT GetProp_Bool(
336     Func_GetHandlerProperty getProp,
337     Func_GetHandlerProperty2 getProp2,
338     UInt32 index, PROPID propID, bool &res)
339 {
340   res = false;
341   NCOM::CPropVariant prop;
342   RINOK(GetProp(getProp, getProp2, index, propID, prop))
343   if (prop.vt == VT_BOOL)
344     res = VARIANT_BOOLToBool(prop.boolVal);
345   else if (prop.vt != VT_EMPTY)
346     return E_FAIL;
347   return S_OK;
348 }
349 
GetProp_UInt32(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UInt32 & res,bool & defined)350 static HRESULT GetProp_UInt32(
351     Func_GetHandlerProperty getProp,
352     Func_GetHandlerProperty2 getProp2,
353     UInt32 index, PROPID propID, UInt32 &res, bool &defined)
354 {
355   res = 0;
356   defined = false;
357   NCOM::CPropVariant prop;
358   RINOK(GetProp(getProp, getProp2, index, propID, prop))
359   if (prop.vt == VT_UI4)
360   {
361     res = prop.ulVal;
362     defined = true;
363   }
364   else if (prop.vt != VT_EMPTY)
365     return E_FAIL;
366   return S_OK;
367 }
368 
GetProp_String(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UString & res)369 static HRESULT GetProp_String(
370     Func_GetHandlerProperty getProp,
371     Func_GetHandlerProperty2 getProp2,
372     UInt32 index, PROPID propID, UString &res)
373 {
374   res.Empty();
375   NCOM::CPropVariant prop;
376   RINOK(GetProp(getProp, getProp2, index, propID, prop))
377   if (prop.vt == VT_BSTR)
378     res.SetFromBstr(prop.bstrVal);
379   else if (prop.vt != VT_EMPTY)
380     return E_FAIL;
381   return S_OK;
382 }
383 
GetProp_RawData(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,CByteBuffer & bb)384 static HRESULT GetProp_RawData(
385     Func_GetHandlerProperty getProp,
386     Func_GetHandlerProperty2 getProp2,
387     UInt32 index, PROPID propID, CByteBuffer &bb)
388 {
389   bb.Free();
390   NCOM::CPropVariant prop;
391   RINOK(GetProp(getProp, getProp2, index, propID, prop))
392   if (prop.vt == VT_BSTR)
393   {
394     UINT len = ::SysStringByteLen(prop.bstrVal);
395     bb.CopyFrom((const Byte *)prop.bstrVal, len);
396   }
397   else if (prop.vt != VT_EMPTY)
398     return E_FAIL;
399   return S_OK;
400 }
401 
402 static const UInt32 kArcFlagsPars[] =
403 {
404   NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
405   NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
406   NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
407 };
408 
LoadFormats()409 HRESULT CCodecs::LoadFormats()
410 {
411   const NDLL::CLibrary &lib = Libs.Back().Lib;
412 
413   Func_GetHandlerProperty getProp = NULL;
414   MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib, "GetHandlerProperty2")
415   MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib, "GetIsArc")
416 
417   UInt32 numFormats = 1;
418 
419   if (getProp2)
420   {
421     MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib, "GetNumberOfFormats")
422     if (getNumberOfFormats)
423     {
424       RINOK(getNumberOfFormats(&numFormats))
425     }
426   }
427   else
428   {
429     MY_GET_FUNC (getProp, Func_GetHandlerProperty, lib, "GetHandlerProperty")
430     if (!getProp)
431       return S_OK;
432   }
433 
434   for (UInt32 i = 0; i < numFormats; i++)
435   {
436     CArcInfoEx item;
437     item.LibIndex = (int)(Libs.Size() - 1);
438     item.FormatIndex = i;
439 
440     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name))
441 
442     {
443       NCOM::CPropVariant prop;
444       if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
445         continue;
446       if (prop.vt != VT_BSTR)
447         continue;
448       if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
449         return E_FAIL;
450       item.ClassID = *(const GUID *)(const void *)prop.bstrVal;
451       prop.Clear();
452     }
453 
454     UString ext, addExt;
455     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext))
456     RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt))
457     item.AddExts(ext, addExt);
458 
459     GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
460     bool flags_Defined = false;
461     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined))
462     item.NewInterface = flags_Defined;
463     if (!flags_Defined) // && item.UpdateEnabled
464     {
465       // support for DLL version before 9.31:
466       for (unsigned j = 0; j < Z7_ARRAY_SIZE(kArcFlagsPars); j += 2)
467       {
468         bool val = false;
469         GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
470         if (val)
471           item.Flags |= kArcFlagsPars[j + 1];
472       }
473     }
474 
475     {
476       bool defined = false;
477       RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined))
478     }
479 
480     CByteBuffer sig;
481     RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig))
482     if (sig.Size() != 0)
483       item.Signatures.Add(sig);
484     else
485     {
486       RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig))
487       ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
488     }
489 
490     bool signatureOffset_Defined;
491     RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined))
492 
493     // bool version_Defined;
494     // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
495 
496     if (getIsArc)
497       getIsArc(i, &item.IsArcFunc);
498 
499     Formats.Add(item);
500   }
501   return S_OK;
502 }
503 
504 #ifdef Z7_LARGE_PAGES
505 extern "C"
506 {
507   extern SIZE_T g_LargePageSize;
508 }
509 #endif
510 
511 
AddLastError(const FString & path)512 void CCodecs::AddLastError(const FString &path)
513 {
514   const HRESULT res = GetLastError_noZero_HRESULT();
515   CCodecError &error = Errors.AddNew();
516   error.Path = path;
517   error.ErrorCode = res;
518 }
519 
520 
IsSupportedDll(CCodecLib & lib)521 static bool IsSupportedDll(CCodecLib &lib)
522 {
523   MY_GET_FUNC_LOC (
524      f_GetModuleProp,
525   Func_GetModuleProp, lib.Lib,
526       "GetModuleProp")
527   /* p7zip and 7-Zip before v23 used virtual destructor in IUnknown,
528      if _WIN32 is not defined */
529   UInt32 flags =
530     #ifdef _WIN32
531       NModuleInterfaceType::k_IUnknown_VirtDestructor_No;
532     #else
533       NModuleInterfaceType::k_IUnknown_VirtDestructor_Yes;
534     #endif
535   if (f_GetModuleProp)
536   {
537     {
538       NCOM::CPropVariant prop;
539       if (f_GetModuleProp(NModulePropID::kInterfaceType, &prop) == S_OK)
540       {
541         if (prop.vt == VT_UI4)
542           flags = prop.ulVal;
543         else if (prop.vt != VT_EMPTY)
544           return false;
545       }
546     }
547     {
548       NCOM::CPropVariant prop;
549       if (f_GetModuleProp(NModulePropID::kVersion, &prop) == S_OK)
550       {
551         if (prop.vt == VT_UI4)
552           lib.Version = prop.ulVal;
553       }
554     }
555   }
556   if (
557       flags
558       // (flags & NModuleFlags::kMask)
559       != NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule)
560     return false;
561   return true;
562 }
563 
564 
LoadDll(const FString & dllPath,bool needCheckDll,bool * loadedOK)565 HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
566 {
567   if (loadedOK)
568     *loadedOK = false;
569 
570   // needCheckDll = 1;
571 
572   #ifdef _WIN32
573   if (needCheckDll)
574   {
575     NDLL::CLibrary lib;
576     if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
577     {
578       /* if is not win32
579       //  %1 is not a valid Win32 application.
580       //  #define ERROR_BAD_EXE_FORMAT             193L
581       */
582       // return GetLastError_noZero_HRESULT();
583       const DWORD lastError = GetLastError();
584       if (lastError != ERROR_BAD_EXE_FORMAT)
585       {
586         CCodecError &error = Errors.AddNew();
587         error.Path = dllPath;
588         error.Message = "cannot load file as datafile library";
589         error.ErrorCode = HRESULT_FROM_WIN32(lastError);
590       }
591       return S_OK;
592     }
593   }
594   #else
595   UNUSED_VAR(needCheckDll)
596   #endif
597 
598   Libs.AddNew();
599   CCodecLib &lib = Libs.Back();
600   lib.Path = dllPath;
601   bool used = false;
602   // HRESULT res = S_OK;
603 
604  if (lib.Lib.Load(dllPath))
605  {
606   if (!IsSupportedDll(lib))
607   {
608     CCodecError &error = Errors.AddNew();
609     error.Path = dllPath;
610     error.Message = "the module is not compatible with program";
611   }
612   else
613   {
614     if (loadedOK)
615       *loadedOK = true;
616     /*
617     #ifdef NEW_FOLDER_INTERFACE
618     lib.LoadIcons();
619     #endif
620     */
621 
622     /*
623     {
624       MY_GET_FUNC_LOC (_libStartup, Func_libStartup, lib.Lib, "LibStartup")
625       if (_libStartup)
626       {
627         HRESULT res = _libStartup();
628         if (res != 0)
629         {
630           CCodecError &error = Errors.AddNew();
631           error.Path = dllPath;
632           error.ErrorCode = res;
633         }
634       }
635     }
636     */
637 
638     #ifdef Z7_LARGE_PAGES
639     if (g_LargePageSize != 0)
640     {
641       MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib, "SetLargePageMode")
642       if (setLargePageMode)
643         setLargePageMode();
644     }
645     #endif
646 
647     if (CaseSensitive_Change)
648     {
649       MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib, "SetCaseSensitive")
650       if (setCaseSensitive)
651         setCaseSensitive(CaseSensitive ? 1 : 0);
652     }
653 
654     /*
655     {
656       MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib, "SetClientVersion")
657       if (setClientVersion)
658       {
659         // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR;
660         setClientVersion(g_ClientVersion);
661       }
662     }
663     */
664 
665 
666     MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib, "CreateObject")
667     {
668       unsigned startSize = Codecs.Size() + Hashers.Size();
669       HRESULT res = LoadCodecs();
670       if (startSize != Codecs.Size() + Hashers.Size())
671         used = true;
672       if (res == S_OK && lib.CreateObject)
673       {
674         startSize = Formats.Size();
675         res = LoadFormats();
676         if (startSize != Formats.Size())
677           used = true;
678       }
679       if (res != S_OK)
680       {
681         CCodecError &error = Errors.AddNew();
682         error.Path = dllPath;
683         error.ErrorCode = res;
684       }
685     }
686     // plugins can use non-7-zip dlls, so we silently ignore non7zip DLLs
687     /*
688     if (!used)
689     {
690       CCodecError &error = Errors.AddNew();
691       error.Path = dllPath;
692       error.Message = "no 7-Zip code";
693     }
694     */
695   }
696  }
697  else
698   {
699     AddLastError(dllPath);
700   }
701 
702   if (!used)
703     Libs.DeleteBack();
704 
705   return S_OK;
706 }
707 
LoadDllsFromFolder(const FString & folderPath)708 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPath)
709 {
710   if (!NFile::NFind::DoesDirExist_FollowLink(folderPath))
711   // if (!NFile::NFind::DoesDirExist(folderPath))
712   {
713     // AddLastError(folderPath);
714     return S_OK;
715   }
716 
717   FString folderPrefix = folderPath;
718   folderPrefix.Add_PathSepar();
719 
720   NFile::NFind::CEnumerator enumerator;
721   enumerator.SetDirPrefix(folderPrefix);
722   NFile::NFind::CDirEntry fi;
723   for (;;)
724   {
725     bool found;
726     if (!enumerator.Next(fi, found))
727     {
728       // it can be wrong Symbolic link to folder here
729       AddLastError(folderPath);
730       break;
731       // return GetLastError_noZero_HRESULT();
732     }
733     if (!found)
734       break;
735     #ifdef _WIN32
736     if (fi.IsDir())
737       continue;
738     #else
739     if (enumerator.DirEntry_IsDir(fi, true)) // followLink
740       continue;
741     #endif
742 
743     RINOK(LoadDll(folderPrefix + fi.Name, true))
744   }
745   return S_OK;
746 }
747 
CloseLibs()748 void CCodecs::CloseLibs()
749 {
750   // OutputDebugStringA("~CloseLibs start");
751   /*
752   WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected,
753   if it's called from another FreeLibrary() call.
754   So we need to call FreeLibrary() before global destructors.
755 
756   Also we free global links from DLLs to object of this module before CLibrary::Free() call.
757   */
758 
759   FOR_VECTOR(i, Libs)
760   {
761     const CCodecLib &lib = Libs[i];
762     if (lib.SetCodecs)
763       lib.SetCodecs(NULL);
764   }
765 
766   // OutputDebugStringA("~CloseLibs after SetCodecs");
767   Libs.Clear();
768   // OutputDebugStringA("~CloseLibs end");
769 }
770 
771 #endif // Z7_EXTERNAL_CODECS
772 
773 
Load()774 HRESULT CCodecs::Load()
775 {
776   /*
777   #ifdef NEW_FOLDER_INTERFACE
778   InternalIcons.LoadIcons(g_hInstance);
779   #endif
780   */
781 
782   Formats.Clear();
783 
784   #ifdef Z7_EXTERNAL_CODECS
785     Errors.Clear();
786     MainDll_ErrorPath.Empty();
787     Codecs.Clear();
788     Hashers.Clear();
789   #endif
790 
791   for (UInt32 i = 0; i < g_NumArcs; i++)
792   {
793     const CArcInfo &arc = *g_Arcs[i];
794     CArcInfoEx item;
795 
796     item.Name = arc.Name;
797     item.CreateInArchive = arc.CreateInArchive;
798     item.IsArcFunc = arc.IsArc;
799     item.Flags = arc.Flags;
800 
801     {
802       UString e, ae;
803       if (arc.Ext)
804         e = arc.Ext;
805       if (arc.AddExt)
806         ae = arc.AddExt;
807       item.AddExts(e, ae);
808     }
809 
810     #ifndef Z7_SFX
811 
812     item.CreateOutArchive = arc.CreateOutArchive;
813     item.UpdateEnabled = (arc.CreateOutArchive != NULL);
814     item.SignatureOffset = arc.SignatureOffset;
815     // item.Version = MY_VER_MIX;
816     item.NewInterface = true;
817 
818     if (arc.IsMultiSignature())
819       ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
820     else
821     {
822       if (arc.SignatureSize != 0) // 21.04
823         item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
824     }
825 
826     #endif
827 
828     Formats.Add(item);
829   }
830 
831   // printf("\nLoad codecs \n");
832 
833   #ifdef Z7_EXTERNAL_CODECS
834     const FString baseFolder = GetBaseFolderPrefixFromRegistry();
835     {
836       bool loadedOK;
837       RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK))
838       if (!loadedOK)
839         MainDll_ErrorPath = kMainDll;
840     }
841     RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName))
842     RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName))
843 
844   NeedSetLibCodecs = true;
845 
846   if (Libs.Size() == 0)
847     NeedSetLibCodecs = false;
848   else if (Libs.Size() == 1)
849   {
850     // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
851     #ifndef EXPORT_CODECS
852     if (g_NumArcs == 0)
853       NeedSetLibCodecs = false;
854     #endif
855   }
856 
857   if (NeedSetLibCodecs)
858   {
859     /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
860        old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
861 
862     FOR_VECTOR(i, Libs)
863     {
864       CCodecLib &lib = Libs[i];
865       MY_GET_FUNC (lib.SetCodecs, Func_SetCodecs, lib.Lib, "SetCodecs")
866       if (lib.SetCodecs)
867       {
868         RINOK(lib.SetCodecs(this))
869       }
870     }
871   }
872 
873   #endif
874 
875   // we sort Formats to get fixed order of Formats after compilation.
876   Formats.Sort();
877   return S_OK;
878 }
879 
880 #ifndef Z7_SFX
881 
FindFormatForArchiveName(const UString & arcPath) const882 int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
883 {
884   int dotPos = arcPath.ReverseFind_Dot();
885   if (dotPos <= arcPath.ReverseFind_PathSepar())
886     return -1;
887   const UString ext = arcPath.Ptr((unsigned)(dotPos + 1));
888   if (ext.IsEmpty())
889     return -1;
890   if (ext.IsEqualTo_Ascii_NoCase("exe"))
891     return -1;
892   FOR_VECTOR (i, Formats)
893   {
894     const CArcInfoEx &arc = Formats[i];
895     /*
896     if (!arc.UpdateEnabled)
897       continue;
898     */
899     if (arc.FindExtension(ext) >= 0)
900       return (int)i;
901   }
902   return -1;
903 }
904 
FindFormatForExtension(const UString & ext) const905 int CCodecs::FindFormatForExtension(const UString &ext) const
906 {
907   if (ext.IsEmpty())
908     return -1;
909   FOR_VECTOR (i, Formats)
910     if (Formats[i].FindExtension(ext) >= 0)
911       return (int)i;
912   return -1;
913 }
914 
FindFormatForArchiveType(const UString & arcType) const915 int CCodecs::FindFormatForArchiveType(const UString &arcType) const
916 {
917   FOR_VECTOR (i, Formats)
918     if (Formats[i].Name.IsEqualTo_NoCase(arcType))
919       return (int)i;
920   return -1;
921 }
922 
FindFormatForArchiveType(const UString & arcType,CIntVector & formatIndices) const923 bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
924 {
925   formatIndices.Clear();
926   for (unsigned pos = 0; pos < arcType.Len();)
927   {
928     int pos2 = arcType.Find(L'.', pos);
929     if (pos2 < 0)
930       pos2 = (int)arcType.Len();
931     const UString name = arcType.Mid(pos, (unsigned)pos2 - pos);
932     if (name.IsEmpty())
933       return false;
934     int index = FindFormatForArchiveType(name);
935     if (index < 0 && name != L"*")
936     {
937       formatIndices.Clear();
938       return false;
939     }
940     formatIndices.Add(index);
941     pos = (unsigned)pos2 + 1;
942   }
943   return true;
944 }
945 
946 #endif // Z7_SFX
947 
948 
949 #ifdef Z7_EXTERNAL_CODECS
950 
951 // #define EXPORT_CODECS
952 
953 #ifdef EXPORT_CODECS
954 
955 extern unsigned g_NumCodecs;
956 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
957 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
958 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
959 #define NUM_EXPORT_CODECS g_NumCodecs
960 
961 extern unsigned g_NumHashers;
962 STDAPI CreateHasher(UInt32 index, IHasher **hasher);
963 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
964 #define NUM_EXPORT_HASHERS g_NumHashers
965 
966 #else // EXPORT_CODECS
967 
968 #define NUM_EXPORT_CODECS 0
969 #define NUM_EXPORT_HASHERS 0
970 
971 #endif // EXPORT_CODECS
972 
Z7_COM7F_IMF(CCodecs::GetNumMethods (UInt32 * numMethods))973 Z7_COM7F_IMF(CCodecs::GetNumMethods(UInt32 *numMethods))
974 {
975   *numMethods = NUM_EXPORT_CODECS
976     #ifdef Z7_EXTERNAL_CODECS
977     + Codecs.Size()
978     #endif
979     ;
980   return S_OK;
981 }
982 
Z7_COM7F_IMF(CCodecs::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))983 Z7_COM7F_IMF(CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
984 {
985   #ifdef EXPORT_CODECS
986   if (index < g_NumCodecs)
987     return GetMethodProperty(index, propID, value);
988   #endif
989 
990   #ifdef Z7_EXTERNAL_CODECS
991   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
992 
993   if (propID == NMethodPropID::kDecoderIsAssigned ||
994       propID == NMethodPropID::kEncoderIsAssigned)
995   {
996     NCOM::CPropVariant prop;
997     prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ?
998         ci.DecoderIsAssigned :
999         ci.EncoderIsAssigned);
1000     prop.Detach(value);
1001     return S_OK;
1002   }
1003 
1004   if (propID == NMethodPropID::kIsFilter && ci.IsFilter_Assigned)
1005   {
1006     NCOM::CPropVariant prop;
1007     prop = (bool)ci.IsFilter;
1008     prop.Detach(value);
1009     return S_OK;
1010   }
1011 
1012   const CCodecLib &lib = Libs[ci.LibIndex];
1013   return lib.GetMethodProperty(ci.CodecIndex, propID, value);
1014   #else
1015   return E_FAIL;
1016   #endif
1017 }
1018 
Z7_COM7F_IMF(CCodecs::CreateDecoder (UInt32 index,const GUID * iid,void ** coder))1019 Z7_COM7F_IMF(CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder))
1020 {
1021   #ifdef EXPORT_CODECS
1022   if (index < g_NumCodecs)
1023     return CreateDecoder(index, iid, coder);
1024   #endif
1025 
1026   #ifdef Z7_EXTERNAL_CODECS
1027   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
1028   if (ci.DecoderIsAssigned)
1029   {
1030     const CCodecLib &lib = Libs[ci.LibIndex];
1031     if (lib.CreateDecoder)
1032       return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
1033     if (lib.CreateObject)
1034       return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
1035   }
1036   return S_OK;
1037   #else
1038   return E_FAIL;
1039   #endif
1040 }
1041 
Z7_COM7F_IMF(CCodecs::CreateEncoder (UInt32 index,const GUID * iid,void ** coder))1042 Z7_COM7F_IMF(CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder))
1043 {
1044   #ifdef EXPORT_CODECS
1045   if (index < g_NumCodecs)
1046     return CreateEncoder(index, iid, coder);
1047   #endif
1048 
1049   #ifdef Z7_EXTERNAL_CODECS
1050   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
1051   if (ci.EncoderIsAssigned)
1052   {
1053     const CCodecLib &lib = Libs[ci.LibIndex];
1054     if (lib.CreateEncoder)
1055       return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
1056     if (lib.CreateObject)
1057       return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
1058   }
1059   return S_OK;
1060   #else
1061   return E_FAIL;
1062   #endif
1063 }
1064 
1065 
Z7_COM7F_IMF2(UInt32,CCodecs::GetNumHashers ())1066 Z7_COM7F_IMF2(UInt32, CCodecs::GetNumHashers())
1067 {
1068   return NUM_EXPORT_HASHERS
1069     #ifdef Z7_EXTERNAL_CODECS
1070     + Hashers.Size()
1071     #endif
1072     ;
1073 }
1074 
Z7_COM7F_IMF(CCodecs::GetHasherProp (UInt32 index,PROPID propID,PROPVARIANT * value))1075 Z7_COM7F_IMF(CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value))
1076 {
1077   #ifdef EXPORT_CODECS
1078   if (index < g_NumHashers)
1079     return ::GetHasherProp(index, propID, value);
1080   #endif
1081 
1082   #ifdef Z7_EXTERNAL_CODECS
1083   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
1084   return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
1085   #else
1086   return E_FAIL;
1087   #endif
1088 }
1089 
Z7_COM7F_IMF(CCodecs::CreateHasher (UInt32 index,IHasher ** hasher))1090 Z7_COM7F_IMF(CCodecs::CreateHasher(UInt32 index, IHasher **hasher))
1091 {
1092   #ifdef EXPORT_CODECS
1093   if (index < g_NumHashers)
1094     return CreateHasher(index, hasher);
1095   #endif
1096   #ifdef Z7_EXTERNAL_CODECS
1097   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
1098   return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
1099   #else
1100   return E_FAIL;
1101   #endif
1102 }
1103 
GetCodec_LibIndex(UInt32 index) const1104 int CCodecs::GetCodec_LibIndex(UInt32 index) const
1105 {
1106   #ifdef EXPORT_CODECS
1107   if (index < g_NumCodecs)
1108     return -1;
1109   #endif
1110 
1111   #ifdef Z7_EXTERNAL_CODECS
1112   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
1113   return (int)ci.LibIndex;
1114   #else
1115   return -1;
1116   #endif
1117 }
1118 
GetHasherLibIndex(UInt32 index)1119 int CCodecs::GetHasherLibIndex(UInt32 index)
1120 {
1121   #ifdef EXPORT_CODECS
1122   if (index < g_NumHashers)
1123     return -1;
1124   #endif
1125 
1126   #ifdef Z7_EXTERNAL_CODECS
1127   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
1128   return (int)ci.LibIndex;
1129   #else
1130   return -1;
1131   #endif
1132 }
1133 
GetCodec_DecoderIsAssigned(UInt32 index) const1134 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
1135 {
1136   #ifdef EXPORT_CODECS
1137   if (index < g_NumCodecs)
1138   {
1139     NCOM::CPropVariant prop;
1140     if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
1141     {
1142       if (prop.vt == VT_BOOL)
1143         return VARIANT_BOOLToBool(prop.boolVal);
1144     }
1145     return false;
1146   }
1147   #endif
1148 
1149   #ifdef Z7_EXTERNAL_CODECS
1150   return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
1151   #else
1152   return false;
1153   #endif
1154 }
1155 
1156 
GetCodec_EncoderIsAssigned(UInt32 index) const1157 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
1158 {
1159   #ifdef EXPORT_CODECS
1160   if (index < g_NumCodecs)
1161   {
1162     NCOM::CPropVariant prop;
1163     if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
1164     {
1165       if (prop.vt == VT_BOOL)
1166         return VARIANT_BOOLToBool(prop.boolVal);
1167     }
1168     return false;
1169   }
1170   #endif
1171 
1172   #ifdef Z7_EXTERNAL_CODECS
1173   return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
1174   #else
1175   return false;
1176   #endif
1177 }
1178 
1179 
GetCodec_IsFilter(UInt32 index,bool & isAssigned) const1180 bool CCodecs::GetCodec_IsFilter(UInt32 index, bool &isAssigned) const
1181 {
1182   isAssigned = false;
1183   #ifdef EXPORT_CODECS
1184   if (index < g_NumCodecs)
1185   {
1186     NCOM::CPropVariant prop;
1187     if (GetProperty(index, NMethodPropID::kIsFilter, &prop) == S_OK)
1188     {
1189       if (prop.vt == VT_BOOL)
1190       {
1191         isAssigned = true;
1192         return VARIANT_BOOLToBool(prop.boolVal);
1193       }
1194     }
1195     return false;
1196   }
1197   #endif
1198 
1199   #ifdef Z7_EXTERNAL_CODECS
1200   {
1201     const CDllCodecInfo &c = Codecs[index - NUM_EXPORT_CODECS];
1202     isAssigned = c.IsFilter_Assigned;
1203     return c.IsFilter;
1204   }
1205   #else
1206   return false;
1207   #endif
1208 }
1209 
1210 
GetCodec_NumStreams(UInt32 index)1211 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
1212 {
1213   NCOM::CPropVariant prop;
1214   if (GetProperty(index, NMethodPropID::kPackStreams, &prop) != S_OK)
1215     return 0;
1216   if (prop.vt == VT_UI4)
1217     return (UInt32)prop.ulVal;
1218   if (prop.vt == VT_EMPTY)
1219     return 1;
1220   return 0;
1221 }
1222 
GetCodec_Id(UInt32 index,UInt64 & id)1223 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
1224 {
1225   NCOM::CPropVariant prop;
1226   RINOK(GetProperty(index, NMethodPropID::kID, &prop))
1227   if (prop.vt != VT_UI8)
1228     return E_INVALIDARG;
1229   id = prop.uhVal.QuadPart;
1230   return S_OK;
1231 }
1232 
GetCodec_Name(UInt32 index)1233 AString CCodecs::GetCodec_Name(UInt32 index)
1234 {
1235   AString s;
1236   NCOM::CPropVariant prop;
1237   if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
1238     if (prop.vt == VT_BSTR)
1239       s.SetFromWStr_if_Ascii(prop.bstrVal);
1240   return s;
1241 }
1242 
GetHasherId(UInt32 index)1243 UInt64 CCodecs::GetHasherId(UInt32 index)
1244 {
1245   NCOM::CPropVariant prop;
1246   if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
1247     return 0;
1248   if (prop.vt != VT_UI8)
1249     return 0;
1250   return prop.uhVal.QuadPart;
1251 }
1252 
GetHasherName(UInt32 index)1253 AString CCodecs::GetHasherName(UInt32 index)
1254 {
1255   AString s;
1256   NCOM::CPropVariant prop;
1257   if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
1258     if (prop.vt == VT_BSTR)
1259       s.SetFromWStr_if_Ascii(prop.bstrVal);
1260   return s;
1261 }
1262 
GetHasherDigestSize(UInt32 index)1263 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
1264 {
1265   NCOM::CPropVariant prop;
1266   if (GetHasherProp(index, NMethodPropID::kDigestSize, &prop) != S_OK)
1267     return 0;
1268   if (prop.vt != VT_UI4)
1269     return 0;
1270   return prop.ulVal;
1271 }
1272 
GetCodecsErrorMessage(UString & s)1273 void CCodecs::GetCodecsErrorMessage(UString &s)
1274 {
1275   s.Empty();
1276   FOR_VECTOR (i, Errors)
1277   {
1278     const CCodecError &ce = Errors[i];
1279     s += "Codec Load Error: ";
1280     s += fs2us(ce.Path);
1281     if (ce.ErrorCode != 0)
1282     {
1283       s += " : ";
1284       s += NWindows::NError::MyFormatMessage(ce.ErrorCode);
1285     }
1286     if (!ce.Message.IsEmpty())
1287     {
1288       s += " : ";
1289       s += ce.Message;
1290     }
1291     s.Add_LF();
1292   }
1293 }
1294 
1295 #endif // Z7_EXTERNAL_CODECS
1296 
1297 #ifndef Z7_SFX
1298 
1299 extern unsigned g_NumCodecs;
1300 extern const CCodecInfo *g_Codecs[];
1301 
Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> & v)1302 void CCodecs::Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v)
1303 {
1304   v.Clear();
1305   {
1306     for (unsigned i = 0; i < g_NumCodecs; i++)
1307     {
1308       const CCodecInfo &cod = *g_Codecs[i];
1309       CCodecInfoUser &u = v.AddNew();
1310       u.EncoderIsAssigned = (cod.CreateEncoder != NULL);
1311       u.DecoderIsAssigned = (cod.CreateDecoder != NULL);
1312       u.IsFilter_Assigned = true;
1313       u.IsFilter = cod.IsFilter;
1314       u.NumStreams = cod.NumStreams;
1315       u.Name = cod.Name;
1316     }
1317   }
1318 
1319 
1320   #ifdef Z7_EXTERNAL_CODECS
1321   {
1322     UInt32 numMethods;
1323     if (GetNumMethods(&numMethods) == S_OK)
1324     for (UInt32 j = 0; j < numMethods; j++)
1325     {
1326       CCodecInfoUser &u = v.AddNew();
1327       u.EncoderIsAssigned = GetCodec_EncoderIsAssigned(j);
1328       u.DecoderIsAssigned = GetCodec_DecoderIsAssigned(j);
1329       u.IsFilter = GetCodec_IsFilter(j, u.IsFilter_Assigned);
1330       u.NumStreams = GetCodec_NumStreams(j);
1331       u.Name = GetCodec_Name(j);
1332     }
1333   }
1334   #endif
1335 }
1336 
1337 #endif
1338