Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* WriteMemoryDump.h
|
||||
* -----------------
|
||||
* Purpose: Code for writing memory dumps to a file.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091) // 'typedef ': ignored on left of '' when no variable is declared
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#include <dbghelp.h>
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
);
|
||||
|
||||
static bool WriteMemoryDump(_EXCEPTION_POINTERS *pExceptionInfo, const TCHAR *filename, bool fullMemDump)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
HMODULE hDll = ::LoadLibrary(_T("DBGHELP.DLL"));
|
||||
if (hDll)
|
||||
{
|
||||
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
|
||||
if (pDump)
|
||||
{
|
||||
|
||||
HANDLE hFile = ::CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
|
||||
|
||||
if(pExceptionInfo)
|
||||
{
|
||||
ExInfo.ThreadId = ::GetCurrentThreadId();
|
||||
ExInfo.ExceptionPointers = pExceptionInfo;
|
||||
ExInfo.ClientPointers = NULL;
|
||||
}
|
||||
|
||||
pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||
fullMemDump ?
|
||||
(MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo
|
||||
#if MPT_COMPILER_MSVC
|
||||
| MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation
|
||||
#endif
|
||||
)
|
||||
:
|
||||
MiniDumpNormal,
|
||||
pExceptionInfo ? &ExInfo : NULL, NULL, NULL);
|
||||
::CloseHandle(hFile);
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
::FreeLibrary(hDll);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
258
Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp
Normal file
258
Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* mptCPU.cpp
|
||||
* ----------
|
||||
* Purpose: CPU feature detection.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptCPU.h"
|
||||
|
||||
#include "../common/mptStringBuffer.h"
|
||||
|
||||
#if defined(MPT_ENABLE_ARCH_INTRINSICS)
|
||||
#if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
|
||||
#include <intrin.h>
|
||||
#endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64)
|
||||
#endif // MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace CPU
|
||||
{
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_ARCH_INTRINSICS)
|
||||
|
||||
|
||||
uint32 EnabledFeatures = 0;
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
|
||||
|
||||
|
||||
typedef char cpuid_result_string[12];
|
||||
|
||||
|
||||
struct cpuid_result {
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
uint32 c;
|
||||
uint32 d;
|
||||
std::string as_string() const
|
||||
{
|
||||
cpuid_result_string result;
|
||||
result[0+0] = (b >> 0) & 0xff;
|
||||
result[0+1] = (b >> 8) & 0xff;
|
||||
result[0+2] = (b >>16) & 0xff;
|
||||
result[0+3] = (b >>24) & 0xff;
|
||||
result[4+0] = (d >> 0) & 0xff;
|
||||
result[4+1] = (d >> 8) & 0xff;
|
||||
result[4+2] = (d >>16) & 0xff;
|
||||
result[4+3] = (d >>24) & 0xff;
|
||||
result[8+0] = (c >> 0) & 0xff;
|
||||
result[8+1] = (c >> 8) & 0xff;
|
||||
result[8+2] = (c >>16) & 0xff;
|
||||
result[8+3] = (c >>24) & 0xff;
|
||||
return std::string(result, result + 12);
|
||||
}
|
||||
std::string as_string4() const
|
||||
{
|
||||
std::string result;
|
||||
result.push_back(static_cast<uint8>((a >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 24) & 0xff));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static cpuid_result cpuid(uint32 function)
|
||||
{
|
||||
cpuid_result result;
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
result.a = CPUInfo[0];
|
||||
result.b = CPUInfo[1];
|
||||
result.c = CPUInfo[2];
|
||||
result.d = CPUInfo[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
|
||||
{
|
||||
cpuid_result result;
|
||||
int CPUInfo[4];
|
||||
__cpuidex(CPUInfo, function_a, function_c);
|
||||
result.a = CPUInfo[0];
|
||||
result.b = CPUInfo[1];
|
||||
result.c = CPUInfo[2];
|
||||
result.d = CPUInfo[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Info::Info()
|
||||
{
|
||||
|
||||
cpuid_result VendorString = cpuid(0x00000000u);
|
||||
mpt::String::WriteAutoBuf(VendorID) = VendorString.as_string();
|
||||
if(VendorString.a >= 0x00000001u)
|
||||
{
|
||||
cpuid_result StandardFeatureFlags = cpuid(0x00000001u);
|
||||
CPUID = StandardFeatureFlags.a;
|
||||
uint32 BaseStepping = (StandardFeatureFlags.a >> 0) & 0x0f;
|
||||
uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f;
|
||||
uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f;
|
||||
uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f;
|
||||
uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff;
|
||||
if(BaseFamily == 0xf)
|
||||
{
|
||||
Family = static_cast<uint16>(ExtFamily + BaseFamily);
|
||||
} else
|
||||
{
|
||||
Family = static_cast<uint16>(BaseFamily);
|
||||
}
|
||||
if((BaseFamily == 0x6) || (BaseFamily == 0xf))
|
||||
{
|
||||
Model = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
|
||||
} else
|
||||
{
|
||||
Model = static_cast<uint8>(BaseModel);
|
||||
}
|
||||
Stepping = static_cast<uint8>(BaseStepping);
|
||||
if(StandardFeatureFlags.d & (1<<23)) AvailableFeatures |= feature::mmx;
|
||||
if(StandardFeatureFlags.d & (1<<25)) AvailableFeatures |= feature::sse;
|
||||
if(StandardFeatureFlags.d & (1<<26)) AvailableFeatures |= feature::sse2;
|
||||
if(StandardFeatureFlags.c & (1<< 0)) AvailableFeatures |= feature::sse3;
|
||||
if(StandardFeatureFlags.c & (1<< 9)) AvailableFeatures |= feature::ssse3;
|
||||
if(StandardFeatureFlags.c & (1<<19)) AvailableFeatures |= feature::sse4_1;
|
||||
if(StandardFeatureFlags.c & (1<<20)) AvailableFeatures |= feature::sse4_2;
|
||||
if(StandardFeatureFlags.c & (1<<28)) AvailableFeatures |= feature::avx;
|
||||
}
|
||||
if(VendorString.a >= 0x00000007u)
|
||||
{
|
||||
cpuid_result ExtendedFeatures = cpuidex(0x00000007u, 0x00000000u);
|
||||
if(ExtendedFeatures.b & (1<< 5)) AvailableFeatures |= feature::avx2;
|
||||
}
|
||||
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<29)) AvailableFeatures |= feature::lm;
|
||||
}
|
||||
if(ExtendedVendorString.a >= 0x80000004u)
|
||||
{
|
||||
mpt::String::WriteAutoBuf(BrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#elif MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
|
||||
|
||||
|
||||
Info::Info()
|
||||
{
|
||||
|
||||
if(IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::mmx;
|
||||
if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse;
|
||||
if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse2;
|
||||
if(IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse3;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else // !(MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64))
|
||||
|
||||
|
||||
Info::Info()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64)
|
||||
|
||||
|
||||
const Info & Info::Get()
|
||||
{
|
||||
static Info info;
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
struct InfoInitializer
|
||||
{
|
||||
InfoInitializer()
|
||||
{
|
||||
Info::Get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static InfoInitializer g_InfoInitializer;
|
||||
|
||||
|
||||
void EnableAvailableFeatures()
|
||||
{
|
||||
EnabledFeatures = Info::Get().AvailableFeatures;
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
|
||||
uint32 GetMinimumFeatures()
|
||||
{
|
||||
uint32 flags = 0;
|
||||
#ifdef MPT_ENABLE_ARCH_INTRINSICS
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if defined(_M_X64)
|
||||
flags |= feature::lm | feature::sse | feature::sse2;
|
||||
#elif defined(_M_IX86)
|
||||
#if defined(_M_IX86_FP)
|
||||
#if (_M_IX86_FP >= 2)
|
||||
flags |= feature::sse | feature::sse2;
|
||||
#elif (_M_IX86_FP == 1)
|
||||
flags |= feature::sse;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__AVX__)
|
||||
flags |= feature::avx;
|
||||
#endif
|
||||
#if defined(__AVX2__)
|
||||
flags |= feature::avx2;
|
||||
#endif
|
||||
#endif
|
||||
#endif // MPT_ENABLE_ARCH_INTRINSICS
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace CPU
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
93
Src/external_dependencies/openmpt-trunk/misc/mptCPU.h
Normal file
93
Src/external_dependencies/openmpt-trunk/misc/mptCPU.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* mptCPU.h
|
||||
* --------
|
||||
* Purpose: CPU feature detection.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace CPU
|
||||
{
|
||||
|
||||
|
||||
namespace feature {
|
||||
inline constexpr uint32 lm = 0x00004; // Processor supports long mode (amd64)
|
||||
inline constexpr uint32 mmx = 0x00010; // Processor supports MMX instructions
|
||||
inline constexpr uint32 sse = 0x00100; // Processor supports SSE instructions
|
||||
inline constexpr uint32 sse2 = 0x00200; // Processor supports SSE2 instructions
|
||||
inline constexpr uint32 sse3 = 0x00400; // Processor supports SSE3 instructions
|
||||
inline constexpr uint32 ssse3 = 0x00800; // Processor supports SSSE3 instructions
|
||||
inline constexpr uint32 sse4_1 = 0x01000; // Processor supports SSE4.1 instructions
|
||||
inline constexpr uint32 sse4_2 = 0x02000; // Processor supports SSE4.2 instructions
|
||||
inline constexpr uint32 avx = 0x10000; // Processor supports AVX instructions
|
||||
inline constexpr uint32 avx2 = 0x20000; // Processor supports AVX2 instructions
|
||||
} // namespace feature
|
||||
|
||||
|
||||
#ifdef MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
|
||||
extern uint32 EnabledFeatures;
|
||||
|
||||
|
||||
struct Info
|
||||
{
|
||||
public:
|
||||
uint32 AvailableFeatures = 0;
|
||||
uint32 CPUID = 0;
|
||||
char VendorID[16+1] = {};
|
||||
char BrandID[4*4*3+1] = {};
|
||||
uint16 Family = 0;
|
||||
uint8 Model = 0;
|
||||
uint8 Stepping = 0;
|
||||
private:
|
||||
Info();
|
||||
public:
|
||||
static const Info & Get();
|
||||
};
|
||||
|
||||
|
||||
void EnableAvailableFeatures();
|
||||
|
||||
|
||||
struct AvailableFeaturesEnabler
|
||||
{
|
||||
AvailableFeaturesEnabler()
|
||||
{
|
||||
EnableAvailableFeatures();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// enabled processor features for inline asm and intrinsics
|
||||
MPT_FORCEINLINE uint32 GetEnabledFeatures()
|
||||
{
|
||||
return EnabledFeatures;
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE bool HasFeatureSet(uint32 features)
|
||||
{
|
||||
return features == (GetEnabledFeatures() & features);
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
|
||||
uint32 GetMinimumFeatures();
|
||||
|
||||
|
||||
} // namespace CPU
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
95
Src/external_dependencies/openmpt-trunk/misc/mptColor.cpp
Normal file
95
Src/external_dependencies/openmpt-trunk/misc/mptColor.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* mptColor.cpp
|
||||
* ------------
|
||||
* Purpose: Color space conversion and other color-related code.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptColor.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt::Color
|
||||
{
|
||||
|
||||
uint8 GetLuma(uint8 r, uint8 g, uint8 b) noexcept
|
||||
{
|
||||
return mpt::saturate_cast<uint8>(r * 0.299f + g * 0.587f + b * 0.114f);
|
||||
}
|
||||
|
||||
|
||||
HSV RGB::ToHSV() const noexcept
|
||||
{
|
||||
const auto min = std::min({r, g, b});
|
||||
const auto max = std::max({r, g, b});
|
||||
const auto delta = max - min;
|
||||
|
||||
HSV hsv;
|
||||
hsv.v = max;
|
||||
if(delta < 0.00001f)
|
||||
{
|
||||
hsv.s = 0;
|
||||
hsv.h = 0;
|
||||
return hsv;
|
||||
}
|
||||
if(max > 0.0f)
|
||||
{
|
||||
hsv.s = (delta / max);
|
||||
} else
|
||||
{
|
||||
// black
|
||||
hsv.s = 0.0f;
|
||||
hsv.h = 0.0f;
|
||||
return hsv;
|
||||
}
|
||||
if(r >= max)
|
||||
hsv.h = (g - b) / delta;
|
||||
else if(g >= max)
|
||||
hsv.h = 2.0f + (b - r) / delta;
|
||||
else
|
||||
hsv.h = 4.0f + (r - g) / delta;
|
||||
|
||||
if(hsv.h < 0.0f)
|
||||
hsv.h += 6.0f;
|
||||
|
||||
hsv.h *= 60.0f;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
|
||||
RGB HSV::ToRGB() const noexcept
|
||||
{
|
||||
// Optimization for greyscale
|
||||
if(s <= 0.0f)
|
||||
return {v, v, v};
|
||||
|
||||
const float hh = h / 60.0f;
|
||||
const int region = static_cast<int>(hh);
|
||||
const float fract = hh - region;
|
||||
const float p = v * (1.0f - s);
|
||||
const float q = v * (1.0f - (s * fract));
|
||||
const float t = v * (1.0f - (s * (1.0f - fract)));
|
||||
|
||||
switch(region % 6)
|
||||
{
|
||||
default:
|
||||
case 0: return {v, t, p};
|
||||
case 1: return {q, v, p};
|
||||
case 2: return {p, v, t};
|
||||
case 3: return {p, q, v};
|
||||
case 4: return {t, p, v};
|
||||
case 5: return {v, p, q};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt::Color
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
47
Src/external_dependencies/openmpt-trunk/misc/mptColor.h
Normal file
47
Src/external_dependencies/openmpt-trunk/misc/mptColor.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* mptColor.h
|
||||
* ----------
|
||||
* Purpose: Color space conversion and other color-related code.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt::Color
|
||||
{
|
||||
|
||||
uint8 GetLuma(uint8 r, uint8 g, uint8 b) noexcept;
|
||||
|
||||
struct HSV;
|
||||
|
||||
struct RGB
|
||||
{
|
||||
float r; // 0...1
|
||||
float g; // 0...1
|
||||
float b; // 0...1
|
||||
|
||||
HSV ToHSV() const noexcept;
|
||||
};
|
||||
|
||||
struct HSV
|
||||
{
|
||||
float h; // angle in degrees
|
||||
float s; // 0...1
|
||||
float v; // 0...1
|
||||
|
||||
RGB ToRGB() const noexcept;
|
||||
};
|
||||
|
||||
} // namespace mpt::Color
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
553
Src/external_dependencies/openmpt-trunk/misc/mptLibrary.cpp
Normal file
553
Src/external_dependencies/openmpt-trunk/misc/mptLibrary.cpp
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
* mptLibrary.cpp
|
||||
* --------------
|
||||
* Purpose: Shared library handling.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptLibrary.h"
|
||||
|
||||
#include "mpt/osinfo/windows_version.hpp"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#elif MPT_OS_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
#include <ltdl.h>
|
||||
#elif defined(MPT_WITH_DL)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
// KB2533623 / Win8
|
||||
#ifndef LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
|
||||
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
|
||||
#define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
|
||||
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
|
||||
#endif
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
HMODULE hModule;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: hModule(NULL)
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
(void)path;
|
||||
hModule = NULL; // unsupported
|
||||
#else
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPath::Default:
|
||||
hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
|
||||
break;
|
||||
case mpt::LibrarySearchPath::Application:
|
||||
hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
|
||||
break;
|
||||
case mpt::LibrarySearchPath::System:
|
||||
hModule = NULL; // Only application packaged libraries can be loaded dynamically in WinRT
|
||||
break;
|
||||
case mpt::LibrarySearchPath::FullPath:
|
||||
hModule = NULL; // Absolute path is not supported in WinRT
|
||||
break;
|
||||
case mpt::LibrarySearchPath::Invalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0602)
|
||||
bool hasKB2533623 = true;
|
||||
#else
|
||||
// Check for KB2533623:
|
||||
bool hasKB2533623 = false;
|
||||
mpt::osinfo::windows::Version WindowsVersion = mpt::osinfo::windows::Version::Current();
|
||||
if(WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::Win8))
|
||||
{
|
||||
hasKB2533623 = true;
|
||||
} else if(WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::WinVista))
|
||||
{
|
||||
HMODULE hKernel32DLL = LoadLibrary(TEXT("kernel32.dll"));
|
||||
if(hKernel32DLL)
|
||||
{
|
||||
if(::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr)
|
||||
{
|
||||
hasKB2533623 = true;
|
||||
}
|
||||
FreeLibrary(hKernel32DLL);
|
||||
hKernel32DLL = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MPT_MAYBE_CONSTANT_IF(hasKB2533623)
|
||||
{
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPath::Default:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
break;
|
||||
case mpt::LibrarySearchPath::System:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
break;
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
// Using restricted search paths applies to potential DLL dependencies
|
||||
// recursively.
|
||||
// This fails loading for e.g. Codec or Plugin DLLs in application
|
||||
// directory if they depend on the MSVC C or C++ runtime (which is
|
||||
// located in the system directory).
|
||||
// Just rely on the default search path here.
|
||||
case mpt::LibrarySearchPath::Application:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetExecutablePath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPath::FullPath:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
#else
|
||||
// For libopenmpt, do the safe thing.
|
||||
case mpt::LibrarySearchPath::Application:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
break;
|
||||
case mpt::LibrarySearchPath::FullPath:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
break;
|
||||
#endif
|
||||
case mpt::LibrarySearchPath::Invalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPath::Default:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPath::Application:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetExecutablePath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPath::System:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetSystemPath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPath::FullPath:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPath::Invalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
hModule = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (hModule != NULL);
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(::GetProcAddress(hModule, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#elif MPT_OS_ANDROID
|
||||
|
||||
|
||||
// Fake implementation.
|
||||
// Load shared objects from the JAVA side of things.
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(dlsym(0, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
bool inited;
|
||||
lt_dlhandle handle;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: inited(false)
|
||||
, handle(0)
|
||||
{
|
||||
if(lt_dlinit() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
inited = true;
|
||||
handle = lt_dlopenext(path.GetFileName().AsNative().c_str());
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
lt_dlclose(handle);
|
||||
}
|
||||
handle = 0;
|
||||
if(inited)
|
||||
{
|
||||
lt_dlexit();
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return handle != 0;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(lt_dlsym(handle, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#elif defined(MPT_WITH_DL)
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
void* handle;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: handle(NULL)
|
||||
{
|
||||
handle = dlopen(path.GetFileName().AsNative().c_str(), RTLD_NOW);
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return handle != NULL;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(dlsym(handle, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#else // MPT_OS
|
||||
|
||||
|
||||
// dummy implementation
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(path);
|
||||
return;
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(symbol);
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // MPT_OS
|
||||
|
||||
|
||||
LibraryPath::LibraryPath(mpt::LibrarySearchPath searchPath, const mpt::PathString &fileName)
|
||||
: searchPath(searchPath)
|
||||
, fileName(fileName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mpt::LibrarySearchPath LibraryPath::GetSearchPath() const
|
||||
{
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetFileName() const
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetDefaultPrefix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return P_("");
|
||||
#elif MPT_OS_ANDROID
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return P_("lib");
|
||||
#else
|
||||
return P_("lib");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetDefaultSuffix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return P_(".dll");
|
||||
#elif MPT_OS_ANDROID
|
||||
return P_(".so");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return P_(""); // handled by libltdl
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return P_(".so");
|
||||
#else
|
||||
return mpt::PathString();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::App(const mpt::PathString &basename)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPath::Application, GetDefaultPrefix() + basename + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::AppFullName(const mpt::PathString &fullname)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPath::Application, fullname + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::System(const mpt::PathString &basename)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPath::System, GetDefaultPrefix() + basename + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::FullPath(const mpt::PathString &path)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPath::FullPath, path);
|
||||
}
|
||||
|
||||
|
||||
Library::Library()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Library::Library(const mpt::LibraryPath &path)
|
||||
{
|
||||
if(path.GetSearchPath() == mpt::LibrarySearchPath::Invalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(path.GetFileName().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Handle = std::make_shared<LibraryHandle>(path);
|
||||
}
|
||||
|
||||
|
||||
void Library::Unload()
|
||||
{
|
||||
*this = mpt::Library();
|
||||
}
|
||||
|
||||
|
||||
bool Library::IsValid() const
|
||||
{
|
||||
return m_Handle && m_Handle->IsValid();
|
||||
}
|
||||
|
||||
|
||||
FuncPtr Library::GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return m_Handle->GetProcAddress(symbol);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
108
Src/external_dependencies/openmpt-trunk/misc/mptLibrary.h
Normal file
108
Src/external_dependencies/openmpt-trunk/misc/mptLibrary.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* mptLibrary.h
|
||||
* ------------
|
||||
* Purpose: Shared library handling.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
typedef void* (*FuncPtr)(); // pointer to function returning void*
|
||||
|
||||
class LibraryHandle;
|
||||
|
||||
enum class LibrarySearchPath
|
||||
{
|
||||
Invalid,
|
||||
Default,
|
||||
Application,
|
||||
System,
|
||||
FullPath,
|
||||
};
|
||||
|
||||
class LibraryPath
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
mpt::LibrarySearchPath searchPath;
|
||||
mpt::PathString fileName;
|
||||
|
||||
private:
|
||||
|
||||
LibraryPath(mpt::LibrarySearchPath searchPath, const mpt::PathString &fileName);
|
||||
|
||||
public:
|
||||
|
||||
mpt::LibrarySearchPath GetSearchPath() const;
|
||||
|
||||
mpt::PathString GetFileName() const;
|
||||
|
||||
public:
|
||||
|
||||
// "lib" on Unix-like systems, "" on Windows
|
||||
static mpt::PathString GetDefaultPrefix();
|
||||
|
||||
// ".so" or ".dylib" or ".dll"
|
||||
static mpt::PathString GetDefaultSuffix();
|
||||
|
||||
// Returns the library path in the application directory, with os-specific prefix and suffix added to basename.
|
||||
// e.g.: basename = "unmo3" --> "libunmo3.so" / "apppath/unmo3.dll"
|
||||
static LibraryPath App(const mpt::PathString &basename);
|
||||
|
||||
// Returns the library path in the application directory, with os-specific suffix added to fullname.
|
||||
// e.g.: fullname = "libunmo3" --> "libunmo3.so" / "apppath/libunmo3.dll"
|
||||
static LibraryPath AppFullName(const mpt::PathString &fullname);
|
||||
|
||||
// Returns a system library name with os-specific prefix and suffix added to basename, but without any full path in order to be searched in the default search path.
|
||||
// e.g.: basename = "unmo3" --> "libunmo3.so" / "unmo3.dll"
|
||||
static LibraryPath System(const mpt::PathString &basename);
|
||||
|
||||
// Returns a system library name with os-specific suffix added to path.
|
||||
// e.g.: path = "somepath/foo" --> "somepath/foo.so" / "somepath/foo.dll"
|
||||
static LibraryPath FullPath(const mpt::PathString &path);
|
||||
|
||||
};
|
||||
|
||||
class Library
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<LibraryHandle> m_Handle;
|
||||
public:
|
||||
Library();
|
||||
Library(const mpt::LibraryPath &path);
|
||||
public:
|
||||
void Unload();
|
||||
bool IsValid() const;
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const;
|
||||
template <typename Tfunc>
|
||||
bool Bind(Tfunc * & f, const std::string &symbol) const
|
||||
{
|
||||
#if !(MPT_OS_WINDOWS && MPT_COMPILER_GCC)
|
||||
// MinGW64 std::is_function is always false for non __cdecl functions.
|
||||
// See https://connect.microsoft.com/VisualStudio/feedback/details/774720/stl-is-function-bug .
|
||||
static_assert(std::is_function<Tfunc>::value);
|
||||
#endif
|
||||
const FuncPtr addr = GetProcAddress(symbol);
|
||||
f = reinterpret_cast<Tfunc*>(addr);
|
||||
return (addr != nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
80
Src/external_dependencies/openmpt-trunk/misc/mptMutex.h
Normal file
80
Src/external_dependencies/openmpt-trunk/misc/mptMutex.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* mptMutex.h
|
||||
* ----------
|
||||
* Purpose: Partially implement c++ mutexes as far as openmpt needs them. Can eventually go away when we only support c++11 compilers some time.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/mutex/mutex.hpp"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt {
|
||||
|
||||
class recursive_mutex_with_lock_count {
|
||||
|
||||
private:
|
||||
|
||||
mpt::recursive_mutex mutex;
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
_Guarded_by_(mutex)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
long lockCount;
|
||||
|
||||
public:
|
||||
|
||||
recursive_mutex_with_lock_count()
|
||||
: lockCount(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
~recursive_mutex_with_lock_count()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
_Acquires_lock_(mutex)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
void lock()
|
||||
{
|
||||
mutex.lock();
|
||||
lockCount++;
|
||||
}
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
_Requires_lock_held_(mutex) _Releases_lock_(mutex)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
void unlock()
|
||||
{
|
||||
lockCount--;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsLockedByCurrentThread() // DEBUGGING only
|
||||
{
|
||||
bool islocked = false;
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
islocked = (lockCount > 0);
|
||||
mutex.unlock();
|
||||
}
|
||||
return islocked;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
551
Src/external_dependencies/openmpt-trunk/misc/mptOS.cpp
Normal file
551
Src/external_dependencies/openmpt-trunk/misc/mptOS.cpp
Normal file
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
* mptOS.cpp
|
||||
* ---------
|
||||
* Purpose: Operating system version information.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptOS.h"
|
||||
|
||||
#include "mpt/binary/hex.hpp"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace {
|
||||
struct WindowsVersionCache
|
||||
{
|
||||
mpt::osinfo::windows::Version version;
|
||||
WindowsVersionCache() noexcept
|
||||
: version(mpt::osinfo::windows::Version::Current())
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static mpt::osinfo::windows::Version GatherWindowsVersionFromCache() noexcept
|
||||
{
|
||||
static WindowsVersionCache gs_WindowsVersionCache;
|
||||
return gs_WindowsVersionCache.version;
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
mpt::osinfo::windows::Version Version::Current() noexcept
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifdef MODPLUG_TRACKER
|
||||
return GatherWindowsVersionFromCache();
|
||||
#else // !MODPLUG_TRACKER
|
||||
return mpt::osinfo::windows::Version::Current();
|
||||
#endif // MODPLUG_TRACKER
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::osinfo::windows::Version::NoWindows();
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
static constexpr struct { mpt::osinfo::windows::Version version; const mpt::uchar * name; bool showDetails; } versionMap[] =
|
||||
{
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::WinNewer, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 22000, 0 }, UL_("Windows 11 (or newer)"), false },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 22000, 0 }, UL_("Windows 11"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 19044, 0 }, UL_("Windows 10 21H2"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 19043, 0 }, UL_("Windows 10 21H1"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 19042, 0 }, UL_("Windows 10 20H2"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 19041, 0 }, UL_("Windows 10 2004"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 18363, 0 }, UL_("Windows 10 1909"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 18362, 0 }, UL_("Windows 10 1903"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 17763, 0 }, UL_("Windows 10 1809"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 17134, 0 }, UL_("Windows 10 1803"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 16299, 0 }, UL_("Windows 10 1709"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 15063, 0 }, UL_("Windows 10 1703"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 14393, 0 }, UL_("Windows 10 1607"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 10586, 0 }, UL_("Windows 10 1511"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 10240, 0 }, UL_("Windows 10 1507"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win81, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows 8.1"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win8, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows 8"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win7, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows 7"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::WinVista, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows Vista"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::WinXP64, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows XP x64 / Windows Server 2003"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::WinXP, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows XP"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::Win2000, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows 2000"), true },
|
||||
{ mpt::osinfo::windows::Version{ mpt::osinfo::windows::Version::WinNT4, mpt::osinfo::windows::Version::ServicePack{ 0, 0 }, 0, 0 }, UL_("Windows NT4"), true }
|
||||
};
|
||||
|
||||
|
||||
mpt::ustring Version::GetName(mpt::osinfo::windows::Version version)
|
||||
{
|
||||
mpt::ustring name = U_("Generic Windows NT");
|
||||
bool showDetails = false;
|
||||
for(const auto &v : versionMap)
|
||||
{
|
||||
if(version.IsAtLeast(v.version))
|
||||
{
|
||||
name = v.name;
|
||||
showDetails = v.showDetails;
|
||||
break;
|
||||
}
|
||||
}
|
||||
name += U_(" (");
|
||||
name += MPT_UFORMAT("Version {}.{}")(version.GetSystem().Major, version.GetSystem().Minor);
|
||||
if(showDetails)
|
||||
{
|
||||
if(version.GetServicePack().HasServicePack())
|
||||
{
|
||||
if(version.GetServicePack().Minor)
|
||||
{
|
||||
name += MPT_UFORMAT(" Service Pack {}.{}")(version.GetServicePack().Major, version.GetServicePack().Minor);
|
||||
} else
|
||||
{
|
||||
name += MPT_UFORMAT(" Service Pack {}")(version.GetServicePack().Major);
|
||||
}
|
||||
}
|
||||
if(version.GetBuild() != 0)
|
||||
{
|
||||
name += MPT_UFORMAT(" (Build {})")(version.GetBuild());
|
||||
}
|
||||
}
|
||||
name += U_(")");
|
||||
mpt::ustring result = name;
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
if(mpt::OS::Windows::IsWine())
|
||||
{
|
||||
mpt::OS::Wine::VersionContext v;
|
||||
if(v.Version().IsValid())
|
||||
{
|
||||
result = MPT_UFORMAT("Wine {} ({})")(
|
||||
v.Version().AsString()
|
||||
, name
|
||||
);
|
||||
} else
|
||||
{
|
||||
result = MPT_UFORMAT("Wine (unknown version: '{}') ({})")(
|
||||
mpt::ToUnicode(mpt::Charset::UTF8, v.RawVersion())
|
||||
, name
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mpt::osinfo::windows::Version Version::GetMinimumKernelLevel() noexcept
|
||||
{
|
||||
uint64 minimumKernelVersion = 0;
|
||||
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
|
||||
#if defined(MPT_BUILD_RETRO)
|
||||
minimumKernelVersion = std::max(minimumKernelVersion, static_cast<uint64>(mpt::osinfo::windows::Version::WinXP));
|
||||
#else
|
||||
minimumKernelVersion = std::max(minimumKernelVersion, static_cast<uint64>(mpt::osinfo::windows::Version::WinVista));
|
||||
#endif
|
||||
#endif
|
||||
return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::System(minimumKernelVersion), mpt::osinfo::windows::Version::ServicePack(0, 0), 0, 0);
|
||||
}
|
||||
|
||||
|
||||
mpt::osinfo::windows::Version Version::GetMinimumAPILevel() noexcept
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return mpt::osinfo::windows::Version::FromSDK();
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::osinfo::windows::Version::NoWindows();
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#ifndef PROCESSOR_ARCHITECTURE_NEUTRAL
|
||||
#define PROCESSOR_ARCHITECTURE_NEUTRAL 11
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM64 12
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 13
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 14
|
||||
#endif
|
||||
|
||||
|
||||
struct OSArchitecture
|
||||
{
|
||||
uint16 ProcessorArchitectur;
|
||||
Architecture Host;
|
||||
Architecture Process;
|
||||
};
|
||||
static constexpr OSArchitecture architectures [] = {
|
||||
{ PROCESSOR_ARCHITECTURE_INTEL , Architecture::x86 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_AMD64 , Architecture::amd64 , Architecture::amd64 },
|
||||
{ PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 , Architecture::amd64 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM , Architecture::arm , Architecture::arm },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM64 , Architecture::arm64 , Architecture::arm64 },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64, Architecture::arm64 , Architecture::arm },
|
||||
{ PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 , Architecture::arm64 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_MIPS , Architecture::mips , Architecture::mips },
|
||||
{ PROCESSOR_ARCHITECTURE_PPC , Architecture::ppc , Architecture::ppc },
|
||||
{ PROCESSOR_ARCHITECTURE_SHX , Architecture::shx , Architecture::shx },
|
||||
{ PROCESSOR_ARCHITECTURE_ALPHA , Architecture::alpha , Architecture::alpha },
|
||||
{ PROCESSOR_ARCHITECTURE_ALPHA64 , Architecture::alpha64, Architecture::alpha64 },
|
||||
{ PROCESSOR_ARCHITECTURE_IA64 , Architecture::ia64 , Architecture::ia64 },
|
||||
{ PROCESSOR_ARCHITECTURE_MSIL , Architecture::unknown, Architecture::unknown },
|
||||
{ PROCESSOR_ARCHITECTURE_NEUTRAL , Architecture::unknown, Architecture::unknown },
|
||||
{ PROCESSOR_ARCHITECTURE_UNKNOWN , Architecture::unknown, Architecture::unknown }
|
||||
};
|
||||
|
||||
|
||||
struct HostArchitecture
|
||||
{
|
||||
Architecture Host;
|
||||
Architecture Process;
|
||||
EmulationLevel Emulation;
|
||||
};
|
||||
static constexpr HostArchitecture hostArchitectureCanRun [] = {
|
||||
{ Architecture::x86 , Architecture::x86 , EmulationLevel::Native },
|
||||
{ Architecture::amd64 , Architecture::amd64 , EmulationLevel::Native },
|
||||
{ Architecture::amd64 , Architecture::x86 , EmulationLevel::Virtual },
|
||||
{ Architecture::arm , Architecture::arm , EmulationLevel::Native },
|
||||
{ Architecture::arm64 , Architecture::arm64 , EmulationLevel::Native },
|
||||
{ Architecture::arm64 , Architecture::arm , EmulationLevel::Virtual },
|
||||
{ Architecture::arm64 , Architecture::x86 , EmulationLevel::Software },
|
||||
{ Architecture::arm64 , Architecture::amd64 , EmulationLevel::Software },
|
||||
{ Architecture::mips , Architecture::mips , EmulationLevel::Native },
|
||||
{ Architecture::ppc , Architecture::ppc , EmulationLevel::Native },
|
||||
{ Architecture::shx , Architecture::shx , EmulationLevel::Native },
|
||||
{ Architecture::alpha , Architecture::alpha , EmulationLevel::Native },
|
||||
{ Architecture::alpha64, Architecture::alpha64, EmulationLevel::Native },
|
||||
{ Architecture::alpha64, Architecture::alpha , EmulationLevel::Virtual },
|
||||
{ Architecture::ia64 , Architecture::ia64 , EmulationLevel::Native },
|
||||
{ Architecture::ia64 , Architecture::x86 , EmulationLevel::Hardware }
|
||||
};
|
||||
|
||||
|
||||
struct ArchitectureInfo
|
||||
{
|
||||
Architecture Arch;
|
||||
int Bitness;
|
||||
const mpt::uchar * Name;
|
||||
};
|
||||
static constexpr ArchitectureInfo architectureInfo [] = {
|
||||
{ Architecture::x86 , 32, UL_("x86") },
|
||||
{ Architecture::amd64 , 64, UL_("amd64") },
|
||||
{ Architecture::arm , 32, UL_("arm") },
|
||||
{ Architecture::arm64 , 64, UL_("arm64") },
|
||||
{ Architecture::mips , 32, UL_("mips") },
|
||||
{ Architecture::ppc , 32, UL_("ppc") },
|
||||
{ Architecture::shx , 32, UL_("shx") },
|
||||
{ Architecture::alpha , 32, UL_("alpha") },
|
||||
{ Architecture::alpha64, 64, UL_("alpha64") },
|
||||
{ Architecture::ia64 , 64, UL_("ia64") }
|
||||
};
|
||||
|
||||
|
||||
int Bitness(Architecture arch) noexcept
|
||||
{
|
||||
for(const auto &info : architectureInfo)
|
||||
{
|
||||
if(arch == info.Arch)
|
||||
{
|
||||
return info.Bitness;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Name(Architecture arch)
|
||||
{
|
||||
for(const auto &info : architectureInfo)
|
||||
{
|
||||
if(arch == info.Arch)
|
||||
{
|
||||
return info.Name;
|
||||
}
|
||||
}
|
||||
return mpt::ustring();
|
||||
}
|
||||
|
||||
|
||||
Architecture GetHostArchitecture() noexcept
|
||||
{
|
||||
SYSTEM_INFO systemInfo = {};
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
for(const auto &arch : architectures)
|
||||
{
|
||||
if(systemInfo.wProcessorArchitecture == arch.ProcessorArchitectur)
|
||||
{
|
||||
return arch.Host;
|
||||
}
|
||||
}
|
||||
return Architecture::unknown;
|
||||
}
|
||||
|
||||
|
||||
Architecture GetProcessArchitecture() noexcept
|
||||
{
|
||||
SYSTEM_INFO systemInfo = {};
|
||||
GetSystemInfo(&systemInfo);
|
||||
for(const auto &arch : architectures)
|
||||
{
|
||||
if(systemInfo.wProcessorArchitecture == arch.ProcessorArchitectur)
|
||||
{
|
||||
return arch.Process;
|
||||
}
|
||||
}
|
||||
return Architecture::unknown;
|
||||
}
|
||||
|
||||
|
||||
EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept
|
||||
{
|
||||
for(const auto & can : hostArchitectureCanRun)
|
||||
{
|
||||
if(can.Host == host && can.Process == process)
|
||||
{
|
||||
return can.Emulation;
|
||||
}
|
||||
}
|
||||
return EmulationLevel::NA;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host)
|
||||
{
|
||||
std::vector<Architecture> result;
|
||||
for(const auto & entry : hostArchitectureCanRun)
|
||||
{
|
||||
if(entry.Host == host)
|
||||
{
|
||||
result.push_back(entry.Process);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint64 GetSystemMemorySize()
|
||||
{
|
||||
MEMORYSTATUSEX memoryStatus = {};
|
||||
memoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
if(GlobalMemoryStatusEx(&memoryStatus) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return memoryStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
static bool GatherSystemIsWine()
|
||||
{
|
||||
bool SystemIsWine = false;
|
||||
std::optional<mpt::library> NTDLL = mpt::library::load({ mpt::library::path_search::system, mpt::library::path_prefix::none, MPT_PATH("ntdll.dll"), mpt::library::path_suffix::none });
|
||||
if(NTDLL)
|
||||
{
|
||||
SystemIsWine = (NTDLL->get_address("wine_get_version") != nullptr);
|
||||
}
|
||||
return SystemIsWine;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct SystemIsWineCache
|
||||
{
|
||||
bool SystemIsWine;
|
||||
SystemIsWineCache()
|
||||
: SystemIsWine(GatherSystemIsWine())
|
||||
{
|
||||
return;
|
||||
}
|
||||
SystemIsWineCache(bool isWine)
|
||||
: SystemIsWine(isWine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
static bool SystemIsWine(bool allowDetection = true)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
static SystemIsWineCache gs_SystemIsWineCache = allowDetection ? SystemIsWineCache() : SystemIsWineCache(false);
|
||||
if(!allowDetection)
|
||||
{ // catch too late calls of PreventWineDetection
|
||||
MPT_ASSERT(!gs_SystemIsWineCache.SystemIsWine);
|
||||
}
|
||||
return gs_SystemIsWineCache.SystemIsWine;
|
||||
#else
|
||||
MPT_UNREFERENCED_PARAMETER(allowDetection);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PreventWineDetection()
|
||||
{
|
||||
SystemIsWine(false);
|
||||
}
|
||||
|
||||
bool IsOriginal()
|
||||
{
|
||||
return mpt::OS::Windows::Version::Current().IsWindows() && !SystemIsWine();
|
||||
}
|
||||
|
||||
bool IsWine()
|
||||
{
|
||||
return mpt::OS::Windows::Version::Current().IsWindows() && SystemIsWine();
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
} // namespace Windows
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
Version::Version()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Version::Version(const mpt::ustring &rawVersion)
|
||||
: mpt::osinfo::windows::wine::version()
|
||||
{
|
||||
if(rawVersion.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::vector<uint8> version = mpt::String::Split<uint8>(rawVersion, U_("."));
|
||||
if(version.size() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mpt::ustring parsedVersion = mpt::String::Combine(version, U_("."));
|
||||
std::size_t len = std::min(parsedVersion.length(), rawVersion.length());
|
||||
if(len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(parsedVersion.substr(0, len) != rawVersion.substr(0, len))
|
||||
{
|
||||
return;
|
||||
}
|
||||
valid = true;
|
||||
vmajor = version[0];
|
||||
vminor = version[1];
|
||||
vupdate = (version.size() >= 3) ? version[2] : 0;
|
||||
}
|
||||
|
||||
|
||||
Version::Version(uint8 vmajor, uint8 vminor, uint8 vupdate)
|
||||
: mpt::osinfo::windows::wine::version(vmajor, vminor, vupdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Version::AsString() const
|
||||
{
|
||||
return mpt::ufmt::dec(GetMajor()) + U_(".") + mpt::ufmt::dec(GetMinor()) + U_(".") + mpt::ufmt::dec(GetUpdate());
|
||||
}
|
||||
|
||||
|
||||
|
||||
mpt::OS::Wine::Version GetMinimumWineVersion()
|
||||
{
|
||||
mpt::OS::Wine::Version minimumWineVersion = mpt::OS::Wine::Version(0,0,0);
|
||||
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
|
||||
minimumWineVersion = mpt::OS::Wine::Version(1,8,0);
|
||||
#endif
|
||||
return minimumWineVersion;
|
||||
}
|
||||
|
||||
|
||||
VersionContext::VersionContext()
|
||||
: m_IsWine(false)
|
||||
, m_HostClass(mpt::osinfo::osclass::Unknown)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
m_IsWine = mpt::OS::Windows::IsWine();
|
||||
if(!m_IsWine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::optional<mpt::library> NTDLL = mpt::library::load({mpt::library::path_search::system, mpt::library::path_prefix::none, MPT_PATH("ntdll.dll"), mpt::library::path_suffix::none});
|
||||
if(NTDLL)
|
||||
{
|
||||
const char * (__cdecl * wine_get_version)(void) = nullptr;
|
||||
const char * (__cdecl * wine_get_build_id)(void) = nullptr;
|
||||
void (__cdecl * wine_get_host_version)(const char * *, const char * *) = nullptr;
|
||||
NTDLL->bind(wine_get_version, "wine_get_version");
|
||||
NTDLL->bind(wine_get_build_id, "wine_get_build_id");
|
||||
NTDLL->bind(wine_get_host_version, "wine_get_host_version");
|
||||
const char * wine_version = nullptr;
|
||||
const char * wine_build_id = nullptr;
|
||||
const char * wine_host_sysname = nullptr;
|
||||
const char * wine_host_release = nullptr;
|
||||
wine_version = wine_get_version ? wine_get_version() : "";
|
||||
wine_build_id = wine_get_build_id ? wine_get_build_id() : "";
|
||||
if(wine_get_host_version)
|
||||
{
|
||||
wine_get_host_version(&wine_host_sysname, &wine_host_release);
|
||||
}
|
||||
m_RawVersion = wine_version ? wine_version : "";
|
||||
m_RawBuildID = wine_build_id ? wine_build_id : "";
|
||||
m_RawHostSysName = wine_host_sysname ? wine_host_sysname : "";
|
||||
m_RawHostRelease = wine_host_release ? wine_host_release : "";
|
||||
}
|
||||
m_Version = mpt::OS::Wine::Version(mpt::ToUnicode(mpt::Charset::UTF8, m_RawVersion));
|
||||
m_HostClass = mpt::osinfo::get_class_from_sysname(m_RawHostSysName);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
161
Src/external_dependencies/openmpt-trunk/misc/mptOS.h
Normal file
161
Src/external_dependencies/openmpt-trunk/misc/mptOS.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* mptOS.h
|
||||
* -------
|
||||
* Purpose: Operating system version information.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/library/library.hpp"
|
||||
#include "mpt/osinfo/class.hpp"
|
||||
#include "mpt/osinfo/windows_version.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
namespace Version
|
||||
{
|
||||
|
||||
inline constexpr auto WinNT4 = mpt::osinfo::windows::Version::WinNT4;
|
||||
inline constexpr auto Win2000 = mpt::osinfo::windows::Version::Win2000;
|
||||
inline constexpr auto WinXP = mpt::osinfo::windows::Version::WinXP;
|
||||
inline constexpr auto WinXP64 = mpt::osinfo::windows::Version::WinXP64;
|
||||
inline constexpr auto WinVista = mpt::osinfo::windows::Version::WinVista;
|
||||
inline constexpr auto Win7 = mpt::osinfo::windows::Version::Win7;
|
||||
inline constexpr auto Win8 = mpt::osinfo::windows::Version::Win8;
|
||||
inline constexpr auto Win81 = mpt::osinfo::windows::Version::Win81;
|
||||
inline constexpr auto Win10 = mpt::osinfo::windows::Version::Win10;
|
||||
inline constexpr auto WinNewer = mpt::osinfo::windows::Version::WinNewer;
|
||||
|
||||
mpt::osinfo::windows::Version Current() noexcept;
|
||||
|
||||
mpt::ustring GetName(mpt::osinfo::windows::Version version);
|
||||
mpt::ustring GetNameShort(mpt::osinfo::windows::Version version);
|
||||
|
||||
mpt::osinfo::windows::Version GetMinimumKernelLevel() noexcept;
|
||||
mpt::osinfo::windows::Version GetMinimumAPILevel() noexcept;
|
||||
|
||||
} // namespace Version
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
enum class Architecture
|
||||
{
|
||||
unknown = -1,
|
||||
|
||||
x86 = 0x0401,
|
||||
amd64 = 0x0801,
|
||||
arm = 0x0402,
|
||||
arm64 = 0x0802,
|
||||
|
||||
mips = 0x0403,
|
||||
ppc = 0x0404,
|
||||
shx = 0x0405,
|
||||
|
||||
alpha = 0x0406,
|
||||
alpha64 = 0x0806,
|
||||
|
||||
ia64 = 0x0807,
|
||||
};
|
||||
|
||||
enum class EmulationLevel
|
||||
{
|
||||
Native,
|
||||
Virtual,
|
||||
Hardware,
|
||||
Software,
|
||||
NA,
|
||||
};
|
||||
|
||||
int Bitness(Architecture arch) noexcept;
|
||||
|
||||
mpt::ustring Name(Architecture arch);
|
||||
|
||||
Architecture GetHostArchitecture() noexcept;
|
||||
Architecture GetProcessArchitecture() noexcept;
|
||||
|
||||
EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept;
|
||||
|
||||
std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host);
|
||||
|
||||
uint64 GetSystemMemorySize();
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
void PreventWineDetection();
|
||||
|
||||
bool IsOriginal();
|
||||
bool IsWine();
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
} // namespace Windows
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
class Version
|
||||
: public mpt::osinfo::windows::wine::version
|
||||
{
|
||||
public:
|
||||
Version();
|
||||
Version(uint8 vmajor, uint8 vminor, uint8 vupdate);
|
||||
explicit Version(const mpt::ustring &version);
|
||||
public:
|
||||
mpt::ustring AsString() const;
|
||||
};
|
||||
|
||||
mpt::OS::Wine::Version GetMinimumWineVersion();
|
||||
|
||||
class VersionContext
|
||||
{
|
||||
protected:
|
||||
bool m_IsWine;
|
||||
std::string m_RawVersion;
|
||||
std::string m_RawBuildID;
|
||||
std::string m_RawHostSysName;
|
||||
std::string m_RawHostRelease;
|
||||
mpt::OS::Wine::Version m_Version;
|
||||
mpt::osinfo::osclass m_HostClass;
|
||||
public:
|
||||
VersionContext();
|
||||
public:
|
||||
bool IsWine() const { return m_IsWine; }
|
||||
std::string RawVersion() const { return m_RawVersion; }
|
||||
std::string RawBuildID() const { return m_RawBuildID; }
|
||||
std::string RawHostSysName() const { return m_RawHostSysName; }
|
||||
std::string RawHostRelease() const { return m_RawHostRelease; }
|
||||
mpt::OS::Wine::Version Version() const { return m_Version; }
|
||||
mpt::osinfo::osclass HostClass() const { return m_HostClass; }
|
||||
};
|
||||
|
||||
} // namespace Wine
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
180
Src/external_dependencies/openmpt-trunk/misc/mptOSException.h
Normal file
180
Src/external_dependencies/openmpt-trunk/misc/mptOSException.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* mptOSException.h
|
||||
* ----------------
|
||||
* Purpose: platform-specific exception/signal handling
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
namespace SEH
|
||||
{
|
||||
|
||||
|
||||
struct Code
|
||||
{
|
||||
private:
|
||||
DWORD m_Code;
|
||||
public:
|
||||
constexpr Code(DWORD code) noexcept
|
||||
: m_Code(code)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
constexpr DWORD code() const noexcept
|
||||
{
|
||||
return m_Code;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
auto TryFilterHandleThrow(const Tfn &fn, const Tfilter &filter, const Thandler &handler) -> decltype(fn())
|
||||
{
|
||||
static_assert(std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
DWORD code = 0;
|
||||
__try
|
||||
{
|
||||
return fn();
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
code = GetExceptionCode();
|
||||
}
|
||||
throw Windows::SEH::Code(code);
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
void TryFilterHandleVoid(const Tfn &fn, const Tfilter &filter, const Thandler &handler)
|
||||
{
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
__try
|
||||
{
|
||||
fn();
|
||||
return;
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
DWORD code = GetExceptionCode();
|
||||
handler(code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
auto TryFilterHandleDefault(const Tfn &fn, const Tfilter &filter, const Thandler &handler, decltype(fn()) def = decltype(fn()){}) -> decltype(fn())
|
||||
{
|
||||
static_assert(std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
auto result = def;
|
||||
__try
|
||||
{
|
||||
result = fn();
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
DWORD code = GetExceptionCode();
|
||||
result = handler(code);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
auto TryReturnOrThrow(const Tfn &fn) -> decltype(fn())
|
||||
{
|
||||
return TryFilterHandleThrow(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[](auto code)
|
||||
{
|
||||
throw Windows::SEH::Code(code);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
DWORD TryOrError(const Tfn &fn)
|
||||
{
|
||||
DWORD result = DWORD{0};
|
||||
TryFilterHandleVoid(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[&result](auto code)
|
||||
{
|
||||
result = code;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
auto TryReturnOrDefault(const Tfn &fn, decltype(fn()) def = decltype(fn()){}) -> decltype(fn())
|
||||
{
|
||||
return TryFilterHandleDefault(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[def](auto code)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
return def;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} // namspace SEH
|
||||
|
||||
|
||||
} // namespace Windows
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
750
Src/external_dependencies/openmpt-trunk/misc/mptWine.cpp
Normal file
750
Src/external_dependencies/openmpt-trunk/misc/mptWine.cpp
Normal file
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
* mptWine.cpp
|
||||
* -----------
|
||||
* Purpose: Wine stuff.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptWine.h"
|
||||
|
||||
#include "mptOS.h"
|
||||
#include "../common/mptFileIO.h"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
|
||||
Context::Context(mpt::OS::Wine::VersionContext versionContext)
|
||||
: m_VersionContext(versionContext)
|
||||
, wine_get_dos_file_name(nullptr)
|
||||
, wine_get_unix_file_name(nullptr)
|
||||
{
|
||||
if(!mpt::OS::Windows::IsWine())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine not detected.");
|
||||
}
|
||||
if(!m_VersionContext.Version().IsValid())
|
||||
{
|
||||
throw mpt::Wine::Exception("Unknown Wine version detected.");
|
||||
}
|
||||
m_Kernel32 = std::make_shared<std::optional<mpt::library>>(mpt::library::load({ mpt::library::path_search::system, mpt::library::path_prefix::none, MPT_PATH("kernel32.dll"), mpt::library::path_suffix::none }));
|
||||
if(!m_Kernel32->has_value())
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not load Wine kernel32.dll.");
|
||||
}
|
||||
if(!(*m_Kernel32)->bind(wine_get_unix_file_name, "wine_get_unix_file_name"))
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_unix_file_name.");
|
||||
}
|
||||
if(!(*m_Kernel32)->bind(wine_get_dos_file_name, "wine_get_dos_file_name"))
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_dos_file_name.");
|
||||
}
|
||||
{
|
||||
std::string out;
|
||||
std::string err;
|
||||
try
|
||||
{
|
||||
if(ExecutePosixShellCommand("uname -m", out, err) != 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine 'uname -m' failed.");
|
||||
}
|
||||
if(!err.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine 'uname -m' failed.");
|
||||
}
|
||||
out = mpt::trim(out, std::string("\r\n"));
|
||||
m_Uname_m = out;
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_Uname_m = std::string();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
m_HOME = GetPosixEnvVar("HOME");
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_DATA_HOME = GetPosixEnvVar("XDG_DATA_HOME");
|
||||
if(m_XDG_DATA_HOME.empty())
|
||||
{
|
||||
m_XDG_DATA_HOME = m_HOME + "/.local/share";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_DATA_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_CACHE_HOME = GetPosixEnvVar("XDG_CACHE_HOME");
|
||||
if(m_XDG_CACHE_HOME.empty())
|
||||
{
|
||||
m_XDG_CACHE_HOME = m_HOME + "/.cache";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_CACHE_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_CONFIG_HOME = GetPosixEnvVar("XDG_CONFIG_HOME");
|
||||
if(m_XDG_CONFIG_HOME.empty())
|
||||
{
|
||||
m_XDG_CONFIG_HOME = m_HOME + "/.config";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_CONFIG_HOME = std::string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Context::PathToPosix(mpt::PathString windowsPath)
|
||||
{
|
||||
std::string result;
|
||||
if(windowsPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(windowsPath.Length() >= 32000)
|
||||
{
|
||||
throw mpt::Wine::Exception("Path too long.");
|
||||
}
|
||||
LPSTR tmp = nullptr;
|
||||
tmp = wine_get_unix_file_name(windowsPath.ToWide().c_str());
|
||||
if(!tmp)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_unix_file_name failed.");
|
||||
}
|
||||
result = tmp;
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
tmp = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::PathString Context::PathToWindows(std::string hostPath)
|
||||
{
|
||||
mpt::PathString result;
|
||||
if(hostPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(hostPath.length() >= 32000)
|
||||
{
|
||||
throw mpt::Wine::Exception("Path too long.");
|
||||
}
|
||||
LPWSTR tmp = nullptr;
|
||||
tmp = wine_get_dos_file_name(hostPath.c_str());
|
||||
if(!tmp)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_dos_file_name failed.");
|
||||
}
|
||||
result = mpt::PathString::FromWide(tmp);
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
tmp = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Context::PathToPosixCanonical(mpt::PathString windowsPath)
|
||||
{
|
||||
std::string result;
|
||||
std::string hostPath = PathToPosix(windowsPath);
|
||||
if(hostPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
std::string output;
|
||||
std::string error;
|
||||
int exitcode = ExecutePosixShellCommand(std::string() + "readlink -f " + EscapePosixShell(hostPath), output, error);
|
||||
if(!error.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine readlink failed: " + error);
|
||||
}
|
||||
if(exitcode != 0 && exitcode != 1)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine readlink failed.");
|
||||
}
|
||||
std::string trimmedOutput = mpt::trim(output, std::string("\r\n"));
|
||||
result = trimmedOutput;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void ExecutePosixCommandProgressDefault(void * /*userdata*/ )
|
||||
{
|
||||
::Sleep(10);
|
||||
return;
|
||||
}
|
||||
|
||||
static ExecuteProgressResult ExecutePosixShellScriptProgressDefault(void * /*userdata*/ )
|
||||
{
|
||||
::Sleep(10);
|
||||
return ExecuteProgressContinueWaiting;
|
||||
}
|
||||
|
||||
|
||||
std::string Context::EscapePosixShell(std::string line)
|
||||
{
|
||||
const char escape_chars [] = { '|', '&', ';', '<', '>', '(', ')', '$', '`', '"', '\'', ' ', '\t' };
|
||||
const char maybe_escape_chars [] = { '*', '?', '[', '#', '~', '=', '%' };
|
||||
line = mpt::replace(line, std::string("\\"), std::string("\\\\"));
|
||||
for(char c : escape_chars)
|
||||
{
|
||||
line = mpt::replace(line, std::string(1, c), std::string("\\") + std::string(1, c));
|
||||
}
|
||||
for(char c : maybe_escape_chars)
|
||||
{
|
||||
line = mpt::replace(line, std::string(1, c), std::string("\\") + std::string(1, c));
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata)
|
||||
{
|
||||
// Relevant documentation:
|
||||
// https://stackoverflow.com/questions/6004070/execute-shell-commands-from-program-running-in-wine
|
||||
// https://www.winehq.org/pipermail/wine-bugs/2014-January/374918.html
|
||||
// https://bugs.winehq.org/show_bug.cgi?id=34730
|
||||
|
||||
if(!progress) progress = &ExecutePosixCommandProgressDefault;
|
||||
if(!progressCancel) progressCancel = &ExecutePosixShellScriptProgressDefault;
|
||||
|
||||
if(flags[ExecFlagInteractive]) flags.reset(ExecFlagSilent);
|
||||
if(flags[ExecFlagSplitOutput]) flags.set(ExecFlagSilent);
|
||||
|
||||
std::vector<mpt::PathString> tempfiles;
|
||||
|
||||
progress(userdata);
|
||||
|
||||
mpt::TempDirGuard dirWindowsTemp(mpt::CreateTempFileName());
|
||||
if(dirWindowsTemp.GetDirname().empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Creating temporary directoy failed.");
|
||||
}
|
||||
const std::string dirPosix = PathToPosix(dirWindowsTemp.GetDirname());
|
||||
if(dirPosix.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("mpt::Wine::ConvertWindowsPathToHost returned empty path.");
|
||||
}
|
||||
const std::string dirPosixEscape = EscapePosixShell(dirPosix);
|
||||
const mpt::PathString dirWindows = dirWindowsTemp.GetDirname();
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// write the script to disk
|
||||
mpt::PathString scriptFilenameWindows = dirWindows + P_("script.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(scriptFilenameWindows, std::ios::binary);
|
||||
tempfile << script;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing script.sh.");
|
||||
}
|
||||
}
|
||||
const std::string scriptFilenamePosix = PathToPosix(scriptFilenameWindows);
|
||||
if(scriptFilenamePosix.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Error converting script.sh path.");
|
||||
}
|
||||
const std::string scriptFilenamePosixEscape = EscapePosixShell(scriptFilenamePosix);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// create a wrapper that will call the script and gather result.
|
||||
mpt::PathString wrapperstarterFilenameWindows = dirWindows + P_("wrapperstarter.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperstarterFilenameWindows, std::ios::binary);
|
||||
std::string wrapperstarterscript;
|
||||
wrapperstarterscript += std::string() + "#!/usr/bin/env sh" "\n";
|
||||
wrapperstarterscript += std::string() + "exec /usr/bin/env sh " + dirPosixEscape + "wrapper.sh" "\n";
|
||||
tempfile << wrapperstarterscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing wrapper.sh.");
|
||||
}
|
||||
}
|
||||
mpt::PathString wrapperFilenameWindows = dirWindows + P_("wrapper.sh");
|
||||
std::string cleanupscript;
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperFilenameWindows, std::ios::binary);
|
||||
std::string wrapperscript;
|
||||
if(!flags[ExecFlagSilent])
|
||||
{
|
||||
wrapperscript += "printf \"\\033]0;" + title + "\\a\"" "\n";
|
||||
}
|
||||
wrapperscript += "chmod u+x " + scriptFilenamePosixEscape + "\n";
|
||||
wrapperscript += "cd " + dirPosixEscape + "filetree" "\n";
|
||||
if(flags[ExecFlagInteractive])
|
||||
{ // no stdout/stderr capturing for interactive scripts
|
||||
wrapperscript += scriptFilenamePosixEscape + "\n";
|
||||
wrapperscript += "MPT_RESULT=$?" "\n";
|
||||
wrapperscript += "echo ${MPT_RESULT} > " + dirPosixEscape + "exit" "\n";
|
||||
} else if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
wrapperscript += "(" + scriptFilenamePosixEscape + "; echo $? >&4) 4>" + dirPosixEscape + "exit 1>" + dirPosixEscape + "out 2>" + dirPosixEscape + "err" "\n";
|
||||
} else
|
||||
{
|
||||
wrapperscript += "(" + scriptFilenamePosixEscape + "; echo $? >&4) 2>&1 4>" + dirPosixEscape + "exit | tee " + dirPosixEscape + "out" "\n";
|
||||
}
|
||||
wrapperscript += "echo done > " + dirPosixEscape + "done" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "done" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "exit" "\n";
|
||||
if(flags[ExecFlagInteractive])
|
||||
{
|
||||
// nothing
|
||||
} else if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
cleanupscript += "rm " + dirPosixEscape + "out" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "err" "\n";
|
||||
} else
|
||||
{
|
||||
cleanupscript += "rm " + dirPosixEscape + "out" "\n";
|
||||
}
|
||||
cleanupscript += "rm -r " + dirPosixEscape + "filetree" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "script.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "wrapper.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "wrapperstarter.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "terminal.sh" "\n";
|
||||
if(flags[ExecFlagAsync])
|
||||
{
|
||||
wrapperscript += cleanupscript;
|
||||
cleanupscript.clear();
|
||||
}
|
||||
tempfile << wrapperscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing wrapper.sh.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
::CreateDirectory((dirWindows + P_("filetree")).AsNative().c_str(), nullptr);
|
||||
for(const auto &file : filetree)
|
||||
{
|
||||
std::vector<mpt::ustring> path = mpt::String::Split<mpt::ustring>(mpt::ToUnicode(mpt::Charset::UTF8, file.first), U_("/"));
|
||||
mpt::PathString combinedPath = dirWindows + P_("filetree") + P_("\\");
|
||||
if(path.size() > 1)
|
||||
{
|
||||
for(std::size_t singlepath = 0; singlepath < path.size() - 1; ++singlepath)
|
||||
{
|
||||
if(path[singlepath].empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
combinedPath += mpt::PathString::FromUnicode(path[singlepath]);
|
||||
if(!combinedPath.IsDirectory())
|
||||
{
|
||||
if(::CreateDirectory(combinedPath.AsNative().c_str(), nullptr) == 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing filetree.");
|
||||
}
|
||||
}
|
||||
combinedPath += P_("\\");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
mpt::LazyFileRef out(dirWindows + P_("filetree") + P_("\\") + mpt::PathString::FromUTF8(mpt::replace(file.first, std::string("/"), std::string("\\"))));
|
||||
out = file.second;
|
||||
} catch(std::exception &)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing filetree.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// create a wrapper that will find a suitable terminal and run the wrapper script in the terminal window.
|
||||
mpt::PathString terminalWrapperFilenameWindows = dirWindows + P_("terminal.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(terminalWrapperFilenameWindows, std::ios::binary);
|
||||
// NOTE:
|
||||
// Modern terminals detach themselves from the invoking shell if another instance is already present.
|
||||
// This means we cannot rely on terminal invocation being syncronous.
|
||||
static constexpr const char * terminals[] =
|
||||
{
|
||||
"x-terminal-emulator",
|
||||
"konsole",
|
||||
"mate-terminal",
|
||||
"xfce4-terminal",
|
||||
"gnome-terminal",
|
||||
"uxterm",
|
||||
"xterm",
|
||||
"rxvt",
|
||||
};
|
||||
std::string terminalscript = "\n";
|
||||
for(const std::string terminal : terminals)
|
||||
{
|
||||
// mate-terminal on Debian 8 cannot execute commands with arguments,
|
||||
// thus we use a separate script that requires no arguments to execute.
|
||||
terminalscript += "if command -v " + terminal + " 2>/dev/null 1>/dev/null ; then" "\n";
|
||||
terminalscript += " chmod u+x " + dirPosixEscape + "wrapperstarter.sh" "\n";
|
||||
terminalscript += " exec `command -v " + terminal + "` -e \"" + dirPosixEscape + "wrapperstarter.sh\"" "\n";
|
||||
terminalscript += "fi" "\n";
|
||||
}
|
||||
|
||||
tempfile << terminalscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
return ExecResult::Error();
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// build unix command line
|
||||
std::string unixcommand;
|
||||
bool createProcessSuccess = false;
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
unixcommand = "/usr/bin/env sh \"" + dirPosixEscape + "wrapper.sh\"";
|
||||
} else
|
||||
{
|
||||
unixcommand = "/usr/bin/env sh \"" + dirPosixEscape + "terminal.sh\"";
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::wstring unixcommandW = mpt::ToWide(mpt::Charset::UTF8, unixcommand);
|
||||
std::wstring titleW = mpt::ToWide(mpt::Charset::UTF8, title);
|
||||
STARTUPINFOW startupInfo = {};
|
||||
startupInfo.lpTitle = titleW.data();
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
PROCESS_INFORMATION processInformation = {};
|
||||
|
||||
progress(userdata);
|
||||
|
||||
BOOL success = FALSE;
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
|
||||
} else
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
createProcessSuccess = (success != FALSE);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(success)
|
||||
{
|
||||
|
||||
if(!flags[ExecFlagAsync])
|
||||
{
|
||||
// note: execution is not syncronous with all Wine versions,
|
||||
// we additionally explicitly wait for "done" later
|
||||
while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// Work around Wine being unable to execute PIE binaries on Debian 9.
|
||||
// Luckily, /bin/bash is still non-PIE on Debian 9.
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
unixcommand = "/bin/bash \"" + dirPosixEscape + "wrapper.sh\"";
|
||||
} else
|
||||
{
|
||||
unixcommand = "/bin/bash \"" + dirPosixEscape + "terminal.sh\"";
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::wstring unixcommandW = mpt::ToWide(mpt::Charset::UTF8, unixcommand);
|
||||
std::wstring titleW = mpt::ToWide(mpt::Charset::UTF8, title);
|
||||
STARTUPINFOW startupInfo = {};
|
||||
startupInfo.lpTitle = titleW.data();
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
PROCESS_INFORMATION processInformation = {};
|
||||
|
||||
progress(userdata);
|
||||
|
||||
BOOL success = FALSE;
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
|
||||
} else
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
createProcessSuccess = (success != FALSE);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(success)
|
||||
{
|
||||
if(!flags[ExecFlagAsync])
|
||||
{
|
||||
// note: execution is not syncronous with all Wine versions,
|
||||
// we additionally explicitly wait for "done" later
|
||||
while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
throw mpt::Wine::Exception("CreateProcess failed.");
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(flags[ExecFlagAsync])
|
||||
{
|
||||
ExecResult result;
|
||||
result.exitcode = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
while(!(dirWindows + P_("done")).IsFile())
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
int exitCode = 0;
|
||||
{
|
||||
mpt::ifstream exitFile(dirWindows + P_("exit"), std::ios::binary);
|
||||
if(!exitFile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Script .exit file not found.");
|
||||
}
|
||||
std::string exitString;
|
||||
exitFile >> exitString;
|
||||
if(exitString.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Script .exit file empty.");
|
||||
}
|
||||
exitCode = ConvertStrTo<int>(exitString);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::string outputString;
|
||||
if(!flags[ExecFlagInteractive])
|
||||
{
|
||||
mpt::ifstream outputFile(dirWindows + P_("out"), std::ios::binary);
|
||||
if(outputFile)
|
||||
{
|
||||
outputFile.seekg(0, std::ios::end);
|
||||
std::streampos outputFileSize = outputFile.tellg();
|
||||
outputFile.seekg(0, std::ios::beg);
|
||||
std::vector<char> outputFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(outputFileSize)));
|
||||
outputFile.read(&outputFileBuf[0], outputFileBuf.size());
|
||||
outputString = mpt::buffer_cast<std::string>(outputFileBuf);
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::string errorString;
|
||||
if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
mpt::ifstream errorFile(dirWindows + P_("err"), std::ios::binary);
|
||||
if(errorFile)
|
||||
{
|
||||
errorFile.seekg(0, std::ios::end);
|
||||
std::streampos errorFileSize = errorFile.tellg();
|
||||
errorFile.seekg(0, std::ios::beg);
|
||||
std::vector<char> errorFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(errorFileSize)));
|
||||
errorFile.read(&errorFileBuf[0], errorFileBuf.size());
|
||||
errorString = mpt::buffer_cast<std::string>(errorFileBuf);
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
ExecResult result;
|
||||
result.exitcode = exitCode;
|
||||
result.output = outputString;
|
||||
result.error = errorString;
|
||||
|
||||
std::deque<mpt::PathString> paths;
|
||||
paths.push_back(dirWindows + P_("filetree"));
|
||||
mpt::PathString basePath = (dirWindows + P_("filetree")).EnsureTrailingSlash();
|
||||
while(!paths.empty())
|
||||
{
|
||||
mpt::PathString path = paths.front();
|
||||
paths.pop_front();
|
||||
path.EnsureTrailingSlash();
|
||||
HANDLE hFind = NULL;
|
||||
WIN32_FIND_DATA wfd = {};
|
||||
hFind = FindFirstFile((path + P_("*.*")).AsNative().c_str(), &wfd);
|
||||
if(hFind != NULL && hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName);
|
||||
if(filename != P_(".") && filename != P_(".."))
|
||||
{
|
||||
filename = path + filename;
|
||||
filetree[filename.ToUTF8()] = std::vector<char>();
|
||||
if(filename.IsDirectory())
|
||||
{
|
||||
paths.push_back(filename);
|
||||
} else if(filename.IsFile())
|
||||
{
|
||||
try
|
||||
{
|
||||
mpt::LazyFileRef f(filename);
|
||||
std::vector<char> buf = f;
|
||||
mpt::PathString treeFilename = mpt::PathString::FromNative(filename.AsNative().substr(basePath.AsNative().length()));
|
||||
result.filetree[treeFilename.ToUTF8()] = buf;
|
||||
} catch (std::exception &)
|
||||
{
|
||||
// nothing?!
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(FindNextFile(hFind, &wfd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
|
||||
mpt::DeleteWholeDirectoryTree(dirWindows);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Context::ExecutePosixShellCommand(std::string command, std::string & output, std::string & error)
|
||||
{
|
||||
std::string script;
|
||||
script += "#!/usr/bin/env sh" "\n";
|
||||
script += "exec " + command + "\n";
|
||||
mpt::Wine::ExecResult execResult = ExecutePosixShellScript
|
||||
( script
|
||||
, mpt::Wine::ExecFlagSilent | mpt::Wine::ExecFlagSplitOutput, std::map<std::string, std::vector<char> >()
|
||||
, std::string()
|
||||
, nullptr
|
||||
, nullptr
|
||||
, nullptr
|
||||
);
|
||||
output = execResult.output;
|
||||
error = execResult.error;
|
||||
return execResult.exitcode;
|
||||
}
|
||||
|
||||
|
||||
std::string Context::GetPosixEnvVar(std::string var, std::string def)
|
||||
{
|
||||
// We cannot use std::getenv here because Wine overrides SOME env vars,
|
||||
// in particular, HOME is unset in the Wine environment.
|
||||
// Instead, we just spawn a shell that will catch up a sane environment on
|
||||
// its own.
|
||||
std::string output;
|
||||
std::string error;
|
||||
int exitcode = ExecutePosixShellCommand(std::string() + "echo $" + var, output, error);
|
||||
if(!error.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine echo $var failed: " + error);
|
||||
}
|
||||
if(exitcode != 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine echo $var failed.");
|
||||
}
|
||||
std::string result = mpt::trim_right(output, std::string("\r\n"));
|
||||
if(result.empty())
|
||||
{
|
||||
result = def;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#else // !MPT_OS_WINDOWS
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptWine)
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
131
Src/external_dependencies/openmpt-trunk/misc/mptWine.h
Normal file
131
Src/external_dependencies/openmpt-trunk/misc/mptWine.h
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* mptWine.h
|
||||
* ---------
|
||||
* Purpose: Wine stuff.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mptOS.h"
|
||||
#include "mpt/library/library.hpp"
|
||||
#include "openmpt/base/FlagSet.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
class Exception
|
||||
: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &text)
|
||||
: std::runtime_error(text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef void (*ExecutePosixCommandProgress)(void *userdata);
|
||||
|
||||
enum ExecuteProgressResult
|
||||
{
|
||||
ExecuteProgressContinueWaiting = 0,
|
||||
ExecuteProgressAsyncCancel = -1,
|
||||
};
|
||||
|
||||
typedef ExecuteProgressResult (*ExecutePosixShellScriptProgress)(void *userdata);
|
||||
|
||||
|
||||
enum ExecFlags
|
||||
{
|
||||
ExecFlagNone = 0,
|
||||
ExecFlagSilent = 1<<0, // do not show a terminal window
|
||||
ExecFlagInteractive = 1<<1, // allow interaction (prevents stdout and stderr capturing and implies !silent)
|
||||
ExecFlagAsync = 1<<2, // do not wait for the script to finish
|
||||
ExecFlagProgressWindow = 1<<3, // not implemented by mptOS
|
||||
ExecFlagSplitOutput = 1<<4, // split stdout and stderr (implies silent)
|
||||
ExecFlagsDefault = ExecFlagNone
|
||||
};
|
||||
MPT_DECLARE_ENUM(ExecFlags)
|
||||
|
||||
struct ExecResult
|
||||
{
|
||||
int exitcode;
|
||||
std::string output;
|
||||
std::string error;
|
||||
std::map<std::string, std::vector<char> > filetree;
|
||||
static ExecResult Error()
|
||||
{
|
||||
ExecResult result;
|
||||
result.exitcode = -1;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Context
|
||||
{
|
||||
protected:
|
||||
mpt::OS::Wine::VersionContext m_VersionContext;
|
||||
std::shared_ptr<std::optional<mpt::library>> m_Kernel32;
|
||||
private:
|
||||
LPWSTR (*CDECL wine_get_dos_file_name)(LPCSTR str);
|
||||
LPSTR (*CDECL wine_get_unix_file_name)(LPCWSTR str);
|
||||
protected:
|
||||
std::string m_Uname_m;
|
||||
std::string m_HOME;
|
||||
std::string m_XDG_DATA_HOME;
|
||||
std::string m_XDG_CACHE_HOME;
|
||||
std::string m_XDG_CONFIG_HOME;
|
||||
public:
|
||||
Context(mpt::OS::Wine::VersionContext versionContext);
|
||||
public:
|
||||
std::string EscapePosixShell(std::string line);
|
||||
std::string PathToPosix(mpt::PathString windowsPath);
|
||||
mpt::PathString PathToWindows(std::string hostPath);
|
||||
ExecResult ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata);
|
||||
int ExecutePosixShellCommand(std::string command, std::string & output, std::string & error);
|
||||
std::string PathToPosixCanonical(mpt::PathString windowsPath);
|
||||
std::string GetPosixEnvVar(std::string var, std::string def = std::string());
|
||||
public:
|
||||
mpt::OS::Wine::VersionContext VersionContext() const { return m_VersionContext; }
|
||||
std::shared_ptr<std::optional<mpt::library>> Kernel32() const { return m_Kernel32; }
|
||||
std::string Uname_m() const { return m_Uname_m; }
|
||||
std::string HOME() const { return m_HOME; }
|
||||
std::string XDG_DATA_HOME() const { return m_XDG_DATA_HOME; }
|
||||
std::string XDG_CACHE_HOME() const { return m_XDG_CACHE_HOME; }
|
||||
std::string XDG_CONFIG_HOME() const { return m_XDG_CONFIG_HOME; }
|
||||
};
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
Loading…
Add table
Add a link
Reference in a new issue