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