summaryrefslogtreecommitdiffstats
path: root/xbmc/cores/DllLoader
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/cores/DllLoader')
-rw-r--r--xbmc/cores/DllLoader/CMakeLists.txt38
-rw-r--r--xbmc/cores/DllLoader/DllLoader-linux.cpp69
-rw-r--r--xbmc/cores/DllLoader/DllLoader.cpp808
-rw-r--r--xbmc/cores/DllLoader/DllLoader.h113
-rw-r--r--xbmc/cores/DllLoader/DllLoaderContainer.cpp344
-rw-r--r--xbmc/cores/DllLoader/DllLoaderContainer.h37
-rw-r--r--xbmc/cores/DllLoader/LibraryLoader.cpp62
-rw-r--r--xbmc/cores/DllLoader/LibraryLoader.h46
-rw-r--r--xbmc/cores/DllLoader/SoLoader.cpp101
-rw-r--r--xbmc/cores/DllLoader/SoLoader.h35
-rw-r--r--xbmc/cores/DllLoader/Win32DllLoader.cpp408
-rw-r--r--xbmc/cores/DllLoader/Win32DllLoader.h49
-rw-r--r--xbmc/cores/DllLoader/coff.cpp997
-rw-r--r--xbmc/cores/DllLoader/coff.h491
-rw-r--r--xbmc/cores/DllLoader/coffldr.h79
-rw-r--r--xbmc/cores/DllLoader/dll.cpp252
-rw-r--r--xbmc/cores/DllLoader/dll.h20
-rw-r--r--xbmc/cores/DllLoader/dll_tracker.cpp145
-rw-r--r--xbmc/cores/DllLoader/dll_tracker.h132
-rw-r--r--xbmc/cores/DllLoader/dll_tracker_file.cpp134
-rw-r--r--xbmc/cores/DllLoader/dll_tracker_file.h27
-rw-r--r--xbmc/cores/DllLoader/dll_tracker_library.cpp122
-rw-r--r--xbmc/cores/DllLoader/dll_tracker_library.h17
-rw-r--r--xbmc/cores/DllLoader/dll_util.cpp119
-rw-r--r--xbmc/cores/DllLoader/dll_util.h24
-rw-r--r--xbmc/cores/DllLoader/exports/CMakeLists.txt33
-rw-r--r--xbmc/cores/DllLoader/exports/emu_dummy.cpp20
-rw-r--r--xbmc/cores/DllLoader/exports/emu_dummy.h22
-rw-r--r--xbmc/cores/DllLoader/exports/emu_msvcrt.cpp2074
-rw-r--r--xbmc/cores/DllLoader/exports/emu_msvcrt.h167
-rwxr-xr-xxbmc/cores/DllLoader/exports/kernel32.def25
-rwxr-xr-xxbmc/cores/DllLoader/exports/msvcrt.def123
-rwxr-xr-xxbmc/cores/DllLoader/exports/pncrt.def114
-rw-r--r--xbmc/cores/DllLoader/exports/util/CMakeLists.txt5
-rw-r--r--xbmc/cores/DllLoader/exports/util/EmuFileWrapper.cpp232
-rw-r--r--xbmc/cores/DllLoader/exports/util/EmuFileWrapper.h73
-rwxr-xr-xxbmc/cores/DllLoader/exports/winMM.def6
-rw-r--r--xbmc/cores/DllLoader/exports/wrapper.c513
-rw-r--r--xbmc/cores/DllLoader/exports/wrapper_mach_alias62
-rwxr-xr-xxbmc/cores/DllLoader/exports/ws2_32.def25
-rw-r--r--xbmc/cores/DllLoader/ldt_keeper.c282
-rw-r--r--xbmc/cores/DllLoader/ldt_keeper.h38
-rw-r--r--xbmc/cores/DllLoader/mmap_anon.c75
-rw-r--r--xbmc/cores/DllLoader/mmap_anon.h14
44 files changed, 8572 insertions, 0 deletions
diff --git a/xbmc/cores/DllLoader/CMakeLists.txt b/xbmc/cores/DllLoader/CMakeLists.txt
new file mode 100644
index 0000000..313b8fe
--- /dev/null
+++ b/xbmc/cores/DllLoader/CMakeLists.txt
@@ -0,0 +1,38 @@
+set(SOURCES coff.cpp
+ dll.cpp
+ DllLoader.cpp
+ DllLoaderContainer.cpp
+ dll_tracker.cpp
+ dll_tracker_file.cpp
+ dll_tracker_library.cpp
+ dll_util.cpp
+ LibraryLoader.cpp)
+
+set(HEADERS coff.h
+ coffldr.h
+ dll.h
+ DllLoader.h
+ DllLoaderContainer.h
+ dll_tracker.h
+ dll_tracker_file.h
+ dll_tracker_library.h
+ dll_util.h
+ LibraryLoader.h)
+
+if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+ list(APPEND SOURCES mmap_anon.c
+ SoLoader.cpp)
+ list(APPEND HEADERS mmap_anon.h
+ SoLoader.h)
+ if(NOT CORE_SYSTEM_NAME STREQUAL freebsd)
+ list(APPEND SOURCES ldt_keeper.c)
+ list(APPEND HEADERS ldt_keeper.h)
+ endif()
+else()
+ list(APPEND SOURCES Win32DllLoader.cpp)
+ list(APPEND HEADERS Win32DllLoader.h)
+endif()
+
+add_definitions(-DAPI_DEBUG)
+
+core_add_library(dllloader)
diff --git a/xbmc/cores/DllLoader/DllLoader-linux.cpp b/xbmc/cores/DllLoader/DllLoader-linux.cpp
new file mode 100644
index 0000000..4d56e30
--- /dev/null
+++ b/xbmc/cores/DllLoader/DllLoader-linux.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "DllLoader.h"
+#include "DllLoaderContainer.h"
+
+CoffLoader::CoffLoader() :
+ hModule (NULL ),
+ CoffFileHeader (NULL ),
+ OptionHeader (NULL ),
+ WindowsHeader (NULL ),
+ Directory (NULL ),
+ SectionHeader (NULL ),
+ SymTable (NULL ),
+ StringTable (NULL ),
+ SectionData (NULL ),
+ EntryAddress (0 ),
+ NumberOfSymbols (0 ),
+ SizeOfStringTable (0 ),
+ NumOfDirectories (0 ),
+ NumOfSections (0 ),
+ FileHeaderOffset (0 )
+{
+}
+
+CoffLoader::~CoffLoader()
+{
+}
+
+DllLoaderContainer::DllLoaderContainer()
+{
+}
+
+DllLoader* DllLoaderContainer::LoadModule(const char* sName, const char* sCurrentDir, bool bLoadSymbols)
+{
+ return NULL;
+}
+
+bool DllLoader::Load()
+{
+ return false;
+}
+
+void DllLoader::Unload()
+{
+}
+
+void DllLoaderContainer::ReleaseModule(DllLoader*& pDll)
+{
+}
+
+DllLoader::DllLoader(const char *dll, bool track, bool bSystemDll, bool bLoadSymbols, Export* exp)
+{
+}
+
+DllLoader::~DllLoader()
+{
+}
+
+int DllLoader::ResolveExport(const char* x, void** y)
+{
+}
+
+DllLoaderContainer g_dlls;
diff --git a/xbmc/cores/DllLoader/DllLoader.cpp b/xbmc/cores/DllLoader/DllLoader.cpp
new file mode 100644
index 0000000..d7953de
--- /dev/null
+++ b/xbmc/cores/DllLoader/DllLoader.cpp
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include <stdlib.h>
+#include <algorithm>
+
+#include "DllLoader.h"
+#include "DllLoaderContainer.h"
+#include "filesystem/SpecialProtocol.h"
+#include "dll_tracker.h"
+#include "dll_util.h"
+#include <limits>
+#include "utils/log.h"
+
+#ifdef TARGET_WINDOWS
+extern "C" FILE *fopen_utf8(const char *_Filename, const char *_Mode);
+#else
+#define fopen_utf8 fopen
+#endif
+
+#include "commons/Exception.h"
+
+#define DLL_PROCESS_DETACH 0
+#define DLL_PROCESS_ATTACH 1
+#define DLL_THREAD_ATTACH 2
+#define DLL_THREAD_DETACH 3
+#define DLL_PROCESS_VERIFIER 4
+
+
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+
+// Entry point of a dll (DllMain)
+typedef int (APIENTRY *EntryFunc)(HINSTANCE hinstDLL, DWORD fdwReason, void* lpvReserved);
+
+
+#ifdef TARGET_POSIX
+/*
+ * This is a dirty hack.
+ * The win32 DLLs contain an alloca routine, that first probes the soon
+ * to be allocated new memory *below* the current stack pointer in 4KByte
+ * increments. After the mem probing below the current %esp, the stack
+ * pointer is finally decremented to make room for the "alloca"ed memory.
+ * Maybe the probing code is intended to extend the stack on a windows box.
+ * Anyway, the linux kernel does *not* extend the stack by simply accessing
+ * memory below %esp; it segfaults.
+ * The extend_stack_for_dll_alloca() routine just preallocates a big chunk
+ * of memory on the stack, for use by the DLLs alloca routine.
+ * Added the noinline attribute as e.g. gcc 3.2.2 inlines this function
+ * in a way that breaks it.
+ */
+static void __attribute__((noinline)) extend_stack_for_dll_alloca(void)
+{
+ volatile int* mem =(volatile int*)alloca(0x20000);
+ *mem=0x1234;
+}
+#endif
+
+
+DllLoader::DllLoader(const char *sDll, bool bTrack, bool bSystemDll, bool bLoadSymbols, Export* exps) : LibraryLoader(sDll)
+{
+ ImportDirTable = 0;
+ m_pExportHead = NULL;
+ m_pStaticExports = exps;
+ m_bTrack = bTrack;
+ m_bSystemDll = bSystemDll;
+ m_pDlls = NULL;
+
+
+ if(!bSystemDll)
+ {
+ // Initialize FS segment, important for quicktime dll's
+#if defined(USE_LDT_KEEPER)
+ m_ldt_fs = Setup_LDT_Keeper();
+#endif
+ }
+
+ DllLoaderContainer::RegisterDll(this);
+ if (m_bTrack) tracker_dll_add(this);
+ m_bLoadSymbols=bLoadSymbols;
+
+ m_bUnloadSymbols=false;
+
+ /* system dll's are never loaded in any way, so let's just use the pointer */
+ /* to this object as their base address */
+ if (m_bSystemDll)
+ hModule = (HMODULE)this;
+
+}
+
+DllLoader::~DllLoader()
+{
+ while (m_pExportHead)
+ {
+ ExportEntry* entry = m_pExportHead;
+ m_pExportHead = entry->next;
+
+ free(entry);
+ }
+
+ while (m_pDlls)
+ {
+ LoadedList* entry = m_pDlls;
+ m_pDlls = entry->pNext;
+ LibraryLoader* lib = entry->pDll;
+ if (entry->pDll) DllLoaderContainer::ReleaseModule(lib);
+ delete entry;
+ }
+
+ // can't unload a system dll, as this might be happening during xbmc destruction
+ if(!m_bSystemDll)
+ {
+ DllLoaderContainer::UnRegisterDll(this);
+
+#ifdef USE_LDT_KEEPER
+ Restore_LDT_Keeper(m_ldt_fs);
+#endif
+ }
+ if (m_bTrack) tracker_dll_free(this);
+
+ ImportDirTable = 0;
+
+ // hModule points to DllLoader in this case
+ if (m_bSystemDll)
+ hModule = NULL;
+}
+
+int DllLoader::Parse()
+{
+ int iResult = 0;
+
+ std::string strFileName= GetFileName();
+ FILE* fp = fopen_utf8(CSpecialProtocol::TranslatePath(strFileName).c_str(), "rb");
+
+ if (fp)
+ {
+ if (CoffLoader::ParseCoff(fp))
+ {
+ if(WindowsHeader)
+ tracker_dll_set_addr(this, (uintptr_t)hModule,
+ (uintptr_t)hModule + WindowsHeader->SizeOfImage - 1);
+ else
+ {
+ uintptr_t iMinAddr = std::numeric_limits<uintptr_t>::max();
+ uintptr_t iMaxAddr = 0;
+ // dll is loaded now, this means we also know the base address of it and its size
+ for (int i = 0; i < NumOfSections; ++i)
+ {
+ iMinAddr = std::min<uintptr_t>(iMinAddr,
+ (uintptr_t)SectionHeader[i].VirtualAddress);
+ iMaxAddr = std::max<uintptr_t>(iMaxAddr,
+ (uintptr_t)(SectionHeader[i].VirtualAddress +
+ SectionHeader[i].VirtualSize));
+ }
+ if(iMaxAddr > iMinAddr)
+ {
+ iMinAddr += (uintptr_t)hModule;
+ iMaxAddr += (uintptr_t)hModule;
+ tracker_dll_set_addr(this, iMinAddr, iMaxAddr - 1);
+ }
+ }
+ LoadExports();
+ iResult = 1;
+ }
+ fclose(fp);
+ }
+ if (iResult == 0)
+ {
+ m_bTrack = false;
+ }
+ return iResult;
+}
+
+void DllLoader::PrintImportLookupTable(unsigned long ImportLookupTable_RVA)
+{
+ unsigned long *Table = (unsigned long*)RVA2Data(ImportLookupTable_RVA);
+
+ while (*Table)
+ {
+ if (*Table & 0x80000000)
+ {
+ // Process Ordinal...
+ CLog::Log(LOGDEBUG, " Ordinal: {:01X}", *Table & 0x7fffffff);
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, " Don't process Hint/Name Table yet...");
+ }
+ Table++;
+ }
+}
+
+void DllLoader::PrintImportTable(ImportDirTable_t *ImportDirTable)
+{
+ ImportDirTable_t *Imp = ImportDirTable;
+ int HavePrinted = 0;
+
+ CLog::Log(LOGDEBUG, "The Coff Image contains the following imports:");
+ while ( Imp->ImportLookupTable_RVA != 0 ||
+ Imp->TimeStamp != 0 ||
+ Imp->ForwarderChain != 0 ||
+ Imp->Name_RVA != 0 ||
+ Imp->ImportAddressTable_RVA != 0)
+ {
+ char *Name;
+ HavePrinted = 1;
+
+ Name = (char*)RVA2Data(Imp->Name_RVA);
+
+ CLog::Log(LOGDEBUG, " {}:", Name);
+ CLog::Log(LOGDEBUG, " ImportAddressTable: {:04X}", Imp->ImportAddressTable_RVA);
+ CLog::Log(LOGDEBUG, " ImportLookupTable: {:04X}", Imp->ImportLookupTable_RVA);
+ CLog::Log(LOGDEBUG, " TimeStamp: {:01X}", Imp->TimeStamp);
+ CLog::Log(LOGDEBUG, " Forwarder Chain: {:01X}", Imp->ForwarderChain);
+
+ PrintImportLookupTable(Imp->ImportLookupTable_RVA);
+ CLog::Log(LOGDEBUG, "");
+ Imp++;
+ }
+ if (!HavePrinted) CLog::Log(LOGDEBUG, "None.");
+}
+
+void DllLoader::PrintExportTable(ExportDirTable_t *ExportDirTable)
+{
+ char *Name = (char*)RVA2Data(ExportDirTable->Name_RVA);
+
+ unsigned long *ExportAddressTable = (unsigned long*)RVA2Data(ExportDirTable->ExportAddressTable_RVA);
+ unsigned long *NamePointerTable = (unsigned long*)RVA2Data(ExportDirTable->NamePointerTable_RVA);
+ unsigned short *OrdinalTable = (unsigned short*)RVA2Data(ExportDirTable->OrdinalTable_RVA);
+
+
+ CLog::Log(LOGDEBUG, "Export Table for {}:", Name);
+
+ CLog::Log(LOGDEBUG, "ExportFlags: {:04X}", ExportDirTable->ExportFlags);
+ CLog::Log(LOGDEBUG, "TimeStamp: {:04X}", ExportDirTable->TimeStamp);
+ CLog::Log(LOGDEBUG, "Major Ver: {:02X}", ExportDirTable->MajorVersion);
+ CLog::Log(LOGDEBUG, "Minor Ver: {:02X}", ExportDirTable->MinorVersion);
+ CLog::Log(LOGDEBUG, "Name RVA: {:04X}", ExportDirTable->Name_RVA);
+ CLog::Log(LOGDEBUG, "OrdinalBase {}", ExportDirTable->OrdinalBase);
+ CLog::Log(LOGDEBUG, "NumAddrTable {}", ExportDirTable->NumAddrTable);
+ CLog::Log(LOGDEBUG, "NumNamePtrs {}", ExportDirTable->NumNamePtrs);
+ CLog::Log(LOGDEBUG, "ExportAddressTable_RVA {:04X}", ExportDirTable->ExportAddressTable_RVA);
+ CLog::Log(LOGDEBUG, "NamePointerTable_RVA {:04X}", ExportDirTable->NamePointerTable_RVA);
+ CLog::Log(LOGDEBUG, "OrdinalTable_RVA {:04X}", ExportDirTable->OrdinalTable_RVA);
+
+ CLog::Log(LOGDEBUG, "Public Exports:");
+ CLog::Log(LOGDEBUG, " ordinal hint RVA name");
+ for (unsigned int i = 0; i < ExportDirTable->NumNamePtrs; i++)
+ {
+ char *Name = (char*)RVA2Data(NamePointerTable[i]);
+
+ CLog::Log(LOGDEBUG, " {}", OrdinalTable[i] + ExportDirTable->OrdinalBase);
+ CLog::Log(LOGDEBUG, " {}", OrdinalTable[i]);
+ CLog::Log(LOGDEBUG, " {:08X}", ExportAddressTable[OrdinalTable[i]]);
+ CLog::Log(LOGDEBUG, " {}", Name);
+ }
+}
+
+int DllLoader::ResolveImports(void)
+{
+ int bResult = 1;
+ if ( NumOfDirectories >= 2 && Directory[IMPORT_TABLE].Size > 0 )
+ {
+ ImportDirTable = (ImportDirTable_t*)RVA2Data(Directory[IMPORT_TABLE].RVA);
+
+#ifdef DUMPING_DATA
+ PrintImportTable(ImportDirTable);
+#endif
+
+ ImportDirTable_t *Imp = ImportDirTable;
+
+ while ( Imp->ImportLookupTable_RVA != 0 ||
+ Imp->TimeStamp != 0 ||
+ Imp->ForwarderChain != 0 ||
+ Imp->Name_RVA != 0 ||
+ Imp->ImportAddressTable_RVA != 0)
+ {
+ const char *Name = (const char*)RVA2Data(Imp->Name_RVA);
+
+ const char* FileName=ResolveReferencedDll(Name);
+ // If possible use the dll name WITH path to resolve exports. We could have loaded
+ // a dll with the same name as another dll but from a different directory
+ if (FileName) Name=FileName;
+
+ unsigned long *Table = (unsigned long*)RVA2Data(Imp->ImportLookupTable_RVA);
+ unsigned long *Addr = (unsigned long*)RVA2Data(Imp->ImportAddressTable_RVA);
+
+ while (*Table)
+ {
+ if (*Table & 0x80000000)
+ {
+ void *Fixup;
+ if ( !ResolveOrdinal(Name, *Table&0x7ffffff, &Fixup) )
+ {
+ bResult = 0;
+ char szBuf[128];
+ CLog::Log(LOGDEBUG, "Unable to resolve ordinal {} {}", Name, *Table & 0x7ffffff);
+ sprintf(szBuf, "%lu", *Table&0x7ffffff);
+ *Addr = create_dummy_function(Name, szBuf);
+ tracker_dll_data_track(this, *Addr);
+ }
+ else
+ {
+ *Addr = (unsigned long)Fixup; //woohoo!!
+ }
+ }
+ else
+ {
+ // We don't handle Hint/Name tables yet!!!
+ char *ImpName = (char*)RVA2Data(*Table + 2);
+
+ void *Fixup;
+ if ( !ResolveName(Name, ImpName, &Fixup) )
+ {
+ *Addr=get_win_function_address(Name, ImpName);
+ if(!*Addr)
+ {
+ CLog::Log(LOGDEBUG, "Unable to resolve {} {}", Name, ImpName);
+ *Addr = create_dummy_function(Name, ImpName);
+ tracker_dll_data_track(this, *Addr);
+ bResult = 0;
+ }
+ }
+ else
+ {
+ *Addr = (unsigned long)Fixup;
+ }
+ }
+ Table++;
+ Addr++;
+ }
+ Imp++;
+ }
+ }
+ return bResult;
+}
+
+const char* DllLoader::ResolveReferencedDll(const char* dll)
+{
+ DllLoader* pDll = static_cast<DllLoader*>(DllLoaderContainer::LoadModule(dll, GetPath(), m_bLoadSymbols));
+
+ if (!pDll)
+ {
+ CLog::Log(LOGDEBUG, "Unable to load referenced dll {} - Dll: {}", dll, GetFileName());
+ return NULL;
+ }
+ else if (!pDll->IsSystemDll())
+ {
+ LoadedList* entry=new LoadedList;
+ entry->pDll=pDll;
+ entry->pNext=m_pDlls;
+ m_pDlls=entry;
+ }
+
+ return pDll->GetFileName();
+}
+
+int DllLoader::LoadExports()
+{
+ if ( NumOfDirectories > EXPORT_TABLE && Directory[EXPORT_TABLE].Size > 0 )
+ {
+ ExportDirTable = (ExportDirTable_t*)RVA2Data(Directory[EXPORT_TABLE].RVA);
+
+#ifdef DUMPING_DATA
+ PrintExportTable(ExportDirTable);
+#endif
+
+ //! @todo Validate all pointers are valid. Is a zero RVA valid or not? I'd guess not as it would
+ //! point to the coff file header, thus not right.
+
+ unsigned long *ExportAddressTable = (unsigned long*)RVA2Data(ExportDirTable->ExportAddressTable_RVA);
+ unsigned long *NamePointerTable = (unsigned long*)RVA2Data(ExportDirTable->NamePointerTable_RVA);
+ unsigned short *OrdinalTable = (unsigned short*)RVA2Data(ExportDirTable->OrdinalTable_RVA);
+
+ for (unsigned int i = 0; i < ExportDirTable->NumNamePtrs; i++)
+ {
+ char *Name = (char*)RVA2Data(NamePointerTable[i]);
+ void* Addr = (void*)RVA2Data(ExportAddressTable[OrdinalTable[i]]);
+ AddExport(Name, OrdinalTable[i]+ExportDirTable->OrdinalBase, Addr);
+ }
+ }
+ return 0;
+}
+
+int DllLoader::ResolveExport(const char *sName, void **pAddr, bool logging)
+{
+ Export* pExport=GetExportByFunctionName(sName);
+
+ if (pExport)
+ {
+ if (m_bTrack && pExport->track_function)
+ *pAddr=(void*)pExport->track_function;
+ else
+ *pAddr=(void*)pExport->function;
+
+ return 1;
+ }
+
+ const char* sDllName = strrchr(GetFileName(), '\\');
+ if (sDllName) sDllName += 1;
+ else sDllName = GetFileName();
+
+ if (logging)
+ CLog::Log(LOGWARNING, "Unable to resolve: {} {}", sDllName, sName);
+ return 0;
+}
+
+int DllLoader::ResolveOrdinal(unsigned long ordinal, void **pAddr)
+{
+ Export* pExport=GetExportByOrdinal(ordinal);
+
+ if (pExport)
+ {
+ if (m_bTrack && pExport->track_function)
+ *pAddr=(void*)pExport->track_function;
+ else
+ *pAddr=(void*)pExport->function;
+
+ return 1;
+ }
+
+ const char* sDllName = strrchr(GetFileName(), '\\');
+ if (sDllName) sDllName += 1;
+ else sDllName = GetFileName();
+
+ CLog::Log(LOGWARNING, "Unable to resolve: {} {}", sDllName, ordinal);
+ return 0;
+}
+
+Export* DllLoader::GetExportByOrdinal(unsigned long ordinal)
+{
+ ExportEntry* entry = m_pExportHead;
+
+ while (entry)
+ {
+ if (ordinal == entry->exp.ordinal)
+ {
+ return &entry->exp;
+ }
+ entry = entry->next;
+ }
+
+ if( m_pStaticExports )
+ {
+ Export* exp = m_pStaticExports;
+ while(exp->function || exp->track_function || exp->name)
+ {
+ if (ordinal == exp->ordinal)
+ return exp;
+ exp++;
+ }
+ }
+
+ return NULL;
+}
+
+Export* DllLoader::GetExportByFunctionName(const char* sFunctionName)
+{
+ ExportEntry* entry = m_pExportHead;
+
+ while (entry)
+ {
+ if (entry->exp.name && strcmp(sFunctionName, entry->exp.name) == 0)
+ {
+ return &entry->exp;
+ }
+ entry = entry->next;
+ }
+
+ if( m_pStaticExports )
+ {
+ Export* exp = m_pStaticExports;
+ while(exp->function || exp->track_function || exp->name)
+ {
+ if (exp->name && strcmp(sFunctionName, exp->name) == 0)
+ return exp;
+ exp++;
+ }
+ }
+
+ return NULL;
+}
+
+int DllLoader::ResolveOrdinal(const char *sName, unsigned long ordinal, void **fixup)
+{
+ DllLoader* pDll = static_cast<DllLoader*>(DllLoaderContainer::GetModule(sName));
+
+ if (pDll)
+ {
+ Export* pExp = pDll->GetExportByOrdinal(ordinal);
+ if(pExp)
+ {
+ if (m_bTrack && pExp->track_function)
+ *fixup = (void*)(pExp->track_function);
+ else
+ *fixup = (void*)(pExp->function);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int DllLoader::ResolveName(const char *sName, char* sFunction, void **fixup)
+{
+ DllLoader* pDll = static_cast<DllLoader*>(DllLoaderContainer::GetModule(sName));
+
+ if (pDll)
+ {
+ Export* pExp = pDll->GetExportByFunctionName(sFunction);
+ if(pExp)
+ {
+ if (m_bTrack && pExp->track_function)
+ *fixup = (void*)(pExp->track_function);
+ else
+ *fixup = (void*)(pExp->function);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void DllLoader::AddExport(unsigned long ordinal, void* function, void* track_function)
+{
+ ExportEntry* entry = (ExportEntry*)malloc(sizeof(ExportEntry));
+ if (!entry)
+ return;
+ entry->exp.function = function;
+ entry->exp.ordinal = ordinal;
+ entry->exp.track_function = track_function;
+ entry->exp.name = NULL;
+
+ entry->next = m_pExportHead;
+ m_pExportHead = entry;
+}
+
+void DllLoader::AddExport(char* sFunctionName, unsigned long ordinal, void* function, void* track_function)
+{
+ int len = sizeof(ExportEntry);
+
+ ExportEntry* entry = (ExportEntry*)malloc(len + strlen(sFunctionName) + 1);
+ if (!entry)
+ return;
+ entry->exp.function = function;
+ entry->exp.ordinal = ordinal;
+ entry->exp.track_function = track_function;
+ entry->exp.name = ((char*)(entry)) + len;
+ strcpy(const_cast<char*>(entry->exp.name), sFunctionName);
+
+ entry->next = m_pExportHead;
+ m_pExportHead = entry;
+}
+
+void DllLoader::AddExport(char* sFunctionName, void* function, void* track_function)
+{
+ int len = sizeof(ExportEntry);
+
+ ExportEntry* entry = (ExportEntry*)malloc(len + strlen(sFunctionName) + 1);
+ if (!entry)
+ return;
+ entry->exp.function = (void*)function;
+ entry->exp.ordinal = -1;
+ entry->exp.track_function = track_function;
+ entry->exp.name = ((char*)(entry)) + len;
+ strcpy(const_cast<char*>(entry->exp.name), sFunctionName);
+
+ entry->next = m_pExportHead;
+ m_pExportHead = entry;
+}
+
+bool DllLoader::Load()
+{
+ if (!Parse())
+ {
+ CLog::Log(LOGERROR, "Unable to open dll {}", GetFileName());
+ return false;
+ }
+
+ ResolveImports();
+ LoadSymbols();
+
+ // only execute DllMain if no EntryPoint is found
+ if (!EntryAddress)
+ ResolveExport("DllMain", (void**)&EntryAddress);
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Executing EntryPoint with DLL_PROCESS_ATTACH at: 0x{:x} - Dll: {}",
+ pLoader->EntryAddress, sName);
+#endif
+
+ if(EntryAddress)
+ {
+ EntryFunc initdll = (EntryFunc)EntryAddress;
+ /* since we are handing execution over to unknown code, safeguard here */
+ try
+ {
+#ifdef TARGET_POSIX
+ extend_stack_for_dll_alloca();
+#endif
+ initdll((HINSTANCE)hModule, DLL_PROCESS_ATTACH , 0); //call "DllMain" with DLL_PROCESS_ATTACH
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "EntryPoint with DLL_PROCESS_ATTACH called - Dll: {}", sName);
+#endif
+
+ }
+ XBMCCOMMONS_HANDLE_UNCHECKED
+ catch(...)
+ {
+ CLog::Log(LOGERROR, "{} - Unhandled exception during DLL_PROCESS_ATTACH", __FUNCTION__);
+
+ // vp7vfw.dll throws a CUserException due to a missing export
+ // but the export isn't really needed for normal operation
+ // and dll works anyway, so let's ignore it
+
+ if (StringUtils::CompareNoCase(GetName(), "vp7vfw.dll") != 0)
+ return false;
+
+
+ CLog::Log(LOGDEBUG, "{} - Ignoring exception during DLL_PROCESS_ATTACH", __FUNCTION__);
+ }
+
+ // init function may have fixed up the export table
+ // this is what I expect should happens on PECompact2
+ // dll's if export table is compressed.
+ if(!m_pExportHead)
+ LoadExports();
+ }
+
+ return true;
+}
+
+void DllLoader::Unload()
+{
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Executing EntryPoint with DLL_PROCESS_DETACH at: 0x{:x} - Dll: {}",
+ pDll->EntryAddress, pDll->GetFileName());
+#endif
+
+ //call "DllMain" with DLL_PROCESS_DETACH
+ if(EntryAddress)
+ {
+ EntryFunc initdll = (EntryFunc)EntryAddress;
+ initdll((HINSTANCE)hModule, DLL_PROCESS_DETACH , 0);
+ }
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "EntryPoint with DLL_PROCESS_DETACH called - Dll: {}", pDll->GetFileName());
+#endif
+
+ if (m_bUnloadSymbols)
+ UnloadSymbols();
+}
+
+// This function is a hack to get symbols loaded for
+// dlls. The function FFinishImageLoad internally allocates
+// memory which is/can never be freed. And the dll can not be
+// unloaded.
+void DllLoader::LoadSymbols()
+{
+#ifdef ENABLE_SYMBOL_LOADING
+ if (!m_bLoadSymbols ) return;
+
+ // don't load debug symbols unless we have a debugger present
+ // seems these calls break on some bioses. i suppose it could
+ // be related to if the bios has debug capabilities.
+ if (!DmIsDebuggerPresent())
+ {
+ m_bLoadSymbols=false;
+ return;
+ }
+
+ LPVOID pBaseAddress=GetXbdmBaseAddress();
+
+ if (pBaseAddress)
+ {
+ CoffLoader dllxbdm;
+ if (dllxbdm.ParseHeaders(pBaseAddress))
+ {
+ int offset=GetFFinishImageLoadOffset(dllxbdm.WindowsHeader->CheckSum);
+
+ if (offset==0)
+ {
+ CLog::Log(LOGDEBUG,
+ "DllLoader: Unable to load symbols for {}. No offset for xbdm.dll with checksum "
+ "{:#08X} found",
+ GetName(), dllxbdm.WindowsHeader->CheckSum);
+ return;
+ }
+
+ // Get a function pointer to the unexported function FFinishImageLoad
+ fnFFinishImageLoad FFinishImageLoad=(fnFFinishImageLoad)((LPBYTE)pBaseAddress+offset);
+
+ // Prepare parameter for the function call
+ LDR_DATA_TABLE_ENTRY ldte;
+ LPLDR_DATA_TABLE_ENTRY pldteout;
+ ldte.DllBase=hModule; // Address where this dll is loaded into memory
+ char* szName=GetName(); // Name of this dll without path
+
+ try
+ {
+ // Call FFinishImageLoad to register this dll to the debugger and load its symbols.
+ FFinishImageLoad(&ldte, szName, &pldteout);
+ }
+ catch(...)
+ {
+ CLog::Log(LOGDEBUG, "DllLoader: Loading symbols for {} failed with an exception.",
+ GetName());
+ }
+ }
+ }
+ else
+ CLog::Log(LOGDEBUG, "DllLoader: Can't load symbols for {}. xbdm.dll is needed and not loaded",
+ GetName());
+
+#ifdef ENABLE_SYMBOL_UNLOADING
+ m_bUnloadSymbols=true; // Do this to allow unloading this dll from dllloadercontainer
+#endif
+
+#else
+ m_bLoadSymbols=false;
+#endif
+}
+
+// This function is even more a hack
+// It will remove the dll from the Debug manager
+// but vs.net does not unload the symbols (don't know why)
+// The dll can be loaded again after unloading.
+// This function leaks memory.
+void DllLoader::UnloadSymbols()
+{
+#ifdef ENABLE_SYMBOL_UNLOADING
+ ANSI_STRING name;
+ OBJECT_ATTRIBUTES attributes;
+ RtlInitAnsiString(&name, GetName());
+ InitializeObjectAttributes(&attributes, &name, OBJ_CASE_INSENSITIVE, NULL);
+
+ // Try to unload the symbols from vs.net debugger
+ DbgUnLoadImageSymbols(&name, (ULONG)hModule, 0xFFFFFFFF);
+
+ LPVOID pBaseAddress=GetXbdmBaseAddress();
+
+ if (pBaseAddress)
+ {
+ CoffLoader dllxbdm;
+ if (dllxbdm.ParseHeaders(pBaseAddress))
+ {
+ int offset=GetDmiOffset(dllxbdm.WindowsHeader->CheckSum);
+
+ if (offset==0)
+ {
+ CLog::Log(LOGDEBUG,
+ "DllLoader: Unable to unload symbols for {}. No offset for xbdm.dll with "
+ "checksum {:#08X} found",
+ GetName(), dllxbdm.WindowsHeader->CheckSum);
+ return;
+ }
+
+ try
+ {
+ std::wstring strNameW;
+ g_charsetConverter.utf8ToW(GetName(), strNameW);
+
+ // Get the address of the global struct g_dmi
+ // It is located inside the xbdm.dll and
+ // get the LoadedModuleList member (here the entry var)
+ // of the structure.
+ LPBYTE g_dmi=((LPBYTE)pBaseAddress)+offset;
+ LIST_ENTRY* entry=(LIST_ENTRY*)(g_dmi+4);
+
+ // Search for the dll we are unloading...
+ while (entry)
+ {
+ std::wstring baseName=(wchar_t*)((LDR_DATA_TABLE_ENTRY*)entry)->BaseDllName.Buffer;
+ if (baseName == strNameW)
+ {
+ // ...and remove it from the LoadedModuleList and free its memory.
+ LIST_ENTRY* back=entry->Blink;
+ LIST_ENTRY* front=entry->Flink;
+ back->Flink=front;
+ front->Blink=back;
+ DmFreePool(entry);
+ break;
+ }
+
+ entry=entry->Flink;
+ }
+ }
+ catch(...)
+ {
+ CLog::Log(LOGDEBUG, "DllLoader: Unloading symbols for {} failed with an exception.",
+ GetName());
+ }
+ }
+ }
+ else
+ CLog::Log(LOGDEBUG, "DllLoader: Can't unload symbols for {}. xbdm.dll is needed and not loaded",
+ GetName());
+#endif
+}
diff --git a/xbmc/cores/DllLoader/DllLoader.h b/xbmc/cores/DllLoader/DllLoader.h
new file mode 100644
index 0000000..79e019d
--- /dev/null
+++ b/xbmc/cores/DllLoader/DllLoader.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "coffldr.h"
+#include "LibraryLoader.h"
+
+// clang-format off
+#if defined(__linux__) && \
+ !defined(__aarch64__) && \
+ !defined(__alpha__) && \
+ !defined(__arc__) && \
+ !defined(__arm__) && \
+ !defined(__loongarch__) && \
+ !defined(__mips__) && \
+ !defined(__powerpc__) && \
+ !defined(__or1k__) && \
+ !defined(__riscv) && \
+ !defined(__SH4__) && \
+ !defined(__s390x__) && \
+ !defined(__sparc__) && \
+ !defined(__xtensa__)
+#define USE_LDT_KEEPER
+#include "ldt_keeper.h"
+#endif
+// clang-format on
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+class DllLoader;
+
+
+typedef struct Export
+{
+ const char* name;
+ unsigned long ordinal;
+ void* function;
+ void* track_function;
+} Export;
+
+typedef struct ExportEntry
+{
+ Export exp;
+ ExportEntry* next;
+} ExportEntry;
+
+typedef struct _LoadedList
+{
+ DllLoader* pDll;
+ _LoadedList* pNext;
+} LoadedList;
+
+class DllLoader : public CoffLoader, public LibraryLoader
+{
+public:
+ DllLoader(const char *dll, bool track = false, bool bSystemDll = false, bool bLoadSymbols = false, Export* exports = NULL);
+ ~DllLoader() override;
+
+ bool Load() override;
+ void Unload() override;
+
+ int ResolveExport(const char*, void** ptr, bool logging = true) override;
+ int ResolveOrdinal(unsigned long ordinal, void** ptr) override;
+ bool HasSymbols() override { return m_bLoadSymbols && !m_bUnloadSymbols; }
+ bool IsSystemDll() override { return m_bSystemDll; }
+ HMODULE GetHModule() override { return (HMODULE)hModule; }
+
+ Export* GetExportByFunctionName(const char* sFunctionName);
+ Export* GetExportByOrdinal(unsigned long ordinal);
+protected:
+ int Parse();
+ int ResolveImports();
+
+ void AddExport(unsigned long ordinal, void* function, void* track_function = NULL);
+ void AddExport(char* sFunctionName, unsigned long ordinal, void* function, void* track_function = NULL);
+ void AddExport(char* sFunctionName, void* function, void* track_function = NULL);
+ void SetExports(Export* exports) { m_pStaticExports = exports; }
+
+protected:
+ // Just pointers; don't delete...
+ ImportDirTable_t *ImportDirTable;
+ ExportDirTable_t *ExportDirTable;
+ bool m_bTrack;
+ bool m_bSystemDll; // true if this dll should not be removed
+ bool m_bLoadSymbols; // when true this dll should not be removed
+ bool m_bUnloadSymbols;
+ ExportEntry* m_pExportHead;
+ Export* m_pStaticExports;
+ LoadedList* m_pDlls;
+
+#ifdef USE_LDT_KEEPER
+ ldt_fs_t* m_ldt_fs;
+#endif
+
+ void PrintImportLookupTable(unsigned long ImportLookupTable_RVA);
+ void PrintImportTable(ImportDirTable_t *ImportDirTable);
+ void PrintExportTable(ExportDirTable_t *ExportDirTable);
+
+ int ResolveOrdinal(const char*, unsigned long, void**);
+ int ResolveName(const char*, char*, void **);
+ const char* ResolveReferencedDll(const char* dll);
+ int LoadExports();
+ void LoadSymbols();
+ static void UnloadSymbols();
+};
diff --git a/xbmc/cores/DllLoader/DllLoaderContainer.cpp b/xbmc/cores/DllLoader/DllLoaderContainer.cpp
new file mode 100644
index 0000000..e56b02f
--- /dev/null
+++ b/xbmc/cores/DllLoader/DllLoaderContainer.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "DllLoaderContainer.h"
+#ifdef TARGET_POSIX
+#include "SoLoader.h"
+#endif
+#ifdef TARGET_WINDOWS
+#include "Win32DllLoader.h"
+#endif
+#include "DllLoader.h"
+#include "dll_tracker.h" // for python unload hack
+#include "filesystem/File.h"
+#include "utils/URIUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+#include "URL.h"
+
+#if defined(TARGET_WINDOWS)
+#define ENV_PARTIAL_PATH \
+ "special://xbmcbin/;" \
+ "special://xbmcbin/system/;" \
+ "special://xbmcbin/system/python/;" \
+ "special://xbmc/;" \
+ "special://xbmc/system/;" \
+ "special://xbmc/system/python/"
+#else
+#define ENV_PARTIAL_PATH \
+ "special://xbmcbin/system/;" \
+ "special://xbmcbin/system/players/mplayer/;" \
+ "special://xbmcbin/system/players/VideoPlayer/;" \
+ "special://xbmcbin/system/players/paplayer/;" \
+ "special://xbmcbin/system/python/;" \
+ "special://xbmc/system/;" \
+ "special://xbmc/system/players/mplayer/;" \
+ "special://xbmc/system/players/VideoPlayer/;" \
+ "special://xbmc/system/players/paplayer/;" \
+ "special://xbmc/system/python/"
+#endif
+#if defined(TARGET_DARWIN)
+#define ENV_PATH ENV_PARTIAL_PATH \
+ ";special://frameworks/"
+#else
+#define ENV_PATH ENV_PARTIAL_PATH
+#endif
+
+//Define this to get logging on all calls to load/unload of dlls
+//#define LOGALL
+
+
+using namespace XFILE;
+
+LibraryLoader* DllLoaderContainer::m_dlls[64] = {};
+int DllLoaderContainer::m_iNrOfDlls = 0;
+bool DllLoaderContainer::m_bTrack = true;
+
+void DllLoaderContainer::Clear()
+{
+}
+
+HMODULE DllLoaderContainer::GetModuleAddress(const char* sName)
+{
+ return (HMODULE)GetModule(sName);
+}
+
+LibraryLoader* DllLoaderContainer::GetModule(const char* sName)
+{
+ for (int i = 0; i < m_iNrOfDlls && m_dlls[i] != NULL; i++)
+ {
+ if (StringUtils::CompareNoCase(m_dlls[i]->GetName(), sName) == 0)
+ return m_dlls[i];
+ if (!m_dlls[i]->IsSystemDll() &&
+ StringUtils::CompareNoCase(m_dlls[i]->GetFileName(), sName) == 0)
+ return m_dlls[i];
+ }
+
+ return NULL;
+}
+
+LibraryLoader* DllLoaderContainer::GetModule(const HMODULE hModule)
+{
+ for (int i = 0; i < m_iNrOfDlls && m_dlls[i] != NULL; i++)
+ {
+ if (m_dlls[i]->GetHModule() == hModule) return m_dlls[i];
+ }
+ return NULL;
+}
+
+LibraryLoader* DllLoaderContainer::LoadModule(const char* sName, const char* sCurrentDir/*=NULL*/, bool bLoadSymbols/*=false*/)
+{
+ LibraryLoader* pDll=NULL;
+
+ if (IsSystemDll(sName))
+ {
+ pDll = GetModule(sName);
+ }
+ else if (sCurrentDir)
+ {
+ std::string strPath=sCurrentDir;
+ strPath+=sName;
+ pDll = GetModule(strPath.c_str());
+ }
+
+ if (!pDll)
+ {
+ pDll = GetModule(sName);
+ }
+
+ if (!pDll)
+ {
+ pDll = FindModule(sName, sCurrentDir, bLoadSymbols);
+ }
+ else if (!pDll->IsSystemDll())
+ {
+ pDll->IncrRef();
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Already loaded Dll {} at 0x{:x}", pDll->GetFileName(), pDll);
+#endif
+
+ }
+
+ return pDll;
+}
+
+LibraryLoader* DllLoaderContainer::FindModule(const char* sName, const char* sCurrentDir, bool bLoadSymbols)
+{
+ if (URIUtils::IsInArchive(sName))
+ {
+ CURL url(sName);
+ std::string newName = "special://temp/";
+ newName += url.GetFileName();
+ CFile::Copy(sName, newName);
+ return FindModule(newName.c_str(), sCurrentDir, bLoadSymbols);
+ }
+
+ if (CURL::IsFullPath(sName))
+ { // Has a path, just try to load
+ return LoadDll(sName, bLoadSymbols);
+ }
+#ifdef TARGET_POSIX
+ else if (strcmp(sName, "xbmc.so") == 0)
+ return LoadDll(sName, bLoadSymbols);
+#endif
+ else if (sCurrentDir)
+ { // in the path of the parent dll?
+ std::string strPath=sCurrentDir;
+ strPath+=sName;
+
+ if (CFile::Exists(strPath))
+ return LoadDll(strPath.c_str(), bLoadSymbols);
+ }
+
+ // in environment variable?
+ std::vector<std::string> vecEnv;
+
+#if defined(TARGET_ANDROID)
+ std::string systemLibs = getenv("KODI_ANDROID_SYSTEM_LIBS");
+ vecEnv = StringUtils::Split(systemLibs, ':');
+ std::string localLibs = getenv("KODI_ANDROID_LIBS");
+ vecEnv.insert(vecEnv.begin(),localLibs);
+#else
+ vecEnv = StringUtils::Split(ENV_PATH, ';');
+#endif
+ LibraryLoader* pDll = NULL;
+
+ for (std::vector<std::string>::const_iterator i = vecEnv.begin(); i != vecEnv.end(); ++i)
+ {
+ std::string strPath = *i;
+ URIUtils::AddSlashAtEnd(strPath);
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Searching for the dll {} in directory {}", sName, strPath);
+#endif
+
+ strPath+=sName;
+
+ // Have we already loaded this dll
+ if ((pDll = GetModule(strPath.c_str())) != NULL)
+ return pDll;
+
+ if (CFile::Exists(strPath))
+ return LoadDll(strPath.c_str(), bLoadSymbols);
+ }
+
+ // can't find it in any of our paths - could be a system dll
+ if ((pDll = LoadDll(sName, bLoadSymbols)) != NULL)
+ return pDll;
+
+ CLog::Log(LOGDEBUG, "Dll {} was not found in path", sName);
+ return NULL;
+}
+
+void DllLoaderContainer::ReleaseModule(LibraryLoader*& pDll)
+{
+ if (!pDll)
+ return;
+ if (pDll->IsSystemDll())
+ {
+ CLog::Log(LOGFATAL, "{} is a system dll and should never be released", pDll->GetName());
+ return;
+ }
+
+ int iRefCount=pDll->DecrRef();
+ if (iRefCount==0)
+ {
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Releasing Dll {}", pDll->GetFileName());
+#endif
+
+ if (!pDll->HasSymbols())
+ {
+ pDll->Unload();
+ delete pDll;
+ pDll=NULL;
+ }
+ else
+ CLog::Log(LOGINFO, "{} has symbols loaded and can never be unloaded", pDll->GetName());
+ }
+#ifdef LOGALL
+ else
+ {
+ CLog::Log(LOGDEBUG, "Dll {} is still referenced with a count of {}", pDll->GetFileName(),
+ iRefCount);
+ }
+#endif
+}
+
+LibraryLoader* DllLoaderContainer::LoadDll(const char* sName, bool bLoadSymbols)
+{
+
+#ifdef LOGALL
+ CLog::Log(LOGDEBUG, "Loading dll {}", sName);
+#endif
+
+ LibraryLoader* pLoader;
+#ifdef TARGET_POSIX
+ pLoader = new SoLoader(sName, bLoadSymbols);
+#elif defined(TARGET_WINDOWS)
+ pLoader = new Win32DllLoader(sName, false);
+#else
+ pLoader = new DllLoader(sName, m_bTrack, false, bLoadSymbols);
+#endif
+
+ if (!pLoader)
+ {
+ CLog::Log(LOGERROR, "Unable to create dll {}", sName);
+ return NULL;
+ }
+
+ if (!pLoader->Load())
+ {
+ delete pLoader;
+ return NULL;
+ }
+
+ return pLoader;
+}
+
+bool DllLoaderContainer::IsSystemDll(const char* sName)
+{
+ for (int i = 0; i < m_iNrOfDlls && m_dlls[i] != NULL; i++)
+ {
+ if (m_dlls[i]->IsSystemDll() && StringUtils::CompareNoCase(m_dlls[i]->GetName(), sName) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+int DllLoaderContainer::GetNrOfModules()
+{
+ return m_iNrOfDlls;
+}
+
+LibraryLoader* DllLoaderContainer::GetModule(int iPos)
+{
+ if (iPos < m_iNrOfDlls) return m_dlls[iPos];
+ return NULL;
+}
+
+void DllLoaderContainer::RegisterDll(LibraryLoader* pDll)
+{
+ for (LibraryLoader*& dll : m_dlls)
+ {
+ if (dll == NULL)
+ {
+ dll = pDll;
+ m_iNrOfDlls++;
+ break;
+ }
+ }
+}
+
+void DllLoaderContainer::UnRegisterDll(LibraryLoader* pDll)
+{
+ if (pDll)
+ {
+ if (pDll->IsSystemDll())
+ {
+ CLog::Log(LOGFATAL, "{} is a system dll and should never be removed", pDll->GetName());
+ }
+ else
+ {
+ // remove from the list
+ bool bRemoved = false;
+ for (int i = 0; i < m_iNrOfDlls && m_dlls[i]; i++)
+ {
+ if (m_dlls[i] == pDll) bRemoved = true;
+ if (bRemoved && i + 1 < m_iNrOfDlls)
+ {
+ m_dlls[i] = m_dlls[i + 1];
+ }
+ }
+ if (bRemoved)
+ {
+ m_iNrOfDlls--;
+ m_dlls[m_iNrOfDlls] = NULL;
+ }
+ }
+ }
+}
+
+void DllLoaderContainer::UnloadPythonDlls()
+{
+ // unload all dlls that python could have loaded
+ for (int i = 0; i < m_iNrOfDlls && m_dlls[i] != NULL; i++)
+ {
+ const char* name = m_dlls[i]->GetName();
+ if (strstr(name, ".pyd") != NULL)
+ {
+ LibraryLoader* pDll = m_dlls[i];
+ ReleaseModule(pDll);
+ i = 0;
+ }
+ }
+
+}
diff --git a/xbmc/cores/DllLoader/DllLoaderContainer.h b/xbmc/cores/DllLoader/DllLoaderContainer.h
new file mode 100644
index 0000000..3769ff8
--- /dev/null
+++ b/xbmc/cores/DllLoader/DllLoaderContainer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "LibraryLoader.h"
+
+class DllLoaderContainer
+{
+public:
+ static void Clear();
+ static HMODULE GetModuleAddress(const char* sName);
+ static int GetNrOfModules();
+ static LibraryLoader* GetModule(int iPos);
+ static LibraryLoader* GetModule(const char* sName);
+ static LibraryLoader* GetModule(const HMODULE hModule);
+ static LibraryLoader* LoadModule(const char* sName, const char* sCurrentDir=NULL, bool bLoadSymbols=false);
+ static void ReleaseModule(LibraryLoader*& pDll);
+
+ static void RegisterDll(LibraryLoader* pDll);
+ static void UnRegisterDll(LibraryLoader* pDll);
+ static void UnloadPythonDlls();
+
+private:
+ static LibraryLoader* FindModule(const char* sName, const char* sCurrentDir, bool bLoadSymbols);
+ static LibraryLoader* LoadDll(const char* sName, bool bLoadSymbols);
+ static bool IsSystemDll(const char* sName);
+
+ static LibraryLoader* m_dlls[64];
+ static int m_iNrOfDlls;
+ static bool m_bTrack;
+};
diff --git a/xbmc/cores/DllLoader/LibraryLoader.cpp b/xbmc/cores/DllLoader/LibraryLoader.cpp
new file mode 100644
index 0000000..5689900
--- /dev/null
+++ b/xbmc/cores/DllLoader/LibraryLoader.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "LibraryLoader.h"
+
+#include "utils/log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+LibraryLoader::LibraryLoader(const std::string& libraryFile):
+ m_fileName(libraryFile)
+{
+ size_t pos = m_fileName.find_last_of("\\/");
+ if (pos != std::string::npos)
+ m_path = m_fileName.substr(0, pos);
+
+ m_iRefCount = 1;
+}
+
+LibraryLoader::~LibraryLoader() = default;
+
+const char *LibraryLoader::GetName() const
+{
+ size_t pos = m_fileName.find_last_of('/');
+ if (pos != std::string::npos)
+ return &m_fileName.at(pos + 1); // don't include /
+ return m_fileName.c_str();
+}
+
+const char *LibraryLoader::GetFileName() const
+{
+ return m_fileName.c_str();
+}
+
+const char *LibraryLoader::GetPath() const
+{
+ return m_path.c_str();
+}
+
+int LibraryLoader::IncrRef()
+{
+ m_iRefCount++;
+ return m_iRefCount;
+}
+
+int LibraryLoader::DecrRef()
+{
+ m_iRefCount--;
+ return m_iRefCount;
+}
+
+int LibraryLoader::ResolveOrdinal(unsigned long ordinal, void** ptr)
+{
+ CLog::Log(LOGWARNING, "{} - Unable to resolve {} in dll {}", __FUNCTION__, ordinal, GetName());
+ return 0;
+}
diff --git a/xbmc/cores/DllLoader/LibraryLoader.h b/xbmc/cores/DllLoader/LibraryLoader.h
new file mode 100644
index 0000000..a8db986
--- /dev/null
+++ b/xbmc/cores/DllLoader/LibraryLoader.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#ifdef TARGET_POSIX
+#include "PlatformDefs.h"
+#endif
+
+class LibraryLoader
+{
+public:
+ explicit LibraryLoader(const std::string& libraryFile);
+ virtual ~LibraryLoader();
+
+ virtual bool Load() = 0;
+ virtual void Unload() = 0;
+
+ virtual int ResolveExport(const char* symbol, void** ptr, bool logging = true) = 0;
+ virtual int ResolveOrdinal(unsigned long ordinal, void** ptr);
+ virtual bool IsSystemDll() = 0;
+ virtual HMODULE GetHModule() = 0;
+ virtual bool HasSymbols() = 0;
+
+ const char *GetName() const; // eg "mplayer.dll"
+ const char *GetFileName() const; // "special://xbmcbin/system/mplayer/players/mplayer.dll"
+ const char *GetPath() const; // "special://xbmcbin/system/mplayer/players/"
+
+ int IncrRef();
+ int DecrRef();
+ int GetRef();
+
+private:
+ LibraryLoader(const LibraryLoader&);
+ LibraryLoader& operator=(const LibraryLoader&);
+ std::string m_fileName;
+ std::string m_path;
+ int m_iRefCount;
+};
diff --git a/xbmc/cores/DllLoader/SoLoader.cpp b/xbmc/cores/DllLoader/SoLoader.cpp
new file mode 100644
index 0000000..2b5cbce
--- /dev/null
+++ b/xbmc/cores/DllLoader/SoLoader.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "SoLoader.h"
+
+#include "filesystem/SpecialProtocol.h"
+#include "utils/log.h"
+
+#include <dlfcn.h>
+
+SoLoader::SoLoader(const std::string &so, bool bGlobal) : LibraryLoader(so)
+{
+ m_soHandle = NULL;
+ m_bGlobal = bGlobal;
+ m_bLoaded = false;
+}
+
+SoLoader::~SoLoader()
+{
+ if (m_bLoaded)
+ Unload();
+}
+
+bool SoLoader::Load()
+{
+ if (m_soHandle != NULL)
+ return true;
+
+ std::string strFileName= CSpecialProtocol::TranslatePath(GetFileName());
+ if (strFileName == "xbmc.so")
+ {
+ CLog::Log(LOGDEBUG, "Loading Internal Library");
+ m_soHandle = RTLD_DEFAULT;
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "Loading: {}", strFileName);
+ int flags = RTLD_LAZY;
+ m_soHandle = dlopen(strFileName.c_str(), flags);
+ if (!m_soHandle)
+ {
+ CLog::Log(LOGERROR, "Unable to load {}, reason: {}", strFileName, dlerror());
+ return false;
+ }
+ }
+ m_bLoaded = true;
+ return true;
+}
+
+void SoLoader::Unload()
+{
+
+ if (m_soHandle)
+ {
+ if (dlclose(m_soHandle) != 0)
+ CLog::Log(LOGERROR, "Unable to unload {}, reason: {}", GetName(), dlerror());
+ }
+ m_bLoaded = false;
+ m_soHandle = NULL;
+}
+
+int SoLoader::ResolveExport(const char* symbol, void** f, bool logging)
+{
+ if (!m_bLoaded && !Load())
+ {
+ if (logging)
+ CLog::Log(LOGWARNING, "Unable to resolve: {} {}, reason: so not loaded", GetName(), symbol);
+ return 0;
+ }
+
+ void* s = dlsym(m_soHandle, symbol);
+ if (!s)
+ {
+ if (logging)
+ CLog::Log(LOGWARNING, "Unable to resolve: {} {}, reason: {}", GetName(), symbol, dlerror());
+ return 0;
+ }
+
+ *f = s;
+ return 1;
+}
+
+bool SoLoader::IsSystemDll()
+{
+ return false;
+}
+
+HMODULE SoLoader::GetHModule()
+{
+ return m_soHandle;
+}
+
+bool SoLoader::HasSymbols()
+{
+ return false;
+}
diff --git a/xbmc/cores/DllLoader/SoLoader.h b/xbmc/cores/DllLoader/SoLoader.h
new file mode 100644
index 0000000..4adc7e9
--- /dev/null
+++ b/xbmc/cores/DllLoader/SoLoader.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#ifdef TARGET_POSIX
+#include "PlatformDefs.h"
+#endif
+#include "DllLoader.h"
+
+class SoLoader : public LibraryLoader
+{
+public:
+ SoLoader(const std::string &so, bool bGlobal = false);
+ ~SoLoader() override;
+
+ bool Load() override;
+ void Unload() override;
+
+ int ResolveExport(const char* symbol, void** ptr, bool logging = true) override;
+ bool IsSystemDll() override;
+ HMODULE GetHModule() override;
+ bool HasSymbols() override;
+
+private:
+ void* m_soHandle;
+ bool m_bGlobal;
+ bool m_bLoaded;
+};
diff --git a/xbmc/cores/DllLoader/Win32DllLoader.cpp b/xbmc/cores/DllLoader/Win32DllLoader.cpp
new file mode 100644
index 0000000..be0d4a6
--- /dev/null
+++ b/xbmc/cores/DllLoader/Win32DllLoader.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "Win32DllLoader.h"
+
+#include "DllLoader.h"
+#include "DllLoaderContainer.h"
+#include "dll_tracker_file.h"
+#include "dll_tracker_library.h"
+#include "exports/emu_msvcrt.h"
+#include "filesystem/SpecialProtocol.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include "platform/win32/CharsetConverter.h"
+
+#include <limits>
+
+extern "C" FARPROC WINAPI dllWin32GetProcAddress(HMODULE hModule, LPCSTR function);
+
+//dllLoadLibraryA, dllFreeLibrary, dllGetProcAddress are from dllLoader,
+//they are wrapper functions of COFF/PE32 loader.
+extern "C" HMODULE WINAPI dllLoadLibraryA(LPCSTR libname);
+extern "C" BOOL WINAPI dllFreeLibrary(HINSTANCE hLibModule);
+
+// our exports
+Export win32_exports[] =
+{
+ { "LoadLibraryA", -1, (void*)dllLoadLibraryA, (void*)track_LoadLibraryA },
+ { "FreeLibrary", -1, (void*)dllFreeLibrary, (void*)track_FreeLibrary },
+// msvcrt
+ { "_close", -1, (void*)dll_close, (void*)track_close},
+ { "_lseek", -1, (void*)dll_lseek, NULL },
+ { "_read", -1, (void*)dll_read, NULL },
+ { "_write", -1, (void*)dll_write, NULL },
+ { "_lseeki64", -1, (void*)dll_lseeki64, NULL },
+ { "_open", -1, (void*)dll_open, (void*)track_open },
+ { "fflush", -1, (void*)dll_fflush, NULL },
+ { "fprintf", -1, (void*)dll_fprintf, NULL },
+ { "fwrite", -1, (void*)dll_fwrite, NULL },
+ { "putchar", -1, (void*)dll_putchar, NULL },
+ { "_fstat", -1, (void*)dll_fstat, NULL },
+ { "_mkdir", -1, (void*)dll_mkdir, NULL },
+ { "_stat", -1, (void*)dll_stat, NULL },
+ { "_fstat32", -1, (void*)dll_fstat, NULL },
+ { "_stat32", -1, (void*)dll_stat, NULL },
+ { "_findclose", -1, (void*)dll_findclose, NULL },
+ { "_findfirst", -1, (void*)dll_findfirst, NULL },
+ { "_findnext", -1, (void*)dll_findnext, NULL },
+ { "_findfirst64i32", -1, (void*)dll_findfirst64i32, NULL },
+ { "_findnext64i32", -1, (void*)dll_findnext64i32, NULL },
+ { "fclose", -1, (void*)dll_fclose, (void*)track_fclose},
+ { "feof", -1, (void*)dll_feof, NULL },
+ { "fgets", -1, (void*)dll_fgets, NULL },
+ { "fopen", -1, (void*)dll_fopen, (void*)track_fopen},
+ { "fopen_s", -1, (void*)dll_fopen_s, NULL },
+ { "putc", -1, (void*)dll_putc, NULL },
+ { "fputc", -1, (void*)dll_fputc, NULL },
+ { "fputs", -1, (void*)dll_fputs, NULL },
+ { "fread", -1, (void*)dll_fread, NULL },
+ { "fseek", -1, (void*)dll_fseek, NULL },
+ { "ftell", -1, (void*)dll_ftell, NULL },
+ { "getc", -1, (void*)dll_getc, NULL },
+ { "fgetc", -1, (void*)dll_getc, NULL },
+ { "rewind", -1, (void*)dll_rewind, NULL },
+ { "vfprintf", -1, (void*)dll_vfprintf, NULL },
+ { "fgetpos", -1, (void*)dll_fgetpos, NULL },
+ { "fsetpos", -1, (void*)dll_fsetpos, NULL },
+ { "_stati64", -1, (void*)dll_stati64, NULL },
+ { "_stat64", -1, (void*)dll_stat64, NULL },
+ { "_stat64i32", -1, (void*)dll_stat64i32, NULL },
+ { "_fstati64", -1, (void*)dll_fstati64, NULL },
+ { "_fstat64", -1, (void*)dll_fstat64, NULL },
+ { "_fstat64i32", -1, (void*)dll_fstat64i32, NULL },
+ { "_telli64", -1, (void*)dll_telli64, NULL },
+ { "_tell", -1, (void*)dll_tell, NULL },
+ { "_fileno", -1, (void*)dll_fileno, NULL },
+ { "ferror", -1, (void*)dll_ferror, NULL },
+ { "freopen", -1, (void*)dll_freopen, (void*)track_freopen},
+ { "fscanf", -1, (void*)dll_fscanf, NULL },
+ { "ungetc", -1, (void*)dll_ungetc, NULL },
+ { "_fdopen", -1, (void*)dll_fdopen, NULL },
+ { "clearerr", -1, (void*)dll_clearerr, NULL },
+ // for debugging
+ { "printf", -1, (void*)dllprintf, NULL },
+ { "vprintf", -1, (void*)dllvprintf, NULL },
+ { "perror", -1, (void*)dllperror, NULL },
+ { "puts", -1, (void*)dllputs, NULL },
+ // workarounds for non-win32 signals
+ { "signal", -1, (void*)dll_signal, NULL },
+
+ // libdvdnav + python need this (due to us using dll_putenv() to put stuff only?)
+ { "getenv", -1, (void*)dll_getenv, NULL },
+ { "_environ", -1, (void*)&dll__environ, NULL },
+ { "_open_osfhandle", -1, (void*)dll_open_osfhandle, NULL },
+
+ { NULL, -1, NULL, NULL }
+};
+
+Win32DllLoader::Win32DllLoader(const std::string& dll, bool isSystemDll)
+ : LibraryLoader(dll)
+ , bIsSystemDll(isSystemDll)
+{
+ m_dllHandle = NULL;
+ DllLoaderContainer::RegisterDll(this);
+}
+
+Win32DllLoader::~Win32DllLoader()
+{
+ if (m_dllHandle)
+ Unload();
+ DllLoaderContainer::UnRegisterDll(this);
+}
+
+bool Win32DllLoader::Load()
+{
+ using namespace KODI::PLATFORM::WINDOWS;
+
+ if (m_dllHandle != NULL)
+ return true;
+
+ std::string strFileName = GetFileName();
+ auto strDllW = ToW(CSpecialProtocol::TranslatePath(strFileName));
+
+#ifdef TARGET_WINDOWS_STORE
+ // The path cannot be an absolute path or a relative path that contains ".." in the path.
+ auto appPath = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path();
+ size_t len = appPath.size();
+
+ if (!appPath.empty() && wcsnicmp(appPath.c_str(), strDllW.c_str(), len) == 0)
+ {
+ if (strDllW.at(len) == '\\' || strDllW.at(len) == '/')
+ len++;
+ std::wstring relative = strDllW.substr(len);
+ m_dllHandle = LoadPackagedLibrary(relative.c_str(), 0);
+ }
+ else
+ m_dllHandle = LoadPackagedLibrary(strDllW.c_str(), 0);
+#else
+ m_dllHandle = LoadLibraryExW(strDllW.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+#endif
+
+ if (!m_dllHandle)
+ {
+ DWORD dw = GetLastError();
+ wchar_t* lpMsgBuf = NULL;
+ DWORD strLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPWSTR)&lpMsgBuf, 0, NULL);
+ if (strLen == 0)
+ strLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (LPWSTR)&lpMsgBuf, 0, NULL);
+
+ if (strLen != 0)
+ {
+ auto strMessage = FromW(lpMsgBuf, strLen);
+ CLog::Log(LOGERROR, "{}: Failed to load \"{}\" with error {}: \"{}\"", __FUNCTION__,
+ CSpecialProtocol::TranslatePath(strFileName), dw, strMessage);
+ }
+ else
+ CLog::Log(LOGERROR, "{}: Failed to load \"{}\" with error {}", __FUNCTION__,
+ CSpecialProtocol::TranslatePath(strFileName), dw);
+
+ LocalFree(lpMsgBuf);
+ return false;
+ }
+
+ // handle functions that the dll imports
+ if (NeedsHooking(strFileName.c_str()))
+ OverrideImports(strFileName);
+
+ return true;
+}
+
+void Win32DllLoader::Unload()
+{
+ // restore our imports
+ RestoreImports();
+
+ if (m_dllHandle)
+ {
+ if (!FreeLibrary(m_dllHandle))
+ CLog::Log(LOGERROR, "{} Unable to unload {}", __FUNCTION__, GetName());
+ }
+
+ m_dllHandle = NULL;
+}
+
+int Win32DllLoader::ResolveExport(const char* symbol, void** f, bool logging)
+{
+ if (!m_dllHandle && !Load())
+ {
+ if (logging)
+ CLog::Log(LOGWARNING, "{} - Unable to resolve: {} {}, reason: DLL not loaded", __FUNCTION__,
+ GetName(), symbol);
+ return 0;
+ }
+
+ void *s = GetProcAddress(m_dllHandle, symbol);
+
+ if (!s)
+ {
+ if (logging)
+ CLog::Log(LOGWARNING, "{} - Unable to resolve: {} {}", __FUNCTION__, GetName(), symbol);
+ return 0;
+ }
+
+ *f = s;
+ return 1;
+}
+
+bool Win32DllLoader::IsSystemDll()
+{
+ return bIsSystemDll;
+}
+
+HMODULE Win32DllLoader::GetHModule()
+{
+ return m_dllHandle;
+}
+
+bool Win32DllLoader::HasSymbols()
+{
+ return false;
+}
+
+void Win32DllLoader::OverrideImports(const std::string &dll)
+{
+ using KODI::PLATFORM::WINDOWS::ToW;
+ auto strdllW = ToW(CSpecialProtocol::TranslatePath(dll));
+ auto image_base = reinterpret_cast<BYTE*>(m_dllHandle);
+
+ if (!image_base)
+ {
+ CLog::Log(LOGERROR, "{} - unable to GetModuleHandle for dll {}", __FUNCTION__, dll);
+ return;
+ }
+
+ auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(image_base);
+ auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(image_base + dos_header->e_lfanew); // e_lfanew = value at 0x3c
+
+ auto imp_desc = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
+ image_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+
+ if (!imp_desc)
+ {
+ CLog::Log(LOGERROR, "{} - unable to get import directory for dll {}", __FUNCTION__, dll);
+ return;
+ }
+
+ // loop over all imported dlls
+ for (int i = 0; imp_desc[i].Characteristics != 0; i++)
+ {
+ auto dllName = reinterpret_cast<char*>(image_base + imp_desc[i].Name);
+
+ // check whether this is one of our dll's.
+ if (NeedsHooking(dllName))
+ {
+ // this will do a loadlibrary on it, which should effectively make sure that it's hooked
+ // Note that the library has obviously already been loaded by the OS (as it's implicitly linked)
+ // so all this will do is insert our hook and make sure our DllLoaderContainer knows about it
+ auto hModule = dllLoadLibraryA(dllName);
+ if (hModule)
+ m_referencedDlls.push_back(hModule);
+ }
+
+ PIMAGE_THUNK_DATA orig_first_thunk = reinterpret_cast<PIMAGE_THUNK_DATA>(image_base + imp_desc[i].OriginalFirstThunk);
+ PIMAGE_THUNK_DATA first_thunk = reinterpret_cast<PIMAGE_THUNK_DATA>(image_base + imp_desc[i].FirstThunk);
+
+ // and then loop over all imported functions
+ for (int j = 0; orig_first_thunk[j].u1.Function != 0; j++)
+ {
+ void *fixup = NULL;
+ if (orig_first_thunk[j].u1.Function & 0x80000000)
+ ResolveOrdinal(dllName, (orig_first_thunk[j].u1.Ordinal & 0x7fffffff), &fixup);
+ else
+ { // resolve by name
+ PIMAGE_IMPORT_BY_NAME orig_imports_by_name = (PIMAGE_IMPORT_BY_NAME)(
+ image_base + orig_first_thunk[j].u1.AddressOfData);
+
+ ResolveImport(dllName, (char*)orig_imports_by_name->Name, &fixup);
+ }/*
+ if (!fixup)
+ { // create a dummy function for tracking purposes
+ PIMAGE_IMPORT_BY_NAME orig_imports_by_name = (PIMAGE_IMPORT_BY_NAME)(
+ image_base + orig_first_thunk[j].u1.AddressOfData);
+ fixup = CreateDummyFunction(dllName, (char*)orig_imports_by_name->Name);
+ }*/
+ if (fixup)
+ {
+ // save the old function
+ Import import;
+ import.table = &first_thunk[j].u1.Function;
+ import.function = first_thunk[j].u1.Function;
+ m_overriddenImports.push_back(import);
+
+ DWORD old_prot = 0;
+
+ // change to protection settings so we can write to memory area
+ VirtualProtect((PVOID)&first_thunk[j].u1.Function, 4, PAGE_EXECUTE_READWRITE, &old_prot);
+
+ // patch the address of function to point to our overridden version
+ first_thunk[j].u1.Function = (uintptr_t)fixup;
+
+ // reset to old settings
+ VirtualProtect((PVOID)&first_thunk[j].u1.Function, 4, old_prot, &old_prot);
+ }
+ }
+ }
+}
+
+bool Win32DllLoader::NeedsHooking(const char *dllName)
+{
+ if ( !StringUtils::EndsWithNoCase(dllName, "libdvdcss-2.dll")
+ && !StringUtils::EndsWithNoCase(dllName, "libdvdnav.dll"))
+ return false;
+
+ LibraryLoader *loader = DllLoaderContainer::GetModule(dllName);
+ if (loader)
+ {
+ // may have hooked this already (we can have repeats in the import table)
+ for (unsigned int i = 0; i < m_referencedDlls.size(); i++)
+ {
+ if (loader->GetHModule() == m_referencedDlls[i])
+ return false;
+ }
+ }
+ return true;
+}
+
+void Win32DllLoader::RestoreImports()
+{
+ // first unhook any referenced dll's
+ for (auto& module : m_referencedDlls)
+ dllFreeLibrary(module);
+ m_referencedDlls.clear();
+
+ for (auto& import : m_overriddenImports)
+ {
+ // change to protection settings so we can write to memory area
+ DWORD old_prot = 0;
+ VirtualProtect(import.table, 4, PAGE_EXECUTE_READWRITE, &old_prot);
+
+ *static_cast<uintptr_t *>(import.table) = import.function;
+
+ // reset to old settings
+ VirtualProtect(import.table, 4, old_prot, &old_prot);
+ }
+}
+
+bool FunctionNeedsWrapping(Export *exports, const char *functionName, void **fixup)
+{
+ Export *exp = exports;
+ while (exp->name)
+ {
+ if (strcmp(exp->name, functionName) == 0)
+ { //! @todo Should we be tracking stuff?
+ if (0)
+ *fixup = exp->track_function;
+ else
+ *fixup = exp->function;
+ return true;
+ }
+ exp++;
+ }
+ return false;
+}
+
+bool Win32DllLoader::ResolveImport(const char *dllName, const char *functionName, void **fixup)
+{
+ return FunctionNeedsWrapping(win32_exports, functionName, fixup);
+}
+
+bool Win32DllLoader::ResolveOrdinal(const char *dllName, unsigned long ordinal, void **fixup)
+{
+ Export *exp = win32_exports;
+ while (exp->name)
+ {
+ if (exp->ordinal == ordinal)
+ { //! @todo Should we be tracking stuff?
+ if (0)
+ *fixup = exp->track_function;
+ else
+ *fixup = exp->function;
+ return true;
+ }
+ exp++;
+ }
+ return false;
+}
+
+extern "C" FARPROC __stdcall dllWin32GetProcAddress(HMODULE hModule, LPCSTR function)
+{
+ // if the high-order word is zero, then lpProcName is the function's ordinal value
+ if (reinterpret_cast<uintptr_t>(function) > std::numeric_limits<WORD>::max())
+ {
+ // first check whether this function is one of the ones we need to wrap
+ void *fixup = NULL;
+ if (FunctionNeedsWrapping(win32_exports, function, &fixup))
+ return (FARPROC)fixup;
+ }
+
+ // Nope
+ return GetProcAddress(hModule, function);
+}
+
diff --git a/xbmc/cores/DllLoader/Win32DllLoader.h b/xbmc/cores/DllLoader/Win32DllLoader.h
new file mode 100644
index 0000000..f11eb54
--- /dev/null
+++ b/xbmc/cores/DllLoader/Win32DllLoader.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "LibraryLoader.h"
+
+#include <vector>
+
+class Win32DllLoader : public LibraryLoader
+{
+public:
+ class Import
+ {
+ public:
+ void *table;
+ uintptr_t function;
+ };
+
+ Win32DllLoader(const std::string& dll, bool isSystemDll);
+ ~Win32DllLoader();
+
+ virtual bool Load();
+ virtual void Unload();
+
+ virtual int ResolveExport(const char* symbol, void** ptr, bool logging = true);
+ virtual bool IsSystemDll();
+ virtual HMODULE GetHModule();
+ virtual bool HasSymbols();
+
+private:
+ void OverrideImports(const std::string &dll);
+ void RestoreImports();
+ static bool ResolveImport(const char *dllName, const char *functionName, void **fixup);
+ static bool ResolveOrdinal(const char *dllName, unsigned long ordinal, void **fixup);
+ bool NeedsHooking(const char *dllName);
+
+ HMODULE m_dllHandle;
+ bool bIsSystemDll;
+
+ std::vector<Import> m_overriddenImports;
+ std::vector<HMODULE> m_referencedDlls;
+};
+
diff --git a/xbmc/cores/DllLoader/coff.cpp b/xbmc/cores/DllLoader/coff.cpp
new file mode 100644
index 0000000..6e330c9
--- /dev/null
+++ b/xbmc/cores/DllLoader/coff.cpp
@@ -0,0 +1,997 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "coff.h"
+#include "coffldr.h"
+
+//#define DUMPING_DATA 1
+
+#ifndef __GNUC__
+#pragma warning (disable:4806)
+#endif
+
+#include "utils/log.h"
+#define printf(format, ...) CLog::Log(LOGDEBUG, format , ##__VA_ARGS__)
+
+const char *DATA_DIR_NAME[16] =
+ {
+ "Export Table",
+ "Import Table",
+ "Resource Table",
+ "Exception Table",
+ "Certificate Table",
+ "Base Relocation Table",
+ "Debug",
+ "Architecture",
+ "Global Ptr",
+ "TLS Table",
+ "Load Config Table",
+ "Bound Import",
+ "IAT",
+ "Delay Import Descriptor",
+ "COM+ Runtime Header",
+ "Reserved"
+ };
+
+
+CoffLoader::CoffLoader()
+{
+ CoffFileHeader = 0;
+ OptionHeader = 0;
+ WindowsHeader = 0;
+ Directory = 0;
+ SectionHeader = 0;
+ SymTable = 0;
+ StringTable = 0;
+ SectionData = 0;
+
+ NumberOfSymbols = 0;
+ SizeOfStringTable = 0;
+ NumOfDirectories = 0;
+ NumOfSections = 0;
+ FileHeaderOffset = 0;
+ EntryAddress = 0;
+ hModule = NULL;
+}
+
+CoffLoader::~CoffLoader()
+{
+ if ( hModule )
+ {
+#ifdef TARGET_POSIX
+ free(hModule);
+#else
+ VirtualFree(hModule, 0, MEM_RELEASE);
+#endif
+ hModule = NULL;
+ }
+ if ( SymTable )
+ {
+ delete [] SymTable;
+ SymTable = 0;
+ }
+ if ( StringTable )
+ {
+ delete [] StringTable;
+ StringTable = 0;
+ }
+ if ( SectionData )
+ {
+ delete [] SectionData;
+ SectionData = 0;
+ }
+}
+
+// Has nothing to do with the coff loader itself
+// it can be used to parse the headers of a dll
+// already loaded into memory
+int CoffLoader::ParseHeaders(void* hModule)
+{
+ if (strncmp((char*)hModule, "MZ", 2) != 0)
+ return 0;
+
+ int* Offset = (int*)((char*)hModule+0x3c);
+ if (*Offset <= 0)
+ return 0;
+
+ if (strncmp((char*)hModule+*Offset, "PE\0\0", 4) != 0)
+ return 0;
+
+ FileHeaderOffset = *Offset + 4;
+
+ CoffFileHeader = (COFF_FileHeader_t *) ( (char*)hModule + FileHeaderOffset );
+ NumOfSections = CoffFileHeader->NumberOfSections;
+
+ OptionHeader = (OptionHeader_t *) ( (char*)CoffFileHeader + sizeof(COFF_FileHeader_t) );
+ WindowsHeader = (WindowsHeader_t *) ( (char*)OptionHeader + OPTHDR_SIZE );
+ EntryAddress = OptionHeader->Entry;
+ NumOfDirectories = WindowsHeader->NumDirectories;
+
+ Directory = (Image_Data_Directory_t *) ( (char*)WindowsHeader + WINHDR_SIZE);
+ SectionHeader = (SectionHeader_t *) ( (char*)Directory + sizeof(Image_Data_Directory_t) * NumOfDirectories);
+
+ if (CoffFileHeader->MachineType != IMAGE_FILE_MACHINE_I386)
+ return 0;
+
+#ifdef DUMPING_DATA
+ PrintFileHeader(CoffFileHeader);
+#endif
+
+ if ( CoffFileHeader->SizeOfOptionHeader == 0 ) //not an image file, object file maybe
+ return 0;
+
+ // process Option Header
+ if (OptionHeader->Magic == OPTMAGIC_PE32P)
+ {
+ printf("PE32+ not supported\n");
+ return 0;
+ }
+ else if (OptionHeader->Magic == OPTMAGIC_PE32)
+ {
+
+#ifdef DUMPING_DATA
+ PrintOptionHeader(OptionHeader);
+ PrintWindowsHeader(WindowsHeader);
+#endif
+
+ }
+ else
+ {
+ //add error message
+ return 0;
+ }
+
+#ifdef DUMPING_DATA
+ for (int DirCount = 0; DirCount < NumOfDirectories; DirCount++)
+ {
+ printf("Data Directory %02d: %s\n", DirCount + 1, DATA_DIR_NAME[DirCount]);
+ printf(" RVA: %08X\n", Directory[DirCount].RVA);
+ printf(" Size: %08X\n\n", Directory[DirCount].Size);
+ }
+#endif
+
+ return 1;
+
+}
+
+int CoffLoader::LoadCoffHModule(FILE *fp)
+{
+ //test file signatures
+ char Sig[4];
+ rewind(fp);
+ memset(Sig, 0, sizeof(Sig));
+ if (!fread(Sig, 1, 2, fp) || strncmp(Sig, "MZ", 2) != 0)
+ return 0;
+
+ if (fseek(fp, 0x3c, SEEK_SET) != 0)
+ return 0;
+
+ int Offset = 0;
+ if (!fread(&Offset, sizeof(int), 1, fp) || (Offset <= 0))
+ return 0;
+
+ if (fseek(fp, Offset, SEEK_SET) != 0)
+ return 0;
+
+ memset(Sig, 0, sizeof(Sig));
+ if (!fread(Sig, 1, 4, fp) || strncmp(Sig, "PE\0\0", 4) != 0)
+ return 0;
+
+ Offset += 4;
+ FileHeaderOffset = Offset;
+
+ // Load and process Header
+ if (fseek(fp, FileHeaderOffset + sizeof(COFF_FileHeader_t) + OPTHDR_SIZE, SEEK_SET)) //skip to winows headers
+ return 0;
+
+ WindowsHeader_t tempWindowsHeader;
+ size_t readcount = fread(&tempWindowsHeader, 1, WINHDR_SIZE, fp);
+ if (readcount != WINHDR_SIZE) //test file size error
+ return 0;
+
+ // alloc aligned memory
+#ifdef TARGET_POSIX
+ hModule = malloc(tempWindowsHeader.SizeOfImage);
+#elif defined TARGET_WINDOWS_STORE
+ hModule = VirtualAllocFromApp(GetCurrentProcess(), tempWindowsHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+#else
+ hModule = VirtualAllocEx(GetCurrentProcess(), (PVOID)tempWindowsHeader.ImageBase, tempWindowsHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (hModule == NULL)
+ hModule = VirtualAlloc(GetCurrentProcess(), tempWindowsHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+#endif
+ if (hModule == NULL)
+ return 0; //memory allocation fails
+
+ rewind(fp);
+ readcount = fread(hModule, 1, tempWindowsHeader.SizeOfHeaders, fp);
+ if (readcount != tempWindowsHeader.SizeOfHeaders) //file size error
+ return 0;
+
+ CoffFileHeader = (COFF_FileHeader_t *) ( (char*)hModule + FileHeaderOffset );
+ NumOfSections = CoffFileHeader->NumberOfSections;
+
+ OptionHeader = (OptionHeader_t *) ( (char*)CoffFileHeader + sizeof(COFF_FileHeader_t) );
+ WindowsHeader = (WindowsHeader_t *) ( (char*)OptionHeader + OPTHDR_SIZE );
+ EntryAddress = OptionHeader->Entry;
+ NumOfDirectories = WindowsHeader->NumDirectories;
+
+ Directory = (Image_Data_Directory_t *) ( (char*)WindowsHeader + WINHDR_SIZE);
+ SectionHeader = (SectionHeader_t *) ( (char*)Directory + sizeof(Image_Data_Directory_t) * NumOfDirectories);
+
+ if (CoffFileHeader->MachineType != IMAGE_FILE_MACHINE_I386)
+ return 0;
+
+#ifdef DUMPING_DATA
+ PrintFileHeader(CoffFileHeader);
+#endif
+
+ if ( CoffFileHeader->SizeOfOptionHeader == 0 ) //not an image file, object file maybe
+ return 0;
+
+ // process Option Header
+ if (OptionHeader->Magic == OPTMAGIC_PE32P)
+ {
+ printf("PE32+ not supported\n");
+ return 0;
+ }
+ else if (OptionHeader->Magic == OPTMAGIC_PE32)
+ {
+
+#ifdef DUMPING_DATA
+ PrintOptionHeader(OptionHeader);
+ PrintWindowsHeader(WindowsHeader);
+#endif
+
+ }
+ else
+ {
+ //add error message
+ return 0;
+ }
+
+#ifdef DUMPING_DATA
+ for (int DirCount = 0; DirCount < NumOfDirectories; DirCount++)
+ {
+ printf("Data Directory %02d: %s\n", DirCount + 1, DATA_DIR_NAME[DirCount]);
+ printf(" RVA: %08X\n", Directory[DirCount].RVA);
+ printf(" Size: %08X\n\n", Directory[DirCount].Size);
+ }
+#endif
+
+ return 1;
+
+}
+
+int CoffLoader::LoadSymTable(FILE *fp)
+{
+ int Offset = ftell(fp);
+ if (Offset < 0)
+ return 0;
+
+ if ( CoffFileHeader->PointerToSymbolTable == 0 )
+ return 1;
+
+ if (fseek(fp, CoffFileHeader->PointerToSymbolTable /* + CoffBeginOffset*/, SEEK_SET) != 0)
+ return 0;
+
+ SymbolTable_t *tmp = new SymbolTable_t[CoffFileHeader->NumberOfSymbols];
+ if (!tmp)
+ {
+ printf("Could not allocate memory for symbol table!\n");
+ return 0;
+ }
+ if (!fread((void *)tmp, CoffFileHeader->NumberOfSymbols, sizeof(SymbolTable_t), fp))
+ {
+ delete[] tmp;
+ return 0;
+ }
+ NumberOfSymbols = CoffFileHeader->NumberOfSymbols;
+ SymTable = tmp;
+ if (fseek(fp, Offset, SEEK_SET) != 0)
+ return 0;
+ return 1;
+}
+
+int CoffLoader::LoadStringTable(FILE *fp)
+{
+ int StringTableSize;
+ char *tmp = NULL;
+
+ int Offset = ftell(fp);
+ if (Offset < 0)
+ return 0;
+
+ if ( CoffFileHeader->PointerToSymbolTable == 0 )
+ return 1;
+
+ if (fseek(fp, CoffFileHeader->PointerToSymbolTable +
+ CoffFileHeader->NumberOfSymbols * sizeof(SymbolTable_t),
+ SEEK_SET) != 0)
+ return 0;
+
+ if (!fread(&StringTableSize, 1, sizeof(int), fp))
+ return 0;
+ StringTableSize -= 4;
+ if (StringTableSize != 0)
+ {
+ tmp = new char[StringTableSize];
+ if (tmp == NULL)
+ {
+ printf("Could not allocate memory for string table\n");
+ return 0;
+ }
+ if (!fread((void *)tmp, StringTableSize, sizeof(char), fp))
+ {
+ delete[] tmp;
+ return 0;
+ }
+ }
+ SizeOfStringTable = StringTableSize;
+ StringTable = tmp;
+ if (fseek(fp, Offset, SEEK_SET) != 0)
+ return 0;
+ return 1;
+}
+
+int CoffLoader::LoadSections(FILE *fp)
+{
+ NumOfSections = CoffFileHeader->NumberOfSections;
+
+ SectionData = new char * [NumOfSections];
+ if ( !SectionData )
+ return 0;
+
+ // Bobbin007: for debug dlls this check always fails
+
+ //////check VMA size!!!!!
+ //unsigned long vma_size = 0;
+ //for (int SctnCnt = 0; SctnCnt < NumOfSections; SctnCnt++)
+ //{
+ // SectionHeader_t *ScnHdr = (SectionHeader_t *)(SectionHeader + SctnCnt);
+ // vma_size = max(vma_size, ScnHdr->VirtualAddress + ScnHdr->SizeOfRawData);
+ // vma_size = max(vma_size, ScnHdr->VirtualAddress + ScnHdr->VirtualSize);
+ //}
+
+ //if (WindowsHeader->SizeOfImage < vma_size)
+ // return 0; //something wrong with file
+
+ for (int SctnCnt = 0; SctnCnt < NumOfSections; SctnCnt++)
+ {
+ SectionHeader_t *ScnHdr = SectionHeader + SctnCnt;
+ SectionData[SctnCnt] = ((char*)hModule + ScnHdr->VirtualAddress);
+
+ if (fseek(fp, ScnHdr->PtrToRawData, SEEK_SET) != 0)
+ return 0;
+
+ if (!fread(SectionData[SctnCnt], 1, ScnHdr->SizeOfRawData, fp))
+ return 0;
+
+#ifdef DUMPING_DATA
+ //debug blocks
+ char szBuf[128];
+ char namebuf[9];
+ for (int i = 0; i < 8; i++)
+ namebuf[i] = ScnHdr->Name[i];
+ namebuf[8] = '\0';
+ sprintf(szBuf, "Load code Sections %s Memory %p,Length %x\n", namebuf,
+ SectionData[SctnCnt], max(ScnHdr->VirtualSize, ScnHdr->SizeOfRawData));
+ OutputDebugString(szBuf);
+#endif
+
+ if ( ScnHdr->SizeOfRawData < ScnHdr->VirtualSize ) //initialize BSS data in the end of section
+ {
+ memset((char*)((long)(SectionData[SctnCnt]) + ScnHdr->SizeOfRawData), 0, ScnHdr->VirtualSize - ScnHdr->SizeOfRawData);
+ }
+
+ if (ScnHdr->Characteristics & IMAGE_SCN_CNT_BSS) //initialize whole .BSS section, pure .BSS is obsolete
+ {
+ memset(SectionData[SctnCnt], 0, ScnHdr->VirtualSize);
+ }
+
+#ifdef DUMPING_DATA
+ PrintSection(SectionHeader + SctnCnt, SectionData[SctnCnt]);
+#endif
+
+ }
+ return 1;
+}
+
+//FIXME: Add the Free Resources functions
+
+int CoffLoader::RVA2Section(unsigned long RVA)
+{
+ NumOfSections = CoffFileHeader->NumberOfSections;
+ for ( int i = 0; i < NumOfSections; i++)
+ {
+ if ( SectionHeader[i].VirtualAddress <= RVA )
+ {
+ if ( i + 1 != NumOfSections )
+ {
+ if ( RVA < SectionHeader[i + 1].VirtualAddress )
+ {
+ if ( SectionHeader[i].VirtualAddress + SectionHeader[i].VirtualSize <= RVA )
+ printf("Warning! Address outside of Section: %lx!\n", RVA);
+ // else
+ return i;
+ }
+ }
+ else
+ {
+ if ( SectionHeader[i].VirtualAddress + SectionHeader[i].VirtualSize <= RVA )
+ printf("Warning! Address outside of Section: %lx!\n", RVA);
+ // else
+ return i;
+ }
+ }
+ }
+ printf("RVA2Section lookup failure!\n");
+ return 0;
+}
+
+void* CoffLoader::RVA2Data(unsigned long RVA)
+{
+ int Sctn = RVA2Section(RVA);
+
+ if( RVA < SectionHeader[Sctn].VirtualAddress
+ || RVA >= SectionHeader[Sctn].VirtualAddress + SectionHeader[Sctn].VirtualSize)
+ {
+ // RVA2Section is lying, let's use base address of dll instead, only works if
+ // DLL has been loaded fully into memory, which we normally do
+ return (void*)(RVA + (unsigned long)hModule);
+ }
+ return SectionData[Sctn] + RVA - SectionHeader[Sctn].VirtualAddress;
+}
+
+unsigned long CoffLoader::Data2RVA(void* address)
+{
+ for ( int i = 0; i < CoffFileHeader->NumberOfSections; i++)
+ {
+ if(address >= SectionData[i] && address < SectionData[i] + SectionHeader[i].VirtualSize)
+ return (unsigned long)address - (unsigned long)SectionData[i] + SectionHeader[i].VirtualAddress;
+ }
+
+ // Section wasn't found, so use relative to main load of dll
+ return (unsigned long)address - (unsigned long)hModule;
+}
+
+char *CoffLoader::GetStringTblIndex(int index)
+{
+ char *table = StringTable;
+
+ while (index--)
+ table += strlen(table) + 1;
+ return table;
+}
+
+char *CoffLoader::GetStringTblOff(int Offset)
+{
+ return StringTable + Offset - 4;
+}
+
+char *CoffLoader::GetSymbolName(SymbolTable_t *sym)
+{
+ long long index = sym->Name.Offset;
+ int low = (int)(index & 0xFFFFFFFF);
+ int high = (int)((index >> 32) & 0xFFFFFFFF);
+
+ if (low == 0)
+ {
+ return GetStringTblOff(high);
+ }
+ else
+ {
+ static char shortname[9];
+ memset(shortname, 0, 9);
+ strncpy(shortname, (char *)sym->Name.ShortName, 8);
+ return shortname;
+ }
+}
+
+char *CoffLoader::GetSymbolName(int index)
+{
+ SymbolTable_t *sym = &(SymTable[index]);
+ return GetSymbolName(sym);
+}
+
+void CoffLoader::PrintStringTable(void)
+{
+ int size = SizeOfStringTable;
+ int index = 0;
+ char *table = StringTable;
+
+ printf("\nSTRING TABLE\n");
+ while (size)
+ {
+ printf("%2d: %s\n", index++, table);
+ size -= strlen(table) + 1;
+ table += strlen(table) + 1;
+ }
+ printf("\n");
+}
+
+
+void CoffLoader::PrintSymbolTable(void)
+{
+ int SymIndex;
+
+ printf("COFF SYMBOL TABLE\n");
+ for (SymIndex = 0; SymIndex < NumberOfSymbols; SymIndex++)
+ {
+ printf("%03X ", SymIndex);
+ printf("%08lX ", SymTable[SymIndex].Value);
+
+ if (SymTable[SymIndex].SectionNumber == IMAGE_SYM_ABSOLUTE)
+ printf("ABS ");
+ else if (SymTable[SymIndex].SectionNumber == IMAGE_SYM_DEBUG)
+ printf("DEBUG ");
+ else if (SymTable[SymIndex].SectionNumber == IMAGE_SYM_UNDEFINED)
+ printf("UNDEF ");
+ else
+ {
+ printf("SECT%d ", SymTable[SymIndex].SectionNumber);
+ if (SymTable[SymIndex].SectionNumber < 10)
+ printf(" ");
+ if (SymTable[SymIndex].SectionNumber < 100)
+ printf(" ");
+ }
+
+ if (SymTable[SymIndex].Type == 0)
+ printf("notype ");
+ else
+ {
+ printf("%X ", SymTable[SymIndex].Type);
+ if (SymTable[SymIndex].Type < 0x10)
+ printf(" ");
+ if (SymTable[SymIndex].Type < 0x100)
+ printf(" ");
+ if (SymTable[SymIndex].Type < 0x1000)
+ printf(" ");
+ }
+
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_END_OF_FUNCTION)
+ printf("End of Function ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_NULL)
+ printf("Null ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_AUTOMATIC)
+ printf("Automatic ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
+ printf("External ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_STATIC)
+ printf("Static ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_REGISTER)
+ printf("Register ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
+ printf("External Def ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_LABEL)
+ printf("Label ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_UNDEFINED_LABEL)
+ printf("Undefined Label ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_MEMBER_OF_STRUCT)
+ printf("Member Of Struct ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_ARGUMENT)
+ printf("Argument ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_STRUCT_TAG)
+ printf("Struct Tag ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_MEMBER_OF_UNION)
+ printf("Member Of Union ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_UNION_TAG)
+ printf("Union Tag ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_TYPE_DEFINITION)
+ printf("Type Definition ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_UNDEFINED_STATIC)
+ printf("Undefined Static ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_ENUM_TAG)
+ printf("Enum Tag ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_MEMBER_OF_ENUM)
+ printf("Member Of Enum ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_REGISTER_PARAM)
+ printf("Register Param ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_BIT_FIELD)
+ printf("Bit Field ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_BLOCK)
+ printf("Block ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_FUNCTION)
+ printf("Function ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_END_OF_STRUCT)
+ printf("End Of Struct ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_FILE)
+ printf("File ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_SECTION)
+ printf("Section ");
+ if (SymTable[SymIndex].StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL)
+ printf("Weak External ");
+
+ printf("| %s", GetSymbolName(SymIndex));
+
+ SymIndex += SymTable[SymIndex].NumberOfAuxSymbols;
+ printf("\n");
+ }
+ printf("\n");
+
+}
+
+void CoffLoader::PrintFileHeader(COFF_FileHeader_t *FileHeader)
+{
+ printf("COFF Header\n");
+ printf("------------------------------------------\n\n");
+
+ printf("MachineType: 0x%04X\n", FileHeader->MachineType);
+ printf("NumberOfSections: 0x%04X\n", FileHeader->NumberOfSections);
+ printf("TimeDateStamp: 0x%08lX\n",FileHeader->TimeDateStamp);
+ printf("PointerToSymbolTable: 0x%08lX\n",FileHeader->PointerToSymbolTable);
+ printf("NumberOfSymbols: 0x%08lX\n",FileHeader->NumberOfSymbols);
+ printf("SizeOfOptionHeader: 0x%04X\n", FileHeader->SizeOfOptionHeader);
+ printf("Characteristics: 0x%04X\n", FileHeader->Characteristics);
+
+ if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ printf(" IMAGE_FILE_RELOCS_STRIPPED\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
+ printf(" IMAGE_FILE_EXECUTABLE_IMAGE\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED)
+ printf(" IMAGE_FILE_LINE_NUMS_STRIPPED\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED)
+ printf(" IMAGE_FILE_LOCAL_SYMS_STRIPPED\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_AGGRESSIVE_WS_TRIM)
+ printf(" IMAGE_FILE_AGGRESSIVE_WS_TRIM\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
+ printf(" IMAGE_FILE_LARGE_ADDRESS_AWARE\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_16BIT_MACHINE)
+ printf(" IMAGE_FILE_16BIT_MACHINE\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO)
+ printf(" IMAGE_FILE_BYTES_REVERSED_LO\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_32BIT_MACHINE)
+ printf(" IMAGE_FILE_32BIT_MACHINE\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
+ printf(" IMAGE_FILE_DEBUG_STRIPPED\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)
+ printf(" IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_SYSTEM)
+ printf(" IMAGE_FILE_SYSTEM\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_DLL)
+ printf(" IMAGE_FILE_DLL\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
+ printf(" IMAGE_FILE_UP_SYSTEM_ONLY\n");
+
+ if (FileHeader->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)
+ printf(" IMAGE_FILE_BYTES_REVERSED_HI\n");
+
+ printf("\n");
+}
+
+void CoffLoader::PrintOptionHeader(OptionHeader_t *OptHdr)
+{
+ printf("Option Header\n");
+ printf("------------------------------------------\n\n");
+
+ printf("Magic: 0x%04X\n", OptHdr->Magic);
+ printf("Linker Major Ver: 0x%02X\n", VERSION_MAJOR(OptHdr->LinkVersion));
+ printf("Linker Minor Ver: 0x%02X\n", VERSION_MINOR(OptHdr->LinkVersion));
+ printf("Code Size: 0x%08lX\n", OptHdr->CodeSize);
+ printf("Data Size: 0x%08lX\n", OptHdr->DataSize);
+ printf("BSS Size: 0x%08lX\n", OptHdr->BssSize);
+ printf("Entry: 0x%08lX\n", OptHdr->Entry);
+ printf("Code Base: 0x%08lX\n", OptHdr->CodeBase);
+ printf("Data Base: 0x%08lX\n", OptHdr->DataBase);
+ printf("\n");
+}
+
+void CoffLoader::PrintWindowsHeader(WindowsHeader_t *WinHdr)
+{
+ printf("Windows Specific Option Header\n");
+ printf("------------------------------------------\n\n");
+
+ printf("Image Base: 0x%08lX\n", WinHdr->ImageBase);
+ printf("Section Alignment: 0x%08lX\n", WinHdr->SectionAlignment);
+ printf("File Alignment: 0x%08lX\n", WinHdr->FileAlignment);
+ printf("OS Version: %d.%08d\n", BIGVERSION_MAJOR(WinHdr->OSVer), BIGVERSION_MINOR(WinHdr->OSVer));
+ printf("Image Version: %d.%08d\n", BIGVERSION_MAJOR(WinHdr->ImgVer), BIGVERSION_MINOR(WinHdr->ImgVer));
+ printf("SubSystem Version: %d.%08d\n", BIGVERSION_MAJOR(WinHdr->SubSysVer), BIGVERSION_MINOR(WinHdr->SubSysVer));
+ printf("Size of Image: 0x%08lX\n", WinHdr->SizeOfImage);
+ printf("Size of Headers: 0x%08lX\n", WinHdr->SizeOfHeaders);
+ printf("Checksum: 0x%08lX\n", WinHdr->CheckSum);
+ printf("Subsystem: 0x%04X\n", WinHdr->Subsystem);
+ printf("DLL Flags: 0x%04X\n", WinHdr->DLLFlags);
+ printf("Sizeof Stack Resv: 0x%08lX\n", WinHdr->SizeOfStackReserve);
+ printf("Sizeof Stack Comm: 0x%08lX\n", WinHdr->SizeOfStackCommit);
+ printf("Sizeof Heap Resv: 0x%08lX\n", WinHdr->SizeOfHeapReserve);
+ printf("Sizeof Heap Comm: 0x%08lX\n", WinHdr->SizeOfHeapCommit);
+ printf("Loader Flags: 0x%08lX\n", WinHdr->LoaderFlags);
+ printf("Num Directories: %ld\n", WinHdr->NumDirectories);
+ printf("\n");
+}
+
+void CoffLoader::PrintSection(SectionHeader_t* ScnHdr, const char* data)
+{
+ char SectionName[9];
+
+ strncpy(SectionName, (char *)ScnHdr->Name, 8);
+ SectionName[8] = 0;
+ printf("Section: %s\n", SectionName);
+ printf("------------------------------------------\n\n");
+
+ printf("Virtual Size: 0x%08lX\n", ScnHdr->VirtualSize);
+ printf("Virtual Address: 0x%08lX\n", ScnHdr->VirtualAddress);
+ printf("Sizeof Raw Data: 0x%08lX\n", ScnHdr->SizeOfRawData);
+ printf("Ptr To Raw Data: 0x%08lX\n", ScnHdr->PtrToRawData);
+ printf("Ptr To Relocations: 0x%08lX\n", ScnHdr->PtrToRelocations);
+ printf("Ptr To Line Nums: 0x%08lX\n", ScnHdr->PtrToLineNums);
+ printf("Num Relocations: 0x%04X\n", ScnHdr->NumRelocations);
+ printf("Num Line Numbers: 0x%04X\n", ScnHdr->NumLineNumbers);
+ printf("Characteristics: 0x%08lX\n", ScnHdr->Characteristics);
+ if (ScnHdr->Characteristics & IMAGE_SCN_CNT_CODE)
+ printf(" IMAGE_SCN_CNT_CODE\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_CNT_DATA)
+ printf(" IMAGE_SCN_CNT_DATA\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_CNT_BSS)
+ printf(" IMAGE_SCN_CNT_BSS\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_LNK_INFO)
+ printf(" IMAGE_SCN_LNK_INFO\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_LNK_REMOVE)
+ printf(" IMAGE_SCN_LNK_REMOVE\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_LNK_COMDAT)
+ printf(" IMAGE_SCN_LNK_COMDAT\n");
+
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_1BYTES)
+ printf(" IMAGE_SCN_ALIGN_1BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_2BYTES)
+ printf(" IMAGE_SCN_ALIGN_2BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_4BYTES)
+ printf(" IMAGE_SCN_ALIGN_4BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_8BYTES)
+ printf(" IMAGE_SCN_ALIGN_8BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_16BYTES)
+ printf(" IMAGE_SCN_ALIGN_16BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_32BYTES)
+ printf(" IMAGE_SCN_ALIGN_32BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_64BYTES)
+ printf(" IMAGE_SCN_ALIGN_64BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_128BYTES)
+ printf(" IMAGE_SCN_ALIGN_128BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_256BYTES)
+ printf(" IMAGE_SCN_ALIGN_256BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_512BYTES)
+ printf(" IMAGE_SCN_ALIGN_512BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_1024BYTES)
+ printf(" IMAGE_SCN_ALIGN_1024BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_2048BYTES)
+ printf(" IMAGE_SCN_ALIGN_2048BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_4096BYTES)
+ printf(" IMAGE_SCN_ALIGN_4096BYTES\n");
+ if ((ScnHdr->Characteristics & IMAGE_SCN_ALIGN_MASK) == IMAGE_SCN_ALIGN_8192BYTES)
+ printf(" IMAGE_SCN_ALIGN_8192BYTES\n");
+
+ if (ScnHdr->Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL)
+ printf(" IMAGE_SCN_LNK_NRELOC_OVFL\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ printf(" IMAGE_SCN_MEM_DISCARDABLE\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_NOT_CACHED)
+ printf(" IMAGE_SCN_MEM_NOT_CACHED\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_NOT_PAGED)
+ printf(" IMAGE_SCN_MEM_NOT_PAGED\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_SHARED)
+ printf(" IMAGE_SCN_MEM_SHARED\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ printf(" IMAGE_SCN_MEM_EXECUTE\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_READ)
+ printf(" IMAGE_SCN_MEM_READ\n");
+ if (ScnHdr->Characteristics & IMAGE_SCN_MEM_WRITE)
+ printf(" IMAGE_SCN_MEM_WRITE\n");
+ printf("\n");
+
+ // Read the section Data, Relocations, & Line Nums
+ // Save the offset
+
+ if (ScnHdr->SizeOfRawData > 0)
+ {
+ unsigned int i;
+ // Print the Raw Data
+
+ printf("\nRAW DATA");
+ for (i = 0; i < ScnHdr->VirtualSize; i++)
+ {
+ if ((i % 16) == 0)
+ printf("\n %08X: ", i);
+ char ch = data[i];
+ printf("%02X ", (unsigned int)ch);
+ }
+ printf("\n\n");
+ }
+
+ /*
+ #if 0
+ if (ScnHdr->NumRelocations > 0)
+ {
+ // Print Section Relocations
+ ObjReloc_t ObjReloc;
+
+ fseek(fp, ScnHdr->PtrToRelocations/ * + CoffBeginOffset* /, SEEK_SET);
+ printf("RELOCATIONS\n");
+ printf(" Symbol Symbol\n");
+ printf(" Offset Type Index Name\n");
+ printf(" -------- -------- -------- ------\n");
+ for (int i = 0; i < ScnHdr->NumRelocations; i++)
+ {
+ fread(&ObjReloc, 1, sizeof(ObjReloc_t), fp);
+ printf(" %08X ", ObjReloc.VirtualAddress);
+
+ if (ObjReloc.Type == IMAGE_REL_I386_ABSOLUTE)
+ printf("ABSOLUTE ");
+ if (ObjReloc.Type == IMAGE_REL_I386_DIR16)
+ printf("DIR16 ");
+ if (ObjReloc.Type == IMAGE_REL_I386_REL16)
+ printf("REL16 ");
+ if (ObjReloc.Type == IMAGE_REL_I386_DIR32)
+ printf("DIR32 ");
+ if (ObjReloc.Type == IMAGE_REL_I386_DIR32NB)
+ printf("DIR32NB ");
+ if (ObjReloc.Type == IMAGE_REL_I386_SEG12)
+ printf("SEG12 ");
+ if (ObjReloc.Type == IMAGE_REL_I386_SECTION)
+ printf("SECTION ");
+ if (ObjReloc.Type == IMAGE_REL_I386_SECREL)
+ printf("SECREL ");
+ if (ObjReloc.Type == IMAGE_REL_I386_REL32)
+ printf("REL32 ");
+ printf("%8X ", ObjReloc.SymTableIndex);
+ printf("%s\n", GetSymbolName(ObjReloc.SymTableIndex));
+ }
+ printf("\n");
+ }
+
+ if (ScnHdr->NumLineNumbers > 0)
+ {
+ // Print The Line Number Info
+ LineNumbers_t LineNumber;
+ int LineCnt = 0;
+ int BaseLineNum = -1;
+
+ fseek(fp, ScnHdr->PtrToLineNums/ * + CoffBeginOffset* /, SEEK_SET);
+ printf("LINE NUMBERS");
+ for (int i = 0; i < ScnHdr->NumLineNumbers; i++)
+ {
+ int LNOffset = ftell(fp);
+
+ fread(&LineNumber, 1, sizeof(LineNumbers_t), fp);
+ if (LineNumber.LineNum == 0)
+ {
+ SymbolTable_t *Sym;
+ int SymIndex;
+
+ printf("\n");
+ SymIndex = LineNumber.Type.SymbolTableIndex;
+ Sym = &(SymTable[SymIndex]);
+ if (Sym->NumberOfAuxSymbols > 0)
+ {
+ Sym = &(SymTable[SymIndex+1]);
+ AuxFuncDef_t *FuncDef = (AuxFuncDef_t *)Sym;
+
+ if (FuncDef->PtrToLineNumber == LNOffset)
+ {
+ Sym = &(SymTable[FuncDef->TagIndex]);
+ if (Sym->NumberOfAuxSymbols > 0)
+ {
+ Sym = &(SymTable[FuncDef->TagIndex+1]);
+ AuxBfEf_t *Bf = (AuxBfEf_t *)Sym;
+ BaseLineNum = Bf->LineNumber;
+ }
+ }
+ }
+ printf(" Symbol Index: %8x ", SymIndex);
+ printf(" Base line number: %8d\n", BaseLineNum);
+ printf(" Symbol name = %s", GetSymbolName(SymIndex));
+ LineCnt = 0;
+ }
+ else
+ {
+ if ((LineCnt%4) == 0)
+ {
+ printf("\n ");
+ LineCnt = 0;
+ }
+ printf("%08X(%5d) ", LineNumber.Type.VirtualAddress,
+ LineNumber.LineNum + BaseLineNum);
+ LineCnt ++;
+ }
+ }
+ printf("\n");
+ }
+ #endif
+ */
+
+ printf("\n");
+}
+
+int CoffLoader::ParseCoff(FILE *fp)
+{
+ if ( !LoadCoffHModule(fp) )
+ {
+ printf("Failed to load/find COFF hModule header\n");
+ return 0;
+ }
+ if ( !LoadSymTable(fp) ||
+ !LoadStringTable(fp) ||
+ !LoadSections(fp) )
+ return 0;
+
+ PerformFixups();
+
+#ifdef DUMPING_DATA
+ PrintSymbolTable();
+ PrintStringTable();
+#endif
+ return 1;
+}
+
+void CoffLoader::PerformFixups(void)
+{
+ int FixupDataSize;
+ char *FixupData;
+ char *EndData;
+
+ EntryAddress = (unsigned long)RVA2Data(EntryAddress);
+
+ if( reinterpret_cast<void*>(WindowsHeader->ImageBase) == hModule )
+ return;
+
+ if ( !Directory )
+ return ;
+
+ if ( NumOfDirectories <= BASE_RELOCATION_TABLE )
+ return ;
+
+ if ( !Directory[BASE_RELOCATION_TABLE].Size )
+ return ;
+
+ FixupDataSize = Directory[BASE_RELOCATION_TABLE].Size;
+ FixupData = (char*)RVA2Data(Directory[BASE_RELOCATION_TABLE].RVA);
+ EndData = FixupData + FixupDataSize;
+
+ while (FixupData < EndData)
+ {
+ // Starting a new Fixup Block
+ unsigned long PageRVA = *((unsigned long*)FixupData);
+ FixupData += 4;
+ unsigned long BlockSize = *((unsigned long*)FixupData);
+ FixupData += 4;
+
+ BlockSize -= 8;
+ for (unsigned int i = 0; i < BlockSize / 2; i++)
+ {
+ unsigned short Fixup = *((unsigned short*)FixupData);
+ FixupData += 2;
+ int Type = (Fixup >> 12) & 0x0f;
+ Fixup &= 0xfff;
+ if (Type == IMAGE_REL_BASED_HIGHLOW)
+ {
+ unsigned long *Off = (unsigned long*)RVA2Data(Fixup + PageRVA);
+ *Off = (unsigned long)RVA2Data(*Off - WindowsHeader->ImageBase);
+ }
+ else if (Type == IMAGE_REL_BASED_ABSOLUTE)
+ {}
+ else
+ {
+ printf("Unsupported fixup type!!\n");
+ }
+ }
+ }
+}
diff --git a/xbmc/cores/DllLoader/coff.h b/xbmc/cores/DllLoader/coff.h
new file mode 100644
index 0000000..f421d43
--- /dev/null
+++ b/xbmc/cores/DllLoader/coff.h
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+//#pragma message("including coff.h")
+//
+// COFF -- Common Object File Format
+// Used commonly by Un*x and is embedded in Windows PE
+// file format.
+//
+
+// These structures must be packed
+#pragma pack(1)
+
+
+/*
+ * Some general purpose MACROs
+ */
+
+#define VERSION_MAJOR(x) ((unsigned int)((x)& 0xff))
+#define VERSION_MINOR(x) ((unsigned int)(((x)>8) &0xff))
+
+#define BIGVERSION_MAJOR(x) ((unsigned int)((x)& 0xffff))
+#define BIGVERSION_MINOR(x) ((unsigned int)(((x)>16) &0xffff))
+
+/*
+ * COFF File Header (Object & Image)
+ * Spec section 3.3
+ */
+
+typedef struct
+{
+ unsigned short MachineType; /* magic type */
+ unsigned short NumberOfSections; /* number of sections */
+ unsigned long TimeDateStamp; /* time & date stamp */
+ unsigned long PointerToSymbolTable; /* file pointer to symtab */
+ unsigned long NumberOfSymbols; /* number of symtab entries */
+ unsigned short SizeOfOptionHeader; /* sizeof(optional hdr) */
+ unsigned short Characteristics; /* flags */
+}
+COFF_FileHeader_t;
+
+/*
+ * Machine Types
+ * Spec section 3.3.1
+ * (only i386 relevant for us)
+ */
+
+#if 1
+
+#ifndef IMAGE_FILE_MACHINE_I386
+#define IMAGE_FILE_MACHINE_I386 0x14c
+#endif
+
+
+
+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
+#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
+#define IMAGE_FILE_16BIT_MACHINE 0x0040
+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
+#define IMAGE_FILE_32BIT_MACHINE 0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
+#define IMAGE_FILE_SYSTEM 0x1000
+#define IMAGE_FILE_DLL 0x2000
+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
+
+#endif
+
+
+
+#define OPTMAGIC_PE32 0x010b
+#define OPTMAGIC_PE32P 0x020b
+
+#define OPTHDR_SIZE 28
+#define OPTHDR_SIZEP 24
+#define WINHDR_SIZE 68
+#define WINHDR_SIZEP 88
+
+/*
+ * Optional Header Standard Fields (Image Only)
+ * Spec section 3.4.1
+ */
+
+typedef struct
+{
+ unsigned short Magic;
+ unsigned short LinkVersion;
+ unsigned long CodeSize;
+ unsigned long DataSize;
+ unsigned long BssSize;
+ unsigned long Entry;
+ unsigned long CodeBase;
+ unsigned long DataBase;
+}
+OptionHeader_t;
+
+typedef struct
+{
+ unsigned short Magic;
+ unsigned short LinkVersion;
+ unsigned long CodeSize;
+ unsigned long DataSize;
+ unsigned long BssSize;
+ unsigned long Entry;
+ unsigned long CodeBase;
+}
+OptionHeaderPlus_t;
+
+/*
+ * Optional Header Windows NT-Specific Fields (Image Only)
+ * Spec section 3.4.2
+ */
+
+typedef struct
+{
+ unsigned long ImageBase;
+ unsigned long SectionAlignment;
+ unsigned long FileAlignment;
+ unsigned long OSVer;
+ unsigned long ImgVer;
+ unsigned long SubSysVer;
+ unsigned long Reserved;
+ unsigned long SizeOfImage;
+ unsigned long SizeOfHeaders;
+ unsigned long CheckSum;
+ unsigned short Subsystem;
+ unsigned short DLLFlags;
+ unsigned long SizeOfStackReserve;
+ unsigned long SizeOfStackCommit;
+ unsigned long SizeOfHeapReserve;
+ unsigned long SizeOfHeapCommit;
+ unsigned long LoaderFlags;
+ unsigned long NumDirectories;
+}
+WindowsHeader_t;
+
+typedef struct
+{
+ unsigned long long ImageBase;
+ unsigned long SectionAlignment;
+ unsigned long FileAlignment;
+ unsigned long OSVer;
+ unsigned long ImgVer;
+ unsigned long SubSysVer;
+ unsigned long Reserved;
+ unsigned long SizeOfImage;
+ unsigned long SizeOfHeaders;
+ unsigned long CheckSum;
+ unsigned short Subsystem;
+ unsigned short DLLFlags;
+ unsigned long long SizeOfStackReserve;
+ unsigned long long SizeOfStackCommit;
+ unsigned long long SizeOfHeapReserve;
+ unsigned long long SizeOfHeapCommit;
+ unsigned long LoaderFlags;
+ unsigned long NumDirectories;
+}
+WindowsHeaderPlus_t;
+
+/*
+#define IMAGE_SUBSYSTEM_UNKNOWN 0
+#define IMAGE_SUBSYSTEM_NATIVE 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+
+#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
+#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
+#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0X8000
+*/
+
+/*
+ * Optional Header Data Directories (Image Only)
+ * Spec section 3.4.3
+ */
+
+typedef struct
+{
+ unsigned long RVA;
+ unsigned long Size;
+}
+Image_Data_Directory_t;
+
+enum Directory_Items {
+ EXPORT_TABLE = 0,
+ IMPORT_TABLE,
+ RESOURCE_TABLE,
+ EXCEPTION_TABLE,
+ CERTIFICATE_TABLE,
+ BASE_RELOCATION_TABLE,
+ DEBUG_,
+ ARCHITECTURE,
+ GLOBAL_PTR,
+ TLS_TABLE,
+ LOAD_CONFIG_TABLE,
+ BOUND_IMPORT,
+ IAT,
+ DELAY_IMPORT_DESCRIPTOR,
+ COM_RUNTIME_HEADER,
+ RESERVED
+};
+
+/*
+ * Section Table (Section Headers)
+ * Spec section 4.
+ */
+
+
+typedef struct
+{
+ unsigned char Name[8];
+ unsigned long VirtualSize;
+ unsigned long VirtualAddress;
+ unsigned long SizeOfRawData;
+ unsigned long PtrToRawData;
+ unsigned long PtrToRelocations;
+ unsigned long PtrToLineNums;
+ unsigned short NumRelocations;
+ unsigned short NumLineNumbers;
+ unsigned long Characteristics;
+}
+SectionHeader_t;
+
+/*
+ * Section Flags (Characteristics)
+ * Spec section 4.1
+ */
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_DATA 0x00000040
+#define IMAGE_SCN_CNT_BSS 0x00000080
+#define IMAGE_SCN_LNK_INFO 0x00000200
+#define IMAGE_SCN_LNK_REMOVE 0x00000800
+#define IMAGE_SCN_LNK_COMDAT 0x00001000
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
+#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000
+#define IMAGE_SCN_ALIGN_MASK 0x00F00000
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
+/*
+ * COFF Relocations (Object Only)
+ * Spec section 5.2
+ */
+
+typedef struct
+{
+ unsigned long VirtualAddress;
+ unsigned long SymTableIndex;
+ unsigned short Type;
+}
+ObjReloc_t;
+
+/*
+ * COFF Relocation Type Indicators
+ * Spec section 5.2.1
+ */
+
+#define IMAGE_REL_I386_ABSOLUTE 0x0000
+#define IMAGE_REL_I386_DIR16 0x0001
+#define IMAGE_REL_I386_REL16 0x0002
+#define IMAGE_REL_I386_DIR32 0x0006
+#define IMAGE_REL_I386_DIR32NB 0x0007
+#define IMAGE_REL_I386_SEG12 0x0009
+#define IMAGE_REL_I386_SECTION 0x000A
+#define IMAGE_REL_I386_SECREL 0x000B
+#define IMAGE_REL_I386_REL32 0x0014
+
+/*
+ * COFF Line Numbers
+ * Spec section 5.3
+ */
+
+typedef struct
+{
+ union {
+ unsigned long SymbolTableIndex;
+ unsigned long VirtualAddress;
+ } Type;
+ unsigned short LineNum;
+}
+LineNumbers_t;
+
+/*
+ * COFF Symbol Table
+ * Spec section 5.4
+ */
+
+typedef struct
+{
+ union {
+ unsigned char ShortName[8];
+ unsigned long long Offset;
+ } Name;
+ unsigned long Value;
+ unsigned short SectionNumber;
+ unsigned short Type;
+ unsigned char StorageClass;
+ unsigned char NumberOfAuxSymbols;
+}
+SymbolTable_t;
+
+#if !defined(TARGET_WINDOWS)
+
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE 0xFFFF
+#define IMAGE_SYM_DEBUG 0xFFFE
+
+
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+
+#define IMAGE_SYM_DWORD_NULL 0
+#define IMAGE_SYM_DWORD_POINTER 1
+#define IMAGE_SYM_DWORD_FUNCTION 2
+#define IMAGE_SYM_DWORD_ARRAY 3
+
+
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION 0xFF
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#endif
+
+typedef struct
+{
+ unsigned long TagIndex;
+ unsigned long TotalSize;
+ unsigned long PtrToLineNumber;
+ unsigned long PtrToNextFunc;
+ unsigned short unused;
+}
+AuxFuncDef_t;
+
+/*
+ * Symbol Auxiliary Record: .bf and .ef
+ * Spec section 5.5.2
+ */
+
+typedef struct
+{
+ unsigned long unused;
+ unsigned short LineNumber;
+ unsigned long unused1;
+ unsigned short unused2;
+ unsigned long PtrToNextFunc;
+ unsigned char unused3;
+}
+AuxBfEf_t;
+
+/*
+ * Export Section (Directory)
+ * Spec section 6.3
+ */
+
+/*
+ * Export Directory Table
+ * Spec section 6.3.1
+ */
+
+typedef struct
+{
+ unsigned long ExportFlags;
+ unsigned long TimeStamp;
+ unsigned short MajorVersion;
+ unsigned short MinorVersion;
+ unsigned long Name_RVA;
+ unsigned long OrdinalBase;
+ unsigned long NumAddrTable;
+ unsigned long NumNamePtrs;
+ unsigned long ExportAddressTable_RVA;
+ unsigned long NamePointerTable_RVA;
+ unsigned long OrdinalTable_RVA;
+}
+ExportDirTable_t;
+
+
+/*
+ * Import Section (Directory)
+ * Spec section 6.4
+ */
+
+/*
+ * Import Directory Table
+ * Spec Section 6.4.1
+ */
+
+typedef struct
+{
+ unsigned long ImportLookupTable_RVA;
+ unsigned long TimeStamp;
+ unsigned long ForwarderChain;
+ unsigned long Name_RVA;
+ unsigned long ImportAddressTable_RVA;
+}
+ImportDirTable_t;
+
+/*
+ * .reloc Relocation types
+ * spec section 6.6
+ */
+
+#if 1
+#define IMAGE_REL_BASED_ABSOLUTE 0
+#define IMAGE_REL_BASED_HIGH 1
+#define IMAGE_REL_BASED_LOW 2
+#define IMAGE_REL_BASED_HIGHLOW 3
+#define IMAGE_REL_BASED_HIGHADJ 4
+#define IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define IMAGE_REL_BASED_SECTION 6
+#define IMAGE_REL_BASED_REL32 7
+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define IMAGE_REL_BASED_DIR64 10
+#define IMAGE_REL_BASED_HIGH3ADJ 11
+#endif
+
+
+
+
+#pragma pack()
+
diff --git a/xbmc/cores/DllLoader/coffldr.h b/xbmc/cores/DllLoader/coffldr.h
new file mode 100644
index 0000000..9da7801
--- /dev/null
+++ b/xbmc/cores/DllLoader/coffldr.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+//#pragma message("including coffldr.h")
+#include "coff.h"
+
+#include <stdio.h>
+
+class CoffLoader
+{
+public:
+ CoffLoader();
+ virtual ~CoffLoader();
+
+ int ParseCoff(FILE *fp);
+ int ParseHeaders(void* hModule);
+
+ void *hModule; //standard windows HINSTANCE handle hold the whole image
+ //Pointers to somewhere in hModule, do not free these pointers
+ COFF_FileHeader_t *CoffFileHeader;
+ OptionHeader_t *OptionHeader;
+ WindowsHeader_t *WindowsHeader;
+ Image_Data_Directory_t *Directory;
+ SectionHeader_t *SectionHeader;
+
+protected:
+
+ // Allocated structures... hModule now hold the master Memory handle
+ SymbolTable_t *SymTable;
+ char *StringTable;
+ char **SectionData;
+
+ unsigned long EntryAddress; //Initialize entry point
+
+ // Unnecessary data
+ // This is data that is used only during linking and is not necessary
+ // while the program is running in general
+
+ int NumberOfSymbols;
+ int SizeOfStringTable;
+ int NumOfDirectories;
+ int NumOfSections;
+ int FileHeaderOffset;
+
+ // Members for printing the structures
+ static void PrintFileHeader(COFF_FileHeader_t *FileHeader);
+ static void PrintWindowsHeader(WindowsHeader_t *WinHdr);
+ static void PrintOptionHeader(OptionHeader_t *OptHdr);
+ static void PrintSection(SectionHeader_t* ScnHdr, const char* data);
+ void PrintStringTable(void);
+ void PrintSymbolTable(void);
+
+ // Members for Loading the Different structures
+ int LoadCoffHModule(FILE * fp);
+ int LoadSymTable(FILE *fp);
+ int LoadStringTable(FILE *fp);
+ int LoadSections(FILE *fp);
+
+ // Members for access some of the Data
+
+ int RVA2Section(unsigned long RVA);
+ void* RVA2Data(unsigned long RVA);
+ unsigned long Data2RVA(void* address);
+
+ char *GetStringTblIndex(int index);
+ char *GetStringTblOff(int Offset);
+ char *GetSymbolName(SymbolTable_t *sym);
+ char *GetSymbolName(int index);
+
+ void PerformFixups(void);
+};
+
diff --git a/xbmc/cores/DllLoader/dll.cpp b/xbmc/cores/DllLoader/dll.cpp
new file mode 100644
index 0000000..9690529
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "dll.h"
+
+#include "DllLoader.h"
+#include "DllLoaderContainer.h"
+#include "dll_tracker.h"
+#include "dll_util.h"
+#include "filesystem/SpecialProtocol.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <climits>
+
+#define DEFAULT_DLLPATH "special://xbmc/system/players/mplayer/codecs/"
+#define HIGH_WORD(a) ((uintptr_t)(a) >> 16)
+#define LOW_WORD(a) ((unsigned short)(((uintptr_t)(a)) & MAXWORD))
+
+//#define API_DEBUG
+
+char* getpath(char *buf, const char *full)
+{
+ const char* pos;
+ if ((pos = strrchr(full, PATH_SEPARATOR_CHAR)))
+ {
+ strncpy(buf, full, pos - full + 1 );
+ buf[pos - full + 1] = 0;
+ return buf;
+ }
+ else
+ {
+ buf[0] = 0;
+ return buf;
+ }
+}
+
+extern "C" HMODULE __stdcall dllLoadLibraryExtended(const char* lib_file, const char* sourcedll)
+{
+ char libname[MAX_PATH + 1] = {};
+ char libpath[MAX_PATH + 1] = {};
+ LibraryLoader* dll = NULL;
+
+ /* extract name */
+ const char* p = strrchr(lib_file, PATH_SEPARATOR_CHAR);
+ if (p)
+ strncpy(libname, p+1, sizeof(libname) - 1);
+ else
+ strncpy(libname, lib_file, sizeof(libname) - 1);
+ libname[sizeof(libname) - 1] = '\0';
+
+ if( libname[0] == '\0' )
+ return NULL;
+
+ /* extract path */
+ getpath(libpath, lib_file);
+
+ if (sourcedll)
+ {
+ /* also check for invalid paths which begin with a \ */
+ if( libpath[0] == '\0' || libpath[0] == PATH_SEPARATOR_CHAR )
+ {
+ /* use calling dll's path as base address for this call */
+ getpath(libpath, sourcedll);
+
+ /* mplayer has all it's dlls in a codecs subdirectory */
+ if (strstr(sourcedll, "mplayer.dll"))
+ strcat(libpath, "codecs\\");
+ }
+ }
+
+ /* if we still don't have a path, use default path */
+ if( libpath[0] == '\0' )
+ strcpy(libpath, DEFAULT_DLLPATH);
+
+ /* msdn docs state */
+ /* "If no file name extension is specified in the lpFileName parameter, the default library extension .dll is appended. */
+ /* However, the file name string can include a trailing point character (.) to indicate that the module name has no extension." */
+ if( strrchr(libname, '.') == NULL )
+ strcat(libname, ".dll");
+ else if( libname[strlen(libname)-1] == '.' )
+ libname[strlen(libname)-1] = '\0';
+
+ dll = DllLoaderContainer::LoadModule(libname, libpath);
+
+ if (dll)
+ return (HMODULE)dll->GetHModule();
+
+ CLog::Log(LOGERROR, "LoadLibrary('{}') failed", libname);
+ return NULL;
+}
+
+extern "C" HMODULE __stdcall dllLoadLibraryA(const char* file)
+{
+ return dllLoadLibraryExtended(file, NULL);
+}
+
+#define DONT_RESOLVE_DLL_REFERENCES 0x00000001
+#define LOAD_LIBRARY_AS_DATAFILE 0x00000002
+#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
+#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x00000010
+
+extern "C" HMODULE __stdcall dllLoadLibraryExExtended(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags, const char* sourcedll)
+{
+ char strFlags[512];
+ strFlags[0] = '\0';
+
+ if (dwFlags & DONT_RESOLVE_DLL_REFERENCES) strcat(strFlags, "\n - DONT_RESOLVE_DLL_REFERENCES");
+ if (dwFlags & LOAD_IGNORE_CODE_AUTHZ_LEVEL) strcat(strFlags, "\n - LOAD_IGNORE_CODE_AUTHZ_LEVEL");
+ if (dwFlags & LOAD_LIBRARY_AS_DATAFILE) strcat(strFlags, "\n - LOAD_LIBRARY_AS_DATAFILE");
+ if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) strcat(strFlags, "\n - LOAD_WITH_ALTERED_SEARCH_PATH");
+
+ CLog::Log(LOGDEBUG, "LoadLibraryExA called with flags: {}", strFlags);
+
+ return dllLoadLibraryExtended(lpLibFileName, sourcedll);
+}
+
+extern "C" HMODULE __stdcall dllLoadLibraryExA(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ return dllLoadLibraryExExtended(lpLibFileName, hFile, dwFlags, NULL);
+}
+
+extern "C" int __stdcall dllFreeLibrary(HINSTANCE hLibModule)
+{
+ LibraryLoader* dllhandle = DllLoaderContainer::GetModule(hLibModule);
+
+ if( !dllhandle )
+ {
+ CLog::Log(LOGERROR, "{} - Invalid hModule specified", __FUNCTION__);
+ return 1;
+ }
+
+ // to make sure systems dlls are never deleted
+ if (dllhandle->IsSystemDll()) return 1;
+
+ DllLoaderContainer::ReleaseModule(dllhandle);
+
+ return 1;
+}
+
+extern "C" intptr_t (*__stdcall dllGetProcAddress(HMODULE hModule, const char* function))(void)
+{
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ void* address = NULL;
+ LibraryLoader* dll = DllLoaderContainer::GetModule(hModule);
+
+ if( !dll )
+ {
+ CLog::Log(LOGERROR, "{} - Invalid hModule specified", __FUNCTION__);
+ return NULL;
+ }
+
+ /* how can somebody get the stupid idea to create such a stupid function */
+ /* where you never know if the given pointer is a pointer or a value */
+ if( HIGH_WORD(function) == 0 && LOW_WORD(function) < 1000)
+ {
+ if( dll->ResolveOrdinal(LOW_WORD(function), &address) )
+ {
+ CLog::Log(LOGDEBUG, "{}({}({}), {}) => {}", __FUNCTION__, fmt::ptr(hModule), dll->GetName(),
+ LOW_WORD(function), fmt::ptr(address));
+ }
+ else if( dll->IsSystemDll() )
+ {
+ char ordinal[6] = {};
+ sprintf(ordinal, "%u", LOW_WORD(function));
+ address = (void*)create_dummy_function(dll->GetName(), ordinal);
+
+ /* add to tracklist if we are tracking this source dll */
+ DllTrackInfo* track = tracker_get_dlltrackinfo(loc);
+ if( track )
+ tracker_dll_data_track(track->pDll, (uintptr_t)address);
+
+ CLog::Log(LOGDEBUG, "{} - created dummy function {}!{}", __FUNCTION__, dll->GetName(),
+ ordinal);
+ }
+ else
+ {
+ address = NULL;
+ CLog::Log(LOGDEBUG, "{}({}({}), '{}') => {}", __FUNCTION__, fmt::ptr(hModule), dll->GetName(),
+ function, fmt::ptr(address));
+ }
+ }
+ else
+ {
+ if( dll->ResolveExport(function, &address) )
+ {
+ CLog::Log(LOGDEBUG, "{}({}({}), '{}') => {}", __FUNCTION__, fmt::ptr(hModule), dll->GetName(),
+ function, fmt::ptr(address));
+ }
+ else
+ {
+ DllTrackInfo* track = tracker_get_dlltrackinfo(loc);
+ /* some dll's require us to always return a function or it will fail, other's */
+ /* decide functionality depending on if the functions exist and may fail */
+ if (dll->IsSystemDll() && track &&
+ StringUtils::CompareNoCase(track->pDll->GetName(), "CoreAVCDecoder.ax") == 0)
+ {
+ address = (void*)create_dummy_function(dll->GetName(), function);
+ tracker_dll_data_track(track->pDll, (uintptr_t)address);
+ CLog::Log(LOGDEBUG, "{} - created dummy function {}!{}", __FUNCTION__, dll->GetName(),
+ function);
+ }
+ else
+ {
+ address = NULL;
+ CLog::Log(LOGDEBUG, "{}({}({}), '{}') => {}", __FUNCTION__, fmt::ptr(hModule),
+ dll->GetName(), function, fmt::ptr(address));
+ }
+ }
+ }
+
+ return (intptr_t(*)(void)) address;
+}
+
+extern "C" HMODULE WINAPI dllGetModuleHandleA(const char* lpModuleName)
+{
+ /*
+ If the file name extension is omitted, the default library extension .dll is appended.
+ The file name string can include a trailing point character (.) to indicate that the module name has no extension.
+ The string does not have to specify a path. When specifying a path, be sure to use backslashes (\), not forward slashes (/).
+ The name is compared (case independently)
+ If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).
+ */
+
+ if( lpModuleName == NULL )
+ return NULL;
+
+ char* strModuleName = new char[strlen(lpModuleName) + 5];
+ strcpy(strModuleName, lpModuleName);
+
+ if (strrchr(strModuleName, '.') == 0) strcat(strModuleName, ".dll");
+
+ //CLog::Log(LOGDEBUG, "GetModuleHandleA({}) .. looking up", lpModuleName);
+
+ LibraryLoader *p = DllLoaderContainer::GetModule(strModuleName);
+ delete []strModuleName;
+
+ if (p)
+ {
+ //CLog::Log(LOGDEBUG, "GetModuleHandleA('{}') => 0x{:x}", lpModuleName, h);
+ return (HMODULE)p->GetHModule();
+ }
+
+ CLog::Log(LOGDEBUG, "GetModuleHandleA('{}') failed", lpModuleName);
+ return NULL;
+}
diff --git a/xbmc/cores/DllLoader/dll.h b/xbmc/cores/DllLoader/dll.h
new file mode 100644
index 0000000..5a0b605
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "PlatformDefs.h"
+
+extern "C" HMODULE __stdcall dllLoadLibraryExtended(const char* file, const char* sourcedll);
+extern "C" HMODULE __stdcall dllLoadLibraryA(const char* file);
+extern "C" HMODULE __stdcall dllLoadLibraryExExtended(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags, const char* sourcedll);
+extern "C" HMODULE __stdcall dllLoadLibraryExA(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags);
+extern "C" int __stdcall dllFreeLibrary(HINSTANCE hLibModule);
+extern "C" intptr_t (*__stdcall dllGetProcAddress(HMODULE hModule, const char* function))(void);
+extern "C" HMODULE WINAPI dllGetModuleHandleA(const char* lpModuleName);
+
diff --git a/xbmc/cores/DllLoader/dll_tracker.cpp b/xbmc/cores/DllLoader/dll_tracker.cpp
new file mode 100644
index 0000000..252232d
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "dll_tracker.h"
+
+#include "DllLoader.h"
+#include "dll_tracker_file.h"
+#include "dll_tracker_library.h"
+#include "utils/log.h"
+
+#include <mutex>
+#include <stdlib.h>
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif
+
+CCriticalSection g_trackerLock;
+TrackedDllList g_trackedDlls;
+
+void tracker_dll_add(DllLoader* pDll)
+{
+ DllTrackInfo* trackInfo = new DllTrackInfo;
+ trackInfo->pDll = pDll;
+ trackInfo->lMinAddr = 0;
+ trackInfo->lMaxAddr = 0;
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ g_trackedDlls.push_back(trackInfo);
+}
+
+void tracker_dll_free(DllLoader* pDll)
+{
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end();)
+ {
+ // NOTE: This code assumes that the same dll pointer can be in more than one
+ // slot of the vector g_trackedDlls. If it's not, then it can be
+ // simplified by returning after we've found the one we want, saving
+ // the iterator shuffling, and reducing potential bugs.
+ if ((*it)->pDll == pDll)
+ {
+ try
+ {
+ tracker_library_free_all(*it);
+ tracker_file_free_all(*it);
+ }
+ catch (...)
+ {
+ CLog::Log(LOGFATAL, "Error freeing tracked dll resources");
+ }
+ // free all functions which where created at the time we loaded the dll
+ DummyListIter dit = (*it)->dummyList.begin();
+ while (dit != (*it)->dummyList.end()) { free((void*)*dit); ++dit; }
+ (*it)->dummyList.clear();
+
+ delete (*it);
+ it = g_trackedDlls.erase(it);
+ }
+ else
+ ++it;
+ }
+}
+
+void tracker_dll_set_addr(const DllLoader* pDll, uintptr_t min, uintptr_t max)
+{
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end(); ++it)
+ {
+ if ((*it)->pDll == pDll)
+ {
+ (*it)->lMinAddr = min;
+ (*it)->lMaxAddr = max;
+ break;
+ }
+ }
+}
+
+const char* tracker_getdllname(uintptr_t caller)
+{
+ DllTrackInfo *track = tracker_get_dlltrackinfo(caller);
+ if(track)
+ return track->pDll->GetFileName();
+ return "";
+}
+
+DllTrackInfo* tracker_get_dlltrackinfo(uintptr_t caller)
+{
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end(); ++it)
+ {
+ if (caller >= (*it)->lMinAddr && caller <= (*it)->lMaxAddr)
+ {
+ return *it;
+ }
+ }
+
+ // crap not in any base address, check if it may be in virtual spaces
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end(); ++it)
+ {
+ for(VAllocListIter it2 = (*it)->virtualList.begin(); it2 != (*it)->virtualList.end(); ++it2)
+ {
+ if( it2->first <= caller && caller < it2->first + it2->second.size )
+ return *it;
+
+ }
+ }
+
+ return NULL;
+}
+
+DllTrackInfo* tracker_get_dlltrackinfo_byobject(const DllLoader* pDll)
+{
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end(); ++it)
+ {
+ if ((*it)->pDll == pDll)
+ {
+ return *it;
+ }
+ }
+ return NULL;
+}
+
+void tracker_dll_data_track(const DllLoader* pDll, uintptr_t addr)
+{
+ std::unique_lock<CCriticalSection> locktd(g_trackerLock);
+ for (TrackedDllsIter it = g_trackedDlls.begin(); it != g_trackedDlls.end(); ++it)
+ {
+ if (pDll == (*it)->pDll)
+ {
+ (*it)->dummyList.push_back((uintptr_t)addr);
+ break;
+ }
+ }
+}
+
+#ifdef _cplusplus
+}
+#endif
diff --git a/xbmc/cores/DllLoader/dll_tracker.h b/xbmc/cores/DllLoader/dll_tracker.h
new file mode 100644
index 0000000..68e1779
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "threads/CriticalSection.h"
+#include "PlatformDefs.h"
+#ifdef TARGET_WINDOWS
+#if defined(TARGET_WINDOWS_STORE)
+#include <WinSock2.h>
+#endif
+#endif
+
+#include <list>
+#include <map>
+
+class DllLoader;
+
+struct AllocLenCaller
+{
+ size_t size;
+ uintptr_t calleraddr;
+};
+
+enum TrackedFileType
+{
+ FILE_XBMC_OPEN,
+ FILE_XBMC_FOPEN,
+ FILE_OPEN,
+ FILE_FOPEN
+};
+
+typedef struct _TrackedFile
+{
+ TrackedFileType type;
+ uintptr_t handle;
+ char* name;
+} TrackedFile;
+
+typedef std::map<uintptr_t, AllocLenCaller> DataList;
+typedef std::map<uintptr_t, AllocLenCaller>::iterator DataListIter;
+
+typedef std::list<TrackedFile*> FileList;
+typedef std::list<TrackedFile*>::iterator FileListIter;
+
+typedef std::list<HMODULE> DllList;
+typedef std::list<HMODULE>::iterator DllListIter;
+
+typedef std::list<uintptr_t> DummyList;
+typedef std::list<uintptr_t>::iterator DummyListIter;
+
+typedef std::list<SOCKET> SocketList;
+typedef std::list<SOCKET>::iterator SocketListIter;
+
+typedef std::list<HANDLE> HeapObjectList;
+typedef std::list<HANDLE>::iterator HeapObjectListIter;
+
+typedef std::map<uintptr_t, AllocLenCaller> VAllocList;
+typedef std::map<uintptr_t, AllocLenCaller>::iterator VAllocListIter;
+
+typedef struct _DllTrackInfo
+{
+ DllLoader* pDll;
+ uintptr_t lMinAddr;
+ uintptr_t lMaxAddr;
+
+ DataList dataList;
+
+ // list with dll's that are loaded by this dll
+ DllList dllList;
+
+ // for dummy functions that are created if no exported function could be found
+ DummyList dummyList;
+
+ FileList fileList;
+ SocketList socketList;
+
+ HeapObjectList heapobjectList;
+
+ VAllocList virtualList;
+} DllTrackInfo;
+
+class TrackedDllList : public std::list<DllTrackInfo*>, public CCriticalSection {};
+typedef std::list<DllTrackInfo*>::iterator TrackedDllsIter;
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif
+
+extern CCriticalSection g_trackerLock;
+extern TrackedDllList g_trackedDlls;
+
+// add a dll for tracking
+void tracker_dll_add(DllLoader* pDll);
+
+// remove a dll, and free all its resources
+void tracker_dll_free(DllLoader* pDll);
+
+// sets the dll base address and size
+void tracker_dll_set_addr(const DllLoader* pDll, uintptr_t min, uintptr_t max);
+
+// returns the name from the dll that contains this address or "" if not found
+const char* tracker_getdllname(uintptr_t caller);
+
+// returns a function pointer if there is one available for it, or NULL if not ofund
+void* tracker_dll_get_function(DllLoader* pDll, char* sFunctionName);
+
+DllTrackInfo* tracker_get_dlltrackinfo_byobject(const DllLoader* pDll);
+
+DllTrackInfo* tracker_get_dlltrackinfo(uintptr_t caller);
+
+void tracker_dll_data_track(const DllLoader* pDll, uintptr_t addr);
+
+#ifdef TARGET_POSIX
+#define _ReturnAddress() __builtin_return_address(0)
+#endif
+
+#ifdef _cplusplus
+}
+#endif
+
+#ifndef TARGET_POSIX
+extern "C" void * _ReturnAddress(void);
+#pragma intrinsic(_ReturnAddress)
+#endif
+
diff --git a/xbmc/cores/DllLoader/dll_tracker_file.cpp b/xbmc/cores/DllLoader/dll_tracker_file.cpp
new file mode 100644
index 0000000..b5d1214
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker_file.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "dll_tracker_file.h"
+
+#include "DllLoader.h"
+#include "dll_tracker.h"
+#include "utils/log.h"
+
+#include <mutex>
+#include <stdlib.h>
+
+#ifdef TARGET_POSIX
+#define dll_open open
+#define dll_fopen fopen
+#define dll_close close
+#define dll_fclose fclose
+#define dll_freopen freopen
+#else
+#include "exports/emu_msvcrt.h"
+#include <io.h>
+#endif
+
+extern "C" void tracker_file_track(uintptr_t caller, uintptr_t handle, TrackedFileType type, const char* sFile)
+{
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(caller);
+ if (pInfo)
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ TrackedFile* file = new TrackedFile;
+ file->handle = handle;
+ file->type = type;
+ file->name = strdup(sFile);
+ pInfo->fileList.push_back(file);
+ }
+}
+
+extern "C" void tracker_file_free(uintptr_t caller, uintptr_t handle, TrackedFileType type)
+{
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(caller);
+ if (pInfo)
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ for (FileListIter it = pInfo->fileList.begin(); it != pInfo->fileList.end(); ++it)
+ {
+ TrackedFile* file = *it;
+ if (file->handle == handle && file->type == type)
+ {
+ free(file->name);
+ delete file;
+ pInfo->fileList.erase(it);
+ return;
+ }
+ }
+ }
+ CLog::Log(LOGWARNING, "unable to remove tracked file from tracker");
+}
+
+extern "C" void tracker_file_free_all(DllTrackInfo* pInfo)
+{
+ if (!pInfo->fileList.empty())
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ CLog::Log(LOGDEBUG, "{0}: Detected open files: {1}", pInfo->pDll->GetFileName(), pInfo->fileList.size());
+ for (FileListIter it = pInfo->fileList.begin(); it != pInfo->fileList.end(); ++it)
+ {
+ TrackedFile* file = *it;
+ CLog::Log(LOGDEBUG, "{}", file->name);
+ free(file->name);
+
+ if (file->type == FILE_XBMC_OPEN) dll_close(file->handle);
+ else if (file->type == FILE_XBMC_FOPEN) dll_fclose((FILE*)file->handle);
+ else if (file->type == FILE_OPEN) close(file->handle);
+ else if (file->type == FILE_FOPEN) fclose((FILE*)file->handle);
+
+ delete file;
+ }
+ }
+ pInfo->fileList.erase(pInfo->fileList.begin(), pInfo->fileList.end());
+}
+
+extern "C"
+{
+ int track_open(const char* sFileName, int iMode)
+ {
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ int fd = dll_open(sFileName, iMode);
+ if (fd >= 0) tracker_file_track(loc, fd, FILE_XBMC_OPEN, sFileName);
+ return fd;
+ }
+
+ int track_close(int fd)
+ {
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ tracker_file_free(loc, fd, FILE_XBMC_OPEN);
+ return dll_close(fd);
+ }
+
+ FILE* track_fopen(const char* sFileName, const char* mode)
+ {
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ FILE* fd = dll_fopen(sFileName, mode);
+ if (fd) tracker_file_track(loc, (uintptr_t)fd, FILE_XBMC_FOPEN, sFileName);
+ return fd;
+ }
+
+ int track_fclose(FILE* stream)
+ {
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ tracker_file_free(loc, (uintptr_t)stream, FILE_XBMC_FOPEN);
+ return dll_fclose(stream);
+ }
+
+ FILE* track_freopen(const char *path, const char *mode, FILE *stream)
+ {
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ tracker_file_free(loc, (uintptr_t)stream, FILE_XBMC_FOPEN);
+ stream = dll_freopen(path, mode, stream);
+ if (stream)
+ tracker_file_track(loc, (uintptr_t)stream, FILE_XBMC_FOPEN, path);
+ return stream;
+ }
+
+}
diff --git a/xbmc/cores/DllLoader/dll_tracker_file.h b/xbmc/cores/DllLoader/dll_tracker_file.h
new file mode 100644
index 0000000..e6be371
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker_file.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "dll_tracker.h"
+
+#include <stdio.h>
+
+extern "C" void tracker_file_track(uintptr_t caller, uintptr_t handle, TrackedFileType type, const char* sFile = "");
+extern "C" void tracker_file_free(uintptr_t caller, uintptr_t handle, TrackedFileType type);
+extern "C" void tracker_file_free_all(DllTrackInfo* pInfo);
+
+extern "C"
+{
+ int track_open(const char* sFileName, int iMode);
+ int track_close(int fd);
+ FILE* track_fopen(const char* sFileName, const char* mode);
+ int track_fclose(FILE* stream);
+ FILE* track_freopen(const char *path, const char *mode, FILE *stream);
+}
+
diff --git a/xbmc/cores/DllLoader/dll_tracker_library.cpp b/xbmc/cores/DllLoader/dll_tracker_library.cpp
new file mode 100644
index 0000000..8cfac13
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker_library.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "dll_tracker_library.h"
+
+#include "DllLoader.h"
+#include "DllLoaderContainer.h"
+#include "dll.h"
+#include "dll_tracker.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+extern "C" inline void tracker_library_track(uintptr_t caller, HMODULE hHandle)
+{
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(caller);
+ if (pInfo && hHandle)
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ pInfo->dllList.push_back(hHandle);
+ }
+}
+
+extern "C" inline void tracker_library_free(uintptr_t caller, HMODULE hHandle)
+{
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(caller);
+ if (pInfo && hHandle)
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ for (DllListIter it = pInfo->dllList.begin(); it != pInfo->dllList.end(); ++it)
+ {
+ if (*it == hHandle)
+ {
+ pInfo->dllList.erase(it);
+ break;
+ }
+ }
+ }
+}
+
+extern "C" void tracker_library_free_all(DllTrackInfo* pInfo)
+{
+ // unloading unloaded dll's
+ if (!pInfo->dllList.empty())
+ {
+ std::unique_lock<CCriticalSection> lock(g_trackerLock);
+ CLog::Log(LOGDEBUG,"{0}: Detected {1} unloaded dll's", pInfo->pDll->GetFileName(), pInfo->dllList.size());
+ for (DllListIter it = pInfo->dllList.begin(); it != pInfo->dllList.end(); ++it)
+ {
+ LibraryLoader* pDll = DllLoaderContainer::GetModule((HMODULE)*it);
+ if( !pDll)
+ {
+ CLog::Log(LOGERROR, "{} - Invalid module in tracker", __FUNCTION__);
+ return;
+ }
+
+ if (!pDll->IsSystemDll())
+ {
+ if (strlen(pDll->GetFileName()) > 0)
+ CLog::Log(LOGDEBUG, " : {}", pDll->GetFileName());
+ }
+ }
+
+ // now unload the dlls
+ for (DllListIter it = pInfo->dllList.begin(); it != pInfo->dllList.end(); ++it)
+ {
+ LibraryLoader* pDll = DllLoaderContainer::GetModule((HMODULE)*it);
+ if( !pDll)
+ {
+ CLog::Log(LOGERROR, "{} - Invalid module in tracker", __FUNCTION__);
+ return;
+ }
+
+ if (!pDll->IsSystemDll())
+ {
+ dllFreeLibrary((HMODULE)pDll->GetHModule());
+ }
+ }
+ }
+}
+
+extern "C" HMODULE __stdcall track_LoadLibraryA(const char* file)
+{
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(loc);
+ const char* path = NULL;
+ if (pInfo) path = pInfo->pDll->GetFileName();
+
+ HMODULE hHandle = dllLoadLibraryExtended(file, path);
+ tracker_library_track(loc, hHandle);
+
+ return hHandle;
+}
+
+extern "C" HMODULE __stdcall track_LoadLibraryExA(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ DllTrackInfo* pInfo = tracker_get_dlltrackinfo(loc);
+ const char* path = NULL;
+ if (pInfo) path = pInfo->pDll->GetFileName();
+
+ HMODULE hHandle = dllLoadLibraryExExtended(lpLibFileName, hFile, dwFlags, path);
+ tracker_library_track(loc, hHandle);
+
+ return hHandle;
+}
+
+extern "C" int __stdcall track_FreeLibrary(HINSTANCE hLibModule)
+{
+ uintptr_t loc = (uintptr_t)_ReturnAddress();
+
+ tracker_library_free(loc, hLibModule);
+
+ return dllFreeLibrary(hLibModule);
+}
diff --git a/xbmc/cores/DllLoader/dll_tracker_library.h b/xbmc/cores/DllLoader/dll_tracker_library.h
new file mode 100644
index 0000000..6670d70
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_tracker_library.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "dll_tracker.h"
+
+extern "C" void tracker_library_free_all(DllTrackInfo* pInfo);
+
+extern "C" HMODULE __stdcall track_LoadLibraryA(const char* file);
+extern "C" HMODULE __stdcall track_LoadLibraryExA(const char* lpLibFileName, HANDLE hFile, DWORD dwFlags);
+extern "C" int __stdcall track_FreeLibrary(HINSTANCE hLibModule);
diff --git a/xbmc/cores/DllLoader/dll_util.cpp b/xbmc/cores/DllLoader/dll_util.cpp
new file mode 100644
index 0000000..b33c02e
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_util.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "utils/log.h"
+#include "dll_util.h"
+
+#ifdef TARGET_WINDOWS
+#include "platform/win32/CharsetConverter.h"
+#include <windows.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif
+
+static int iDllDummyOutputCall = 0;
+void dll_dummy_output(char* dllname, char* funcname)
+{
+ CLog::Log(LOGERROR, "{}: Unresolved function called ({}), Count number {}", dllname, funcname,
+ ++iDllDummyOutputCall);
+}
+
+// this piece of asm code only calls dll_dummy_output(s, s) and will return NULL
+unsigned char dummy_func[] = {
+ 0x55, // push ebp
+ 0x8b, 0xec, // mov ebp,esp
+ 0xa1, 0, 0, 0, 0, // mov eax,dword ptr [0 0 0 0]
+ 0x50, // push eax
+ 0xa1, 0, 0, 0, 0, // mov eax,dword ptr [0 0 0 0]
+ 0x50, // push eax
+ 0xff, 0x15, 0, 0, 0, 0, // call dword ptr[dll_dummy_output]
+ 0x83, 0xc4, 0x08, // add esp,8
+ 0x33, 0xc0, // xor eax,eax // return NULL
+ 0x5d, // pop ebp
+ 0xc3 // ret
+ };
+
+/* Create a new callable function
+ * This allocates a few bytes with the next content
+ *
+ * 1 function in assembly code (dummy_func)
+ * 2 datapointer (pointer to dll string)
+ * 3 datapointer (pointer to function string)
+ * 4 datapointer (pointer to function string)
+ * 5 string (string of chars representing dll name)
+ * 6 string (string of chars representing function name)
+ */
+uintptr_t create_dummy_function(const char* strDllName, const char* strFunctionName)
+{
+ size_t iFunctionSize = sizeof(dummy_func);
+ size_t iDllNameSize = strlen(strDllName) + 1;
+ size_t iFunctionNameSize = strlen(strFunctionName) + 1;
+
+ // allocate memory for function + strings + 3 x 4 bytes for three datapointers
+ char* pData = (char*)malloc(iFunctionSize + 12 + iDllNameSize + iFunctionNameSize);
+ if (!pData)
+ return 0;
+
+ char* offDataPointer1 = pData + iFunctionSize;
+ char* offDataPointer2 = pData + iFunctionSize + 4;
+ char* offDataPointer3 = pData + iFunctionSize + 8;
+ char* offStringDll = pData + iFunctionSize + 12;
+ char* offStringFunc = pData + iFunctionSize + 12 + iDllNameSize;
+
+ // 1 copy assembly code
+ memcpy(pData, dummy_func, iFunctionSize);
+
+ // insert pointers to datapointers into assembly code (fills 0x00000000 in dummy_func)
+ *(int*)(pData + 4) = (intptr_t)offDataPointer1;
+ *(int*)(pData + 10) = (intptr_t)offDataPointer2;
+ *(int*)(pData + 17) = (intptr_t)offDataPointer3;
+
+ // 2 fill datapointer with pointer to 5 (string)
+ *(int*)offDataPointer1 = (intptr_t)offStringFunc;
+ // 3 fill datapointer with pointer to 6 (string)
+ *(int*)offDataPointer2 = (intptr_t)offStringDll;
+ // 4 fill datapointer with pointer to dll_dummy_output
+ *(int*)offDataPointer3 = (intptr_t)dll_dummy_output;
+
+ // copy arguments to 5 (string) and 6 (string)
+ memcpy(offStringDll, strDllName, iDllNameSize);
+ memcpy(offStringFunc, strFunctionName, iFunctionNameSize);
+
+ return (uintptr_t)pData;
+}
+
+uintptr_t get_win_function_address(const char* strDllName, const char* strFunctionName)
+{
+#ifdef TARGET_WINDOWS_DESKTOP
+ using KODI::PLATFORM::WINDOWS::ToW;
+ auto strDllNameW = ToW(strDllName);
+ HMODULE handle = GetModuleHandle(strDllNameW.c_str());
+ if(handle == nullptr)
+ {
+ handle = LoadLibrary(strDllNameW.c_str());
+ }
+ if(handle != nullptr)
+ {
+ auto pGNSI = reinterpret_cast<uintptr_t>(GetProcAddress(handle, strFunctionName));
+ if(pGNSI != NULL)
+ return pGNSI;
+
+ FreeLibrary(handle);
+ }
+#endif
+ return 0;
+}
+
+#ifdef _cplusplus
+}
+#endif
diff --git a/xbmc/cores/DllLoader/dll_util.h b/xbmc/cores/DllLoader/dll_util.h
new file mode 100644
index 0000000..3b0b6c4
--- /dev/null
+++ b/xbmc/cores/DllLoader/dll_util.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif
+
+uintptr_t create_dummy_function(const char* strDllName, const char* strFunctionName);
+uintptr_t get_win_function_address(const char* strDllName, const char* strFunctionName);
+
+#ifdef _cplusplus
+}
+#endif
+
diff --git a/xbmc/cores/DllLoader/exports/CMakeLists.txt b/xbmc/cores/DllLoader/exports/CMakeLists.txt
new file mode 100644
index 0000000..4039669
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/CMakeLists.txt
@@ -0,0 +1,33 @@
+set(SOURCES emu_dummy.cpp
+ emu_msvcrt.cpp)
+
+set(HEADERS emu_dummy.h
+ emu_msvcrt.h)
+
+core_add_library(dllexports)
+
+if(APPLE)
+ add_library(wrapper OBJECT wrapper.c)
+ add_custom_target(wrapper.def ALL ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_mach_alias wrapper.def)
+ set_target_properties(wrapper PROPERTIES FOLDER "Build Utilities")
+ set_target_properties(wrapper.def PROPERTIES FOLDER "Build Utilities")
+ add_dependencies(wrapper.def wrapper)
+elseif(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+ add_options(C ALL_BUILDS "-fPIC")
+ add_library(wrapper OBJECT wrapper.c)
+
+ if(USE_LTO)
+ add_custom_target(wrapper.def ALL ${CMAKE_NM} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/wrapper.dir/wrapper.c.o | grep __wrap | awk '{ printf(\"%s \", \$\$3) }' | sed \"s/^/${CMAKE_C_COMPILE_OPTIONS_IPO} /\" | sed \"s/___wrap_/__wrap_/g\" | sed \"s/__wrap_/-Wl,-wrap,/g\" > wrapper.def && test -s wrapper.def)
+ else()
+ add_custom_target(wrapper.def ALL ${CMAKE_NM} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/wrapper.dir/wrapper.c.o | grep __wrap | awk '{ printf(\"%s \", \$\$3) }' | sed \"s/___wrap_/__wrap_/g\" | sed \"s/__wrap_/-Wl,-wrap,/g\" > wrapper.def && test -s wrapper.def)
+ endif()
+
+ if(CORE_SYSTEM_NAME STREQUAL android)
+ add_custom_command(TARGET wrapper.def COMMAND echo \"-L${DEPENDS_PATH}/lib/dummy-lib${APP_NAME_LC} -l${APP_NAME_LC}\" >> wrapper.def)
+ endif()
+
+ set_target_properties(wrapper PROPERTIES FOLDER "Build Utilities")
+ set_target_properties(wrapper.def PROPERTIES FOLDER "Build Utilities")
+ add_dependencies(wrapper.def wrapper)
+endif()
+
diff --git a/xbmc/cores/DllLoader/exports/emu_dummy.cpp b/xbmc/cores/DllLoader/exports/emu_dummy.cpp
new file mode 100644
index 0000000..813c901
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/emu_dummy.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "emu_dummy.h"
+
+#include "utils/log.h"
+
+extern "C" void not_implement( const char* debuginfo)
+{
+ if (debuginfo)
+ {
+ CLog::Log(LOGDEBUG, "{}", debuginfo);
+ }
+}
+
diff --git a/xbmc/cores/DllLoader/exports/emu_dummy.h b/xbmc/cores/DllLoader/exports/emu_dummy.h
new file mode 100644
index 0000000..f49e214
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/emu_dummy.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ void not_implement( const char* );
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp
new file mode 100644
index 0000000..3f555db
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp
@@ -0,0 +1,2074 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include <math.h>
+#include <mutex>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef TARGET_POSIX
+#include <io.h>
+#include <direct.h>
+#include <process.h>
+#include <errno.h>
+#else
+#if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
+#include <mntent.h>
+#endif
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#if !defined(TARGET_FREEBSD) && (!defined(TARGET_ANDROID) && defined(__LP64__))
+#include <sys/timeb.h>
+#endif
+#ifdef HAS_DVD_DRIVE
+ #ifdef TARGET_POSIX
+ #include <sys/ioctl.h>
+ #if defined(TARGET_DARWIN)
+ #include <IOKit/storage/IODVDMediaBSDClient.h>
+ #elif !defined(TARGET_FREEBSD)
+ #include <linux/cdrom.h>
+ #endif
+ #endif
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#ifdef TARGET_POSIX
+#include "PlatformDefs.h" // for __stat64
+#endif
+#include "CompileInfo.h"
+#include "FileItem.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "emu_dummy.h"
+#include "emu_msvcrt.h"
+#include "filesystem/Directory.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "util/EmuFileWrapper.h"
+#include "utils/log.h"
+#ifndef TARGET_POSIX
+#include "utils/CharsetConverter.h"
+#include "utils/URIUtils.h"
+#endif
+#if !defined(TARGET_WINDOWS)
+#include <dlfcn.h>
+#endif
+#include "platform/Environment.h"
+#include "utils/StringUtils.h"
+#include "utils/XTimeUtils.h"
+
+#if defined(TARGET_WINDOWS)
+#include "platform/win32/CharsetConverter.h"
+#endif
+
+using namespace XFILE;
+
+struct SDirData
+{
+ CFileItemList items;
+ int curr_index;
+ struct dirent *last_entry;
+ SDirData()
+ {
+ curr_index = -1;
+ last_entry = NULL;
+ }
+};
+
+#define MAX_OPEN_DIRS 10
+static SDirData vecDirsOpen[MAX_OPEN_DIRS];
+bool bVecDirsInited = false;
+extern void update_cache_dialog(const char* tmp);
+
+#define EMU_MAX_ENVIRONMENT_ITEMS 100
+static char *dll__environ_imp[EMU_MAX_ENVIRONMENT_ITEMS + 1];
+extern "C" char **dll__environ;
+char **dll__environ = dll__environ_imp;
+
+CCriticalSection dll_cs_environ;
+
+extern "C" void __stdcall init_emu_environ()
+{
+ memset(dll__environ, 0, EMU_MAX_ENVIRONMENT_ITEMS + 1);
+
+ // python
+#if defined(TARGET_WINDOWS_DESKTOP)
+ using KODI::PLATFORM::WINDOWS::FromW;
+ // fill our array with the windows system vars
+ LPTSTR lpszVariable;
+ LPTCH lpvEnv = NULL;
+ lpvEnv = GetEnvironmentStrings();
+ if (lpvEnv != NULL)
+ {
+ lpszVariable = (LPTSTR) lpvEnv;
+ while (*lpszVariable)
+ {
+ dll_putenv(FromW(lpszVariable).c_str());
+ lpszVariable += lstrlen(lpszVariable) + 1;
+ }
+ FreeEnvironmentStrings(lpvEnv);
+ }
+ dll_putenv("OS=win32");
+#elif defined(TARGET_WINDOWS_STORE)
+ dll_putenv("OS=win10");
+#elif defined(TARGET_DARWIN)
+ dll_putenv("OS=darwin");
+#elif defined(TARGET_POSIX)
+ dll_putenv("OS=linux");
+#else
+ dll_putenv("OS=unknown");
+#endif
+
+ // check if we are running as real xbmc.app or just binary
+ if (!CUtil::GetFrameworksPath(true).empty())
+ {
+ // using external python, it's build looking for xxx/lib/python(VERSIONMAJOR.MINOR)
+ // so point it to frameworks which is where python is located
+ dll_putenv(("PYTHONPATH=" +
+ CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
+ dll_putenv(("PYTHONHOME=" +
+ CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
+ dll_putenv(("PATH=.;" +
+ CSpecialProtocol::TranslatePath("special://xbmc") + ";" +
+ CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
+ }
+ else
+ {
+ dll_putenv(("PYTHONPATH=" +
+ CSpecialProtocol::TranslatePath("special://xbmc/system/python/DLLs") + ";" +
+ CSpecialProtocol::TranslatePath("special://xbmc/system/python/Lib")).c_str());
+ dll_putenv(("PYTHONHOME=" +
+ CSpecialProtocol::TranslatePath("special://xbmc/system/python")).c_str());
+ dll_putenv(("PATH=.;" + CSpecialProtocol::TranslatePath("special://xbmc") + ";" +
+ CSpecialProtocol::TranslatePath("special://xbmc/system/python")).c_str());
+ }
+
+#if defined(TARGET_ANDROID)
+ std::string apkPath = getenv("KODI_ANDROID_APK");
+ apkPath += "/assets/python" + CCompileInfo::GetPythonVersion();
+ dll_putenv(("PYTHONHOME=" + apkPath).c_str());
+ dll_putenv("PYTHONOPTIMIZE=");
+ dll_putenv("PYTHONNOUSERSITE=1");
+ dll_putenv("PYTHONPATH=");
+#else
+ dll_putenv("PYTHONOPTIMIZE=1");
+#endif
+
+ //dll_putenv("PYTHONCASEOK=1");
+ //dll_putenv("PYTHONDEBUG=1");
+ //dll_putenv("PYTHONVERBOSE=2"); // "1" for normal verbose, "2" for more verbose ?
+ //dll_putenv("PYTHONDUMPREFS=1");
+ //dll_putenv("THREADDEBUG=1");
+ //dll_putenv("PYTHONMALLOCSTATS=1");
+ //dll_putenv("PYTHONY2K=1");
+ dll_putenv("TEMP=special://temp/temp"); // for python tempdir
+
+ // libdvdnav
+ dll_putenv("DVDREAD_NOKEYS=1");
+ //dll_putenv("DVDREAD_VERBOSE=1");
+ //dll_putenv("DVDREAD_USE_DIRECT=1");
+
+ // libdvdcss
+ dll_putenv("DVDCSS_METHOD=key");
+ dll_putenv("DVDCSS_VERBOSE=3");
+ dll_putenv("DVDCSS_CACHE=special://masterprofile/cache");
+}
+
+extern "C" void __stdcall update_emu_environ()
+{
+ const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
+
+ // Use a proxy, if the GUI was configured as such
+ if (settings->GetBool(CSettings::SETTING_NETWORK_USEHTTPPROXY)
+ && !settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER).empty()
+ && settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT) > 0
+ && settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYTYPE) == 0)
+ {
+ std::string strProxy;
+ if (!settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME).empty() &&
+ !settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD).empty())
+ {
+ strProxy = StringUtils::Format(
+ "{}:{}@", settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME),
+ settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD));
+ }
+
+ strProxy += settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER);
+ strProxy +=
+ StringUtils::Format(":{}", settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT));
+
+ CEnvironment::setenv( "HTTP_PROXY", "http://" + strProxy, true );
+ CEnvironment::setenv( "HTTPS_PROXY", "http://" + strProxy, true );
+ }
+ else
+ {
+ // is there a better way to delete an environment variable?
+ // this works but leaves the variable
+ dll_putenv( "HTTP_PROXY=" );
+ dll_putenv( "HTTPS_PROXY=" );
+ }
+}
+
+extern "C" void __stdcall cleanup_emu_environ()
+{
+ for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS; i++)
+ {
+ free(dll__environ[i]);
+ dll__environ[i] = NULL;
+ }
+}
+
+static int convert_fmode(const char* mode)
+{
+ int iMode = O_BINARY;
+ if (strstr(mode, "r+"))
+ iMode |= O_RDWR;
+ else if (strchr(mode, 'r'))
+ iMode |= _O_RDONLY;
+ if (strstr(mode, "w+"))
+ iMode |= O_RDWR | _O_TRUNC;
+ else if (strchr(mode, 'w'))
+ iMode |= _O_WRONLY | O_CREAT;
+ return iMode;
+}
+
+#ifdef TARGET_WINDOWS
+static void to_finddata64i32(_wfinddata64i32_t *wdata, _finddata64i32_t *data)
+{
+ std::string strname;
+ g_charsetConverter.wToUTF8(wdata->name, strname);
+ size_t size = sizeof(data->name) / sizeof(char);
+ strncpy(data->name, strname.c_str(), size);
+ if (size)
+ data->name[size - 1] = '\0';
+ data->attrib = wdata->attrib;
+ data->time_create = wdata->time_create;
+ data->time_access = wdata->time_access;
+ data->time_write = wdata->time_write;
+ data->size = wdata->size;
+}
+
+static void to_wfinddata64i32(_finddata64i32_t *data, _wfinddata64i32_t *wdata)
+{
+ std::wstring strwname;
+ g_charsetConverter.utf8ToW(data->name, strwname, false);
+ size_t size = sizeof(wdata->name) / sizeof(wchar_t);
+ wcsncpy(wdata->name, strwname.c_str(), size);
+ if (size)
+ wdata->name[size - 1] = '\0';
+ wdata->attrib = data->attrib;
+ wdata->time_create = data->time_create;
+ wdata->time_access = data->time_access;
+ wdata->time_write = data->time_write;
+ wdata->size = data->size;
+}
+#endif
+
+extern "C"
+{
+ void dll_sleep(unsigned long imSec) { KODI::TIME::Sleep(std::chrono::milliseconds(imSec)); }
+
+ // FIXME, XXX, !!!!!!
+ void dllReleaseAll( )
+ {
+ // close all open dirs...
+ if (bVecDirsInited)
+ {
+ for (SDirData& dir : vecDirsOpen)
+ {
+ dir.items.Clear();
+ }
+ bVecDirsInited = false;
+ }
+ }
+
+ void* dllmalloc(size_t size)
+ {
+ void* pBlock = malloc(size);
+ if (!pBlock)
+ {
+ CLog::Log(LOGFATAL, "malloc {0} bytes failed, crash imminent", size);
+ }
+ return pBlock;
+ }
+
+ void dllfree( void* pPtr )
+ {
+ free(pPtr);
+ }
+
+ void* dllcalloc(size_t num, size_t size)
+ {
+ void* pBlock = calloc(num, size);
+ if (!pBlock)
+ {
+ CLog::Log(LOGFATAL, "calloc {0} bytes failed, crash imminent", size);
+ }
+ return pBlock;
+ }
+
+ void* dllrealloc( void *memblock, size_t size )
+ {
+ void* pBlock = realloc(memblock, size);
+ if (!pBlock)
+ {
+ CLog::Log(LOGFATAL, "realloc {0} bytes failed, crash imminent", size);
+ }
+ return pBlock;
+ }
+
+ void dllexit(int iCode)
+ {
+ not_implement("msvcrt.dll fake function exit() called\n"); //warning
+ }
+
+ void dllabort()
+ {
+ not_implement("msvcrt.dll fake function abort() called\n"); //warning
+ }
+
+ void* dll__dllonexit(PFV input, PFV ** start, PFV ** end)
+ {
+ //ported from WINE code
+ PFV *tmp;
+ int len;
+
+ if (!start || !*start || !end || !*end)
+ {
+ //FIXME("bad table\n");
+ return NULL;
+ }
+
+ len = (*end - *start);
+
+ if (++len <= 0)
+ return NULL;
+
+ tmp = (PFV*) realloc (*start, len * sizeof(tmp) );
+ if (!tmp)
+ return NULL;
+ *start = tmp;
+ *end = tmp + len;
+ tmp[len - 1] = input;
+ return (void *)input;
+
+ //wrong handling, this function is used for register functions
+ //that called before exit use _initterm functions.
+
+ //dllReleaseAll( );
+ //return TRUE;
+ }
+
+ _onexit_t dll_onexit(_onexit_t func)
+ {
+ not_implement("msvcrt.dll fake function dll_onexit() called\n");
+
+ // register to dll unload list
+ // return func if successfully added to the dll unload list
+ return NULL;
+ }
+
+ int dllputs(const char* szLine)
+ {
+ if (!szLine[0]) return EOF;
+ if (szLine[strlen(szLine) - 1] != '\n')
+ CLog::Log(LOGDEBUG, " msg: {}", szLine);
+ else
+ CLog::Log(LOGDEBUG, " msg: {}", szLine);
+
+ // return a non negative value
+ return 0;
+ }
+
+ int dllprintf(const char *format, ...)
+ {
+ va_list va;
+ static char tmp[2048];
+ va_start(va, format);
+ _vsnprintf(tmp, 2048, format, va);
+ va_end(va);
+ tmp[2048 - 1] = 0;
+ CLog::Log(LOGDEBUG, " msg: {}", tmp);
+
+ return strlen(tmp);
+ }
+
+ char *dll_fullpath(char *absPath, const char *relPath, size_t maxLength)
+ {
+ unsigned int len = strlen(relPath);
+ if (len > maxLength && absPath != NULL) return NULL;
+
+ // dll has to make sure it uses the correct path for now
+ if (len > 1 && relPath[1] == ':')
+ {
+ if (absPath == NULL) absPath = dll_strdup(relPath);
+ else
+ {
+ strncpy(absPath, relPath, maxLength);
+ if (maxLength != 0)
+ absPath[maxLength-1] = '\0';
+ }
+ return absPath;
+ }
+ if (!strncmp(relPath, "\\Device\\Cdrom0", 14))
+ {
+ // needed?
+ if (absPath == NULL) absPath = strdup(relPath);
+ else
+ {
+ strncpy(absPath, relPath, maxLength);
+ if (maxLength != 0)
+ absPath[maxLength-1] = '\0';
+ }
+ return absPath;
+ }
+
+ not_implement("msvcrt.dll incomplete function _fullpath(...) called\n"); //warning
+ return NULL;
+ }
+
+ FILE* dll_popen(const char *command, const char *mode)
+ {
+ not_implement("msvcrt.dll fake function _popen(...) called\n"); //warning
+ return NULL;
+ }
+
+ void *dll_dlopen(const char *filename, int flag)
+ {
+#if !defined(TARGET_WINDOWS)
+ return dlopen(filename, flag);
+#else
+ return NULL;
+#endif
+ }
+
+ int dll_pclose(FILE *stream)
+ {
+ not_implement("msvcrt.dll fake function _pclose(...) called\n"); //warning
+ return 0;
+ }
+
+ FILE* dll_fdopen(int fd, const char* mode)
+ {
+ EmuFileObject* o = g_emuFileWrapper.GetFileObjectByDescriptor(fd);
+ if (o)
+ {
+ if(!o->used)
+ return NULL;
+
+ int nmode = convert_fmode(mode);
+ if( (o->mode & nmode) != nmode)
+ CLog::Log(LOGWARNING, "dll_fdopen - mode 0x{:x} differs from fd mode 0x{:x}", nmode,
+ o->mode);
+ return reinterpret_cast<FILE*>(o);
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ return _fdopen(fd, mode);
+ }
+
+ not_implement("msvcrt.dll incomplete function _fdopen(...) called\n");
+ return NULL;
+ }
+
+ int dll_open(const char* szFileName, int iMode)
+ {
+ char str[1024];
+ int size = sizeof(str);
+ // move to CFile classes
+ if (strncmp(szFileName, "\\Device\\Cdrom0", 14) == 0)
+ {
+ // replace "\\Device\\Cdrom0" with "D:"
+ strncpy(str, "D:", size);
+ if (size)
+ {
+ str[size-1] = '\0';
+ strncat(str, szFileName + 14, size - strlen(str));
+ }
+ }
+ else
+ {
+ strncpy(str, szFileName, size);
+ if (size)
+ str[size-1] = '\0';
+ }
+
+ CFile* pFile = new CFile();
+ bool bWrite = false;
+ if ((iMode & O_RDWR) || (iMode & O_WRONLY))
+ bWrite = true;
+ bool bOverwrite=false;
+ if ((iMode & _O_TRUNC) || (iMode & O_CREAT))
+ bOverwrite = true;
+ // currently always overwrites
+ bool bResult;
+
+ // We need to validate the path here as some calls from ie. libdvdnav
+ // or the python DLLs have malformed slashes on Win32
+ // (-> E:\test\VIDEO_TS/VIDEO_TS.BUP))
+ if (bWrite)
+ bResult = pFile->OpenForWrite(CUtil::ValidatePath(str), bOverwrite);
+ else
+ bResult = pFile->Open(CUtil::ValidatePath(str), READ_TRUNCATED);
+
+ if (bResult)
+ {
+ EmuFileObject* object = g_emuFileWrapper.RegisterFileObject(pFile);
+ if (object == NULL)
+ {
+ pFile->Close();
+ delete pFile;
+ return -1;
+ }
+ object->mode = iMode;
+ FILE* f = reinterpret_cast<FILE*>(object);
+ return g_emuFileWrapper.GetDescriptorByStream(f);
+ }
+ delete pFile;
+ return -1;
+ }
+
+ FILE* dll_freopen(const char *path, const char *mode, FILE *stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ dll_fclose(stream);
+ return dll_fopen(path, mode);
+ }
+
+ // error
+ // close stream and return NULL
+ dll_fclose(stream);
+ return NULL;
+ }
+
+ int dll_read(int fd, void* buffer, unsigned int uiSize)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ errno = 0;
+ const ssize_t ret = pFile->Read(buffer, uiSize);
+ if (ret < 0)
+ {
+ const int err = errno; // help compiler to optimize, "errno" can be macro
+ if (err == 0 ||
+ (err != EAGAIN && err != EINTR && err != EIO && err != EOVERFLOW && err != EWOULDBLOCK &&
+ err != ECONNRESET && err != ENOTCONN && err != ETIMEDOUT &&
+ err != ENOBUFS && err != ENOMEM && err != ENXIO))
+ errno = EIO; // exact errno is unknown or incorrect, use default error number
+
+ return -1;
+ }
+ return ret;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ return read(fd, buffer, uiSize);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ errno = EBADF;
+ return -1;
+ }
+
+ int dll_write(int fd, const void* buffer, unsigned int uiSize)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ errno = 0;
+ const ssize_t ret = pFile->Write(buffer, uiSize);
+ if (ret < 0)
+ {
+ const int err = errno; // help compiler to optimize, "errno" can be macro
+ if (err == 0 ||
+ (err != EAGAIN && err != EFBIG && err != EINTR && err != EIO && err != ENOSPC && err != EPIPE && err != EWOULDBLOCK &&
+ err != ECONNRESET &&
+ err != ENOBUFS && err != ENXIO &&
+ err != EACCES && err != ENETDOWN && err != ENETUNREACH))
+ errno = EIO; // exact errno is unknown or incorrect, use default error number
+
+ return -1;
+ }
+ return ret;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ return write(fd, buffer, uiSize);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ errno = EBADF;
+ return -1;
+ }
+
+ int dll_fstat64(int fd, struct __stat64 *buf)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ return pFile->Stat(buf);
+ else if (IS_STD_DESCRIPTOR(fd))
+#if defined(TARGET_WINDOWS)
+ return _fstat64(fd, buf);
+#else
+ return fstat64(fd, buf);
+#endif
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ int dll_close(int fd)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ g_emuFileWrapper.UnRegisterFileObjectByDescriptor(fd);
+
+ pFile->Close();
+ delete pFile;
+ return 0;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd) && fd >= 0)
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ return close(fd);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ __off64_t dll_lseeki64(int fd, __off64_t lPos, int iWhence)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ lPos = pFile->Seek(lPos, iWhence);
+ return lPos;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ // not supported: return lseeki64(fd, lPos, iWhence);
+ CLog::Log(LOGWARNING, "msvcrt.dll: dll_lseeki64 called, TODO: add 'int64 -> long' type checking"); //warning
+ return static_cast<long long>(lseek(fd, (long)lPos, iWhence));
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1ll;
+ }
+
+ __off_t dll_lseek(int fd, __off_t lPos, int iWhence)
+ {
+ if (g_emuFileWrapper.DescriptorIsEmulatedFile(fd))
+ {
+ return (__off_t)dll_lseeki64(fd, lPos, iWhence);
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ return lseek(fd, lPos, iWhence);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ void dll_rewind(FILE* stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ dll_lseeki64(fd, 0, SEEK_SET);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ }
+ }
+
+ //---------------------------------------------------------------------------------------------------------
+ void dll_flockfile(FILE *stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ g_emuFileWrapper.LockFileObjectByDescriptor(fd);
+ return;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ }
+
+ int dll_ftrylockfile(FILE *stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ if (g_emuFileWrapper.TryLockFileObjectByDescriptor(fd))
+ return 0;
+ return -1;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ void dll_funlockfile(FILE *stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ g_emuFileWrapper.UnlockFileObjectByDescriptor(fd);
+ return;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ }
+
+ int dll_fclose(FILE * stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ return dll_close(fd) == 0 ? 0 : EOF;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+#ifndef TARGET_POSIX
+ // should be moved to CFile classes
+ intptr_t dll_findfirst(const char *file, struct _finddata_t *data)
+ {
+ struct _finddata64i32_t data64i32;
+ intptr_t ret = dll_findfirst64i32(file, &data64i32);
+ if (ret != -1)
+ {
+ int size = sizeof(data->name);
+ strncpy(data->name, data64i32.name, size);
+ if (size)
+ data->name[size - 1] = '\0';
+ data->size = (_fsize_t)data64i32.size;
+ data->time_write = (time_t)data64i32.time_write;
+ data->time_access = (time_t)data64i32.time_access;
+ }
+ return ret;
+ }
+
+ intptr_t dll_findfirst64i32(const char *file, struct _finddata64i32_t *data)
+ {
+ char str[1024];
+ int size = sizeof(str);
+ CURL url(CSpecialProtocol::TranslatePath(file));
+ if (url.IsLocal())
+ {
+ // move to CFile classes
+ if (strncmp(file, "\\Device\\Cdrom0", 14) == 0)
+ {
+ // replace "\\Device\\Cdrom0" with "D:"
+ strncpy(str, "D:", size);
+ if (size)
+ {
+ str[size - 1] = '\0';
+ strncat(str, file + 14, size - strlen(str));
+ }
+ }
+ else
+ {
+ strncpy(str, file, size);
+ if (size)
+ str[size - 1] = '\0';
+ }
+
+ // Make sure the slashes are correct & translate the path
+ struct _wfinddata64i32_t wdata;
+ std::wstring strwfile;
+ g_charsetConverter.utf8ToW(CUtil::ValidatePath(CSpecialProtocol::TranslatePath(str)), strwfile, false);
+ intptr_t ret = _wfindfirst64i32(strwfile.c_str(), &wdata);
+ if (ret != -1)
+ to_finddata64i32(&wdata, data);
+ return ret;
+ }
+ // non-local files. handle through IDirectory-class - only supports '*.bah' or '*.*'
+ std::string strURL(file);
+ std::string strMask;
+ if (url.GetFileName().find("*.*") != std::string::npos)
+ {
+ std::string strReplaced = url.GetFileName();
+ StringUtils::Replace(strReplaced, "*.*","");
+ url.SetFileName(strReplaced);
+ }
+ else if (url.GetFileName().find("*.") != std::string::npos)
+ {
+ strMask = URIUtils::GetExtension(url.GetFileName());
+ url.SetFileName(url.GetFileName().substr(0, url.GetFileName().find("*.")));
+ }
+ else if (url.GetFileName().find("*") != std::string::npos)
+ {
+ std::string strReplaced = url.GetFileName();
+ StringUtils::Replace(strReplaced, "*","");
+ url.SetFileName(strReplaced);
+ }
+ int iDirSlot=0; // locate next free directory
+ while ((iDirSlot < MAX_OPEN_DIRS) && (vecDirsOpen[iDirSlot].curr_index != -1)) iDirSlot++;
+ if (iDirSlot >= MAX_OPEN_DIRS)
+ return -1; // no free slots
+ strURL = url.Get();
+ bVecDirsInited = true;
+ vecDirsOpen[iDirSlot].items.Clear();
+ XFILE::CDirectory::GetDirectory(strURL, vecDirsOpen[iDirSlot].items, strMask, DIR_FLAG_DEFAULTS);
+ if (vecDirsOpen[iDirSlot].items.Size())
+ {
+ int size = sizeof(data->name);
+ strncpy(data->name,vecDirsOpen[iDirSlot].items[0]->GetLabel().c_str(), size);
+ if (size)
+ data->name[size - 1] = '\0';
+ data->size = static_cast<_fsize_t>(vecDirsOpen[iDirSlot].items[0]->m_dwSize);
+ data->time_write = 0;
+ data->time_access = 0;
+ vecDirsOpen[iDirSlot].curr_index = 0;
+ return (intptr_t)&vecDirsOpen[iDirSlot];
+ }
+ vecDirsOpen[iDirSlot].curr_index = -1;
+ return -1; // whatever != NULL
+ }
+
+ // should be moved to CFile classes
+ int dll_findnext(intptr_t f, _finddata_t* data)
+ {
+ struct _finddata64i32_t data64i32;
+ int ret = dll_findnext64i32(f, &data64i32);
+ if (ret == 0)
+ {
+ int size = sizeof(data->name);
+ strncpy(data->name, data64i32.name, size);
+ if (size)
+ data->name[size - 1] = '\0';
+ data->size = (_fsize_t)data64i32.size;
+ data->time_write = (time_t)data64i32.time_write;
+ data->time_access = (time_t)data64i32.time_access;
+ }
+ return ret;
+ }
+
+ int dll_findnext64i32(intptr_t f, _finddata64i32_t* data)
+ {
+ int found = MAX_OPEN_DIRS;
+ for (int i = 0; i < MAX_OPEN_DIRS; i++)
+ {
+ if (f == (intptr_t)&vecDirsOpen[i] && vecDirsOpen[i].curr_index != -1)
+ {
+ found = i;
+ break;
+ }
+ }
+ if (found >= MAX_OPEN_DIRS)
+ {
+ struct _wfinddata64i32_t wdata;
+ to_wfinddata64i32(data, &wdata);
+ intptr_t ret = _wfindnext64i32(f, &wdata); // local dir
+ if (ret != -1)
+ to_finddata64i32(&wdata, data);
+ return ret;
+ }
+
+ // we have a valid data structure. get next item!
+ int iItem = vecDirsOpen[found].curr_index;
+ if (iItem+1 < vecDirsOpen[found].items.Size()) // we have a winner!
+ {
+ int size = sizeof(data->name);
+ strncpy(data->name,vecDirsOpen[found].items[iItem+1]->GetLabel().c_str(), size);
+ if (size)
+ data->name[size - 1] = '\0';
+ data->size = static_cast<_fsize_t>(vecDirsOpen[found].items[iItem+1]->m_dwSize);
+ vecDirsOpen[found].curr_index++;
+ return 0;
+ }
+
+ vecDirsOpen[found].items.Clear();
+ return -1;
+ }
+
+ int dll_findclose(intptr_t handle)
+ {
+ int found = MAX_OPEN_DIRS;
+ for (int i = 0; i < MAX_OPEN_DIRS; i++)
+ {
+ if (handle == (intptr_t)&vecDirsOpen[i] && vecDirsOpen[i].curr_index != -1)
+ {
+ found = i;
+ break;
+ }
+ }
+ if (found >= MAX_OPEN_DIRS)
+ return _findclose(handle);
+
+ vecDirsOpen[found].items.Clear();
+ vecDirsOpen[found].curr_index = -1;
+ return 0;
+ }
+
+ void dll__security_error_handler(int code, void *data)
+ {
+ //NOTE: __security_error_handler has been removed in VS2005 and up
+ CLog::Log(LOGERROR, "security_error, code {}", code);
+ }
+
+#endif
+
+ DIR *dll_opendir(const char *file)
+ {
+ CURL url(CSpecialProtocol::TranslatePath(file));
+ if (url.IsLocal())
+ { // Make sure the slashes are correct & translate the path
+ return opendir(CUtil::ValidatePath(url.Get().c_str()).c_str());
+ }
+
+ // locate next free directory
+ int iDirSlot=0;
+ while ((iDirSlot<MAX_OPEN_DIRS) && (vecDirsOpen[iDirSlot].curr_index != -1)) iDirSlot++;
+ if (iDirSlot >= MAX_OPEN_DIRS)
+ {
+ CLog::Log(LOGDEBUG, "Dll: Max open dirs reached");
+ return NULL; // no free slots
+ }
+
+ bVecDirsInited = true;
+ vecDirsOpen[iDirSlot].items.Clear();
+
+ if (XFILE::CDirectory::GetDirectory(url.Get(), vecDirsOpen[iDirSlot].items, "", DIR_FLAG_DEFAULTS))
+ {
+ vecDirsOpen[iDirSlot].curr_index = 0;
+ return (DIR *)&vecDirsOpen[iDirSlot];
+ }
+ else
+ return NULL;
+ }
+
+ struct dirent *dll_readdir(DIR *dirp)
+ {
+ if (!dirp)
+ return NULL;
+
+ bool emulated(false);
+ for (const SDirData& dir : vecDirsOpen)
+ {
+ if (dirp == (DIR*)&dir)
+ {
+ emulated = true;
+ break;
+ }
+ }
+ if (!emulated)
+ return readdir(dirp); // local dir
+
+ // dirp is actually a SDirData*
+ SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
+ if (dirData->last_entry)
+ free(dirData->last_entry);
+ struct dirent *entry = NULL;
+ entry = (dirent*) malloc(sizeof(*entry));
+ if (dirData->curr_index < dirData->items.Size() + 2)
+ { // simulate the '.' and '..' dir entries
+ if (dirData->curr_index == 0)
+ strncpy(entry->d_name, ".\0", 2);
+ else if (dirData->curr_index == 1)
+ strncpy(entry->d_name, "..\0", 3);
+ else
+ {
+ strncpy(entry->d_name, dirData->items[dirData->curr_index - 2]->GetLabel().c_str(), sizeof(entry->d_name));
+ entry->d_name[sizeof(entry->d_name)-1] = '\0'; // null-terminate any truncated paths
+ }
+ dirData->last_entry = entry;
+ dirData->curr_index++;
+ return entry;
+ }
+ free(entry);
+ return NULL;
+ }
+
+ int dll_closedir(DIR *dirp)
+ {
+ bool emulated(false);
+ for (const SDirData& dir : vecDirsOpen)
+ {
+ if (dirp == (DIR*)&dir)
+ {
+ emulated = true;
+ break;
+ }
+ }
+ if (!emulated)
+ return closedir(dirp);
+
+ SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
+ dirData->items.Clear();
+ if (dirData->last_entry)
+ {
+ dirData->last_entry = NULL;
+ }
+ dirData->curr_index = -1;
+ return 0;
+ }
+
+ void dll_rewinddir(DIR *dirp)
+ {
+ bool emulated(false);
+ for (const SDirData& dir : vecDirsOpen)
+ {
+ if (dirp == (DIR*)&dir)
+ {
+ emulated = true;
+ break;
+ }
+ }
+ if (!emulated)
+ {
+ rewinddir(dirp);
+ return;
+ }
+
+ SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
+ if (dirData->last_entry)
+ {
+ dirData->last_entry = NULL;
+ }
+ dirData->curr_index = 0;
+ }
+
+ char* dll_fgets(char* pszString, int num ,FILE * stream)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ if (pFile->GetPosition() < pFile->GetLength())
+ {
+ bool bRead = pFile->ReadString(pszString, num);
+ if (bRead)
+ {
+ return pszString;
+ }
+ }
+ else return NULL; //eof
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return NULL;
+ }
+
+ int dll_feof(FILE * stream)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ if (pFile->GetPosition() < pFile->GetLength()) return 0;
+ else return 1;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return 1; // eof by default
+ }
+
+ int dll_fread(void * buffer, size_t size, size_t count, FILE * stream)
+ {
+ if (size == 0 || count == 0)
+ return 0;
+
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ size_t read = 0;
+ const size_t bufSize = size * count;
+ do // fread() must read all data until buffer is filled or eof/error occurs
+ {
+ const ssize_t r = pFile->Read(((int8_t*)buffer) + read, bufSize - read);
+ if (r <= 0)
+ break;
+ read += r;
+ } while (bufSize > read);
+ return read / size;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return 0;
+ }
+
+ int dll_fgetc(FILE* stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ // it is a emulated file
+ unsigned char buf;
+
+ if (dll_fread(&buf, 1, 1, stream) <= 0)
+ return EOF;
+
+ return (int)buf;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+ int dll_getc(FILE* stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ // This routine is normally implemented as a macro with the same result as fgetc().
+ return dll_fgetc(stream);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+ FILE* dll_fopen(const char* filename, const char* mode)
+ {
+ FILE* file = NULL;
+#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID)
+ if (strcmp(filename, _PATH_MOUNTED) == 0
+ || strcmp(filename, _PATH_MNTTAB) == 0)
+ {
+ CLog::Log(LOGINFO,
+ "{} - something opened the mount file, let's hope it knows what it's doing",
+ __FUNCTION__);
+ return fopen(filename, mode);
+ }
+#endif
+ int fd = dll_open(filename, convert_fmode(mode));
+ if (fd >= 0)
+ {
+ file = g_emuFileWrapper.GetStreamByDescriptor(fd);
+ }
+
+ return file;
+ }
+
+ int dll_fopen_s(FILE** pFile, const char * filename, const char * mode)
+ {
+ if (pFile == NULL || filename == NULL || mode == NULL)
+ return EINVAL;
+
+ *pFile = dll_fopen(filename, mode);
+ if (*pFile == NULL)
+ return errno;
+
+ return 0;
+ }
+
+ int dll_putc(int c, FILE *stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream) || IS_STD_STREAM(stream))
+ {
+ return dll_fputc(c, stream);
+ }
+ return EOF;
+ }
+
+ int dll_putchar(int c)
+ {
+ return dll_putc(c, stdout);
+ }
+
+ int dll_fputc(int character, FILE* stream)
+ {
+ if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
+ {
+ unsigned char tmp[2] = { (unsigned char)character, 0 };
+ dllputs((char *)tmp);
+ return character;
+ }
+ else
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ unsigned char c = (unsigned char)character;
+ int iItemsWritten = dll_write(fd, &c, 1);
+ if (iItemsWritten == 1)
+ return character;
+ }
+ }
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+ int dll_fputs(const char * szLine, FILE* stream)
+ {
+ if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
+ {
+ dllputs(szLine);
+ return 0;
+ }
+ else
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ size_t len = strlen(szLine);
+ return dll_fwrite(static_cast<const void*>(szLine), sizeof(char), len, stream);
+ }
+ }
+
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+ int dll_fseek64(FILE* stream, off64_t offset, int origin)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ if (dll_lseeki64(fd, offset, origin) != -1)
+ {
+ return 0;
+ }
+ else return -1;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ int dll_fseek(FILE *stream, long offset, int origin)
+ {
+ return dll_fseek64(stream, offset, origin);
+ }
+
+ int dll_ungetc(int c, FILE* stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ // it is a emulated file
+ int d;
+ if (dll_fseek(stream, -1, SEEK_CUR)!=0)
+ return EOF;
+ d = dll_fgetc(stream);
+ if (d == EOF)
+ return EOF;
+
+ dll_fseek(stream, -1, SEEK_CUR);
+ if (c != d)
+ {
+ CLog::Log(LOGWARNING, "{}: c != d", __FUNCTION__);
+ d = fputc(c, stream);
+ if (d != c)
+ CLog::Log(LOGERROR, "{}: Write failed!", __FUNCTION__);
+ else
+ dll_fseek(stream, -1, SEEK_CUR);
+ }
+ return d;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EOF;
+ }
+
+ long dll_ftell(FILE *stream)
+ {
+ return (long)dll_ftell64(stream);
+ }
+
+ off64_t dll_ftell64(FILE *stream)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ return (off64_t)pFile->GetPosition();
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ long dll_tell(int fd)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ return (long)pFile->GetPosition();
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+#ifndef TARGET_POSIX
+ return tell(fd);
+#else
+ return lseek(fd, 0, SEEK_CUR);
+#endif
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ long long dll_telli64(int fd)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ return static_cast<long long>(pFile->GetPosition());
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+ // not supported return telli64(fd);
+ CLog::Log(LOGWARNING, "msvcrt.dll: dll_telli64 called, TODO: add 'int64 -> long' type checking"); //warning
+#ifndef TARGET_POSIX
+ return static_cast<long long>(tell(fd));
+#elif defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+ return lseek(fd, 0, SEEK_CUR);
+#else
+ return lseek64(fd, 0, SEEK_CUR);
+#endif
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return -1;
+ }
+
+ size_t dll_fwrite(const void * buffer, size_t size, size_t count, FILE* stream)
+ {
+ if (size == 0 || count == 0)
+ return 0;
+
+ if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
+ {
+ char* buf = (char*)malloc(size * count + 1);
+ if (buf)
+ {
+ memcpy(buf, buffer, size * count);
+ buf[size * count] = 0; // string termination
+
+ CLog::Log(LOGDEBUG, "{}", buf);
+
+ free(buf);
+ return count;
+ }
+ }
+ else
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ size_t written = 0;
+ const size_t bufSize = size * count;
+ do // fwrite() must write all data until whole buffer is written or error occurs
+ {
+ const ssize_t w = pFile->Write(((const int8_t*)buffer) + written, bufSize - written);
+ if (w <= 0)
+ break;
+ written += w;
+ } while (bufSize > written);
+ return written / size;
+ }
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return 0;
+ }
+
+ int dll_fflush(FILE* stream)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ pFile->Flush();
+ return 0;
+ }
+
+ // std stream, no need to flush
+ return 0;
+ }
+
+ int dll_ferror(FILE* stream)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ // unimplemented
+ return 0;
+ }
+ else if (IS_STD_STREAM(stream))
+ return 0;
+ else
+ return ferror(stream);
+ }
+
+ int dllvprintf(const char *format, va_list va)
+ {
+ std::string buffer = StringUtils::FormatV(format, va);
+ CLog::Log(LOGDEBUG, " msg: {}", buffer);
+ return buffer.length();
+ }
+
+ int dll_vfprintf(FILE *stream, const char *format, va_list va)
+ {
+ static char tmp[2048];
+
+ if (_vsnprintf(tmp, 2048, format, va) == -1)
+ {
+ CLog::Log(LOGWARNING, "dll_vfprintf: Data lost due to undersized buffer");
+ }
+ tmp[2048 - 1] = 0;
+
+ if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
+ {
+ CLog::Log(LOGINFO, " msg: {}", tmp);
+ return strlen(tmp);
+ }
+ else
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+ int len = strlen(tmp);
+ // replace all '\n' occurrences with '\r\n'...
+ char tmp2[2048];
+ int j = 0;
+ for (int i = 0; i < len; i++)
+ {
+ if (j == 2047)
+ { // out of space
+ if (i != len-1)
+ CLog::Log(LOGWARNING, "dll_fprintf: Data lost due to undersized buffer");
+ break;
+ }
+ if (tmp[i] == '\n' && ((i > 0 && tmp[i-1] != '\r') || i == 0) && j < 2047 - 2)
+ { // need to add a \r
+ tmp2[j++] = '\r';
+ tmp2[j++] = '\n';
+ }
+ else
+ { // just add the character as-is
+ tmp2[j++] = tmp[i];
+ }
+ }
+ // terminate string
+ tmp2[j] = 0;
+ len = strlen(tmp2);
+ pFile->Write(tmp2, len);
+ return len;
+ }
+ }
+
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return strlen(tmp);
+ }
+
+ int dll_fscanf(FILE* stream, const char* format, ...)
+ {
+ CLog::Log(LOGERROR, "{} is not implemented", __FUNCTION__);
+ return -1;
+ }
+
+ int dll_fprintf(FILE* stream, const char* format, ...)
+ {
+ int res;
+ va_list va;
+ va_start(va, format);
+ res = dll_vfprintf(stream, format, va);
+ va_end(va);
+ return res;
+ }
+
+ int dll_fgetpos(FILE* stream, fpos_t* pos)
+ {
+ fpos64_t tmpPos = {};
+ int ret;
+
+ ret = dll_fgetpos64(stream, &tmpPos);
+#if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+ *pos = (fpos_t)tmpPos;
+#else
+ pos->__pos = (off_t)tmpPos.__pos;
+#endif
+ return ret;
+ }
+
+ int dll_fgetpos64(FILE *stream, fpos64_t *pos)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
+ if (pFile != NULL)
+ {
+#if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+ *pos = pFile->GetPosition();
+#else
+ pos->__pos = pFile->GetPosition();
+#endif
+ return 0;
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EINVAL;
+ }
+
+ int dll_fsetpos64(FILE* stream, const fpos64_t* pos)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+#if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+ if (dll_lseeki64(fd, *pos, SEEK_SET) >= 0)
+#else
+ if (dll_lseeki64(fd, (__off64_t)pos->__pos, SEEK_SET) >= 0)
+#endif
+ {
+ return 0;
+ }
+ else
+ {
+ return EINVAL;
+ }
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EINVAL;
+ }
+
+ int dll_fsetpos(FILE* stream, const fpos_t* pos)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ fpos64_t tmpPos;
+#if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+ tmpPos= *pos;
+#else
+ tmpPos.__pos = (off64_t)(pos->__pos);
+#endif
+ return dll_fsetpos64(stream, &tmpPos);
+ }
+ CLog::Log(LOGERROR, "{} emulated function failed", __FUNCTION__);
+ return EINVAL;
+ }
+
+ int dll_fileno(FILE* stream)
+ {
+ int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
+ if (fd >= 0)
+ {
+ return fd;
+ }
+ else if (IS_STDIN_STREAM(stream))
+ {
+ return 0;
+ }
+ else if (IS_STDOUT_STREAM(stream))
+ {
+ return 1;
+ }
+ else if (IS_STDERR_STREAM(stream))
+ {
+ return 2;
+ }
+ else
+ {
+ return fileno(stream);
+ }
+
+ return -1;
+ }
+
+ void dll_clearerr(FILE* stream)
+ {
+ if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
+ {
+ // not implemented
+ }
+ }
+
+ char* dll_strdup( const char* str)
+ {
+ char* pdup;
+ pdup = strdup(str);
+ return pdup;
+ }
+
+ //Critical Section has been fixed in EMUkernel32.cpp
+
+ int dll_initterm(PFV* start, const PFV* end) //pncrt.dll
+ {
+ PFV * temp;
+ for (temp = start; temp < end; temp ++)
+ if (*temp)
+ (*temp)(); //call initial function table.
+ return 0;
+ }
+
+ //SLOW CODE SHOULD BE REVISED
+ int dll_stat(const char *path, struct stat *buffer)
+ {
+ if (!StringUtils::CompareNoCase(path, "shout://", 8)) // don't stat shoutcast
+ return -1;
+ if (!StringUtils::CompareNoCase(path, "mms://", 6)) // don't stat mms
+ return -1;
+
+#ifdef TARGET_POSIX
+ if (!StringUtils::CompareNoCase(path, "D:") || !StringUtils::CompareNoCase(path, "D:\\"))
+ {
+ buffer->st_mode = S_IFDIR;
+ return 0;
+ }
+#endif
+ if (!StringUtils::CompareNoCase(path, "\\Device\\Cdrom0") ||
+ !StringUtils::CompareNoCase(path, "\\Device\\Cdrom0\\"))
+ {
+ buffer->st_mode = _S_IFDIR;
+ return 0;
+ }
+
+ struct __stat64 tStat;
+ if (CFile::Stat(path, &tStat) == 0)
+ {
+ CUtil::Stat64ToStat(buffer, &tStat);
+ return 0;
+ }
+ // errno is set by file.Stat(...)
+ return -1;
+ }
+
+ int dll_stati64(const char *path, struct _stati64 *buffer)
+ {
+ struct __stat64 a;
+ memset(&a, 0, sizeof(a));
+
+ if(dll_stat64(path, &a) == 0)
+ {
+ CUtil::Stat64ToStatI64(buffer, &a);
+ return 0;
+ }
+ return -1;
+ }
+
+ int dll_stat64(const char *path, struct __stat64 *buffer)
+ {
+ if (!StringUtils::CompareNoCase(path, "shout://", 8)) // don't stat shoutcast
+ return -1;
+ if (!StringUtils::CompareNoCase(path, "mms://", 6)) // don't stat mms
+ return -1;
+
+#ifdef TARGET_POSIX
+ if (!StringUtils::CompareNoCase(path, "D:") || !StringUtils::CompareNoCase(path, "D:\\"))
+ {
+ buffer->st_mode = _S_IFDIR;
+ return 0;
+ }
+#endif
+ if (!StringUtils::CompareNoCase(path, "\\Device\\Cdrom0") ||
+ !StringUtils::CompareNoCase(path, "\\Device\\Cdrom0\\"))
+ {
+ buffer->st_mode = _S_IFDIR;
+ return 0;
+ }
+
+ return CFile::Stat(path, buffer);
+ }
+
+#ifdef TARGET_WINDOWS
+ int dll_stat64i32(const char *path, struct _stat64i32 *buffer)
+ {
+ struct __stat64 a;
+ if(dll_stat64(path, &a) == 0)
+ {
+ CUtil::Stat64ToStat64i32(buffer, &a);
+ return 0;
+ }
+ return -1;
+ }
+#endif
+
+ int dll_fstat(int fd, struct stat* buffer)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ struct __stat64 tStat;
+ if (pFile->Stat(&tStat) == 0)
+ {
+ CUtil::Stat64ToStat(buffer, &tStat);
+ return 0;
+ }
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ return fstat(fd, buffer);
+ }
+
+ // fstat on stdin, stdout or stderr should fail
+ // this is what python expects
+ return -1;
+ }
+
+ int dll_fstati64(int fd, struct _stati64 *buffer)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ CLog::Log(LOGINFO, "Stating open file");
+
+ buffer->st_size = pFile->GetLength();
+ buffer->st_mode = _S_IFREG;
+ return 0;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ CLog::Log(LOGWARNING, "msvcrt.dll: dll_fstati64 called, TODO: add 'int64 <-> long' type checking"); //warning
+ // need to use fstat and convert everything
+ struct stat temp;
+ int res = fstat(fd, &temp);
+ if (res == 0)
+ {
+ CUtil::StatToStatI64(buffer, &temp);
+ }
+ return res;
+ }
+
+ // fstat on stdin, stdout or stderr should fail
+ // this is what python expects
+ return -1;
+ }
+
+#ifdef TARGET_WINDOWS
+ int dll_fstat64i32(int fd, struct _stat64i32 *buffer)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ struct __stat64 tStat = {};
+ if (pFile->Stat(&tStat) == 0)
+ {
+ CUtil::Stat64ToStat64i32(buffer, &tStat);
+ return 0;
+ }
+ return -1;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ CLog::Log(LOGWARNING, "msvcrt.dll: dll_fstati64 called, TODO: add 'int64 <-> long' type checking"); //warning
+ // need to use fstat and convert everything
+ struct __stat64 temp;
+ int res = _fstat64(fd, &temp);
+ if (res == 0)
+ {
+ CUtil::Stat64ToStat64i32(buffer, &temp);
+ }
+ return res;
+ }
+
+ // fstat on stdin, stdout or stderr should fail
+ // this is what python expects
+ return -1;
+ }
+#endif
+
+ int dll_setmode ( int handle, int mode )
+ {
+ not_implement("msvcrt.dll fake function dll_setmode() called\n");
+ return -1;
+ }
+
+ void dllperror(const char* s)
+ {
+ if (s)
+ {
+ CLog::Log(LOGERROR, "perror: {}", s);
+ }
+ }
+
+ char* dllstrerror(int iErr)
+ {
+ static char szError[32];
+ sprintf(szError, "err:%i", iErr);
+ return (char*)szError;
+ }
+
+ int dll_mkdir(const char* dir)
+ {
+ if (!dir) return -1;
+
+ // Make sure the slashes are correct & translate the path
+ std::string strPath = CUtil::ValidatePath(CSpecialProtocol::TranslatePath(dir));
+#ifndef TARGET_POSIX
+ std::wstring strWPath;
+ g_charsetConverter.utf8ToW(strPath, strWPath, false);
+ return _wmkdir(strWPath.c_str());
+#else
+ return mkdir(strPath.c_str(), 0755);
+#endif
+ }
+
+ const char* dll_getcwd(char *buffer, int maxlen)
+ {
+ not_implement("msvcrt.dll fake function dll_getcwd() called\n");
+ return "special://xbmc/";
+ }
+
+ int dll_putenv(const char* envstring)
+ {
+ bool added = false;
+
+ if (envstring != NULL)
+ {
+ const char *value_start = strchr(envstring, '=');
+
+ if (value_start != NULL)
+ {
+ char var[64];
+ int size = strlen(envstring) + 1;
+ char *value = (char*)malloc(size);
+
+ if (!value)
+ return -1;
+ value[0] = 0;
+
+ memcpy(var, envstring, value_start - envstring);
+ var[value_start - envstring] = 0;
+ char* temp = var;
+ while (*temp)
+ {
+ *temp = (char)toupper(*temp);
+ temp++;
+ }
+
+ strncpy(value, value_start + 1, size);
+ if (size)
+ value[size - 1] = '\0';
+
+ {
+ std::unique_lock<CCriticalSection> lock(dll_cs_environ);
+
+ char** free_position = NULL;
+ for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS && free_position == NULL; i++)
+ {
+ if (dll__environ[i] != NULL)
+ {
+ // we only support overwriting the old values
+ if (StringUtils::CompareNoCase(dll__environ[i], var, strlen(var)) == 0)
+ {
+ // free it first
+ free(dll__environ[i]);
+ dll__environ[i] = NULL;
+ free_position = &dll__environ[i];
+ }
+ }
+ else
+ {
+ free_position = &dll__environ[i];
+ }
+ }
+
+ if (free_position != NULL)
+ {
+ // free position, copy value
+ size = strlen(var) + strlen(value) + 2;
+ *free_position = (char*)malloc(size); // for '=' and 0 termination
+ if ((*free_position))
+ {
+ strncpy(*free_position, var, size);
+ (*free_position)[size - 1] = '\0';
+ strncat(*free_position, "=", size - strlen(*free_position));
+ strncat(*free_position, value, size - strlen(*free_position));
+ added = true;
+ }
+ }
+
+ }
+
+ free(value);
+ }
+ }
+
+ return added ? 0 : -1;
+ }
+
+ char* dll_getenv(const char* szKey)
+ {
+ char* value = NULL;
+
+ {
+ std::unique_lock<CCriticalSection> lock(dll_cs_environ);
+
+ update_emu_environ();//apply any changes
+
+ for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS && value == NULL; i++)
+ {
+ if (dll__environ[i])
+ {
+ if (StringUtils::CompareNoCase(dll__environ[i], szKey, strlen(szKey)) == 0)
+ {
+ // found it
+ value = dll__environ[i] + strlen(szKey) + 1;
+ }
+ }
+ }
+ }
+
+ if (value != NULL)
+ {
+ return value;
+ }
+
+ return NULL;
+ }
+
+ int dll_ctype(int i)
+ {
+ not_implement("msvcrt.dll fake function dll_ctype() called\n");
+ return 0;
+ }
+
+ int dll_system(const char *command)
+ {
+ not_implement("msvcrt.dll fake function dll_system() called\n");
+ return 0; //system(command);
+ }
+
+ void (__cdecl * dll_signal(int sig, void (__cdecl *func)(int)))(int)
+ {
+#if defined(TARGET_WINDOWS)
+ //vs2008 asserts for known signals, return err for everything unknown to windows.
+ if (sig == 5 || sig == 7 || sig == 9 || sig == 10 || sig == 12 || sig == 14 || sig == 18 || sig == 19 || sig == 20)
+ return SIG_ERR;
+#endif
+ return signal(sig, func);
+ }
+
+ int dll_getpid()
+ {
+ return 1;
+ }
+
+ int dll__commit(int fd)
+ {
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (pFile != NULL)
+ {
+ pFile->Flush();
+ return 0;
+ }
+ else if (!IS_STD_DESCRIPTOR(fd))
+ {
+ // it might be something else than a file, or the file is not emulated
+ // let the operating system handle it
+#ifndef TARGET_POSIX
+ return _commit(fd);
+#else
+ return fsync(fd);
+#endif
+ }
+
+ // std stream, no need to flush
+ return 0;
+ }
+
+ char*** dll___p__environ()
+ {
+ static char*** t = &dll__environ;
+ return (char***)&t;
+ }
+
+#ifdef TARGET_POSIX
+#if defined(TARGET_ANDROID)
+ volatile int * __cdecl dll_errno(void)
+ {
+ return &errno;
+ }
+#else
+ int * __cdecl dll_errno(void)
+ {
+ return &errno;
+ }
+#endif
+
+ int __cdecl dll_ioctl(int fd, unsigned long int request, va_list va)
+ {
+ int ret;
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
+ if (!pFile)
+ return -1;
+
+#if defined(HAS_DVD_DRIVE) && !defined(TARGET_FREEBSD)
+#if !defined(TARGET_DARWIN)
+ if(request == DVD_READ_STRUCT || request == DVD_AUTH)
+#else
+ if(request == DKIOCDVDSENDKEY || request == DKIOCDVDREPORTKEY || request == DKIOCDVDREADSTRUCTURE)
+#endif
+ {
+ void *p1 = va_arg(va, void*);
+ SNativeIoControl d;
+ d.request = request;
+ d.param = p1;
+ ret = pFile->IoControl(IOCTRL_NATIVE, &d);
+ if(ret<0)
+ CLog::Log(LOGWARNING, "{} - {} request failed with error [{}] {}", __FUNCTION__, request,
+ errno, strerror(errno));
+ }
+ else
+#endif
+ {
+ CLog::Log(LOGWARNING, "{} - Unknown request type {}", __FUNCTION__, request);
+ ret = -1;
+ }
+ return ret;
+ }
+#endif
+
+ int dll_setvbuf(FILE *stream, char *buf, int type, size_t size)
+ {
+ CLog::Log(LOGWARNING, "{} - May not be implemented correctly", __FUNCTION__);
+ return 0;
+ }
+
+ struct mntent *dll_getmntent(FILE *fp)
+ {
+ if (!fp)
+ return nullptr;
+
+#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID)
+ struct mntent* mountPoint = getmntent(fp);
+ if (mountPoint)
+ return mountPoint;
+
+ // warn if this is a kodi vfs file not associated with a mountpoint
+ CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(fp);
+ if (pFile)
+ {
+ CLog::LogF(LOGWARNING, "getmntent is not implemented for our virtual filesystem");
+ }
+ return nullptr;
+#else
+ CLog::LogF(LOGWARNING, "Unimplemented function called");
+ return nullptr;
+#endif
+ }
+
+ struct mntent* dll_getmntent_r(FILE* fp, struct mntent* result, char* buffer, int bufsize)
+ {
+ if (!fp || !result || !buffer)
+ return nullptr;
+
+#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID)
+ struct mntent* mountPoint = getmntent_r(fp, result, buffer, bufsize);
+ if (mountPoint)
+ return mountPoint;
+#endif
+ return nullptr;
+ }
+
+ // this needs to be wrapped, since dll's have their own file
+ // descriptor list, but we always use app's list with our wrappers
+ int __cdecl dll_open_osfhandle(intptr_t _OSFileHandle, int _Flags)
+ {
+#ifdef TARGET_WINDOWS
+ return _open_osfhandle(_OSFileHandle, _Flags);
+#else
+ return -1;
+#endif
+ }
+
+}
diff --git a/xbmc/cores/DllLoader/exports/emu_msvcrt.h b/xbmc/cores/DllLoader/exports/emu_msvcrt.h
new file mode 100644
index 0000000..cee233b
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/emu_msvcrt.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "PlatformDefs.h"
+
+#ifdef TARGET_POSIX
+#define _onexit_t void*
+#endif
+
+#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+typedef off_t __off_t;
+typedef int64_t off64_t;
+typedef off64_t __off64_t;
+typedef fpos_t fpos64_t;
+#endif
+
+#ifdef TARGET_WINDOWS
+#include "platform/win32/dirent.h"
+#else
+#include <dirent.h>
+#endif
+
+typedef void ( *PFV)(void);
+
+#define __IS_STDIN_STREAM(stream) (stream == stdin || fileno(stream) == fileno(stdin) || fileno(stream) == 0)
+#define __IS_STDOUT_STREAM(stream) (stream == stdout || fileno(stream) == fileno(stdout) || fileno(stream) == 1)
+#define __IS_STDERR_STREAM(stream) (stream == stderr || fileno(stream) == fileno(stderr) || fileno(stream) == 2)
+#define IS_STDIN_STREAM(stream) (stream != NULL && __IS_STDIN_STREAM(stream))
+#define IS_STDOUT_STREAM(stream) (stream != NULL && __IS_STDOUT_STREAM(stream))
+#define IS_STDERR_STREAM(stream) (stream != NULL && __IS_STDERR_STREAM(stream))
+#define IS_VALID_STREAM(stream) (stream != nullptr)
+
+
+#define IS_STD_STREAM(stream) (stream != NULL && (__IS_STDIN_STREAM(stream) || __IS_STDOUT_STREAM(stream) || __IS_STDERR_STREAM(stream)))
+
+#define IS_STDIN_DESCRIPTOR(fd) (fd == 0)
+#define IS_STDOUT_DESCRIPTOR(fd) (fd == 1)
+#define IS_STDERR_DESCRIPTOR(fd) (fd == 2)
+
+#define IS_STD_DESCRIPTOR(fd) (IS_STDIN_DESCRIPTOR(fd) || IS_STDOUT_DESCRIPTOR(fd) || IS_STDERR_DESCRIPTOR(fd))
+
+
+extern "C"
+{
+ char* dll_strdup( const char* str);
+ void dll_sleep(unsigned long imSec);
+ void InitFiles();
+ void dllReleaseAll( );
+ void* dllmalloc(size_t size);
+ void dllfree( void* pPtr );
+ void* dllcalloc( size_t num, size_t size );
+ void* dllrealloc( void *memblock, size_t size );
+ void dllexit(int iCode);
+ void dllabort();
+ void* dll__dllonexit(PFV input, PFV ** start, PFV ** end);
+ _onexit_t dll_onexit(_onexit_t func);
+ int dllputs(const char* szLine);
+ int dll_putchar(int c);
+ int dll_putc(int c, FILE *stream);
+ int dllprintf( const char *format, ... );
+ int dllvprintf(const char *format, va_list va);
+ char *dll_fullpath(char *absPath, const char *relPath, size_t maxLength);
+ FILE *dll_popen(const char *command, const char *mode);
+ int dll_pclose(FILE *stream);
+ FILE* dll_fdopen(int i, const char* file);
+ int dll_open(const char* szFileName, int iMode);
+ int dll_read(int fd, void* buffer, unsigned int uiSize);
+ int dll_write(int fd, const void* buffer, unsigned int uiSize);
+ int dll_close(int fd);
+ __off64_t dll_lseeki64(int fd, __off64_t lPos, int iWhence);
+ __off_t dll_lseek(int fd, __off_t lPos, int iWhence);
+ char* dll_getenv(const char* szKey);
+ int dll_fclose (FILE * stream);
+#ifndef TARGET_POSIX
+ intptr_t dll_findfirst(const char *file, struct _finddata_t *data);
+ int dll_findnext(intptr_t f, _finddata_t* data);
+ int dll_findclose(intptr_t handle);
+ intptr_t dll_findfirst64i32(const char *file, struct _finddata64i32_t *data);
+ int dll_findnext64i32(intptr_t f, _finddata64i32_t* data);
+ void dll__security_error_handler(int code, void *data);
+#endif
+ DIR *dll_opendir(const char *filename);
+ struct dirent *dll_readdir(DIR *dirp);
+ int dll_closedir(DIR *dirp);
+ void dll_rewinddir(DIR *dirp);
+ char * dll_fgets (char* pszString, int num , FILE * stream);
+ int dll_fgetc (FILE* stream);
+ int dll_feof (FILE * stream);
+ int dll_fread (void * buffer, size_t size, size_t count, FILE * stream);
+ int dll_getc (FILE * stream);
+ FILE * dll_fopen(const char * filename, const char * mode);
+ int dll_fopen_s(FILE** pFile, const char * filename, const char * mode);
+ int dll_fputc (int character, FILE * stream);
+ int dll_putcchar (int character);
+ int dll_fputs (const char * szLine , FILE* stream);
+ int dll_fseek ( FILE * stream , long offset , int origin );
+ int dll_fseek64(FILE *stream, off64_t offset, int origin);
+ int dll_ungetc (int c, FILE * stream);
+ long dll_ftell(FILE *stream);
+ off64_t dll_ftell64(FILE *stream);
+ long dll_tell ( int fd );
+ long long dll_telli64 ( int fd );
+ size_t dll_fwrite ( const void * buffer, size_t size, size_t count, FILE * stream );
+ int dll_fflush (FILE * stream);
+ int dll_ferror (FILE * stream);
+ int dll_vfprintf(FILE *stream, const char *format, va_list va);
+ int dll_fprintf(FILE* stream , const char * format, ...);
+ int dll_fgetpos(FILE* stream, fpos_t* pos);
+ int dll_fgetpos64(FILE *stream, fpos64_t *pos);
+ int dll_fsetpos(FILE* stream, const fpos_t* pos);
+ int dll_fsetpos64(FILE* stream, const fpos64_t* pos);
+ int dll_fileno(FILE* stream);
+ void dll_rewind(FILE* stream);
+ void dll_clearerr(FILE* stream);
+ int dll_initterm(PFV* start, const PFV* end);
+ uintptr_t dll_beginthread(void( *start_address )( void * ),unsigned stack_size,void *arglist);
+ int dll_stati64(const char *path, struct _stati64 *buffer);
+ int dll_stat64(const char *path, struct __stat64 *buffer);
+#ifdef TARGET_WINDOWS
+ int dll_stat64i32(const char *path, struct _stat64i32 *buffer);
+#endif
+ int dll_stat(const char *path, struct stat *buffer);
+ int dll_fstat(int fd, struct stat *buffer);
+ int dll_fstati64(int fd, struct _stati64 *buffer);
+ int dll_setmode(int handle, int mode );
+ void dllperror(const char* s);
+ char* dllstrerror(int iErr);
+ int dll_mkdir(const char* dir);
+ const char* dll_getcwd(char *buffer, int maxlen);
+ int dll_putenv(const char* envstring);
+ int dll_ctype(int i);
+ int dll_system(const char *command);
+ void (__cdecl * dll_signal(int sig, void (__cdecl *func)(int)))(int);
+ int dll_getpid();
+ int dll__commit(int fd);
+ char*** dll___p__environ();
+ FILE* dll_freopen(const char *path, const char *mode, FILE *stream);
+ int dll_fscanf(FILE *stream, const char *format , ...);
+ void dll_flockfile(FILE *file);
+ int dll_ftrylockfile(FILE *file);
+ void dll_funlockfile(FILE *file);
+ int dll_fstat64(int fd, struct __stat64 *buf);
+#ifdef TARGET_WINDOWS
+ int dll_fstat64i32(int fd, struct _stat64i32 *buffer);
+ int dll_open_osfhandle(intptr_t _OSFileHandle, int _Flags);
+#endif
+ int dll_setvbuf(FILE *stream, char *buf, int type, size_t size);
+
+#if defined(TARGET_ANDROID)
+ volatile int * __cdecl dll_errno(void);
+#elif defined(TARGET_POSIX)
+ int * __cdecl dll_errno(void);
+#endif
+
+ extern char **dll__environ;
+}
+
diff --git a/xbmc/cores/DllLoader/exports/kernel32.def b/xbmc/cores/DllLoader/exports/kernel32.def
new file mode 100755
index 0000000..b23a9be
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/kernel32.def
@@ -0,0 +1,25 @@
+LIBRARY kernel32.dll
+
+VERSION 1.0
+
+EXPORTS
+ AddAtomA
+ FindAtomA
+ GetAtomNameA
+ CreateThread
+ FindClose
+ FindFirstFileA
+ FindNextFileA
+ GetFileAttributesA
+ GetLastError
+ GetModuleFileNameA
+ GetNumberOfConsoleInputEvents
+ GetStdHandle
+ ReadConsoleInputA
+ SetUnhandledExceptionFilter
+ Sleep
+ TerminateThread
+ GetCurrentThread
+ QueryPerformanceCounter
+ QueryPerformanceFrequency
+ SetThreadPriority \ No newline at end of file
diff --git a/xbmc/cores/DllLoader/exports/msvcrt.def b/xbmc/cores/DllLoader/exports/msvcrt.def
new file mode 100755
index 0000000..73a63b4
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/msvcrt.def
@@ -0,0 +1,123 @@
+LIBRARY msvcrt.dll
+
+VERSION 1.0
+
+EXPORTS
+ _close
+ _lseek
+ _read
+ _write
+ __dllonexit
+ __mb_cur_max
+ _assert
+ _errno
+ _ftime
+ _iob
+ _isctype
+ _lseeki64
+ _open
+ _snprintf
+ _stricmp
+ _strnicmp
+ _vsnprintf
+ abort
+ atof
+ atoi
+ cos
+ cosh
+ exp
+ fflush
+ floor
+ fprintf
+ free
+ frexp
+ fwrite
+ gmtime
+ ldexp
+ localtime
+ log
+ log10
+ malloc
+ memcpy
+ memmove
+ memset
+ mktime
+ perror
+ printf
+ putchar
+ puts
+ qsort
+ realloc
+ sin
+ sinh
+ sprintf
+ sqrt
+ sscanf
+ strchr
+ strcmp
+ strcpy
+ strlen
+ strncpy
+ strrchr
+ strtod
+ strtok
+ strtol
+ strtoul
+ tan
+ tanh
+ time
+ toupper
+ _memccpy
+ _fstat
+ _memccpy
+ _mkdir
+ _pclose
+ _popen
+ _sleep
+ _stat
+ _strdup
+ _swab
+ _findclose
+ _findfirst
+ _findnext
+ _fullpath
+ _pctype
+ calloc
+ ceil
+ ctime
+ exit
+ fclose
+ feof
+ fgets
+ fopen
+ fputc
+ fputs
+ fread
+ fseek
+ ftell
+ getc
+ getenv
+ putc
+ rand
+ remove
+ rewind
+ setlocale
+ signal
+ srand
+ strcat
+ strcoll
+ strerror
+ strncat
+ strncmp
+ strpbrk
+ strstr
+ tolower
+ strspn
+ strcspn
+ fsetpos
+ fgetpos
+ _fstati64
+ _stati64
+ _tell
+ _telli64
+ _setmode \ No newline at end of file
diff --git a/xbmc/cores/DllLoader/exports/pncrt.def b/xbmc/cores/DllLoader/exports/pncrt.def
new file mode 100755
index 0000000..ba34b22
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/pncrt.def
@@ -0,0 +1,114 @@
+LIBRARY msvcrt.dll
+
+VERSION 1.0
+
+EXPORTS
+ _close
+ _lseek
+ _read
+ _write
+ __dllonexit
+ __mb_cur_max
+ _assert
+ _errno
+ _ftime
+ _iob
+ _isctype
+ _lseeki64
+ _open
+ _snprintf
+ _stricmp
+ _strnicmp
+ _vsnprintf
+ abort
+ atof
+ atoi
+ cos
+ cosh
+ exp
+ fflush
+ floor
+ fprintf
+ free
+ frexp
+ fwrite
+ gmtime
+ ldexp
+ localtime
+ log
+ log10
+ malloc
+ memcpy
+ memmove
+ memset
+ mktime
+ perror
+ printf
+ putchar
+ puts
+ qsort
+ realloc
+ sin
+ sinh
+ sprintf
+ sqrt
+ sscanf
+ strchr
+ strcmp
+ strcpy
+ strlen
+ strncpy
+ strrchr
+ strtod
+ strtok
+ strtol
+ strtoul
+ tan
+ tanh
+ time
+ toupper
+ _memccpy
+ _fstat
+ _memccpy
+ _mkdir
+ _pclose
+ _popen
+ _sleep
+ _stat
+ _strdup
+ _swab
+ _findclose
+ _findfirst
+ _findnext
+ _fullpath
+ _pctype
+ calloc
+ ceil
+ ctime
+ exit
+ fclose
+ feof
+ fgets
+ fopen
+ fputc
+ fputs
+ fread
+ fseek
+ ftell
+ getc
+ getenv
+ putc
+ rand
+ remove
+ rewind
+ setlocale
+ signal
+ srand
+ strcat
+ strcoll
+ strerror
+ strncat
+ strncmp
+ strpbrk
+ strstr
+ tolower \ No newline at end of file
diff --git a/xbmc/cores/DllLoader/exports/util/CMakeLists.txt b/xbmc/cores/DllLoader/exports/util/CMakeLists.txt
new file mode 100644
index 0000000..3fa6f31
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/util/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(SOURCES EmuFileWrapper.cpp)
+
+set(HEADERS EmuFileWrapper.h)
+
+core_add_library(exports_utils)
diff --git a/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.cpp b/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.cpp
new file mode 100644
index 0000000..40d6b61
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "EmuFileWrapper.h"
+
+#include "filesystem/File.h"
+
+#include <mutex>
+
+CEmuFileWrapper g_emuFileWrapper;
+
+namespace
+{
+
+constexpr bool isValidFilePtr(const FILE* f)
+{
+ return (f != nullptr);
+}
+
+}
+CEmuFileWrapper::CEmuFileWrapper()
+{
+ // since we always use dlls we might just initialize it directly
+ for (EmuFileObject& file : m_files)
+ {
+ memset(&file, 0, sizeof(EmuFileObject));
+ file.used = false;
+ file.fd = -1;
+ }
+}
+
+CEmuFileWrapper::~CEmuFileWrapper()
+{
+ CleanUp();
+}
+
+void CEmuFileWrapper::CleanUp()
+{
+ std::unique_lock<CCriticalSection> lock(m_criticalSection);
+ for (EmuFileObject& file : m_files)
+ {
+ if (file.used)
+ {
+ file.file_xbmc->Close();
+ delete file.file_xbmc;
+
+ if (file.file_lock)
+ {
+ delete file.file_lock;
+ file.file_lock = nullptr;
+ }
+ file.used = false;
+ file.fd = -1;
+ }
+ }
+}
+
+EmuFileObject* CEmuFileWrapper::RegisterFileObject(XFILE::CFile* pFile)
+{
+ EmuFileObject* object = nullptr;
+
+ std::unique_lock<CCriticalSection> lock(m_criticalSection);
+
+ for (int i = 0; i < MAX_EMULATED_FILES; i++)
+ {
+ if (!m_files[i].used)
+ {
+ // found a free location
+ object = &m_files[i];
+ object->used = true;
+ object->file_xbmc = pFile;
+ object->fd = (i + FILE_WRAPPER_OFFSET);
+ object->file_lock = new CCriticalSection();
+ break;
+ }
+ }
+
+ return object;
+}
+
+void CEmuFileWrapper::UnRegisterFileObjectByDescriptor(int fd)
+{
+ int i = fd - FILE_WRAPPER_OFFSET;
+ if (! (i >= 0 && i < MAX_EMULATED_FILES))
+ return;
+
+ if (!m_files[i].used)
+ return;
+
+ std::unique_lock<CCriticalSection> lock(m_criticalSection);
+
+ // we assume the emulated function already deleted the CFile object
+ if (m_files[i].file_lock)
+ {
+ delete m_files[i].file_lock;
+ m_files[i].file_lock = nullptr;
+ }
+ m_files[i].used = false;
+ m_files[i].fd = -1;
+}
+
+void CEmuFileWrapper::UnRegisterFileObjectByStream(FILE* stream)
+{
+ if (isValidFilePtr(stream))
+ {
+ EmuFileObject* o = reinterpret_cast<EmuFileObject*>(stream);
+ return UnRegisterFileObjectByDescriptor(o->fd);
+ }
+}
+
+void CEmuFileWrapper::LockFileObjectByDescriptor(int fd)
+{
+ int i = fd - FILE_WRAPPER_OFFSET;
+ if (i >= 0 && i < MAX_EMULATED_FILES)
+ {
+ if (m_files[i].used)
+ {
+ m_files[i].file_lock->lock();
+ }
+ }
+}
+
+bool CEmuFileWrapper::TryLockFileObjectByDescriptor(int fd)
+{
+ int i = fd - FILE_WRAPPER_OFFSET;
+ if (i >= 0 && i < MAX_EMULATED_FILES)
+ {
+ if (m_files[i].used)
+ {
+ return m_files[i].file_lock->try_lock();
+ }
+ }
+ return false;
+}
+
+void CEmuFileWrapper::UnlockFileObjectByDescriptor(int fd)
+{
+ int i = fd - FILE_WRAPPER_OFFSET;
+ if (i >= 0 && i < MAX_EMULATED_FILES)
+ {
+ if (m_files[i].used)
+ {
+ m_files[i].file_lock->unlock();
+ }
+ }
+}
+
+EmuFileObject* CEmuFileWrapper::GetFileObjectByDescriptor(int fd)
+{
+ int i = fd - FILE_WRAPPER_OFFSET;
+ if (i >= 0 && i < MAX_EMULATED_FILES)
+ {
+ if (m_files[i].used)
+ {
+ return &m_files[i];
+ }
+ }
+ return nullptr;
+}
+
+EmuFileObject* CEmuFileWrapper::GetFileObjectByStream(FILE* stream)
+{
+ if (isValidFilePtr(stream))
+ {
+ EmuFileObject* o = reinterpret_cast<EmuFileObject*>(stream);
+ return GetFileObjectByDescriptor(o->fd);
+ }
+
+ return nullptr;
+}
+
+XFILE::CFile* CEmuFileWrapper::GetFileXbmcByDescriptor(int fd)
+{
+ auto object = GetFileObjectByDescriptor(fd);
+ if (object != nullptr && object->used)
+ {
+ return object->file_xbmc;
+ }
+ return nullptr;
+}
+
+XFILE::CFile* CEmuFileWrapper::GetFileXbmcByStream(FILE* stream)
+{
+ if (isValidFilePtr(stream))
+ {
+ EmuFileObject* object = reinterpret_cast<EmuFileObject*>(stream);
+ if (object != nullptr && object->used)
+ {
+ return object->file_xbmc;
+ }
+ }
+ return nullptr;
+}
+
+int CEmuFileWrapper::GetDescriptorByStream(FILE* stream)
+{
+ if (isValidFilePtr(stream))
+ {
+ EmuFileObject* obj = reinterpret_cast<EmuFileObject*>(stream);
+ int i = obj->fd - FILE_WRAPPER_OFFSET;
+ if (i >= 0 && i < MAX_EMULATED_FILES)
+ {
+ return i + FILE_WRAPPER_OFFSET;
+ }
+ }
+ return -1;
+}
+
+FILE* CEmuFileWrapper::GetStreamByDescriptor(int fd)
+{
+ auto object = GetFileObjectByDescriptor(fd);
+ if (object != nullptr && object->used)
+ {
+ return reinterpret_cast<FILE*>(object);
+ }
+ return nullptr;
+}
+
+bool CEmuFileWrapper::StreamIsEmulatedFile(FILE* stream)
+{
+ if (isValidFilePtr(stream))
+ {
+ EmuFileObject* obj = reinterpret_cast<EmuFileObject*>(stream);
+ return DescriptorIsEmulatedFile(obj->fd);
+ }
+ return false;
+}
diff --git a/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.h b/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.h
new file mode 100644
index 0000000..a8a70fa
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/util/EmuFileWrapper.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "threads/CriticalSection.h"
+
+#include <stdio.h>
+
+#if defined(TARGET_POSIX) && !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD) && !defined(TARGET_ANDROID) && !defined(__UCLIBC__)
+#define _file _fileno
+#elif defined(__UCLIBC__)
+#define _file __filedes
+#endif
+
+#define MAX_EMULATED_FILES 50
+#define FILE_WRAPPER_OFFSET 0x00000200
+
+namespace XFILE
+{
+ class CFile;
+}
+
+typedef struct stEmuFileObject
+{
+ XFILE::CFile* file_xbmc;
+ CCriticalSection *file_lock;
+ int mode;
+ //Stick this last to avoid 3-7 bytes of padding
+ bool used;
+ int fd;
+} EmuFileObject;
+
+class CEmuFileWrapper
+{
+public:
+ CEmuFileWrapper();
+ ~CEmuFileWrapper();
+
+ /**
+ * Only to be called when shutting down xbmc
+ */
+ void CleanUp();
+
+ EmuFileObject* RegisterFileObject(XFILE::CFile* pFile);
+ void UnRegisterFileObjectByDescriptor(int fd);
+ void UnRegisterFileObjectByStream(FILE* stream);
+ void LockFileObjectByDescriptor(int fd);
+ bool TryLockFileObjectByDescriptor(int fd);
+ void UnlockFileObjectByDescriptor(int fd);
+ EmuFileObject* GetFileObjectByDescriptor(int fd);
+ EmuFileObject* GetFileObjectByStream(FILE* stream);
+ XFILE::CFile* GetFileXbmcByDescriptor(int fd);
+ XFILE::CFile* GetFileXbmcByStream(FILE* stream);
+ static int GetDescriptorByStream(FILE* stream);
+ FILE* GetStreamByDescriptor(int fd);
+ static constexpr bool DescriptorIsEmulatedFile(int fd)
+ {
+ return fd >= FILE_WRAPPER_OFFSET && fd < FILE_WRAPPER_OFFSET + MAX_EMULATED_FILES;
+ }
+ static bool StreamIsEmulatedFile(FILE* stream);
+private:
+ EmuFileObject m_files[MAX_EMULATED_FILES];
+ CCriticalSection m_criticalSection;
+};
+
+extern CEmuFileWrapper g_emuFileWrapper;
+
diff --git a/xbmc/cores/DllLoader/exports/winMM.def b/xbmc/cores/DllLoader/exports/winMM.def
new file mode 100755
index 0000000..c389b3d
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/winMM.def
@@ -0,0 +1,6 @@
+LIBRARY WINMM.DLL
+
+VERSION 1.0
+
+EXPORTS
+ timeGetTime \ No newline at end of file
diff --git a/xbmc/cores/DllLoader/exports/wrapper.c b/xbmc/cores/DllLoader/exports/wrapper.c
new file mode 100644
index 0000000..455ec0b
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/wrapper.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+//
+// To recreate wrapper.def:
+//
+// bash# (echo -n "-Wl"; grep __wrap wrapper.c | grep -v bash | sed "s/.*__wrap_//g" | sed "s/(.*//g" | awk '{printf(",-wrap,%s",$0);}') > wrapper.def
+//
+#include <sys/types.h>
+#include <sys/stat.h>
+#if !defined(TARGET_ANDROID)
+#include <sys/statvfs.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
+typedef off_t __off_t;
+typedef int64_t off64_t;
+typedef off64_t __off64_t;
+typedef fpos_t fpos64_t;
+#define stat64 stat
+#endif
+
+#ifdef TARGET_POSIX
+#define _stat stat
+#endif
+
+struct mntent;
+
+void* dllmalloc(size_t );
+void* dllcalloc( size_t , size_t );
+void* dllrealloc(void*, size_t);
+void dllfree(void*);
+
+int dll_open(const char* szFileName, int iMode);
+int dll_write(int fd, const void* buffer, unsigned int uiSize);
+int dll_read(int fd, void* buffer, unsigned int uiSize);
+off_t dll_lseek(int fd, __off_t lPos, int iWhence);
+__off64_t dll_lseeki64(int fd, __off64_t lPos, int iWhence);
+int dll_close(int fd);
+
+FILE * dll_fopen (const char * filename, const char * mode);
+FILE* dll_freopen(const char *path, const char *mode, FILE *stream);
+FILE* dll_fdopen(int i, const char* file);
+int dll_fclose (FILE * stream);
+int dll_ferror (FILE * stream);
+int dll_feof (FILE * stream);
+int dll_fileno(FILE* stream);
+void dll_clearerr(FILE* stream);
+int dll_fread (void * buffer, size_t size, size_t count, FILE * stream);
+size_t dll_fwrite ( const void * buffer, size_t size, size_t count, FILE * stream );
+int dll_fflush (FILE * stream);
+int dll_fputc (int character, FILE * stream);
+int dll_fputs (const char * szLine , FILE* stream);
+int dll_putc(int c, FILE *stream);
+int dll_fseek ( FILE * stream , long offset , int origin );
+int dll_fseek64(FILE *stream, off64_t offset, int origin);
+long dll_ftell(FILE *stream);
+off64_t dll_ftell64(FILE *stream);
+void dll_rewind(FILE* stream);
+int dll_fgetpos(FILE* stream, fpos_t* pos);
+int dll_fgetpos64(FILE *stream, fpos64_t *pos);
+int dll_fsetpos(FILE* stream, const fpos_t* pos);
+int dll_fsetpos64(FILE* stream, const fpos64_t* pos);
+DIR* dll_opendir(const char* name);
+struct dirent* dll_readdir(DIR* dirp);
+int dll_closedir(DIR* dirp);
+void dll_rewinddir(DIR* dirp);
+int dll_fprintf(FILE* stream , const char * format, ...);
+int dllprintf(const char *format, ...);
+int dll_vfprintf(FILE *stream, const char *format, va_list va);
+int dll_fgetc (FILE* stream);
+char * dll_fgets (char* pszString, int num , FILE * stream);
+int dll_getc (FILE * stream);
+int dll_ungetc (int c, FILE * stream);
+int dll_ioctl(int d, unsigned long int request, va_list va);
+int dll_stat(const char *path, struct _stat *buffer);
+int dll_stat64(const char *path, struct stat64 *buffer);
+void dll_flockfile(FILE *file);
+int dll_ftrylockfile(FILE *file);
+void dll_funlockfile(FILE *file);
+int dll_fstat64(int fd, struct stat64 *buf);
+int dll_fstat(int fd, struct _stat *buf);
+FILE* dll_popen(const char *command, const char *mode);
+void* dll_dlopen(const char *filename, int flag);
+int dll_setvbuf(FILE *stream, char *buf, int type, size_t size);
+struct mntent *dll_getmntent(FILE *fp);
+struct mntent* dll_getmntent_r(FILE* fp, struct mntent* result, char* buffer, int bufsize);
+
+void *__wrap_dlopen(const char *filename, int flag)
+{
+ return dlopen(filename, flag);
+}
+
+FILE *__wrap_popen(const char *command, const char *mode)
+{
+ return dll_popen(command, mode);
+}
+
+void* __wrap_calloc( size_t num, size_t size )
+{
+ return dllcalloc(num, size);
+}
+
+void* __wrap_malloc(size_t size)
+{
+ return dllmalloc(size);
+}
+
+void* __wrap_realloc( void *memblock, size_t size )
+{
+ return dllrealloc(memblock, size);
+}
+
+void __wrap_free( void* pPtr )
+{
+ dllfree(pPtr);
+}
+
+int __wrap_open(const char *file, int oflag, ...)
+{
+ return dll_open(file, oflag);
+}
+
+int __wrap_open64(const char *file, int oflag, ...)
+{
+ return dll_open(file, oflag);
+}
+
+int __wrap_close(int fd)
+{
+ return dll_close(fd);
+}
+
+ssize_t __wrap_write(int fd, const void *buf, size_t count)
+{
+ return dll_write(fd, buf, count);
+}
+
+ssize_t __wrap_read(int fd, void *buf, size_t count)
+{
+ return dll_read(fd, buf, count);
+}
+
+__off_t __wrap_lseek(int filedes, __off_t offset, int whence)
+{
+ return dll_lseek(filedes, offset, whence);
+}
+
+__off64_t __wrap_lseek64(int filedes, __off64_t offset, int whence)
+{
+ __off64_t seekRes = dll_lseeki64(filedes, offset, whence);
+ return seekRes;
+}
+
+int __wrap_fclose(FILE *fp)
+{
+ return dll_fclose(fp);
+}
+
+int __wrap_ferror(FILE *stream)
+{
+ return dll_ferror(stream);
+}
+
+void __wrap_clearerr(FILE *stream)
+{
+ dll_clearerr(stream);
+}
+
+int __wrap_feof(FILE *stream)
+{
+ return dll_feof(stream);
+}
+
+int __wrap_fileno(FILE *stream)
+{
+ return dll_fileno(stream);
+}
+
+FILE *__wrap_fopen(const char *path, const char *mode)
+{
+ return dll_fopen(path, mode);
+}
+
+FILE *__wrap_fopen64(const char *path, const char *mode)
+{
+ return dll_fopen(path, mode);
+}
+
+FILE *__wrap_fdopen(int filedes, const char *mode)
+{
+ return dll_fdopen(filedes, mode);
+}
+
+FILE *__wrap_freopen(const char *path, const char *mode, FILE *stream)
+{
+ return dll_freopen(path, mode, stream);
+}
+
+size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ return dll_fread(ptr, size, nmemb, stream);
+}
+
+size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ return dll_fwrite(ptr, size, nmemb, stream);
+}
+
+int __wrap_fflush(FILE *stream)
+{
+ return dll_fflush(stream);
+}
+
+int __wrap_fputc(int c, FILE *stream)
+{
+ return dll_fputc(c, stream);
+}
+
+int __wrap_fputs(const char *s, FILE *stream)
+{
+ return dll_fputs(s, stream);
+}
+
+int __wrap__IO_putc(int c, FILE *stream)
+{
+ return dll_putc(c, stream);
+}
+
+int __wrap_fseek(FILE *stream, long offset, int whence)
+{
+ return dll_fseek(stream, offset, whence);
+}
+
+int __wrap_fseeko64(FILE *stream, off64_t offset, int whence)
+{
+ return dll_fseek64(stream, offset, whence);
+}
+
+long __wrap_ftell(FILE *stream)
+{
+ return dll_ftell(stream);
+}
+
+off64_t __wrap_ftello64(FILE *stream)
+{
+ return dll_ftell64(stream);
+}
+
+void __wrap_rewind(FILE *stream)
+{
+ dll_rewind(stream);
+}
+
+int __wrap_fgetpos(FILE *stream, fpos_t *pos)
+{
+ return dll_fgetpos(stream, pos);
+}
+
+int __wrap_fgetpos64(FILE *stream, fpos64_t *pos)
+{
+ return dll_fgetpos64(stream, pos);
+}
+
+int __wrap_fsetpos(FILE *stream, fpos_t *pos)
+{
+ return dll_fsetpos(stream, pos);
+}
+
+int __wrap_fsetpos64(FILE *stream, fpos64_t *pos)
+{
+ return dll_fsetpos64(stream, pos);
+}
+
+DIR * __wrap_opendir(const char *name)
+{
+ return dll_opendir(name);
+}
+
+struct dirent * __wrap_readdir(DIR* dirp)
+{
+ return dll_readdir(dirp);
+}
+
+struct dirent * __wrap_readdir64(DIR* dirp)
+{
+ return dll_readdir(dirp);
+}
+
+int __wrap_closedir(DIR* dirp)
+{
+ return dll_closedir(dirp);
+}
+
+void __wrap_rewinddir(DIR* dirp)
+{
+ dll_rewinddir(dirp);
+}
+
+int __wrap_fprintf(FILE *stream, const char *format, ...)
+{
+ int res;
+ va_list va;
+ va_start(va, format);
+ res = dll_vfprintf(stream, format, va);
+ va_end(va);
+ return res;
+}
+
+int __wrap_vfprintf(FILE *stream, const char *format, va_list ap)
+{
+ return dll_vfprintf(stream, format, ap);
+}
+
+int __wrap_printf(const char *format, ...)
+{
+ int res;
+ va_list va;
+ va_start(va, format);
+ res = dll_vfprintf(stdout, format, va);
+ va_end(va);
+ return res;
+}
+
+int __wrap_fgetc(FILE *stream)
+{
+ return dll_fgetc(stream);
+}
+
+char *__wrap_fgets(char *s, int size, FILE *stream)
+{
+ return dll_fgets(s, size, stream);
+}
+
+int __wrap__IO_getc(FILE *stream)
+{
+ return dll_getc(stream);
+}
+
+int __wrap__IO_getc_unlocked(FILE *stream)
+{
+ return dll_getc(stream);
+}
+
+int __wrap_getc_unlocked(FILE *stream)
+{
+ return dll_getc(stream);
+}
+
+int __wrap_ungetc(int c, FILE *stream)
+{
+ return dll_ungetc(c, stream);
+}
+
+int __wrap_getc(FILE *stream)
+{
+ return dll_getc(stream);
+}
+
+int __wrap_ioctl(int d, unsigned long int request, ...)
+{
+ int res;
+ va_list va;
+ va_start(va, request);
+ res = dll_ioctl(d, request, va);
+ va_end(va);
+ return res;
+}
+
+int __wrap__stat(const char *path, struct _stat *buffer)
+{
+ return dll_stat(path, buffer);
+}
+
+int __wrap_stat(const char *path, struct _stat *buffer)
+{
+ return dll_stat(path, buffer);
+}
+
+int __wrap_stat64(const char* path, struct stat64* buffer)
+{
+ return dll_stat64(path, buffer);
+}
+
+int __wrap___xstat(int __ver, const char *__filename, struct stat *__stat_buf)
+{
+ return dll_stat(__filename, __stat_buf);
+}
+
+int __wrap___xstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
+{
+ return dll_stat64(__filename, __stat_buf);
+}
+
+int __wrap___lxstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
+{
+ return dll_stat64(__filename, __stat_buf);
+}
+
+void __wrap_flockfile(FILE *file)
+{
+ dll_flockfile(file);
+}
+
+int __wrap_ftrylockfile(FILE *file)
+{
+ return dll_ftrylockfile(file);
+}
+
+void __wrap_funlockfile(FILE *file)
+{
+ dll_funlockfile(file);
+}
+
+int __wrap___fxstat64(int ver, int fd, struct stat64 *buf)
+{
+ return dll_fstat64(fd, buf);
+}
+
+int __wrap___fxstat(int ver, int fd, struct stat *buf)
+{
+ return dll_fstat(fd, buf);
+}
+
+int __wrap_fstat(int fd, struct _stat *buf)
+{
+ return dll_fstat(fd, buf);
+}
+
+int __wrap_fstat64(int fd, struct stat64* buf)
+{
+ return dll_fstat64(fd, buf);
+}
+
+int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size)
+{
+ return dll_setvbuf(stream, buf, type, size);
+}
+
+struct mntent *__wrap_getmntent(FILE *fp)
+{
+#ifdef TARGET_POSIX
+ return dll_getmntent(fp);
+#endif
+ return NULL;
+}
+
+struct mntent* __wrap_getmntent_r(FILE* fp, struct mntent* result, char* buffer, int bufsize)
+{
+#ifdef TARGET_POSIX
+ return dll_getmntent_r(fp, result, buffer, bufsize);
+#endif
+ return NULL;
+}
+
+// GCC 4.3 in Ubuntu 8.10 defines _FORTIFY_SOURCE=2 which means, that fread, read etc
+// are actually #defines which are inlined when compiled with -O. Those defines
+// actually call __*chk (for example, __fread_chk). We need to bypass this whole
+// thing to actually call our wrapped functions.
+#if _FORTIFY_SOURCE > 1
+
+size_t __wrap___fread_chk(void * ptr, size_t ptrlen, size_t size, size_t n, FILE * stream)
+{
+ return dll_fread(ptr, size, n, stream);
+}
+
+int __wrap___printf_chk(int flag, const char *format, ...)
+{
+ int res;
+ va_list va;
+ va_start(va, format);
+ res = dll_vfprintf(stdout, format, va);
+ va_end(va);
+ return res;
+}
+
+int __wrap___vfprintf_chk(FILE* stream, int flag, const char *format, va_list ap)
+{
+ return dll_vfprintf(stream, format, ap);
+}
+
+int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...)
+{
+ int res;
+ va_list va;
+ va_start(va, format);
+ res = dll_vfprintf(stream, format, va);
+ va_end(va);
+ return res;
+}
+
+char *__wrap___fgets_chk(char *s, size_t size, int n, FILE *stream)
+{
+ return dll_fgets(s, n, stream);
+}
+
+size_t __wrap___read_chk(int fd, void *buf, size_t nbytes, size_t buflen)
+{
+ return dll_read(fd, buf, nbytes);
+}
+
+#endif
diff --git a/xbmc/cores/DllLoader/exports/wrapper_mach_alias b/xbmc/cores/DllLoader/exports/wrapper_mach_alias
new file mode 100644
index 0000000..88ff675
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/wrapper_mach_alias
@@ -0,0 +1,62 @@
+# List of wrapper aliases for Mach-O
+___wrap_clearerr _clearerr
+___wrap_close _close
+___wrap_fclose _fclose
+___wrap_fdopen _fdopen
+___wrap_feof _feof
+___wrap_ferror _ferror
+___wrap_fflush _fflush
+___wrap_fgetc _fgetc
+___wrap_fgetpos _fgetpos
+___wrap_fgets _fgets
+___wrap_fileno _fileno
+___wrap_flockfile _flockfile
+___wrap_fopen _fopen
+___wrap_fopen64 _fopen64
+___wrap_fprintf _fprintf
+___wrap_fputc _fputc
+___wrap_fputs _fputs
+___wrap_fread _fread
+___wrap_freopen _freopen
+___wrap_fseek _fseek
+___wrap_fsetpos _fsetpos
+___wrap_fstatvfs64 _fstatvfs64
+___wrap_ftell _ftell
+___wrap_ftrylockfile _ftrylockfile
+___wrap_funlockfile _funlockfile
+___wrap_fwrite _fwrite
+___wrap_ioctl _ioctl
+___wrap_lseek _lseek
+___wrap_lseek64 _lseek64
+___wrap_open _open
+___wrap_open64 _open64
+___wrap_popen _popen
+___wrap_printf _printf
+___wrap_read _read
+___wrap_opendir _opendir
+___wrap_readdir _readdir
+___wrap_closedir _closedir
+___wrap_rewinddir _rewinddir
+___wrap_rewind _rewind
+___wrap__stat _stat
+___wrap_fstat _fstat
+___wrap_ungetc _ungetc
+___wrap_vfprintf _vfprintf
+___wrap_write _write
+___wrap__IO_putc _putc
+___wrap__IO_getc _getc
+___wrap__IO_getc_unlocked _getc_unlocked
+___wrap_fwrite _fwrite$UNIX2003
+___wrap_close _close$UNIX2003
+#___wrap_fcntl _fcntl$UNIX2003
+___wrap_open _open$UNIX2003
+___wrap_fopen _fopen$UNIX2003
+___wrap_fputs _fputs$UNIX2003
+___wrap_read _read$UNIX2003
+___wrap_write _write$UNIX2003
+___wrap_fstat _fstat$INODE64
+___wrap__stat _stat$INODE64
+___wrap_opendir _opendir$INODE64$UNIX2003
+___wrap_closedir _closedir$UNIX2003
+___wrap_readdir _readdir$INODE64
+___wrap_opendir _opendir$INODE64
diff --git a/xbmc/cores/DllLoader/exports/ws2_32.def b/xbmc/cores/DllLoader/exports/ws2_32.def
new file mode 100755
index 0000000..ac7712e
--- /dev/null
+++ b/xbmc/cores/DllLoader/exports/ws2_32.def
@@ -0,0 +1,25 @@
+LIBRARY WS2_32.DLL
+
+VERSION 1.0
+
+EXPORTS
+ WSACleanup
+ WSAGetLastError
+ WSAStartup
+ bind
+ closesocket
+ connect
+ gethostbyname
+ getsockopt
+ htonl
+ htons
+ inet_addr
+ inet_ntoa
+ ioctlsocket
+ ntohl
+ recv
+ select
+ send
+ sendto
+ setsockopt
+ socket \ No newline at end of file
diff --git a/xbmc/cores/DllLoader/ldt_keeper.c b/xbmc/cores/DllLoader/ldt_keeper.c
new file mode 100644
index 0000000..325d50c
--- /dev/null
+++ b/xbmc/cores/DllLoader/ldt_keeper.c
@@ -0,0 +1,282 @@
+/**
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file MUST be in main library because LDT must
+ * be modified before program creates first thread
+ * - avifile includes this file from C++ code
+ * and initializes it at the start of player!
+ * it might sound like a hack and it really is - but
+ * as aviplay is decoding video with more than just one
+ * thread currently it's necessary to do it this way
+ * this might change in the future
+ */
+
+/* applied some modification to make make our xine friend more happy */
+
+/*
+ * Modified for use with MPlayer, detailed changelog at
+ * http://svn.mplayerhq.hu/mplayer/trunk/
+ * $Id: ldt_keeper.c 22733 2007-03-18 22:18:11Z nicodvb $
+ */
+
+// clang-format off
+#if !defined(__aarch64__) && \
+ !defined(__alpha__) &&\
+ !defined(__arc__) &&\
+ !defined(__arm__) && \
+ !defined(__loongarch__) && \
+ !defined(__mips__) && \
+ !defined(__or1k__) && \
+ !defined(__powerpc__) && \
+ !defined(__ppc__) && \
+ !defined(__riscv) && \
+ !defined(__SH4__) && \
+ !defined(__s390x__) && \
+ !defined(__sparc__) && \
+ !defined(__xtensa__)
+// clang-format on
+
+#include "ldt_keeper.h"
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "mmap_anon.h"
+#if defined( __linux__ ) && !defined(__powerpc__)
+#include <asm/unistd.h>
+#include <asm/ldt.h>
+/* prototype it here, so we won't depend on kernel headers */
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if defined(TARGET_ANDROID) && (defined(__i386__) || defined(__x86_64__)) && !defined(modify_ldt)
+#define modify_ldt(a,b,c) syscall( __NR_modify_ldt, a, b, c);
+#else
+int modify_ldt(int func, void *ptr, unsigned long bytecount);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#else
+#if defined(__NetBSD__) || defined(TARGET_FREEBSD) || defined(__OpenBSD__) || defined(__DragonFly__)
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+#endif
+#if defined(TARGET_DARWIN)
+#include <i386/user_ldt.h>
+#endif
+
+#ifdef __svr4__
+#include <sys/segment.h>
+#include <sys/sysi86.h>
+
+/* solaris x86: add missing prototype for sysi86(), but only when sysi86(int, void*) is known to be valid */
+#ifdef HAVE_SYSI86_iv
+#ifdef __cplusplus
+extern "C" {
+#endif
+int sysi86(int, void*);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#ifndef NUMSYSLDTS /* SunOS 2.5.1 does not define NUMSYSLDTS */
+#define NUMSYSLDTS 6 /* Let's hope the SunOS 5.8 value is OK */
+#endif
+
+#define TEB_SEL_IDX NUMSYSLDTS
+#endif
+
+#define LDT_ENTRIES 8192
+#define LDT_ENTRY_SIZE 8
+#pragma pack(4)
+struct user_desc {
+ unsigned int entry_number;
+ unsigned long base_addr;
+ unsigned int limit;
+ unsigned int seg_32bit:1;
+ unsigned int contents:2;
+ unsigned int read_exec_only:1;
+ unsigned int limit_in_pages:1;
+ unsigned int seg_not_present:1;
+};
+
+#define MODIFY_LDT_CONTENTS_DATA 0
+#define MODIFY_LDT_CONTENTS_STACK 1
+#define MODIFY_LDT_CONTENTS_CODE 2
+#endif
+
+
+/* user level (privilege level: 3) ldt (1<<2) segment selector */
+#define LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3)
+
+/* i got this value from wine sources, it's the first free LDT entry */
+#if (defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)) && defined(LDT_AUTO_ALLOC)
+#define TEB_SEL_IDX LDT_AUTO_ALLOC
+#define USE_LDT_AA
+#endif
+
+#ifndef TEB_SEL_IDX
+#define TEB_SEL_IDX 17
+#endif
+
+static unsigned int fs_ldt = TEB_SEL_IDX;
+
+
+/**
+ * here is a small logical problem with Restore for multithreaded programs -
+ * in C++ we use static class for this...
+ */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void Setup_FS_Segment(void)
+{
+ unsigned int ldt_desc = LDT_SEL(fs_ldt);
+
+ __asm__ __volatile__(
+ "movl %0,%%eax; movw %%ax, %%fs" : : "r" (ldt_desc)
+ :"eax"
+ );
+}
+
+#if defined(__NetBSD__) || defined(TARGET_FREEBSD) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(TARGET_DARWIN)
+static void LDT_EntryToBytes( unsigned long *buffer, const struct user_desc *content )
+{
+ *buffer++ = ((content->base_addr & 0x0000ffff) << 16) |
+ (content->limit & 0x0ffff);
+ *buffer = (content->base_addr & 0xff000000) |
+ ((content->base_addr & 0x00ff0000)>>16) |
+ (content->limit & 0xf0000) |
+ (content->contents << 10) |
+ ((content->read_exec_only == 0) << 9) |
+ ((content->seg_32bit != 0) << 22) |
+ ((content->limit_in_pages != 0) << 23) |
+ 0xf000;
+}
+#endif
+
+void* fs_seg=0;
+
+ldt_fs_t* Setup_LDT_Keeper(void)
+{
+ struct user_desc array;
+ int ret;
+ int sret;
+ ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t));
+
+ if (!ldt_fs)
+ return NULL;
+
+#if defined(TARGET_DARWIN)
+ if (getenv("DYLD_BIND_AT_LAUNCH") == NULL)
+ printf("DYLD_BIND_AT_LAUNCH");
+#endif // TARGET_DARWIN
+
+ sret = sysconf(_SC_PAGE_SIZE);
+ if (sret == -1)
+ {
+ perror("ERROR: Couldn't allocate memory for fs segment");
+ free(ldt_fs);
+ return NULL;
+ }
+
+ fs_seg = ldt_fs->fs_seg = mmap_anon(NULL, sret, PROT_READ | PROT_WRITE, MAP_PRIVATE, 0);
+ if (ldt_fs->fs_seg == (void*)-1)
+ {
+ perror("ERROR: Couldn't allocate memory for fs segment");
+ free(ldt_fs);
+ return NULL;
+ }
+ *(void**)((char*)ldt_fs->fs_seg + 0x18) = ldt_fs->fs_seg;
+ memset(&array, 0, sizeof(array));
+ array.base_addr = (long)ldt_fs->fs_seg;
+ array.entry_number = TEB_SEL_IDX;
+ array.limit = array.base_addr+sysconf(_SC_PAGE_SIZE) - 1;
+ array.seg_32bit = 1;
+ array.read_exec_only = 0;
+ array.seg_not_present = 0;
+ array.contents=MODIFY_LDT_CONTENTS_DATA;
+ array.limit_in_pages = 0;
+#ifdef __linux__
+ /* ret=LDT_Modify(0x1, &array, sizeof(struct user_desc)); */
+ ret = modify_ldt(0x1, &array, sizeof(struct user_desc));
+ if (ret < 0)
+ {
+ perror("install_fs");
+ printf("Couldn't install fs segment, expect segfault\n");
+ }
+#endif /*linux*/
+
+#if defined(__NetBSD__) || defined(TARGET_FREEBSD) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(TARGET_DARWIN)
+ {
+ unsigned long d[2];
+
+ LDT_EntryToBytes( d, &array );
+#ifdef USE_LDT_AA
+ ret = i386_set_ldt(LDT_AUTO_ALLOC, (const union ldt_entry *)d, 1);
+ array.entry_number = ret;
+ fs_ldt = ret;
+#else
+ ret = i386_set_ldt(array.entry_number, (const union ldt_entry *)d, 1);
+#endif
+ if (ret < 0)
+ {
+ perror("install_fs");
+ printf("Couldn't install fs segment, expect segfault\n");
+ printf("Did you reconfigure the kernel with \"options USER_LDT\"?\n");
+#ifdef __OpenBSD__
+ printf("On newer OpenBSD systems did you set machdep.userldt to 1?\n");
+#endif
+ }
+ }
+#endif // __NetBSD__ || TARGET_FREEBSD || __OpenBSD__ || __DragonFly__ || TARGET_DARWIN
+
+#if defined(__svr4__)
+ {
+ struct ssd ssd;
+ ssd.sel = LDT_SEL(TEB_SEL_IDX);
+ ssd.bo = array.base_addr;
+ ssd.ls = array.limit - array.base_addr;
+ ssd.acc1 = ((array.read_exec_only == 0) << 1) |
+ (array.contents << 2) |
+ 0xf0; /* P(resent) | DPL3 | S */
+ ssd.acc2 = 0x4; /* byte limit, 32-bit segment */
+ if (sysi86(SI86DSCR, &ssd) < 0)
+ {
+ perror("sysi86(SI86DSCR)");
+ printf("Couldn't install fs segment, expect segfault\n");
+ }
+ }
+#endif
+
+ Setup_FS_Segment();
+
+ ldt_fs->prev_struct = malloc(8);
+ array.base_addr = (uintptr_t)(ldt_fs->prev_struct);
+
+ return ldt_fs;
+}
+
+void Restore_LDT_Keeper(ldt_fs_t* ldt_fs)
+{
+ if (ldt_fs == NULL || ldt_fs->fs_seg == 0)
+ return;
+ if (ldt_fs->prev_struct)
+ free(ldt_fs->prev_struct);
+
+ int sret = sysconf(_SC_PAGE_SIZE);
+ if (sret != -1)
+ munmap((char*)ldt_fs->fs_seg, sret);
+ ldt_fs->fs_seg = 0;
+ free(ldt_fs);
+}
+
+#endif
diff --git a/xbmc/cores/DllLoader/ldt_keeper.h b/xbmc/cores/DllLoader/ldt_keeper.h
new file mode 100644
index 0000000..f6a262f
--- /dev/null
+++ b/xbmc/cores/DllLoader/ldt_keeper.h
@@ -0,0 +1,38 @@
+/**
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file MUST be in main library because LDT must
+ * be modified before program creates first thread
+ * - avifile includes this file from C++ code
+ * and initializes it at the start of player!
+ * it might sound like a hack and it really is - but
+ * as aviplay is decoding video with more than just one
+ * thread currently it's necessary to do it this way
+ * this might change in the future
+ */
+
+/* applied some modification to make make our xine friend more happy */
+
+/*
+ * Modified for use with MPlayer, detailed changelog at
+ * http://svn.mplayerhq.hu/mplayer/trunk/
+ * $Id: ldt_keeper.c 22733 2007-03-18 22:18:11Z nicodvb $
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct {
+ void* fs_seg;
+ char* prev_struct;
+ int fd;
+} ldt_fs_t;
+
+void Setup_FS_Segment(void);
+ldt_fs_t* Setup_LDT_Keeper(void);
+void Restore_LDT_Keeper(ldt_fs_t* ldt_fs);
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/xbmc/cores/DllLoader/mmap_anon.c b/xbmc/cores/DllLoader/mmap_anon.c
new file mode 100644
index 0000000..5bb13cf
--- /dev/null
+++ b/xbmc/cores/DllLoader/mmap_anon.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+/**
+ * \file mmap_anon.c
+ * \brief Provide a compatible anonymous space mapping function
+ */
+
+#include <stdio.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/*
+ * mmap() anonymous space, depending on the system's mmap() style. On systems
+ * that use the /dev/zero mapping idiom, zerofd will be set to the file descriptor
+ * of the opened /dev/zero.
+ */
+
+ /**
+ * \brief mmap() anonymous space, depending on the system's mmap() style. On systems
+ * that use the /dev/zero mapping idiom, zerofd will be set to the file descriptor
+ * of the opened /dev/zero.
+ *
+ * \param addr address to map at.
+ * \param len number of bytes from addr to be mapped.
+ * \param prot protections (region accessibility).
+ * \param flags specifies the type of the mapped object.
+ * \param offset start mapping at byte offset.
+ * \param zerofd
+ * \return a pointer to the mapped region upon successful completion, -1 otherwise.
+ */
+void *mmap_anon(void *addr, size_t len, int prot, int flags, off_t offset)
+{
+ void *result;
+
+#ifndef MAP_ANONYMOUS
+ int fd;
+#endif
+
+ /* From loader/ext.c:
+ * "Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap"
+ * Therefore we preserve the same behavior on all platforms, ie. no
+ * shared mappings of anon space (if the concepts are supported). */
+#if defined(MAP_SHARED) && defined(MAP_PRIVATE)
+ flags = (flags & ~MAP_SHARED) | MAP_PRIVATE;
+#endif /* defined(MAP_SHARED) && defined(MAP_PRIVATE) */
+
+#ifdef MAP_ANONYMOUS
+ /* BSD-style anonymous mapping */
+ result = mmap(addr, len, prot, flags | MAP_ANONYMOUS, -1, offset);
+#else
+ /* SysV-style anonymous mapping */
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0){
+ perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: ");
+ return NULL;
+ }
+
+ result = mmap(addr, len, prot, flags, fd, offset);
+ close(fd);
+#endif /* MAP_ANONYMOUS */
+
+ return result;
+}
diff --git a/xbmc/cores/DllLoader/mmap_anon.h b/xbmc/cores/DllLoader/mmap_anon.h
new file mode 100644
index 0000000..291ccf8
--- /dev/null
+++ b/xbmc/cores/DllLoader/mmap_anon.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+void *mmap_anon(void *, size_t, int, int, off_t);
+