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