tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LoadCodecs.cpp (27198B)


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