1 // LoadCodecs.cpp
2
3 /*
4 EXTERNAL_CODECS
5 ---------------
6 CCodecs::Load() tries to detect the directory with plugins.
7 It stops the checking, if it can find any of the following items:
8 - 7z.dll file
9 - "Formats" subdir
10 - "Codecs" subdir
11 The order of check:
12 1) directory of client executable
13 2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**]
14 The order for HKEY_* : Path** :
15 - HKEY_CURRENT_USER : PathXX
16 - HKEY_LOCAL_MACHINE : PathXX
17 - HKEY_CURRENT_USER : Path
18 - HKEY_LOCAL_MACHINE : Path
19 PathXX is Path32 in 32-bit code
20 PathXX is Path64 in 64-bit code
21
22
23 EXPORT_CODECS
24 -------------
25 if (EXTERNAL_CODECS) is defined, then the code exports internal
26 codecs of client from CCodecs object to external plugins.
27 7-Zip doesn't use that feature. 7-Zip uses the scheme:
28 - client application without internal plugins.
29 - 7z.dll module contains all (or almost all) plugins.
30 7z.dll can use codecs from another plugins, if required.
31 */
32
33
34 #include "StdAfx.h"
35
36 #include "../../../../C/7zVersion.h"
37
38 #include "../../../Common/MyCom.h"
39 #include "../../../Common/StringToInt.h"
40 #include "../../../Common/StringConvert.h"
41
42 #include "../../../Windows/PropVariant.h"
43
44 #include "LoadCodecs.h"
45
46 using namespace NWindows;
47
48 #ifdef NEW_FOLDER_INTERFACE
49 #include "../../../Common/StringToInt.h"
50 #endif
51
52 #include "../../ICoder.h"
53 #include "../../Common/RegisterArc.h"
54
55 #ifdef EXTERNAL_CODECS
56
57 // #define EXPORT_CODECS
58
59 #endif
60
61 #ifdef NEW_FOLDER_INTERFACE
62 extern HINSTANCE g_hInstance;
63 #include "../../../Windows/ResourceString.h"
64 static const UINT kIconTypesResId = 100;
65 #endif
66
67 #ifdef EXTERNAL_CODECS
68
69 #include "../../../Windows/FileFind.h"
70 #include "../../../Windows/DLL.h"
71
72 #ifdef _WIN32
73 #include "../../../Windows/FileName.h"
74 #include "../../../Windows/Registry.h"
75 #endif
76
77 using namespace NFile;
78
79
80 #define kCodecsFolderName FTEXT("Codecs")
81 #define kFormatsFolderName FTEXT("Formats")
82
83
84 static CFSTR const kMainDll =
85 // #ifdef _WIN32
86 FTEXT("7z.dll");
87 // #else
88 // FTEXT("7z.so");
89 // #endif
90
91
92 #ifdef _WIN32
93
94 static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
95 static LPCWSTR const kProgramPathValue = L"Path";
96 static LPCWSTR const kProgramPath2Value = L"Path"
97 #ifdef _WIN64
98 L"64";
99 #else
100 L"32";
101 #endif
102
ReadPathFromRegistry(HKEY baseKey,LPCWSTR value,FString & path)103 static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
104 {
105 NRegistry::CKey key;
106 if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
107 {
108 UString pathU;
109 if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
110 {
111 path = us2fs(pathU);
112 NName::NormalizeDirPathPrefix(path);
113 return NFind::DoesFileExist(path + kMainDll);
114 }
115 }
116 return false;
117 }
118
119 #endif // _WIN32
120
121 #endif // EXTERNAL_CODECS
122
123
124 static const unsigned kNumArcsMax = 64;
125 static unsigned g_NumArcs = 0;
126 static const CArcInfo *g_Arcs[kNumArcsMax];
127
RegisterArc(const CArcInfo * arcInfo)128 void RegisterArc(const CArcInfo *arcInfo) throw()
129 {
130 if (g_NumArcs < kNumArcsMax)
131 {
132 g_Arcs[g_NumArcs] = arcInfo;
133 g_NumArcs++;
134 }
135 }
136
SplitString(const UString & srcString,UStringVector & destStrings)137 static void SplitString(const UString &srcString, UStringVector &destStrings)
138 {
139 destStrings.Clear();
140 UString s;
141 unsigned len = srcString.Len();
142 if (len == 0)
143 return;
144 for (unsigned i = 0; i < len; i++)
145 {
146 wchar_t c = srcString[i];
147 if (c == L' ')
148 {
149 if (!s.IsEmpty())
150 {
151 destStrings.Add(s);
152 s.Empty();
153 }
154 }
155 else
156 s += c;
157 }
158 if (!s.IsEmpty())
159 destStrings.Add(s);
160 }
161
FindExtension(const UString & ext) const162 int CArcInfoEx::FindExtension(const UString &ext) const
163 {
164 FOR_VECTOR (i, Exts)
165 if (ext.IsEqualTo_NoCase(Exts[i].Ext))
166 return i;
167 return -1;
168 }
169
AddExts(const UString & ext,const UString & addExt)170 void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
171 {
172 UStringVector exts, addExts;
173 SplitString(ext, exts);
174 SplitString(addExt, addExts);
175 FOR_VECTOR (i, exts)
176 {
177 CArcExtInfo extInfo;
178 extInfo.Ext = exts[i];
179 if (i < addExts.Size())
180 {
181 extInfo.AddExt = addExts[i];
182 if (extInfo.AddExt == L"*")
183 extInfo.AddExt.Empty();
184 }
185 Exts.Add(extInfo);
186 }
187 }
188
189 #ifndef _SFX
190
ParseSignatures(const Byte * data,unsigned size,CObjectVector<CByteBuffer> & signatures)191 static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
192 {
193 signatures.Clear();
194 while (size > 0)
195 {
196 unsigned len = *data++;
197 size--;
198 if (len > size)
199 return false;
200 signatures.AddNew().CopyFrom(data, len);
201 data += len;
202 size -= len;
203 }
204 return true;
205 }
206
207 #endif // _SFX
208
209 #ifdef EXTERNAL_CODECS
210
GetBaseFolderPrefixFromRegistry()211 static FString GetBaseFolderPrefixFromRegistry()
212 {
213 FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
214 #ifdef _WIN32
215 if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
216 !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
217 !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
218 {
219 FString path;
220 if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path;
221 if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
222 if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path;
223 if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path;
224 }
225 #endif
226 return moduleFolderPrefix;
227 }
228
229
GetCoderClass(Func_GetMethodProperty getMethodProperty,UInt32 index,PROPID propId,CLSID & clsId,bool & isAssigned)230 static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
231 PROPID propId, CLSID &clsId, bool &isAssigned)
232 {
233 NCOM::CPropVariant prop;
234 isAssigned = false;
235 RINOK(getMethodProperty(index, propId, &prop));
236 if (prop.vt == VT_BSTR)
237 {
238 if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
239 return E_FAIL;
240 isAssigned = true;
241 clsId = *(const GUID *)prop.bstrVal;
242 }
243 else if (prop.vt != VT_EMPTY)
244 return E_FAIL;
245 return S_OK;
246 }
247
LoadCodecs()248 HRESULT CCodecs::LoadCodecs()
249 {
250 CCodecLib &lib = Libs.Back();
251
252 lib.CreateDecoder = (Func_CreateDecoder)lib.Lib.GetProc("CreateDecoder");
253 lib.CreateEncoder = (Func_CreateEncoder)lib.Lib.GetProc("CreateEncoder");
254 lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");
255
256 if (lib.GetMethodProperty)
257 {
258 UInt32 numMethods = 1;
259 Func_GetNumberOfMethods getNumberOfMethods = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods");
260 if (getNumberOfMethods)
261 {
262 RINOK(getNumberOfMethods(&numMethods));
263 }
264 for (UInt32 i = 0; i < numMethods; i++)
265 {
266 CDllCodecInfo info;
267 info.LibIndex = Libs.Size() - 1;
268 info.CodecIndex = i;
269 RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
270 RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
271 Codecs.Add(info);
272 }
273 }
274
275 Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers");
276 if (getHashers)
277 {
278 RINOK(getHashers(&lib.ComHashers));
279 if (lib.ComHashers)
280 {
281 UInt32 numMethods = lib.ComHashers->GetNumHashers();
282 for (UInt32 i = 0; i < numMethods; i++)
283 {
284 CDllHasherInfo info;
285 info.LibIndex = Libs.Size() - 1;
286 info.HasherIndex = i;
287 Hashers.Add(info);
288 }
289 }
290 }
291
292 return S_OK;
293 }
294
GetProp(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,NCOM::CPropVariant & prop)295 static HRESULT GetProp(
296 Func_GetHandlerProperty getProp,
297 Func_GetHandlerProperty2 getProp2,
298 UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
299 {
300 if (getProp2)
301 return getProp2(index, propID, &prop);;
302 return getProp(propID, &prop);
303 }
304
GetProp_Bool(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,bool & res)305 static HRESULT GetProp_Bool(
306 Func_GetHandlerProperty getProp,
307 Func_GetHandlerProperty2 getProp2,
308 UInt32 index, PROPID propID, bool &res)
309 {
310 res = false;
311 NCOM::CPropVariant prop;
312 RINOK(GetProp(getProp, getProp2, index, propID, prop));
313 if (prop.vt == VT_BOOL)
314 res = VARIANT_BOOLToBool(prop.boolVal);
315 else if (prop.vt != VT_EMPTY)
316 return E_FAIL;
317 return S_OK;
318 }
319
GetProp_UInt32(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UInt32 & res,bool & defined)320 static HRESULT GetProp_UInt32(
321 Func_GetHandlerProperty getProp,
322 Func_GetHandlerProperty2 getProp2,
323 UInt32 index, PROPID propID, UInt32 &res, bool &defined)
324 {
325 res = 0;
326 defined = false;
327 NCOM::CPropVariant prop;
328 RINOK(GetProp(getProp, getProp2, index, propID, prop));
329 if (prop.vt == VT_UI4)
330 {
331 res = prop.ulVal;
332 defined = true;
333 }
334 else if (prop.vt != VT_EMPTY)
335 return E_FAIL;
336 return S_OK;
337 }
338
GetProp_String(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,UString & res)339 static HRESULT GetProp_String(
340 Func_GetHandlerProperty getProp,
341 Func_GetHandlerProperty2 getProp2,
342 UInt32 index, PROPID propID, UString &res)
343 {
344 res.Empty();
345 NCOM::CPropVariant prop;
346 RINOK(GetProp(getProp, getProp2, index, propID, prop));
347 if (prop.vt == VT_BSTR)
348 res.SetFromBstr(prop.bstrVal);
349 else if (prop.vt != VT_EMPTY)
350 return E_FAIL;
351 return S_OK;
352 }
353
GetProp_RawData(Func_GetHandlerProperty getProp,Func_GetHandlerProperty2 getProp2,UInt32 index,PROPID propID,CByteBuffer & bb)354 static HRESULT GetProp_RawData(
355 Func_GetHandlerProperty getProp,
356 Func_GetHandlerProperty2 getProp2,
357 UInt32 index, PROPID propID, CByteBuffer &bb)
358 {
359 bb.Free();
360 NCOM::CPropVariant prop;
361 RINOK(GetProp(getProp, getProp2, index, propID, prop));
362 if (prop.vt == VT_BSTR)
363 {
364 UINT len = ::SysStringByteLen(prop.bstrVal);
365 bb.CopyFrom((const Byte *)prop.bstrVal, len);
366 }
367 else if (prop.vt != VT_EMPTY)
368 return E_FAIL;
369 return S_OK;
370 }
371
372 static const UInt32 kArcFlagsPars[] =
373 {
374 NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
375 NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
376 NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
377 };
378
LoadFormats()379 HRESULT CCodecs::LoadFormats()
380 {
381 const NDLL::CLibrary &lib = Libs.Back().Lib;
382
383 Func_GetHandlerProperty getProp = NULL;
384 Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2");
385 Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc");
386
387 UInt32 numFormats = 1;
388
389 if (getProp2)
390 {
391 Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats");
392 if (getNumberOfFormats)
393 {
394 RINOK(getNumberOfFormats(&numFormats));
395 }
396 }
397 else
398 {
399 getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty");
400 if (!getProp)
401 return S_OK;
402 }
403
404 for (UInt32 i = 0; i < numFormats; i++)
405 {
406 CArcInfoEx item;
407 item.LibIndex = Libs.Size() - 1;
408 item.FormatIndex = i;
409
410 RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name));
411
412 {
413 NCOM::CPropVariant prop;
414 if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
415 continue;
416 if (prop.vt != VT_BSTR)
417 continue;
418 if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
419 return E_FAIL;
420 item.ClassID = *(const GUID *)prop.bstrVal;
421 prop.Clear();
422 }
423
424 UString ext, addExt;
425 RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext));
426 RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt));
427 item.AddExts(ext, addExt);
428
429 GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
430 bool flags_Defined = false;
431 RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined));
432 item.NewInterface = flags_Defined;
433 if (!flags_Defined) // && item.UpdateEnabled
434 {
435 // support for DLL version before 9.31:
436 for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2)
437 {
438 bool val = false;
439 GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
440 if (val)
441 item.Flags |= kArcFlagsPars[j + 1];
442 }
443 }
444
445 CByteBuffer sig;
446 RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig));
447 if (sig.Size() != 0)
448 item.Signatures.Add(sig);
449 else
450 {
451 RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig));
452 ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
453 }
454
455 bool signatureOffset_Defined;
456 RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined));
457
458 // bool version_Defined;
459 // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
460
461 if (getIsArc)
462 getIsArc(i, &item.IsArcFunc);
463
464 Formats.Add(item);
465 }
466 return S_OK;
467 }
468
469 #ifdef _7ZIP_LARGE_PAGES
470 extern "C"
471 {
472 extern SIZE_T g_LargePageSize;
473 }
474 #endif
475
LoadDll(const FString & dllPath,bool needCheckDll,bool * loadedOK)476 HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
477 {
478 if (loadedOK)
479 *loadedOK = false;
480
481 if (needCheckDll)
482 {
483 NDLL::CLibrary lib;
484 if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
485 return S_OK;
486 }
487
488 Libs.AddNew();
489 CCodecLib &lib = Libs.Back();
490 lib.Path = dllPath;
491 bool used = false;
492 HRESULT res = S_OK;
493
494 if (lib.Lib.Load(dllPath))
495 {
496 if (loadedOK)
497 *loadedOK = true;
498 #ifdef NEW_FOLDER_INTERFACE
499 lib.LoadIcons();
500 #endif
501
502 #ifdef _7ZIP_LARGE_PAGES
503 if (g_LargePageSize != 0)
504 {
505 Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");
506 if (setLargePageMode)
507 setLargePageMode();
508 }
509 #endif
510
511 if (CaseSensitiveChange)
512 {
513 Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");
514 if (setCaseSensitive)
515 setCaseSensitive(CaseSensitive ? 1 : 0);
516 }
517
518 lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");
519 {
520 unsigned startSize = Codecs.Size() + Hashers.Size();
521 res = LoadCodecs();
522 used = (startSize != Codecs.Size() + Hashers.Size());
523 if (res == S_OK && lib.CreateObject)
524 {
525 startSize = Formats.Size();
526 res = LoadFormats();
527 if (startSize != Formats.Size())
528 used = true;
529 }
530 }
531 }
532
533 if (!used)
534 Libs.DeleteBack();
535
536 return res;
537 }
538
LoadDllsFromFolder(const FString & folderPrefix)539 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
540 {
541 NFile::NFind::CEnumerator enumerator;
542 enumerator.SetDirPrefix(folderPrefix);
543 NFile::NFind::CFileInfo fi;
544 while (enumerator.Next(fi))
545 {
546 if (fi.IsDir())
547 continue;
548 RINOK(LoadDll(folderPrefix + fi.Name, true));
549 }
550 return S_OK;
551 }
552
CloseLibs()553 void CCodecs::CloseLibs()
554 {
555 // OutputDebugStringA("~CloseLibs start");
556 /*
557 WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected,
558 if it's called from another FreeLibrary() call.
559 So we need to call FreeLibrary() before global destructors.
560
561 Also we free global links from DLLs to object of this module before CLibrary::Free() call.
562 */
563
564 FOR_VECTOR(i, Libs)
565 {
566 const CCodecLib &lib = Libs[i];
567 if (lib.SetCodecs)
568 lib.SetCodecs(NULL);
569 }
570
571 // OutputDebugStringA("~CloseLibs after SetCodecs");
572 Libs.Clear();
573 // OutputDebugStringA("~CloseLibs end");
574 }
575
576 #endif // EXTERNAL_CODECS
577
578
Load()579 HRESULT CCodecs::Load()
580 {
581 #ifdef NEW_FOLDER_INTERFACE
582 InternalIcons.LoadIcons(g_hInstance);
583 #endif
584
585 Formats.Clear();
586
587 #ifdef EXTERNAL_CODECS
588 MainDll_ErrorPath.Empty();
589 Codecs.Clear();
590 Hashers.Clear();
591 #endif
592
593 for (UInt32 i = 0; i < g_NumArcs; i++)
594 {
595 const CArcInfo &arc = *g_Arcs[i];
596 CArcInfoEx item;
597
598 item.Name = arc.Name;
599 item.CreateInArchive = arc.CreateInArchive;
600 item.IsArcFunc = arc.IsArc;
601 item.Flags = arc.Flags;
602
603 {
604 UString e, ae;
605 if (arc.Ext)
606 e = arc.Ext;
607 if (arc.AddExt)
608 ae = arc.AddExt;
609 item.AddExts(e, ae);
610 }
611
612 #ifndef _SFX
613
614 item.CreateOutArchive = arc.CreateOutArchive;
615 item.UpdateEnabled = (arc.CreateOutArchive != NULL);
616 item.SignatureOffset = arc.SignatureOffset;
617 // item.Version = MY_VER_MIX;
618 item.NewInterface = true;
619
620 if (arc.IsMultiSignature())
621 ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
622 else
623 item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
624
625 #endif
626
627 Formats.Add(item);
628 }
629
630 #ifdef EXTERNAL_CODECS
631 const FString baseFolder = GetBaseFolderPrefixFromRegistry();
632 {
633 bool loadedOK;
634 RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK));
635 if (!loadedOK)
636 MainDll_ErrorPath = kMainDll;
637 }
638 RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
639 RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
640
641 NeedSetLibCodecs = true;
642
643 if (Libs.Size() == 0)
644 NeedSetLibCodecs = false;
645 else if (Libs.Size() == 1)
646 {
647 // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
648 #ifndef EXPORT_CODECS
649 if (g_NumArcs == 0)
650 NeedSetLibCodecs = false;
651 #endif
652 }
653
654 if (NeedSetLibCodecs)
655 {
656 /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
657 old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
658
659 FOR_VECTOR(i, Libs)
660 {
661 CCodecLib &lib = Libs[i];
662 lib.SetCodecs = (Func_SetCodecs)lib.Lib.GetProc("SetCodecs");
663 if (lib.SetCodecs)
664 {
665 RINOK(lib.SetCodecs(this));
666 }
667 }
668 }
669
670 #endif
671
672 return S_OK;
673 }
674
675 #ifndef _SFX
676
FindFormatForArchiveName(const UString & arcPath) const677 int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
678 {
679 int dotPos = arcPath.ReverseFind_Dot();
680 if (dotPos <= arcPath.ReverseFind_PathSepar())
681 return -1;
682 const UString ext = arcPath.Ptr(dotPos + 1);
683 if (ext.IsEmpty())
684 return -1;
685 if (ext.IsEqualTo_Ascii_NoCase("exe"))
686 return -1;
687 FOR_VECTOR (i, Formats)
688 {
689 const CArcInfoEx &arc = Formats[i];
690 /*
691 if (!arc.UpdateEnabled)
692 continue;
693 */
694 if (arc.FindExtension(ext) >= 0)
695 return i;
696 }
697 return -1;
698 }
699
FindFormatForExtension(const UString & ext) const700 int CCodecs::FindFormatForExtension(const UString &ext) const
701 {
702 if (ext.IsEmpty())
703 return -1;
704 FOR_VECTOR (i, Formats)
705 if (Formats[i].FindExtension(ext) >= 0)
706 return i;
707 return -1;
708 }
709
FindFormatForArchiveType(const UString & arcType) const710 int CCodecs::FindFormatForArchiveType(const UString &arcType) const
711 {
712 FOR_VECTOR (i, Formats)
713 if (Formats[i].Name.IsEqualTo_NoCase(arcType))
714 return i;
715 return -1;
716 }
717
FindFormatForArchiveType(const UString & arcType,CIntVector & formatIndices) const718 bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
719 {
720 formatIndices.Clear();
721 for (unsigned pos = 0; pos < arcType.Len();)
722 {
723 int pos2 = arcType.Find(L'.', pos);
724 if (pos2 < 0)
725 pos2 = arcType.Len();
726 const UString name = arcType.Mid(pos, pos2 - pos);
727 if (name.IsEmpty())
728 return false;
729 int index = FindFormatForArchiveType(name);
730 if (index < 0 && name != L"*")
731 {
732 formatIndices.Clear();
733 return false;
734 }
735 formatIndices.Add(index);
736 pos = pos2 + 1;
737 }
738 return true;
739 }
740
741 #endif // _SFX
742
743
744 #ifdef NEW_FOLDER_INTERFACE
745
LoadIcons(HMODULE m)746 void CCodecIcons::LoadIcons(HMODULE m)
747 {
748 UString iconTypes;
749 MyLoadString(m, kIconTypesResId, iconTypes);
750 UStringVector pairs;
751 SplitString(iconTypes, pairs);
752 FOR_VECTOR (i, pairs)
753 {
754 const UString &s = pairs[i];
755 int pos = s.Find(L':');
756 CIconPair iconPair;
757 iconPair.IconIndex = -1;
758 if (pos < 0)
759 pos = s.Len();
760 else
761 {
762 UString num = s.Ptr(pos + 1);
763 if (!num.IsEmpty())
764 {
765 const wchar_t *end;
766 iconPair.IconIndex = ConvertStringToUInt32(num, &end);
767 if (*end != 0)
768 continue;
769 }
770 }
771 iconPair.Ext = s.Left(pos);
772 IconPairs.Add(iconPair);
773 }
774 }
775
FindIconIndex(const UString & ext,int & iconIndex) const776 bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
777 {
778 iconIndex = -1;
779 FOR_VECTOR (i, IconPairs)
780 {
781 const CIconPair &pair = IconPairs[i];
782 if (ext.IsEqualTo_NoCase(pair.Ext))
783 {
784 iconIndex = pair.IconIndex;
785 return true;
786 }
787 }
788 return false;
789 }
790
791 #endif // NEW_FOLDER_INTERFACE
792
793
794 #ifdef EXTERNAL_CODECS
795
796 // #define EXPORT_CODECS
797
798 #ifdef EXPORT_CODECS
799
800 extern unsigned g_NumCodecs;
801 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
802 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
803 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
804 #define NUM_EXPORT_CODECS g_NumCodecs
805
806 extern unsigned g_NumHashers;
807 STDAPI CreateHasher(UInt32 index, IHasher **hasher);
808 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
809 #define NUM_EXPORT_HASHERS g_NumHashers
810
811 #else // EXPORT_CODECS
812
813 #define NUM_EXPORT_CODECS 0
814 #define NUM_EXPORT_HASHERS 0
815
816 #endif // EXPORT_CODECS
817
GetNumMethods(UInt32 * numMethods)818 STDMETHODIMP CCodecs::GetNumMethods(UInt32 *numMethods)
819 {
820 *numMethods = NUM_EXPORT_CODECS
821 #ifdef EXTERNAL_CODECS
822 + Codecs.Size()
823 #endif
824 ;
825 return S_OK;
826 }
827
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)828 STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
829 {
830 #ifdef EXPORT_CODECS
831 if (index < g_NumCodecs)
832 return GetMethodProperty(index, propID, value);
833 #endif
834
835 #ifdef EXTERNAL_CODECS
836 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
837
838 if (propID == NMethodPropID::kDecoderIsAssigned ||
839 propID == NMethodPropID::kEncoderIsAssigned)
840 {
841 NCOM::CPropVariant prop;
842 prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ?
843 ci.DecoderIsAssigned :
844 ci.EncoderIsAssigned);
845 prop.Detach(value);
846 return S_OK;
847 }
848 const CCodecLib &lib = Libs[ci.LibIndex];
849 return lib.GetMethodProperty(ci.CodecIndex, propID, value);
850 #else
851 return E_FAIL;
852 #endif
853 }
854
CreateDecoder(UInt32 index,const GUID * iid,void ** coder)855 STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
856 {
857 #ifdef EXPORT_CODECS
858 if (index < g_NumCodecs)
859 return CreateDecoder(index, iid, coder);
860 #endif
861
862 #ifdef EXTERNAL_CODECS
863 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
864 if (ci.DecoderIsAssigned)
865 {
866 const CCodecLib &lib = Libs[ci.LibIndex];
867 if (lib.CreateDecoder)
868 return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
869 if (lib.CreateObject)
870 return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
871 }
872 return S_OK;
873 #else
874 return E_FAIL;
875 #endif
876 }
877
CreateEncoder(UInt32 index,const GUID * iid,void ** coder)878 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
879 {
880 #ifdef EXPORT_CODECS
881 if (index < g_NumCodecs)
882 return CreateEncoder(index, iid, coder);
883 #endif
884
885 #ifdef EXTERNAL_CODECS
886 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
887 if (ci.EncoderIsAssigned)
888 {
889 const CCodecLib &lib = Libs[ci.LibIndex];
890 if (lib.CreateEncoder)
891 return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
892 if (lib.CreateObject)
893 return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
894 }
895 return S_OK;
896 #else
897 return E_FAIL;
898 #endif
899 }
900
901
STDMETHODIMP_(UInt32)902 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
903 {
904 return NUM_EXPORT_HASHERS
905 #ifdef EXTERNAL_CODECS
906 + Hashers.Size()
907 #endif
908 ;
909 }
910
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)911 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
912 {
913 #ifdef EXPORT_CODECS
914 if (index < g_NumHashers)
915 return ::GetHasherProp(index, propID, value);
916 #endif
917
918 #ifdef EXTERNAL_CODECS
919 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
920 return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
921 #else
922 return E_FAIL;
923 #endif
924 }
925
CreateHasher(UInt32 index,IHasher ** hasher)926 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
927 {
928 #ifdef EXPORT_CODECS
929 if (index < g_NumHashers)
930 return CreateHasher(index, hasher);
931 #endif
932 #ifdef EXTERNAL_CODECS
933 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
934 return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
935 #else
936 return E_FAIL;
937 #endif
938 }
939
GetCodec_LibIndex(UInt32 index) const940 int CCodecs::GetCodec_LibIndex(UInt32 index) const
941 {
942 #ifdef EXPORT_CODECS
943 if (index < g_NumCodecs)
944 return -1;
945 #endif
946
947 #ifdef EXTERNAL_CODECS
948 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
949 return ci.LibIndex;
950 #else
951 return -1;
952 #endif
953 }
954
GetHasherLibIndex(UInt32 index)955 int CCodecs::GetHasherLibIndex(UInt32 index)
956 {
957 #ifdef EXPORT_CODECS
958 if (index < g_NumHashers)
959 return -1;
960 #endif
961
962 #ifdef EXTERNAL_CODECS
963 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
964 return ci.LibIndex;
965 #else
966 return -1;
967 #endif
968 }
969
GetCodec_DecoderIsAssigned(UInt32 index) const970 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
971 {
972 #ifdef EXPORT_CODECS
973 if (index < g_NumCodecs)
974 {
975 NCOM::CPropVariant prop;
976 if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
977 {
978 if (prop.vt == VT_BOOL)
979 return VARIANT_BOOLToBool(prop.boolVal);
980 }
981 return false;
982 }
983 #endif
984
985 #ifdef EXTERNAL_CODECS
986 return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
987 #else
988 return false;
989 #endif
990 }
991
GetCodec_EncoderIsAssigned(UInt32 index) const992 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
993 {
994 #ifdef EXPORT_CODECS
995 if (index < g_NumCodecs)
996 {
997 NCOM::CPropVariant prop;
998 if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
999 {
1000 if (prop.vt == VT_BOOL)
1001 return VARIANT_BOOLToBool(prop.boolVal);
1002 }
1003 return false;
1004 }
1005 #endif
1006
1007 #ifdef EXTERNAL_CODECS
1008 return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
1009 #else
1010 return false;
1011 #endif
1012 }
1013
GetCodec_NumStreams(UInt32 index)1014 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
1015 {
1016 NCOM::CPropVariant prop;
1017 RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
1018 if (prop.vt == VT_UI4)
1019 return (UInt32)prop.ulVal;
1020 if (prop.vt == VT_EMPTY)
1021 return 1;
1022 return 0;
1023 }
1024
GetCodec_Id(UInt32 index,UInt64 & id)1025 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
1026 {
1027 NCOM::CPropVariant prop;
1028 RINOK(GetProperty(index, NMethodPropID::kID, &prop));
1029 if (prop.vt != VT_UI8)
1030 return E_INVALIDARG;
1031 id = prop.uhVal.QuadPart;
1032 return S_OK;
1033 }
1034
GetCodec_Name(UInt32 index)1035 AString CCodecs::GetCodec_Name(UInt32 index)
1036 {
1037 AString s;
1038 NCOM::CPropVariant prop;
1039 if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
1040 if (prop.vt == VT_BSTR)
1041 s.SetFromWStr_if_Ascii(prop.bstrVal);
1042 return s;
1043 }
1044
GetHasherId(UInt32 index)1045 UInt64 CCodecs::GetHasherId(UInt32 index)
1046 {
1047 NCOM::CPropVariant prop;
1048 if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
1049 return 0;
1050 if (prop.vt != VT_UI8)
1051 return 0;
1052 return prop.uhVal.QuadPart;
1053 }
1054
GetHasherName(UInt32 index)1055 AString CCodecs::GetHasherName(UInt32 index)
1056 {
1057 AString s;
1058 NCOM::CPropVariant prop;
1059 if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
1060 if (prop.vt == VT_BSTR)
1061 s.SetFromWStr_if_Ascii(prop.bstrVal);
1062 return s;
1063 }
1064
GetHasherDigestSize(UInt32 index)1065 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
1066 {
1067 NCOM::CPropVariant prop;
1068 RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
1069 if (prop.vt != VT_UI4)
1070 return 0;
1071 return prop.ulVal;
1072 }
1073
1074 #endif // EXTERNAL_CODECS
1075