Home | History | Annotate | Download | only in Common
      1 // LoadCodecs.cpp
      2 
      3 /*
      4 EXTERNAL_CODECS
      5 ---------------
      6   CCodecs::Load() tries to detect the directory with plugins.
      7   It stops the checking, if it can find any of the following items:
      8     - 7z.dll file
      9     - "Formats" subdir
     10     - "Codecs"  subdir
     11   The order of check:
     12     1) directory of client executable
     13     2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**]
     14        The order for HKEY_* : Path** :
     15          - HKEY_CURRENT_USER  : PathXX
     16          - HKEY_LOCAL_MACHINE : PathXX
     17          - HKEY_CURRENT_USER  : Path
     18          - HKEY_LOCAL_MACHINE : Path
     19        PathXX is Path32 in 32-bit code
     20        PathXX is Path64 in 64-bit code
     21 
     22 
     23 EXPORT_CODECS
     24 -------------
     25   if (EXTERNAL_CODECS) is defined, then the code exports internal
     26   codecs of client from CCodecs object to external plugins.
     27   7-Zip doesn't use that feature. 7-Zip uses the scheme:
     28     - client application without internal plugins.
     29     - 7z.dll module contains all (or almost all) plugins.
     30       7z.dll can use codecs from another plugins, if required.
     31 */
     32 
     33 
     34 #include "StdAfx.h"
     35 
     36 #include "../../../../C/7zVersion.h"
     37 
     38 #include "../../../Common/MyCom.h"
     39 #include "../../../Common/StringToInt.h"
     40 #include "../../../Common/StringConvert.h"
     41 
     42 #include "../../../Windows/PropVariant.h"
     43 
     44 #include "LoadCodecs.h"
     45 
     46 using namespace NWindows;
     47 
     48 #ifdef NEW_FOLDER_INTERFACE
     49 #include "../../../Common/StringToInt.h"
     50 #endif
     51 
     52 #include "../../ICoder.h"
     53 #include "../../Common/RegisterArc.h"
     54 
     55 #ifdef EXTERNAL_CODECS
     56 
     57 // #define EXPORT_CODECS
     58 
     59 #endif
     60 
     61 #ifdef NEW_FOLDER_INTERFACE
     62 extern HINSTANCE g_hInstance;
     63 #include "../../../Windows/ResourceString.h"
     64 static const UINT kIconTypesResId = 100;
     65 #endif
     66 
     67 #ifdef EXTERNAL_CODECS
     68 
     69 #include "../../../Windows/FileFind.h"
     70 #include "../../../Windows/DLL.h"
     71 
     72 #ifdef _WIN32
     73 #include "../../../Windows/FileName.h"
     74 #include "../../../Windows/Registry.h"
     75 #endif
     76 
     77 using namespace NFile;
     78 
     79 
     80 #define kCodecsFolderName FTEXT("Codecs")
     81 #define kFormatsFolderName FTEXT("Formats")
     82 
     83 
     84 static CFSTR kMainDll =
     85   // #ifdef _WIN32
     86     FTEXT("7z.dll");
     87   // #else
     88   // FTEXT("7z.so");
     89   // #endif
     90 
     91 
     92 #ifdef _WIN32
     93 
     94 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
     95 static LPCWSTR kProgramPathValue = L"Path";
     96 static LPCWSTR kProgramPath2Value = L"Path"
     97   #ifdef _WIN64
     98   L"64";
     99   #else
    100   L"32";
    101   #endif
    102 
    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 
    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 
    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 
    162 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    476 HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
    477 {
    478   if (loadedOK)
    479     *loadedOK = false;
    480 
    481   if (needCheckDll)
    482   {
    483     NDLL::CLibrary lib;
    484     if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
    485       return S_OK;
    486   }
    487 
    488   Libs.AddNew();
    489   CCodecLib &lib = Libs.Back();
    490   lib.Path = dllPath;
    491   bool used = false;
    492   HRESULT res = S_OK;
    493 
    494   if (lib.Lib.Load(dllPath))
    495   {
    496     if (loadedOK)
    497       *loadedOK = true;
    498     #ifdef NEW_FOLDER_INTERFACE
    499     lib.LoadIcons();
    500     #endif
    501 
    502     #ifdef _7ZIP_LARGE_PAGES
    503     if (g_LargePageSize != 0)
    504     {
    505       Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");
    506       if (setLargePageMode)
    507         setLargePageMode();
    508     }
    509     #endif
    510 
    511     if (CaseSensitiveChange)
    512     {
    513       Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");
    514       if (setCaseSensitive)
    515         setCaseSensitive(CaseSensitive ? 1 : 0);
    516     }
    517 
    518     lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");
    519     if (lib.CreateObject)
    520     {
    521       unsigned startSize = Codecs.Size() + Hashers.Size();
    522       res = LoadCodecs();
    523       used = (startSize != Codecs.Size() + Hashers.Size());
    524       if (res == S_OK)
    525       {
    526         startSize = Formats.Size();
    527         res = LoadFormats();
    528         if (startSize != Formats.Size())
    529           used = true;
    530       }
    531     }
    532   }
    533 
    534   if (!used)
    535     Libs.DeleteBack();
    536 
    537   return res;
    538 }
    539 
    540 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
    541 {
    542   NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK);
    543   NFile::NFind::CFileInfo fi;
    544   while (enumerator.Next(fi))
    545   {
    546     if (fi.IsDir())
    547       continue;
    548     RINOK(LoadDll(folderPrefix + fi.Name, true));
    549   }
    550   return S_OK;
    551 }
    552 
    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 
    579 HRESULT CCodecs::Load()
    580 {
    581   #ifdef NEW_FOLDER_INTERFACE
    582   InternalIcons.LoadIcons(g_hInstance);
    583   #endif
    584 
    585   Formats.Clear();
    586 
    587   #ifdef EXTERNAL_CODECS
    588     MainDll_ErrorPath.Empty();
    589     Codecs.Clear();
    590     Hashers.Clear();
    591   #endif
    592 
    593   for (UInt32 i = 0; i < g_NumArcs; i++)
    594   {
    595     const CArcInfo &arc = *g_Arcs[i];
    596     CArcInfoEx item;
    597 
    598     item.Name.SetFromAscii(arc.Name);
    599     item.CreateInArchive = arc.CreateInArchive;
    600     item.IsArcFunc = arc.IsArc;
    601     item.Flags = arc.Flags;
    602 
    603     {
    604       UString e, ae;
    605       if (arc.Ext)
    606         e.SetFromAscii(arc.Ext);
    607       if (arc.AddExt)
    608         ae.SetFromAscii(arc.AddExt);
    609       item.AddExts(e, ae);
    610     }
    611 
    612     #ifndef _SFX
    613 
    614     item.CreateOutArchive = arc.CreateOutArchive;
    615     item.UpdateEnabled = (arc.CreateOutArchive != NULL);
    616     item.SignatureOffset = arc.SignatureOffset;
    617     // item.Version = MY_VER_MIX;
    618     item.NewInterface = true;
    619 
    620     if (arc.IsMultiSignature())
    621       ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
    622     else
    623       item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
    624 
    625     #endif
    626 
    627     Formats.Add(item);
    628   }
    629 
    630   #ifdef EXTERNAL_CODECS
    631     const FString baseFolder = GetBaseFolderPrefixFromRegistry();
    632     {
    633       bool loadedOK;
    634       RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK));
    635       if (!loadedOK)
    636         MainDll_ErrorPath = kMainDll;
    637     }
    638     RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
    639     RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
    640 
    641   NeedSetLibCodecs = true;
    642 
    643   if (Libs.Size() == 0)
    644     NeedSetLibCodecs = false;
    645   else if (Libs.Size() == 1)
    646   {
    647     // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
    648     #ifndef EXPORT_CODECS
    649     if (g_NumArcs == 0)
    650       NeedSetLibCodecs = false;
    651     #endif
    652   }
    653 
    654   if (NeedSetLibCodecs)
    655   {
    656     /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
    657        old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
    658 
    659     FOR_VECTOR(i, Libs)
    660     {
    661       CCodecLib &lib = Libs[i];
    662       lib.SetCodecs = (Func_SetCodecs)lib.Lib.GetProc("SetCodecs");
    663       if (lib.SetCodecs)
    664       {
    665         RINOK(lib.SetCodecs(this));
    666       }
    667     }
    668   }
    669 
    670   #endif
    671 
    672   return S_OK;
    673 }
    674 
    675 #ifndef _SFX
    676 
    677 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 
    700 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 
    710 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 
    718 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 
    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 
    776 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 
    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 
    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 
    855 STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
    856 {
    857   #ifdef EXPORT_CODECS
    858   if (index < g_NumCodecs)
    859     return CreateDecoder(index, iid, coder);
    860   #endif
    861 
    862   #ifdef EXTERNAL_CODECS
    863   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
    864   if (ci.DecoderIsAssigned)
    865   {
    866     const CCodecLib &lib = Libs[ci.LibIndex];
    867     if (lib.CreateDecoder)
    868       return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
    869     return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
    870   }
    871   return S_OK;
    872   #else
    873   return E_FAIL;
    874   #endif
    875 }
    876 
    877 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
    878 {
    879   #ifdef EXPORT_CODECS
    880   if (index < g_NumCodecs)
    881     return CreateEncoder(index, iid, coder);
    882   #endif
    883 
    884   #ifdef EXTERNAL_CODECS
    885   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
    886   if (ci.EncoderIsAssigned)
    887   {
    888     const CCodecLib &lib = Libs[ci.LibIndex];
    889     if (lib.CreateEncoder)
    890       return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
    891     return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
    892   }
    893   return S_OK;
    894   #else
    895   return E_FAIL;
    896   #endif
    897 }
    898 
    899 
    900 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
    901 {
    902   return NUM_EXPORT_HASHERS
    903     #ifdef EXTERNAL_CODECS
    904     + Hashers.Size()
    905     #endif
    906     ;
    907 }
    908 
    909 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
    910 {
    911   #ifdef EXPORT_CODECS
    912   if (index < g_NumHashers)
    913     return ::GetHasherProp(index, propID, value);
    914   #endif
    915 
    916   #ifdef EXTERNAL_CODECS
    917   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
    918   return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
    919   #else
    920   return E_FAIL;
    921   #endif
    922 }
    923 
    924 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
    925 {
    926   #ifdef EXPORT_CODECS
    927   if (index < g_NumHashers)
    928     return CreateHasher(index, hasher);
    929   #endif
    930   #ifdef EXTERNAL_CODECS
    931   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
    932   return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
    933   #else
    934   return E_FAIL;
    935   #endif
    936 }
    937 
    938 int CCodecs::GetCodec_LibIndex(UInt32 index) const
    939 {
    940   #ifdef EXPORT_CODECS
    941   if (index < g_NumCodecs)
    942     return -1;
    943   #endif
    944 
    945   #ifdef EXTERNAL_CODECS
    946   const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
    947   return ci.LibIndex;
    948   #else
    949   return -1;
    950   #endif
    951 }
    952 
    953 int CCodecs::GetHasherLibIndex(UInt32 index)
    954 {
    955   #ifdef EXPORT_CODECS
    956   if (index < g_NumHashers)
    957     return -1;
    958   #endif
    959 
    960   #ifdef EXTERNAL_CODECS
    961   const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
    962   return ci.LibIndex;
    963   #else
    964   return -1;
    965   #endif
    966 }
    967 
    968 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
    969 {
    970   #ifdef EXPORT_CODECS
    971   if (index < g_NumCodecs)
    972   {
    973     NCOM::CPropVariant prop;
    974     if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
    975     {
    976       if (prop.vt == VT_BOOL)
    977         return VARIANT_BOOLToBool(prop.boolVal);
    978     }
    979     return false;
    980   }
    981   #endif
    982 
    983   #ifdef EXTERNAL_CODECS
    984   return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
    985   #else
    986   return false;
    987   #endif
    988 }
    989 
    990 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
    991 {
    992   #ifdef EXPORT_CODECS
    993   if (index < g_NumCodecs)
    994   {
    995     NCOM::CPropVariant prop;
    996     if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
    997     {
    998       if (prop.vt == VT_BOOL)
    999         return VARIANT_BOOLToBool(prop.boolVal);
   1000     }
   1001     return false;
   1002   }
   1003   #endif
   1004 
   1005   #ifdef EXTERNAL_CODECS
   1006   return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
   1007   #else
   1008   return false;
   1009   #endif
   1010 }
   1011 
   1012 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
   1013 {
   1014   NCOM::CPropVariant prop;
   1015   RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
   1016   if (prop.vt == VT_UI4)
   1017     return (UInt32)prop.ulVal;
   1018   if (prop.vt == VT_EMPTY)
   1019     return 1;
   1020   return 0;
   1021 }
   1022 
   1023 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
   1024 {
   1025   NCOM::CPropVariant prop;
   1026   RINOK(GetProperty(index, NMethodPropID::kID, &prop));
   1027   if (prop.vt != VT_UI8)
   1028     return E_INVALIDARG;
   1029   id = prop.uhVal.QuadPart;
   1030   return S_OK;
   1031 }
   1032 
   1033 AString CCodecs::GetCodec_Name(UInt32 index)
   1034 {
   1035   AString s;
   1036   NCOM::CPropVariant prop;
   1037   if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
   1038     if (prop.vt == VT_BSTR)
   1039       s.SetFromWStr_if_Ascii(prop.bstrVal);
   1040   return s;
   1041 }
   1042 
   1043 UInt64 CCodecs::GetHasherId(UInt32 index)
   1044 {
   1045   NCOM::CPropVariant prop;
   1046   if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
   1047     return 0;
   1048   if (prop.vt != VT_UI8)
   1049     return 0;
   1050   return prop.uhVal.QuadPart;
   1051 }
   1052 
   1053 AString CCodecs::GetHasherName(UInt32 index)
   1054 {
   1055   AString s;
   1056   NCOM::CPropVariant prop;
   1057   if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
   1058     if (prop.vt == VT_BSTR)
   1059       s.SetFromWStr_if_Ascii(prop.bstrVal);
   1060   return s;
   1061 }
   1062 
   1063 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
   1064 {
   1065   NCOM::CPropVariant prop;
   1066   RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
   1067   if (prop.vt != VT_UI4)
   1068     return 0;
   1069   return prop.ulVal;
   1070 }
   1071 
   1072 #endif // EXTERNAL_CODECS
   1073