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 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 kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
95 static LPCWSTR kProgramPathValue = L"Path";
96 static LPCWSTR 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 if (lib.CreateObject)
520 {
521 unsigned startSize = Codecs.Size() + Hashers.Size();
522 res = LoadCodecs();
523 used = (startSize != Codecs.Size() + Hashers.Size());
524 if (res == S_OK)
525 {
526 startSize = Formats.Size();
527 res = LoadFormats();
528 if (startSize != Formats.Size())
529 used = true;
530 }
531 }
532 }
533
534 if (!used)
535 Libs.DeleteBack();
536
537 return res;
538 }
539
LoadDllsFromFolder(const FString & folderPrefix)540 HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
541 {
542 NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK);
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.SetFromAscii(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.SetFromAscii(arc.Ext);
607 if (arc.AddExt)
608 ae.SetFromAscii(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 return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
870 }
871 return S_OK;
872 #else
873 return E_FAIL;
874 #endif
875 }
876
CreateEncoder(UInt32 index,const GUID * iid,void ** coder)877 STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
878 {
879 #ifdef EXPORT_CODECS
880 if (index < g_NumCodecs)
881 return CreateEncoder(index, iid, coder);
882 #endif
883
884 #ifdef EXTERNAL_CODECS
885 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
886 if (ci.EncoderIsAssigned)
887 {
888 const CCodecLib &lib = Libs[ci.LibIndex];
889 if (lib.CreateEncoder)
890 return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
891 return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
892 }
893 return S_OK;
894 #else
895 return E_FAIL;
896 #endif
897 }
898
899
STDMETHODIMP_(UInt32)900 STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
901 {
902 return NUM_EXPORT_HASHERS
903 #ifdef EXTERNAL_CODECS
904 + Hashers.Size()
905 #endif
906 ;
907 }
908
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)909 STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
910 {
911 #ifdef EXPORT_CODECS
912 if (index < g_NumHashers)
913 return ::GetHasherProp(index, propID, value);
914 #endif
915
916 #ifdef EXTERNAL_CODECS
917 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
918 return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
919 #else
920 return E_FAIL;
921 #endif
922 }
923
CreateHasher(UInt32 index,IHasher ** hasher)924 STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
925 {
926 #ifdef EXPORT_CODECS
927 if (index < g_NumHashers)
928 return CreateHasher(index, hasher);
929 #endif
930 #ifdef EXTERNAL_CODECS
931 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
932 return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
933 #else
934 return E_FAIL;
935 #endif
936 }
937
GetCodec_LibIndex(UInt32 index) const938 int CCodecs::GetCodec_LibIndex(UInt32 index) const
939 {
940 #ifdef EXPORT_CODECS
941 if (index < g_NumCodecs)
942 return -1;
943 #endif
944
945 #ifdef EXTERNAL_CODECS
946 const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
947 return ci.LibIndex;
948 #else
949 return -1;
950 #endif
951 }
952
GetHasherLibIndex(UInt32 index)953 int CCodecs::GetHasherLibIndex(UInt32 index)
954 {
955 #ifdef EXPORT_CODECS
956 if (index < g_NumHashers)
957 return -1;
958 #endif
959
960 #ifdef EXTERNAL_CODECS
961 const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
962 return ci.LibIndex;
963 #else
964 return -1;
965 #endif
966 }
967
GetCodec_DecoderIsAssigned(UInt32 index) const968 bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
969 {
970 #ifdef EXPORT_CODECS
971 if (index < g_NumCodecs)
972 {
973 NCOM::CPropVariant prop;
974 if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
975 {
976 if (prop.vt == VT_BOOL)
977 return VARIANT_BOOLToBool(prop.boolVal);
978 }
979 return false;
980 }
981 #endif
982
983 #ifdef EXTERNAL_CODECS
984 return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
985 #else
986 return false;
987 #endif
988 }
989
GetCodec_EncoderIsAssigned(UInt32 index) const990 bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
991 {
992 #ifdef EXPORT_CODECS
993 if (index < g_NumCodecs)
994 {
995 NCOM::CPropVariant prop;
996 if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
997 {
998 if (prop.vt == VT_BOOL)
999 return VARIANT_BOOLToBool(prop.boolVal);
1000 }
1001 return false;
1002 }
1003 #endif
1004
1005 #ifdef EXTERNAL_CODECS
1006 return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
1007 #else
1008 return false;
1009 #endif
1010 }
1011
GetCodec_NumStreams(UInt32 index)1012 UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
1013 {
1014 NCOM::CPropVariant prop;
1015 RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
1016 if (prop.vt == VT_UI4)
1017 return (UInt32)prop.ulVal;
1018 if (prop.vt == VT_EMPTY)
1019 return 1;
1020 return 0;
1021 }
1022
GetCodec_Id(UInt32 index,UInt64 & id)1023 HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
1024 {
1025 NCOM::CPropVariant prop;
1026 RINOK(GetProperty(index, NMethodPropID::kID, &prop));
1027 if (prop.vt != VT_UI8)
1028 return E_INVALIDARG;
1029 id = prop.uhVal.QuadPart;
1030 return S_OK;
1031 }
1032
GetCodec_Name(UInt32 index)1033 AString CCodecs::GetCodec_Name(UInt32 index)
1034 {
1035 AString s;
1036 NCOM::CPropVariant prop;
1037 if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
1038 if (prop.vt == VT_BSTR)
1039 s.SetFromWStr_if_Ascii(prop.bstrVal);
1040 return s;
1041 }
1042
GetHasherId(UInt32 index)1043 UInt64 CCodecs::GetHasherId(UInt32 index)
1044 {
1045 NCOM::CPropVariant prop;
1046 if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
1047 return 0;
1048 if (prop.vt != VT_UI8)
1049 return 0;
1050 return prop.uhVal.QuadPart;
1051 }
1052
GetHasherName(UInt32 index)1053 AString CCodecs::GetHasherName(UInt32 index)
1054 {
1055 AString s;
1056 NCOM::CPropVariant prop;
1057 if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
1058 if (prop.vt == VT_BSTR)
1059 s.SetFromWStr_if_Ascii(prop.bstrVal);
1060 return s;
1061 }
1062
GetHasherDigestSize(UInt32 index)1063 UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
1064 {
1065 NCOM::CPropVariant prop;
1066 RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
1067 if (prop.vt != VT_UI4)
1068 return 0;
1069 return prop.ulVal;
1070 }
1071
1072 #endif // EXTERNAL_CODECS
1073