5 #include "LoadCodecs.h"
7 #include "../../../Common/MyCom.h"
8 #ifdef NEW_FOLDER_INTERFACE
9 #include "../../../Common/StringToInt.h"
11 #include "../../../Windows/PropVariant.h"
13 #include "../../ICoder.h"
14 #include "../../Common/RegisterArc.h"
16 #ifdef EXTERNAL_CODECS
17 #include "../../../Windows/FileFind.h"
18 #include "../../../Windows/DLL.h"
19 #ifdef NEW_FOLDER_INTERFACE
20 #include "../../../Windows/ResourceString.h"
21 static const UINT kIconTypesResId = 100;
25 #include "Windows/Registry.h"
28 using namespace NWindows;
29 using namespace NFile;
32 extern HINSTANCE g_hInstance;
35 static CSysString GetLibraryFolderPrefix()
38 TCHAR fullPath[MAX_PATH + 1];
39 ::GetModuleFileName(g_hInstance, fullPath, MAX_PATH);
40 CSysString path = fullPath;
41 int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
42 return path.Left(pos + 1);
44 return CSysString(); // FIX IT
48 #define kCodecsFolderName TEXT("Codecs")
49 #define kFormatsFolderName TEXT("Formats")
50 static TCHAR *kMainDll = TEXT("7z.dll");
53 static LPCTSTR kRegistryPath = TEXT("Software\\7-zip");
54 static LPCTSTR kProgramPathValue = TEXT("Path");
55 static bool ReadPathFromRegistry(HKEY baseKey, CSysString &path)
58 if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
59 if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
61 NName::NormalizeDirPathPrefix(path);
69 CSysString GetBaseFolderPrefixFromRegistry()
71 CSysString moduleFolderPrefix = GetLibraryFolderPrefix();
72 NFind::CFileInfo fileInfo;
73 if (NFind::FindFile(moduleFolderPrefix + kMainDll, fileInfo))
74 if (!fileInfo.IsDirectory())
75 return moduleFolderPrefix;
76 if (NFind::FindFile(moduleFolderPrefix + kCodecsFolderName, fileInfo))
77 if (fileInfo.IsDirectory())
78 return moduleFolderPrefix;
79 if (NFind::FindFile(moduleFolderPrefix + kFormatsFolderName, fileInfo))
80 if (fileInfo.IsDirectory())
81 return moduleFolderPrefix;
84 if (ReadPathFromRegistry(HKEY_CURRENT_USER, path))
86 if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
89 return moduleFolderPrefix;
92 typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods);
93 typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats);
94 typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value);
95 typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value);
96 typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject);
97 typedef UInt32 (WINAPI *SetLargePageModeFunc)();
100 static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index,
101 PROPID propId, CLSID &clsId, bool &isAssigned)
103 NWindows::NCOM::CPropVariant prop;
105 RINOK(getMethodProperty(index, propId, &prop));
106 if (prop.vt == VT_BSTR)
109 clsId = *(const GUID *)prop.bstrVal;
111 else if (prop.vt != VT_EMPTY)
116 HRESULT CCodecs::LoadCodecs()
118 CCodecLib &lib = Libs.Back();
119 lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProcAddress("GetMethodProperty");
120 if (lib.GetMethodProperty == NULL)
123 UInt32 numMethods = 1;
124 GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProcAddress("GetNumberOfMethods");
125 if (getNumberOfMethodsFunc != NULL)
127 RINOK(getNumberOfMethodsFunc(&numMethods));
130 for(UInt32 i = 0; i < numMethods; i++)
133 info.LibIndex = Libs.Size() - 1;
136 RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
137 RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
144 static HRESULT ReadProp(
145 GetHandlerPropertyFunc getProp,
146 GetHandlerPropertyFunc2 getProp2,
147 UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
150 return getProp2(index, propID, &prop);;
151 return getProp(propID, &prop);
154 static HRESULT ReadBoolProp(
155 GetHandlerPropertyFunc getProp,
156 GetHandlerPropertyFunc2 getProp2,
157 UInt32 index, PROPID propID, bool &res)
159 NCOM::CPropVariant prop;
160 RINOK(ReadProp(getProp, getProp2, index, propID, prop));
161 if (prop.vt == VT_BOOL)
162 res = VARIANT_BOOLToBool(prop.boolVal);
163 else if (prop.vt != VT_EMPTY)
168 static HRESULT ReadStringProp(
169 GetHandlerPropertyFunc getProp,
170 GetHandlerPropertyFunc2 getProp2,
171 UInt32 index, PROPID propID, UString &res)
173 NCOM::CPropVariant prop;
174 RINOK(ReadProp(getProp, getProp2, index, propID, prop));
175 if (prop.vt == VT_BSTR)
177 else if (prop.vt != VT_EMPTY)
184 static const unsigned int kNumArcsMax = 32;
185 static unsigned int g_NumArcs = 0;
186 static const CArcInfo *g_Arcs[kNumArcsMax];
187 void RegisterArc(const CArcInfo *arcInfo)
189 if (g_NumArcs < kNumArcsMax)
190 g_Arcs[g_NumArcs++] = arcInfo;
193 static void SplitString(const UString &srcString, UStringVector &destStrings)
197 int len = srcString.Length();
200 for (int i = 0; i < len; i++)
202 wchar_t c = srcString[i];
218 void CArcInfoEx::AddExts(const wchar_t* ext, const wchar_t* addExt)
220 UStringVector exts, addExts;
221 SplitString(ext, exts);
223 SplitString(addExt, addExts);
224 for (int i = 0; i < exts.Size(); i++)
227 extInfo.Ext = exts[i];
228 if (i < addExts.Size())
230 extInfo.AddExt = addExts[i];
231 if (extInfo.AddExt == L"*")
232 extInfo.AddExt.Empty();
238 #ifdef EXTERNAL_CODECS
240 HRESULT CCodecs::LoadFormats()
242 const NDLL::CLibrary &lib = Libs.Back().Lib;
243 GetHandlerPropertyFunc getProp = 0;
244 GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)
245 lib.GetProcAddress("GetHandlerProperty2");
246 if (getProp2 == NULL)
248 getProp = (GetHandlerPropertyFunc)
249 lib.GetProcAddress("GetHandlerProperty");
254 UInt32 numFormats = 1;
255 GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)
256 lib.GetProcAddress("GetNumberOfFormats");
257 if (getNumberOfFormats != NULL)
259 RINOK(getNumberOfFormats(&numFormats));
261 if (getProp2 == NULL)
264 for(UInt32 i = 0; i < numFormats; i++)
267 item.LibIndex = Libs.Size() - 1;
268 item.FormatIndex = i;
270 RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name));
272 NCOM::CPropVariant prop;
273 if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK)
275 if (prop.vt != VT_BSTR)
277 item.ClassID = *(const GUID *)prop.bstrVal;
281 RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext));
282 RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt));
283 item.AddExts(ext, addExt);
285 ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled);
286 if (item.UpdateEnabled)
287 ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName);
289 if (ReadProp(getProp, getProp2, i, NArchive::kStartSignature, prop) == S_OK)
290 if (prop.vt == VT_BSTR)
292 UINT len = ::SysStringByteLen(prop.bstrVal);
293 item.StartSignature.SetCapacity(len);
294 memmove(item.StartSignature, prop.bstrVal, len);
301 #ifdef NEW_FOLDER_INTERFACE
302 void CCodecLib::LoadIcons()
304 UString iconTypes = MyLoadStringW((HMODULE)Lib, kIconTypesResId);
306 SplitString(iconTypes, pairs);
307 for (int i = 0; i < pairs.Size(); i++)
309 const UString &s = pairs[i];
310 int pos = s.Find(L':');
315 UString num = s.Mid(pos + 1);
316 iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end);
319 iconPair.Ext = s.Left(pos);
320 IconPairs.Add(iconPair);
324 int CCodecLib::FindIconIndex(const UString &ext) const
326 for (int i = 0; i < IconPairs.Size(); i++)
328 const CIconPair &pair = IconPairs[i];
329 if (ext.CompareNoCase(pair.Ext) == 0)
330 return pair.IconIndex;
336 #ifdef _7ZIP_LARGE_PAGES
339 extern SIZE_T g_LargePageSize;
343 HRESULT CCodecs::LoadDll(const CSysString &dllPath)
346 NDLL::CLibrary library;
347 if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
350 Libs.Add(CCodecLib());
351 CCodecLib &lib = Libs.Back();
352 #ifdef NEW_FOLDER_INTERFACE
357 if (lib.Lib.Load(dllPath))
359 #ifdef NEW_FOLDER_INTERFACE
363 #ifdef _7ZIP_LARGE_PAGES
364 if (g_LargePageSize != 0)
366 SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProcAddress("SetLargePageMode");
367 if (setLargePageMode != 0)
372 lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProcAddress("CreateObject");
373 if (lib.CreateObject != 0)
375 int startSize = Codecs.Size();
377 used = (Codecs.Size() != startSize);
380 startSize = Formats.Size();
382 used = used || (Formats.Size() != startSize);
391 HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix)
393 NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*")));
394 NFile::NFind::CFileInfo fileInfo;
395 while (enumerator.Next(fileInfo))
397 if (fileInfo.IsDirectory())
399 RINOK(LoadDll(folderPrefix + fileInfo.Name));
407 static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
409 bb.SetCapacity(size);
410 memmove((Byte *)bb, data, size);
414 HRESULT CCodecs::Load()
417 #ifdef EXTERNAL_CODECS
420 for (UInt32 i = 0; i < g_NumArcs; i++)
422 const CArcInfo &arc = *g_Arcs[i];
424 item.Name = arc.Name;
425 item.CreateInArchive = arc.CreateInArchive;
426 item.CreateOutArchive = arc.CreateOutArchive;
427 item.AddExts(arc.Ext, arc.AddExt);
428 item.UpdateEnabled = (arc.CreateOutArchive != 0);
429 item.KeepName = arc.KeepName;
432 SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize);
436 #ifdef EXTERNAL_CODECS
437 const CSysString baseFolder = GetBaseFolderPrefixFromRegistry();
438 RINOK(LoadDll(baseFolder + kMainDll));
439 RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR)));
440 RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR)));
445 int CCodecs::FindFormatForArchiveName(const UString &archivePath) const
447 int slashPos1 = archivePath.ReverseFind(L'\\');
448 int slashPos2 = archivePath.ReverseFind(L'.');
449 int dotPos = archivePath.ReverseFind(L'.');
450 if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
452 UString ext = archivePath.Mid(dotPos + 1);
453 for (int i = 0; i < Formats.Size(); i++)
455 const CArcInfoEx &arc = Formats[i];
456 if (!arc.UpdateEnabled)
458 // if (arc.FindExtension(ext) >= 0)
459 UString mainExt = arc.GetMainExt();
460 if (!mainExt.IsEmpty() && ext.CompareNoCase(mainExt) == 0)
466 int CCodecs::FindFormatForArchiveType(const UString &arcType) const
468 for (int i = 0; i < Formats.Size(); i++)
470 const CArcInfoEx &arc = Formats[i];
471 if (!arc.UpdateEnabled)
473 if (arc.Name.CompareNoCase(arcType) == 0)
479 #ifdef EXTERNAL_CODECS
482 extern unsigned int g_NumCodecs;
483 STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
484 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
485 // STDAPI GetNumberOfMethods(UINT32 *numCodecs);
488 STDMETHODIMP CCodecs::GetNumberOfMethods(UINT32 *numMethods)
498 STDMETHODIMP CCodecs::GetProperty(UINT32 index, PROPID propID, PROPVARIANT *value)
501 if (index < g_NumCodecs)
502 return GetMethodProperty(index, propID, value);
505 const CDllCodecInfo &ci = Codecs[index
511 if (propID == NMethodPropID::kDecoderIsAssigned)
513 NWindows::NCOM::CPropVariant propVariant;
514 propVariant = ci.DecoderIsAssigned;
515 propVariant.Detach(value);
518 if (propID == NMethodPropID::kEncoderIsAssigned)
520 NWindows::NCOM::CPropVariant propVariant;
521 propVariant = ci.EncoderIsAssigned;
522 propVariant.Detach(value);
525 return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
528 STDMETHODIMP CCodecs::CreateDecoder(UINT32 index, const GUID *iid, void **coder)
531 if (index < g_NumCodecs)
532 return CreateCoder2(false, index, iid, coder);
534 const CDllCodecInfo &ci = Codecs[index
539 if (ci.DecoderIsAssigned)
540 return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
544 STDMETHODIMP CCodecs::CreateEncoder(UINT32 index, const GUID *iid, void **coder)
547 if (index < g_NumCodecs)
548 return CreateCoder2(true, index, iid, coder);
550 const CDllCodecInfo &ci = Codecs[index
555 if (ci.EncoderIsAssigned)
556 return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
560 HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
562 for (int i = 0; i < Codecs.Size(); i++)
564 const CDllCodecInfo &codec = Codecs[i];
565 if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
567 const CCodecLib &lib = Libs[codec.LibIndex];
569 NWindows::NCOM::CPropVariant prop;
570 RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
571 if (prop.vt == VT_BSTR)
573 else if (prop.vt != VT_EMPTY)
575 if (name.CompareNoCase(res) == 0)
576 return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
578 return CLASS_E_CLASSNOTAVAILABLE;
581 int CCodecs::GetCodecLibIndex(UInt32 index)
584 if (index < g_NumCodecs)
587 #ifdef EXTERNAL_CODECS
588 const CDllCodecInfo &ci = Codecs[index
599 bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
602 if (index < g_NumCodecs)
604 NWindows::NCOM::CPropVariant prop;
605 if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
606 if (prop.vt != VT_EMPTY)
611 #ifdef EXTERNAL_CODECS
612 const CDllCodecInfo &ci = Codecs[index
617 return ci.EncoderIsAssigned;
623 HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
626 NWindows::NCOM::CPropVariant prop;
627 RINOK(GetProperty(index, NMethodPropID::kID, &prop));
628 if (prop.vt != VT_UI8)
630 id = prop.uhVal.QuadPart;
634 UString CCodecs::GetCodecName(UInt32 index)
637 NWindows::NCOM::CPropVariant prop;
638 if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
639 if (prop.vt == VT_BSTR)