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