set svn:eol-style=native for **.cpp

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1442 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
bushing
2008-12-08 05:30:24 +00:00
parent 901fe7c00f
commit 49cfded60b
177 changed files with 53968 additions and 53968 deletions

View File

@ -1,279 +1,279 @@
#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
using namespace Gen;
// Shared code between Win64 and Unix64
// ====================================
// Sets up a __cdecl function.
void ABI_EmitPrologue(int maxCallParams)
{
#ifdef _M_IX86
// Don't really need to do anything
#elif defined(_M_X64)
#if _WIN32
int stacksize = ((maxCallParams + 1) & ~1)*8 + 8;
// Set up a stack frame so that we can call functions
// TODO: use maxCallParams
SUB(64, R(RSP), Imm8(stacksize));
#endif
#else
#error Arch not supported
#endif
}
void ABI_EmitEpilogue(int maxCallParams)
{
#ifdef _M_IX86
RET();
#elif defined(_M_X64)
#ifdef _WIN32
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
ADD(64, R(RSP), Imm8(stacksize));
#endif
RET();
#else
#error Arch not supported
#endif
}
#ifdef _M_IX86 // All32
// Shared code between Win32 and Unix32
// ====================================
void ABI_CallFunctionC(void *func, u32 param1) {
ABI_AlignStack(1 * 4);
PUSH(32, Imm32(param1));
CALL(func);
ABI_RestoreStack(1 * 4);
}
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
ABI_AlignStack(2 * 4);
PUSH(32, Imm32(param2));
PUSH(32, Imm32(param1));
CALL(func);
ABI_RestoreStack(2 * 4);
}
// Pass a register as a paremeter.
void ABI_CallFunctionR(void *func, X64Reg reg1) {
ABI_AlignStack(1 * 4);
PUSH(32, R(reg1));
CALL(func);
ABI_RestoreStack(1 * 4);
}
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
{
ABI_AlignStack(2 * 4);
PUSH(32, R(reg2));
PUSH(32, R(reg1));
CALL(func);
ABI_RestoreStack(2 * 4);
}
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
{
ABI_AlignStack(2 * 4);
PUSH(32, arg1);
PUSH(32, Imm32(param2));
CALL(func);
ABI_RestoreStack(2 * 4);
}
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
PUSH(EBP);
PUSH(EBX);
PUSH(ESI);
PUSH(EDI);
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(EDI);
POP(ESI);
POP(EBX);
POP(EBP);
}
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
frameSize += 4; // reserve space for return address
unsigned int alignedSize =
#ifdef __GNUC__
(frameSize + 15) & -16;
#else
frameSize;
#endif
return alignedSize;
}
void ABI_AlignStack(unsigned int frameSize) {
// Mac OS X requires the stack to be 16-byte aligned before every call.
// Linux requires the stack to be 16-byte aligned before calls that put SSE
// vectors on the stack, but since we do not keep track of which calls do that,
// it is effectively every call as well.
// Windows binaries compiled with MSVC do not have such a restriction, but I
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
// It would be nice if someone could verify this.
#ifdef __GNUC__
unsigned int fillSize =
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
if (fillSize != 0) {
SUB(32, R(ESP), Imm8(fillSize));
}
#endif
}
void ABI_RestoreStack(unsigned int frameSize) {
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
alignedSize -= 4; // return address is POPped at end of call
if (alignedSize != 0) {
ADD(32, R(ESP), Imm8(alignedSize));
}
}
#else
void ABI_CallFunctionC(void *func, u32 param1) {
MOV(32, R(ABI_PARAM1), Imm32(param1));
CALL(func);
}
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
CALL(func);
}
// Pass a register as a paremeter.
void ABI_CallFunctionR(void *func, X64Reg reg1) {
if (reg1 != ABI_PARAM1)
MOV(32, R(ABI_PARAM1), R(reg1));
CALL(func);
}
// Pass a register as a paremeter.
void ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
if (reg1 != ABI_PARAM1)
MOV(32, R(ABI_PARAM1), R(reg1));
if (reg2 != ABI_PARAM2)
MOV(32, R(ABI_PARAM2), R(reg2));
CALL(func);
}
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
{
if (!arg1.IsSimpleReg(ABI_PARAM1))
MOV(32, R(ABI_PARAM1), arg1);
MOV(32, R(ABI_PARAM2), Imm32(param2));
CALL(func);
}
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
return frameSize;
}
void ABI_AlignStack(unsigned int /*frameSize*/) {
}
void ABI_RestoreStack(unsigned int /*frameSize*/) {
}
#ifdef _WIN32
// Win64 Specific Code
// ====================================
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
//we only want to do this once
PUSH(RBX);
PUSH(RSI);
PUSH(RDI);
PUSH(RBP);
PUSH(R12);
PUSH(R13);
PUSH(R14);
PUSH(R15);
//TODO: Also preserve XMM0-3?
SUB(64, R(RSP), Imm8(0x28));
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
ADD(64, R(RSP), Imm8(0x28));
POP(R15);
POP(R14);
POP(R13);
POP(R12);
POP(RBP);
POP(RDI);
POP(RSI);
POP(RBX);
}
// Win64 Specific Code
// ====================================
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
PUSH(RCX);
PUSH(RDX);
PUSH(RSI);
PUSH(RDI);
PUSH(R8);
PUSH(R9);
PUSH(R10);
PUSH(R11);
//TODO: Also preserve XMM0-15?
SUB(64, R(RSP), Imm8(0x28));
}
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
ADD(64, R(RSP), Imm8(0x28));
POP(R11);
POP(R10);
POP(R9);
POP(R8);
POP(RDI);
POP(RSI);
POP(RDX);
POP(RCX);
}
#else
// Unix64 Specific Code
// ====================================
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
PUSH(RBX);
PUSH(RBP);
PUSH(R12);
PUSH(R13);
PUSH(R14);
PUSH(R15);
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(R15);
POP(R15);
POP(R14);
POP(R13);
POP(R12);
POP(RBP);
POP(RBX);
}
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
INT3();
//not yet supported
}
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
INT3();
//not yet supported
}
#endif
#endif
#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
using namespace Gen;
// Shared code between Win64 and Unix64
// ====================================
// Sets up a __cdecl function.
void ABI_EmitPrologue(int maxCallParams)
{
#ifdef _M_IX86
// Don't really need to do anything
#elif defined(_M_X64)
#if _WIN32
int stacksize = ((maxCallParams + 1) & ~1)*8 + 8;
// Set up a stack frame so that we can call functions
// TODO: use maxCallParams
SUB(64, R(RSP), Imm8(stacksize));
#endif
#else
#error Arch not supported
#endif
}
void ABI_EmitEpilogue(int maxCallParams)
{
#ifdef _M_IX86
RET();
#elif defined(_M_X64)
#ifdef _WIN32
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
ADD(64, R(RSP), Imm8(stacksize));
#endif
RET();
#else
#error Arch not supported
#endif
}
#ifdef _M_IX86 // All32
// Shared code between Win32 and Unix32
// ====================================
void ABI_CallFunctionC(void *func, u32 param1) {
ABI_AlignStack(1 * 4);
PUSH(32, Imm32(param1));
CALL(func);
ABI_RestoreStack(1 * 4);
}
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
ABI_AlignStack(2 * 4);
PUSH(32, Imm32(param2));
PUSH(32, Imm32(param1));
CALL(func);
ABI_RestoreStack(2 * 4);
}
// Pass a register as a paremeter.
void ABI_CallFunctionR(void *func, X64Reg reg1) {
ABI_AlignStack(1 * 4);
PUSH(32, R(reg1));
CALL(func);
ABI_RestoreStack(1 * 4);
}
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
{
ABI_AlignStack(2 * 4);
PUSH(32, R(reg2));
PUSH(32, R(reg1));
CALL(func);
ABI_RestoreStack(2 * 4);
}
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
{
ABI_AlignStack(2 * 4);
PUSH(32, arg1);
PUSH(32, Imm32(param2));
CALL(func);
ABI_RestoreStack(2 * 4);
}
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
PUSH(EBP);
PUSH(EBX);
PUSH(ESI);
PUSH(EDI);
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(EDI);
POP(ESI);
POP(EBX);
POP(EBP);
}
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
frameSize += 4; // reserve space for return address
unsigned int alignedSize =
#ifdef __GNUC__
(frameSize + 15) & -16;
#else
frameSize;
#endif
return alignedSize;
}
void ABI_AlignStack(unsigned int frameSize) {
// Mac OS X requires the stack to be 16-byte aligned before every call.
// Linux requires the stack to be 16-byte aligned before calls that put SSE
// vectors on the stack, but since we do not keep track of which calls do that,
// it is effectively every call as well.
// Windows binaries compiled with MSVC do not have such a restriction, but I
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
// It would be nice if someone could verify this.
#ifdef __GNUC__
unsigned int fillSize =
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
if (fillSize != 0) {
SUB(32, R(ESP), Imm8(fillSize));
}
#endif
}
void ABI_RestoreStack(unsigned int frameSize) {
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
alignedSize -= 4; // return address is POPped at end of call
if (alignedSize != 0) {
ADD(32, R(ESP), Imm8(alignedSize));
}
}
#else
void ABI_CallFunctionC(void *func, u32 param1) {
MOV(32, R(ABI_PARAM1), Imm32(param1));
CALL(func);
}
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
MOV(32, R(ABI_PARAM1), Imm32(param1));
MOV(32, R(ABI_PARAM2), Imm32(param2));
CALL(func);
}
// Pass a register as a paremeter.
void ABI_CallFunctionR(void *func, X64Reg reg1) {
if (reg1 != ABI_PARAM1)
MOV(32, R(ABI_PARAM1), R(reg1));
CALL(func);
}
// Pass a register as a paremeter.
void ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
if (reg1 != ABI_PARAM1)
MOV(32, R(ABI_PARAM1), R(reg1));
if (reg2 != ABI_PARAM2)
MOV(32, R(ABI_PARAM2), R(reg2));
CALL(func);
}
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
{
if (!arg1.IsSimpleReg(ABI_PARAM1))
MOV(32, R(ABI_PARAM1), arg1);
MOV(32, R(ABI_PARAM2), Imm32(param2));
CALL(func);
}
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize) {
return frameSize;
}
void ABI_AlignStack(unsigned int /*frameSize*/) {
}
void ABI_RestoreStack(unsigned int /*frameSize*/) {
}
#ifdef _WIN32
// Win64 Specific Code
// ====================================
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
//we only want to do this once
PUSH(RBX);
PUSH(RSI);
PUSH(RDI);
PUSH(RBP);
PUSH(R12);
PUSH(R13);
PUSH(R14);
PUSH(R15);
//TODO: Also preserve XMM0-3?
SUB(64, R(RSP), Imm8(0x28));
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
ADD(64, R(RSP), Imm8(0x28));
POP(R15);
POP(R14);
POP(R13);
POP(R12);
POP(RBP);
POP(RDI);
POP(RSI);
POP(RBX);
}
// Win64 Specific Code
// ====================================
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
PUSH(RCX);
PUSH(RDX);
PUSH(RSI);
PUSH(RDI);
PUSH(R8);
PUSH(R9);
PUSH(R10);
PUSH(R11);
//TODO: Also preserve XMM0-15?
SUB(64, R(RSP), Imm8(0x28));
}
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
ADD(64, R(RSP), Imm8(0x28));
POP(R11);
POP(R10);
POP(R9);
POP(R8);
POP(RDI);
POP(RSI);
POP(RDX);
POP(RCX);
}
#else
// Unix64 Specific Code
// ====================================
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
PUSH(RBX);
PUSH(RBP);
PUSH(R12);
PUSH(R13);
PUSH(R14);
PUSH(R15);
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(R15);
POP(R15);
POP(R14);
POP(R13);
POP(R12);
POP(RBP);
POP(RBX);
}
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
INT3();
//not yet supported
}
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
INT3();
//not yet supported
}
#endif
#endif

View File

@ -1,200 +1,200 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <memory.h>
#ifdef _WIN32
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
#include <intrin.h>
#undef _interlockedbittestandset
#undef _interlockedbittestandreset
#undef _interlockedbittestandset64
#undef _interlockedbittestandreset64
#else
//#include <config/i386/cpuid.h>
#include <xmmintrin.h>
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
#ifdef _LP64
__asm__("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
);
#else
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to be
// restored at the end of the asm block.
__asm__(
"pushl %%ebx;"
"cpuid;"
"movl %%ebx,%1;"
"popl %%ebx;"
: "=a" (*eax),
"=r" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
);
#endif
}
void __cpuid(int info[4], int x)
{
unsigned int eax = x, ebx = 0, ecx = 0, edx = 0;
do_cpuid(&eax, &ebx, &ecx, &edx);
info[0] = eax;
info[1] = ebx;
info[2] = ecx;
info[3] = edx;
}
#endif
#include "Common.h"
#include "CPUDetect.h"
#include "StringUtil.h"
CPUInfo cpu_info;
void CPUInfo::Detect()
{
memset(this, 0, sizeof(*this));
#ifdef _M_IX86
Mode64bit = false;
#elif defined (_M_X64)
Mode64bit = true;
OS64bit = true;
#endif
num_cores = 1;
#ifdef _WIN32
#ifdef _M_IX86
BOOL f64 = FALSE;
OS64bit = IsWow64Process(GetCurrentProcess(), &f64) && f64;
#endif
#endif
// Set obvious defaults, for extra safety
if (Mode64bit)
{
bSSE = true;
bSSE2 = true;
bLongMode = true;
}
// Assume CPU supports the CPUID instruction. Those that don't can barely boot modern OS:es anyway.
int cpu_id[4];
memset(cpu_string, 0, sizeof(cpu_string));
// Detect CPU's CPUID capabilities, and grab cpu string
__cpuid(cpu_id, 0x00000000);
u32 max_std_fn = cpu_id[0]; // EAX
*((int *)cpu_string) = cpu_id[1];
*((int *)(cpu_string + 4)) = cpu_id[3];
*((int *)(cpu_string + 8)) = cpu_id[2];
__cpuid(cpu_id, 0x80000000);
u32 max_ex_fn = cpu_id[0];
if (!strcmp(cpu_string, "GenuineIntel"))
vendor = VENDOR_INTEL;
else if (!strcmp(cpu_string, "AuthenticAMD"))
vendor = VENDOR_AMD;
else
vendor = VENDOR_OTHER;
// Set reasonable default brand string even if brand string not available.
strcpy(brand_string, cpu_string);
// Detect family and other misc stuff.
bool HTT = false;
int logical_cpu_count = 1;
if (max_std_fn >= 1) {
__cpuid(cpu_id, 0x00000001);
logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
if ((cpu_id[3] >> 28) & 1) {
// wtf, we get here on my core 2
HTT = true;
}
if ((cpu_id[3] >> 25) & 1) bSSE = true;
if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
if (cpu_id[2] & 1) bSSE3 = true;
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
}
if (max_ex_fn >= 0x80000004) {
// Extract brand string
__cpuid(cpu_id, 0x80000002);
memcpy(brand_string, cpu_id, sizeof(cpu_id));
__cpuid(cpu_id, 0x80000003);
memcpy(brand_string + 16, cpu_id, sizeof(cpu_id));
__cpuid(cpu_id, 0x80000004);
memcpy(brand_string + 32, cpu_id, sizeof(cpu_id));
}
if (max_ex_fn >= 0x80000001) {
// Check for more features.
__cpuid(cpu_id, 0x80000001);
bool cmp_legacy = false;
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
}
if (max_ex_fn >= 0x80000008) {
// Get number of cores. This is a bit complicated. Following AMD manual here.
__cpuid(cpu_id, 0x80000008);
int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
if (apic_id_core_id_size == 0) {
// Use what AMD calls the "legacy method" to determine # of cores.
if (HTT) {
num_cores = logical_cpu_count;
} else {
num_cores = 1;
}
} else {
// Use AMD's new method.
num_cores = (cpu_id[2] & 0xFF) + 1;
}
} else {
// Wild guess
if (logical_cpu_count)
num_cores = logical_cpu_count;
}
}
std::string CPUInfo::Summarize()
{
std::string sum;
if (num_cores == 1)
sum = StringFromFormat("%s, %i core, ", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %i cores, ", cpu_string, num_cores);
if (bSSE) sum += "SSE";
if (bSSE2) sum += ", SSE2";
if (bSSE3) sum += ", SSE3";
if (bSSSE3) sum += ", SSSE3";
if (bSSE4_1) sum += ", SSE4.1";
if (bSSE4_2) sum += ", SSE4.2";
if (bLongMode) sum += ", 64-bit support";
return sum;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <memory.h>
#ifdef _WIN32
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
#include <intrin.h>
#undef _interlockedbittestandset
#undef _interlockedbittestandreset
#undef _interlockedbittestandset64
#undef _interlockedbittestandreset64
#else
//#include <config/i386/cpuid.h>
#include <xmmintrin.h>
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
#ifdef _LP64
__asm__("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
);
#else
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to be
// restored at the end of the asm block.
__asm__(
"pushl %%ebx;"
"cpuid;"
"movl %%ebx,%1;"
"popl %%ebx;"
: "=a" (*eax),
"=r" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
);
#endif
}
void __cpuid(int info[4], int x)
{
unsigned int eax = x, ebx = 0, ecx = 0, edx = 0;
do_cpuid(&eax, &ebx, &ecx, &edx);
info[0] = eax;
info[1] = ebx;
info[2] = ecx;
info[3] = edx;
}
#endif
#include "Common.h"
#include "CPUDetect.h"
#include "StringUtil.h"
CPUInfo cpu_info;
void CPUInfo::Detect()
{
memset(this, 0, sizeof(*this));
#ifdef _M_IX86
Mode64bit = false;
#elif defined (_M_X64)
Mode64bit = true;
OS64bit = true;
#endif
num_cores = 1;
#ifdef _WIN32
#ifdef _M_IX86
BOOL f64 = FALSE;
OS64bit = IsWow64Process(GetCurrentProcess(), &f64) && f64;
#endif
#endif
// Set obvious defaults, for extra safety
if (Mode64bit)
{
bSSE = true;
bSSE2 = true;
bLongMode = true;
}
// Assume CPU supports the CPUID instruction. Those that don't can barely boot modern OS:es anyway.
int cpu_id[4];
memset(cpu_string, 0, sizeof(cpu_string));
// Detect CPU's CPUID capabilities, and grab cpu string
__cpuid(cpu_id, 0x00000000);
u32 max_std_fn = cpu_id[0]; // EAX
*((int *)cpu_string) = cpu_id[1];
*((int *)(cpu_string + 4)) = cpu_id[3];
*((int *)(cpu_string + 8)) = cpu_id[2];
__cpuid(cpu_id, 0x80000000);
u32 max_ex_fn = cpu_id[0];
if (!strcmp(cpu_string, "GenuineIntel"))
vendor = VENDOR_INTEL;
else if (!strcmp(cpu_string, "AuthenticAMD"))
vendor = VENDOR_AMD;
else
vendor = VENDOR_OTHER;
// Set reasonable default brand string even if brand string not available.
strcpy(brand_string, cpu_string);
// Detect family and other misc stuff.
bool HTT = false;
int logical_cpu_count = 1;
if (max_std_fn >= 1) {
__cpuid(cpu_id, 0x00000001);
logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
if ((cpu_id[3] >> 28) & 1) {
// wtf, we get here on my core 2
HTT = true;
}
if ((cpu_id[3] >> 25) & 1) bSSE = true;
if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
if (cpu_id[2] & 1) bSSE3 = true;
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
}
if (max_ex_fn >= 0x80000004) {
// Extract brand string
__cpuid(cpu_id, 0x80000002);
memcpy(brand_string, cpu_id, sizeof(cpu_id));
__cpuid(cpu_id, 0x80000003);
memcpy(brand_string + 16, cpu_id, sizeof(cpu_id));
__cpuid(cpu_id, 0x80000004);
memcpy(brand_string + 32, cpu_id, sizeof(cpu_id));
}
if (max_ex_fn >= 0x80000001) {
// Check for more features.
__cpuid(cpu_id, 0x80000001);
bool cmp_legacy = false;
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
}
if (max_ex_fn >= 0x80000008) {
// Get number of cores. This is a bit complicated. Following AMD manual here.
__cpuid(cpu_id, 0x80000008);
int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
if (apic_id_core_id_size == 0) {
// Use what AMD calls the "legacy method" to determine # of cores.
if (HTT) {
num_cores = logical_cpu_count;
} else {
num_cores = 1;
}
} else {
// Use AMD's new method.
num_cores = (cpu_id[2] & 0xFF) + 1;
}
} else {
// Wild guess
if (logical_cpu_count)
num_cores = logical_cpu_count;
}
}
std::string CPUInfo::Summarize()
{
std::string sum;
if (num_cores == 1)
sum = StringFromFormat("%s, %i core, ", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %i cores, ", cpu_string, num_cores);
if (bSSE) sum += "SSE";
if (bSSE2) sum += ", SSE2";
if (bSSE3) sum += ", SSE3";
if (bSSSE3) sum += ", SSSE3";
if (bSSE4_1) sum += ", SSE4.1";
if (bSSE4_2) sum += ", SSE4.2";
if (bLongMode) sum += ", 64-bit support";
return sum;
}

View File

@ -1,22 +1,22 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "ChunkFile.h"
#include <stdio.h>
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "ChunkFile.h"
#include <stdio.h>

View File

@ -1,113 +1,113 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include "Common.h"
#include "StringUtil.h"
namespace
{
static PanicAlertHandler panic_handler = 0;
}
void RegisterPanicAlertHandler(PanicAlertHandler handler)
{
panic_handler = handler;
}
void PanicAlert(const char* format, ...)
{
va_list args;
va_start(args, format);
if (panic_handler)
{
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
panic_handler(msg.c_str(), false);
}
else
{
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
MessageBox(0, msg.c_str(), "PANIC!", MB_ICONWARNING);
#elif __GNUC__
//#error Do a messagebox!
vprintf(format, args);
printf("\n");
// asm ("int $3") ;
#endif
}
va_end(args);
}
bool PanicYesNo(const char* format, ...)
{
va_list args;
va_start(args, format);
bool retval;
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
retval = IDYES == MessageBox(0, msg.c_str(), "PANIC! Continue?", MB_ICONQUESTION | MB_YESNO);
#elif __GNUC__
//vprintf(format, args);
return(true); //#error Do a messagebox!
#endif
va_end(args);
return(retval);
}
bool AskYesNo(const char* format, ...)
{
va_list args;
va_start(args, format);
bool retval;
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "ASK: %s", msg.c_str());
retval = IDYES == MessageBox(0, msg.c_str(), "Dolphin", MB_ICONQUESTION | MB_YESNO);
#elif __GNUC__
//vprintf(format, args);
return(true); //#error Do a messagebox!
#endif
va_end(args);
return(retval);
}
// Standard implementation of logging - simply print to standard output.
// Programs are welcome to override this.
/*
void __Log(int logNumber, const char *text, ...)
{
va_list args;
va_start(args, text);
vprintf(text, args);
va_end(args);
}*/
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdio.h>
#include "Common.h"
#include "StringUtil.h"
namespace
{
static PanicAlertHandler panic_handler = 0;
}
void RegisterPanicAlertHandler(PanicAlertHandler handler)
{
panic_handler = handler;
}
void PanicAlert(const char* format, ...)
{
va_list args;
va_start(args, format);
if (panic_handler)
{
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
panic_handler(msg.c_str(), false);
}
else
{
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
MessageBox(0, msg.c_str(), "PANIC!", MB_ICONWARNING);
#elif __GNUC__
//#error Do a messagebox!
vprintf(format, args);
printf("\n");
// asm ("int $3") ;
#endif
}
va_end(args);
}
bool PanicYesNo(const char* format, ...)
{
va_list args;
va_start(args, format);
bool retval;
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "PANIC: %s", msg.c_str());
retval = IDYES == MessageBox(0, msg.c_str(), "PANIC! Continue?", MB_ICONQUESTION | MB_YESNO);
#elif __GNUC__
//vprintf(format, args);
return(true); //#error Do a messagebox!
#endif
va_end(args);
return(retval);
}
bool AskYesNo(const char* format, ...)
{
va_list args;
va_start(args, format);
bool retval;
#ifdef _WIN32
std::string msg;
StringFromFormatV(&msg, format, args);
LOG(MASTER_LOG, "ASK: %s", msg.c_str());
retval = IDYES == MessageBox(0, msg.c_str(), "Dolphin", MB_ICONQUESTION | MB_YESNO);
#elif __GNUC__
//vprintf(format, args);
return(true); //#error Do a messagebox!
#endif
va_end(args);
return(retval);
}
// Standard implementation of logging - simply print to standard output.
// Programs are welcome to override this.
/*
void __Log(int logNumber, const char *text, ...)
{
va_list args;
va_start(args, text);
vprintf(text, args);
va_end(args);
}*/

View File

@ -1,57 +1,57 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
#endif
void GetAllRemovableDrives(std::vector<std::string> *drives) {
drives->clear();
#ifdef _WIN32
HANDLE hDisk;
DISK_GEOMETRY diskGeometry;
for (int i = 'A'; i < 'Z'; i++)
{
char path[MAX_PATH];
sprintf(path, "\\\\.\\%c:", i);
hDisk = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD dwBytes;
DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(DISK_GEOMETRY), &dwBytes, NULL);
// Only proceed if disk is a removable media
if (diskGeometry.MediaType == RemovableMedia)
{
if (diskGeometry.BytesPerSector == 2048) {
// Probably CD/DVD drive.
// "Remove" the "\\.\" part of the path and return it.
drives->push_back(path + 4);
}
}
}
CloseHandle(hDisk);
}
#else
// TODO
// stat("/media/cdrom") or whatever etc etc
#endif
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
#endif
void GetAllRemovableDrives(std::vector<std::string> *drives) {
drives->clear();
#ifdef _WIN32
HANDLE hDisk;
DISK_GEOMETRY diskGeometry;
for (int i = 'A'; i < 'Z'; i++)
{
char path[MAX_PATH];
sprintf(path, "\\\\.\\%c:", i);
hDisk = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD dwBytes;
DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(DISK_GEOMETRY), &dwBytes, NULL);
// Only proceed if disk is a removable media
if (diskGeometry.MediaType == RemovableMedia)
{
if (diskGeometry.BytesPerSector == 2048) {
// Probably CD/DVD drive.
// "Remove" the "\\.\" part of the path and return it.
drives->push_back(path + 4);
}
}
}
CloseHandle(hDisk);
}
#else
// TODO
// stat("/media/cdrom") or whatever etc etc
#endif
}

View File

@ -1,151 +1,151 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <stdio.h>
#endif
#include "Common.h"
#include "StringUtil.h"
#include "DynamicLibrary.h"
#include "../../Core/Src/PowerPC/PowerPC.h"
DynamicLibrary::DynamicLibrary()
{
library = 0;
}
#ifdef _WIN32
std::string GetLastErrorAsString()
{
LPVOID lpMsgBuf = 0;
DWORD error = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0, NULL);
std::string s;
if (lpMsgBuf)
{
s = ((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
} else {
s = StringFromFormat("(unknown error %08x)", error);
}
return s;
}
#endif
// ------------------------------------------------------------------
/* Loading means loading the dll with LoadLibrary() to get an instance to the dll.
This is done when Dolphin is started to determine which dlls are good, and
before opening the Config and Debugging windowses from Plugin.cpp and
before opening the dll for running the emulation in Video_...cpp in Core. */
// -----------------------
int DynamicLibrary::Load(const char* filename)
{
if (!filename || strlen(filename) == 0)
{
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
return 0;
}
LOG(MASTER_LOG, "Trying to load library %s", filename);
if (IsLoaded())
{
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
return 2;
}
#ifdef _WIN32
library = LoadLibrary(filename);
if (!library) {
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
return 0;
}
#else
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
if (!library)
{
#ifdef LOGGING
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, dlerror());
#else
printf("Error loading DLL %s: %s", filename, dlerror());
#endif
return false;
}
#endif
library_file = filename;
return 1;
}
void DynamicLibrary::Unload()
{
if (!IsLoaded())
{
PanicAlert("Trying to unload non-loaded library");
return;
}
#ifdef _WIN32
/* TEMPORARY SOLUTION: To prevent that Dolphin hangs when a game is stopped
or when we try to close Dolphin. It's possible that it only occur when we render
to the main window. And sometimes FreeLibrary works without any problem, so
don't remove this just because it doesn't hang once. I could not find the
actual cause of it. */
if( ! (library_file.find("OGL.") != std::string::npos) && !PowerPC::CPU_POWERDOWN)
FreeLibrary(library);
#else
dlclose(library);
#endif
library = 0;
}
void* DynamicLibrary::Get(const char* funcname) const
{
void* retval;
#ifdef _WIN32
if (!library)
{
PanicAlert("Can't find function %s - Library not loaded.");
}
retval = GetProcAddress(library, funcname);
//if (!retval)
//{
// PanicAlert("Did not find function %s in library %s.", funcname, library_file.c_str());
//}
#else
retval = dlsym(library, funcname);
if (!retval)
{
printf("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), dlerror());
}
#endif
return retval;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <stdio.h>
#endif
#include "Common.h"
#include "StringUtil.h"
#include "DynamicLibrary.h"
#include "../../Core/Src/PowerPC/PowerPC.h"
DynamicLibrary::DynamicLibrary()
{
library = 0;
}
#ifdef _WIN32
std::string GetLastErrorAsString()
{
LPVOID lpMsgBuf = 0;
DWORD error = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0, NULL);
std::string s;
if (lpMsgBuf)
{
s = ((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
} else {
s = StringFromFormat("(unknown error %08x)", error);
}
return s;
}
#endif
// ------------------------------------------------------------------
/* Loading means loading the dll with LoadLibrary() to get an instance to the dll.
This is done when Dolphin is started to determine which dlls are good, and
before opening the Config and Debugging windowses from Plugin.cpp and
before opening the dll for running the emulation in Video_...cpp in Core. */
// -----------------------
int DynamicLibrary::Load(const char* filename)
{
if (!filename || strlen(filename) == 0)
{
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
return 0;
}
LOG(MASTER_LOG, "Trying to load library %s", filename);
if (IsLoaded())
{
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
return 2;
}
#ifdef _WIN32
library = LoadLibrary(filename);
if (!library) {
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
return 0;
}
#else
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
if (!library)
{
#ifdef LOGGING
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, dlerror());
#else
printf("Error loading DLL %s: %s", filename, dlerror());
#endif
return false;
}
#endif
library_file = filename;
return 1;
}
void DynamicLibrary::Unload()
{
if (!IsLoaded())
{
PanicAlert("Trying to unload non-loaded library");
return;
}
#ifdef _WIN32
/* TEMPORARY SOLUTION: To prevent that Dolphin hangs when a game is stopped
or when we try to close Dolphin. It's possible that it only occur when we render
to the main window. And sometimes FreeLibrary works without any problem, so
don't remove this just because it doesn't hang once. I could not find the
actual cause of it. */
if( ! (library_file.find("OGL.") != std::string::npos) && !PowerPC::CPU_POWERDOWN)
FreeLibrary(library);
#else
dlclose(library);
#endif
library = 0;
}
void* DynamicLibrary::Get(const char* funcname) const
{
void* retval;
#ifdef _WIN32
if (!library)
{
PanicAlert("Can't find function %s - Library not loaded.");
}
retval = GetProcAddress(library, funcname);
//if (!retval)
//{
// PanicAlert("Did not find function %s in library %s.", funcname, library_file.c_str());
//}
#else
retval = dlsym(library, funcname);
if (!retval)
{
printf("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), dlerror());
}
#endif
return retval;
}

View File

@ -1,437 +1,437 @@
//////////////////////////////////////////////////////////////////////////////////////
//
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
// The source is free, but if you want to use it, mention my name and e-mail address
//
// History:
// 1.0 Initial version Zoltan Csizmadia
// 1.1 WhineCube version Masken
// 1.2 Dolphin version Masken
//
//////////////////////////////////////////////////////////////////////////////////////
//
// ExtendedTrace.cpp
//
// Include StdAfx.h, if you're using precompiled
// header through StdAfx.h
//#include "stdafx.h"
#if defined(WIN32)
#include <windows.h>
#include <stdio.h>
#include "ExtendedTrace.h"
using namespace std;
#include <tchar.h>
#include <ImageHlp.h>
#define BUFFERSIZE 0x200
#pragma warning(disable:4996)
// Unicode safe char* -> TCHAR* conversion
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
{
#if defined(UNICODE)||defined(_UNICODE)
ULONG index = 0;
PCSTR lpAct = lpszIn;
for( ; ; lpAct++ )
{
lpszOut[index++] = (TCHAR)(*lpAct);
if ( *lpAct == 0 )
break;
}
#else
// This is trivial :)
strcpy( lpszOut, lpszIn );
#endif
}
// Let's figure out the path for the symbol files
// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath
// Note: There is no size check for lpszSymbolPath!
static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
{
CHAR lpszPath[BUFFERSIZE];
// Creating the default path
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;"
strcpy( lpszSymbolPath, "." );
// environment variable _NT_SYMBOL_PATH
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
}
// environment variable _NT_ALTERNATE_SYMBOL_PATH
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
}
// environment variable SYSTEMROOT
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, ";" );
// SYSTEMROOT\System32
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, "\\System32" );
}
// Add user defined path
if ( lpszIniPath != NULL )
if ( lpszIniPath[0] != '\0' )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszIniPath );
}
}
// Uninitialize the loaded symbol files
BOOL UninitSymInfo() {
return SymCleanup( GetCurrentProcess() );
}
// Initializes the symbol files
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
{
CHAR lpszSymbolPath[BUFFERSIZE];
DWORD symOptions = SymGetOptions();
symOptions |= SYMOPT_LOAD_LINES;
symOptions &= ~SYMOPT_UNDNAME;
SymSetOptions( symOptions );
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
}
// Get the module name from a given address
static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
{
BOOL ret = FALSE;
IMAGEHLP_MODULE moduleInfo;
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
{
// Got it!
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
ret = TRUE;
}
else
// Not found :(
_tcscpy( lpszModule, _T("?") );
return ret;
}
// Get function prototype and parameter info from ip address and stack address
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
{
BOOL ret = FALSE;
DWORD dwDisp = 0;
DWORD dwSymSize = 10000;
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
LPTSTR lpszParamSep = NULL;
LPTSTR lpszParsed = lpszUnDSymbol;
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
::ZeroMemory( pSym, dwSymSize );
pSym->SizeOfStruct = dwSymSize;
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
// Set the default to unknown
_tcscpy( lpszSymbol, _T("?") );
// Get symbol info for IP
#ifndef _M_X64
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
#else
//makes it compile but hell im not sure if this works...
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
#endif
{
// Make the symbol readable for humans
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS );
// Symbol information is ANSI string
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
// I am just smarter than the symbol file :)
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
lpszSymbol[0] = _T('\0');
// Let's go through the stack, and modify the function prototype, and insert the actual
// parameter values from the stack
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
{
ULONG index = 0;
for( ; ; index++ )
{
lpszParamSep = _tcschr( lpszParsed, _T(',') );
if ( lpszParamSep == NULL )
break;
*lpszParamSep = _T('\0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
lpszParamSep = _tcschr( lpszParsed, _T(')') );
if ( lpszParamSep != NULL )
{
*lpszParamSep = _T('\0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
}
_tcscat( lpszSymbol, lpszParsed );
ret = TRUE;
}
GlobalFree( pSym );
return ret;
}
// Get source file name and line number from IP address
// The output format is: "sourcefile(linenumber)" or
// "modulename!address" or
// "address"
static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
{
BOOL ret = FALSE;
IMAGEHLP_LINE lineInfo;
DWORD dwDisp;
TCHAR lpszFileName[BUFFERSIZE] = _T("");
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
_tcscpy( lpszSourceInfo, _T("?(?)") );
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
lineInfo.SizeOfStruct = sizeof( lineInfo );
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
{
// Got it. Let's use "sourcefile(linenumber)" format
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
ret = TRUE;
}
else
{
// There is no source file information. :(
// Let's use the "modulename!address" format
GetModuleNameFromAddress( address, lpModuleInfo );
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
// There is no modulename information. :((
// Let's use the "address" format
_stprintf( lpszSourceInfo, _T("0x%08X"), address );
else
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
ret = FALSE;
}
return ret;
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
{
STACKFRAME callStack;
BOOL bResult;
CONTEXT context;
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
HANDLE hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end
if ( hThread != GetCurrentThread() )
if ( SuspendThread( hThread ) == -1 )
{
// whaaat ?!
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &context, sizeof(context) );
context.ContextFlags = CONTEXT_FULL;
if ( !GetThreadContext( hThread, &context ) )
{
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &callStack, sizeof(callStack) );
#ifndef _M_X64
callStack.AddrPC.Offset = context.Eip;
callStack.AddrStack.Offset = context.Esp;
callStack.AddrFrame.Offset = context.Ebp;
#else
callStack.AddrPC.Offset = context.Rip;
callStack.AddrStack.Offset = context.Rsp;
callStack.AddrFrame.Offset = context.Rbp;
#endif
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrStack.Mode = AddrModeFlat;
callStack.AddrFrame.Mode = AddrModeFlat;
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
NULL,
NULL,
SymFunctionTableAccess,
SymGetModuleBase,
NULL);
if ( index == 0 )
continue;
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
}
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
{
STACKFRAME callStack;
BOOL bResult;
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
HANDLE hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end
if ( hThread != GetCurrentThread() )
if ( SuspendThread( hThread ) == -1 )
{
// whaaat ?!
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &callStack, sizeof(callStack) );
callStack.AddrPC.Offset = eip;
callStack.AddrStack.Offset = esp;
callStack.AddrFrame.Offset = ebp;
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrStack.Mode = AddrModeFlat;
callStack.AddrFrame.Mode = AddrModeFlat;
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
NULL,
NULL,
SymFunctionTableAccess,
SymGetModuleBase,
NULL);
if ( index == 0 )
continue;
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
}
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );
}
char g_uefbuf[2048];
void etfprintf(FILE *file, const char *format, ...) {
va_list ap;
va_start(ap, format);
int len = vsprintf(g_uefbuf, format, ap);
fwrite(g_uefbuf, 1, len, file);
va_end(ap);
}
void etfprint(FILE *file, const std::string &text) {
size_t len = text.length();
fwrite(text.data(), 1, len, file);
}
#endif //WIN32
//////////////////////////////////////////////////////////////////////////////////////
//
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
// The source is free, but if you want to use it, mention my name and e-mail address
//
// History:
// 1.0 Initial version Zoltan Csizmadia
// 1.1 WhineCube version Masken
// 1.2 Dolphin version Masken
//
//////////////////////////////////////////////////////////////////////////////////////
//
// ExtendedTrace.cpp
//
// Include StdAfx.h, if you're using precompiled
// header through StdAfx.h
//#include "stdafx.h"
#if defined(WIN32)
#include <windows.h>
#include <stdio.h>
#include "ExtendedTrace.h"
using namespace std;
#include <tchar.h>
#include <ImageHlp.h>
#define BUFFERSIZE 0x200
#pragma warning(disable:4996)
// Unicode safe char* -> TCHAR* conversion
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
{
#if defined(UNICODE)||defined(_UNICODE)
ULONG index = 0;
PCSTR lpAct = lpszIn;
for( ; ; lpAct++ )
{
lpszOut[index++] = (TCHAR)(*lpAct);
if ( *lpAct == 0 )
break;
}
#else
// This is trivial :)
strcpy( lpszOut, lpszIn );
#endif
}
// Let's figure out the path for the symbol files
// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath
// Note: There is no size check for lpszSymbolPath!
static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
{
CHAR lpszPath[BUFFERSIZE];
// Creating the default path
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;"
strcpy( lpszSymbolPath, "." );
// environment variable _NT_SYMBOL_PATH
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
}
// environment variable _NT_ALTERNATE_SYMBOL_PATH
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
}
// environment variable SYSTEMROOT
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, ";" );
// SYSTEMROOT\System32
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, "\\System32" );
}
// Add user defined path
if ( lpszIniPath != NULL )
if ( lpszIniPath[0] != '\0' )
{
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszIniPath );
}
}
// Uninitialize the loaded symbol files
BOOL UninitSymInfo() {
return SymCleanup( GetCurrentProcess() );
}
// Initializes the symbol files
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
{
CHAR lpszSymbolPath[BUFFERSIZE];
DWORD symOptions = SymGetOptions();
symOptions |= SYMOPT_LOAD_LINES;
symOptions &= ~SYMOPT_UNDNAME;
SymSetOptions( symOptions );
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
}
// Get the module name from a given address
static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
{
BOOL ret = FALSE;
IMAGEHLP_MODULE moduleInfo;
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
{
// Got it!
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
ret = TRUE;
}
else
// Not found :(
_tcscpy( lpszModule, _T("?") );
return ret;
}
// Get function prototype and parameter info from ip address and stack address
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
{
BOOL ret = FALSE;
DWORD dwDisp = 0;
DWORD dwSymSize = 10000;
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
LPTSTR lpszParamSep = NULL;
LPTSTR lpszParsed = lpszUnDSymbol;
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
::ZeroMemory( pSym, dwSymSize );
pSym->SizeOfStruct = dwSymSize;
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
// Set the default to unknown
_tcscpy( lpszSymbol, _T("?") );
// Get symbol info for IP
#ifndef _M_X64
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
#else
//makes it compile but hell im not sure if this works...
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
#endif
{
// Make the symbol readable for humans
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS );
// Symbol information is ANSI string
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
// I am just smarter than the symbol file :)
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
lpszSymbol[0] = _T('\0');
// Let's go through the stack, and modify the function prototype, and insert the actual
// parameter values from the stack
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
{
ULONG index = 0;
for( ; ; index++ )
{
lpszParamSep = _tcschr( lpszParsed, _T(',') );
if ( lpszParamSep == NULL )
break;
*lpszParamSep = _T('\0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
lpszParamSep = _tcschr( lpszParsed, _T(')') );
if ( lpszParamSep != NULL )
{
*lpszParamSep = _T('\0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
}
_tcscat( lpszSymbol, lpszParsed );
ret = TRUE;
}
GlobalFree( pSym );
return ret;
}
// Get source file name and line number from IP address
// The output format is: "sourcefile(linenumber)" or
// "modulename!address" or
// "address"
static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
{
BOOL ret = FALSE;
IMAGEHLP_LINE lineInfo;
DWORD dwDisp;
TCHAR lpszFileName[BUFFERSIZE] = _T("");
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
_tcscpy( lpszSourceInfo, _T("?(?)") );
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
lineInfo.SizeOfStruct = sizeof( lineInfo );
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
{
// Got it. Let's use "sourcefile(linenumber)" format
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
ret = TRUE;
}
else
{
// There is no source file information. :(
// Let's use the "modulename!address" format
GetModuleNameFromAddress( address, lpModuleInfo );
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
// There is no modulename information. :((
// Let's use the "address" format
_stprintf( lpszSourceInfo, _T("0x%08X"), address );
else
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
ret = FALSE;
}
return ret;
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
{
STACKFRAME callStack;
BOOL bResult;
CONTEXT context;
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
HANDLE hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end
if ( hThread != GetCurrentThread() )
if ( SuspendThread( hThread ) == -1 )
{
// whaaat ?!
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &context, sizeof(context) );
context.ContextFlags = CONTEXT_FULL;
if ( !GetThreadContext( hThread, &context ) )
{
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &callStack, sizeof(callStack) );
#ifndef _M_X64
callStack.AddrPC.Offset = context.Eip;
callStack.AddrStack.Offset = context.Esp;
callStack.AddrFrame.Offset = context.Ebp;
#else
callStack.AddrPC.Offset = context.Rip;
callStack.AddrStack.Offset = context.Rsp;
callStack.AddrFrame.Offset = context.Rbp;
#endif
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrStack.Mode = AddrModeFlat;
callStack.AddrFrame.Mode = AddrModeFlat;
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
NULL,
NULL,
SymFunctionTableAccess,
SymGetModuleBase,
NULL);
if ( index == 0 )
continue;
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
}
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
{
STACKFRAME callStack;
BOOL bResult;
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
HANDLE hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end
if ( hThread != GetCurrentThread() )
if ( SuspendThread( hThread ) == -1 )
{
// whaaat ?!
etfprint(file, "Call stack info failed\n");
return;
}
::ZeroMemory( &callStack, sizeof(callStack) );
callStack.AddrPC.Offset = eip;
callStack.AddrStack.Offset = esp;
callStack.AddrFrame.Offset = ebp;
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrStack.Mode = AddrModeFlat;
callStack.AddrFrame.Mode = AddrModeFlat;
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
NULL,
NULL,
SymFunctionTableAccess,
SymGetModuleBase,
NULL);
if ( index == 0 )
continue;
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( callStack.AddrPC.Offset, callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
}
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );
}
char g_uefbuf[2048];
void etfprintf(FILE *file, const char *format, ...) {
va_list ap;
va_start(ap, format);
int len = vsprintf(g_uefbuf, format, ap);
fwrite(g_uefbuf, 1, len, file);
va_end(ap);
}
void etfprint(FILE *file, const std::string &text) {
size_t len = text.length();
fwrite(text.data(), 1, len, file);
}
#endif //WIN32

View File

@ -1,119 +1,119 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
#else
#include <windows.h>
#endif
#include <string>
#include "FileSearch.h"
#include "StringUtil.h"
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
{
// Reverse the loop order for speed?
for (size_t j = 0; j < _rSearchStrings.size(); j++)
{
for (size_t i = 0; i < _rDirectories.size(); i++)
{
FindFiles(_rSearchStrings[j], _rDirectories[i]);
}
}
}
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
{
std::string GCMSearchPath;
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
#ifdef _WIN32
WIN32_FIND_DATA findData;
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
if (FindFirst != INVALID_HANDLE_VALUE)
{
bool bkeepLooping = true;
while (bkeepLooping)
{
if (findData.cFileName[0] != '.')
{
std::string strFilename;
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
m_FileNames.push_back(strFilename);
}
bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
}
}
FindClose(FindFirst);
#else
size_t dot_pos = _searchString.rfind(".");
if (dot_pos == std::string::npos)
{
return;
}
std::string ext = _searchString.substr(dot_pos);
DIR* dir = opendir(_strPath.c_str());
if (!dir)
{
return;
}
dirent* dp;
while (true)
{
dp = readdir(dir);
if (!dp)
{
break;
}
std::string s(dp->d_name);
if ( (s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) )
{
std::string full_name = _strPath + "/" + s;
m_FileNames.push_back(full_name);
}
}
closedir(dir);
#endif
}
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
{
return(m_FileNames);
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
#else
#include <windows.h>
#endif
#include <string>
#include "FileSearch.h"
#include "StringUtil.h"
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
{
// Reverse the loop order for speed?
for (size_t j = 0; j < _rSearchStrings.size(); j++)
{
for (size_t i = 0; i < _rDirectories.size(); i++)
{
FindFiles(_rSearchStrings[j], _rDirectories[i]);
}
}
}
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
{
std::string GCMSearchPath;
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
#ifdef _WIN32
WIN32_FIND_DATA findData;
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
if (FindFirst != INVALID_HANDLE_VALUE)
{
bool bkeepLooping = true;
while (bkeepLooping)
{
if (findData.cFileName[0] != '.')
{
std::string strFilename;
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
m_FileNames.push_back(strFilename);
}
bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
}
}
FindClose(FindFirst);
#else
size_t dot_pos = _searchString.rfind(".");
if (dot_pos == std::string::npos)
{
return;
}
std::string ext = _searchString.substr(dot_pos);
DIR* dir = opendir(_strPath.c_str());
if (!dir)
{
return;
}
dirent* dp;
while (true)
{
dp = readdir(dir);
if (!dp)
{
break;
}
std::string s(dp->d_name);
if ( (s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) )
{
std::string full_name = _strPath + "/" + s;
m_FileNames.push_back(full_name);
}
}
closedir(dir);
#endif
}
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
{
return(m_FileNames);
}

View File

@ -1,496 +1,496 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "FileUtil.h"
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h> // for SHGetFolderPath
#include <shellapi.h>
#include <commdlg.h> // for GetSaveFileName
#include <io.h>
#include <direct.h> // getcwd
#else
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#endif
#include <fstream>
#include <sys/stat.h>
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif
namespace File
{
// =======================================================
// Remove any ending forward slashes from directory paths
// -------------
inline void StripTailDirSlashes(std::string& fname)
{
// Make sure it's not a blank string
if(fname.length() > 0)
{
while(fname.at(fname.length() - 1) == DIR_SEP_CHR)
fname.resize(fname.length() - 1);
}
}
// =============
bool Exists(const char *filename)
{
struct stat file_info;
std::string copy = filename;
StripTailDirSlashes(copy);
int result = stat(copy.c_str(), &file_info);
return (result == 0);
}
bool IsDirectory(const char *filename)
{
struct stat file_info;
std::string copy = filename;
StripTailDirSlashes(copy);
int result = stat(copy.c_str(), &file_info);
if (result == 0)
return S_ISDIR(file_info.st_mode);
else
return false;
}
bool Delete(const char *filename)
{
if (!Exists(filename))
return false;
if (IsDirectory(filename))
return false;
#ifdef _WIN32
DeleteFile(filename);
#else
unlink(filename);
#endif
return true;
}
std::string SanitizePath(const char *filename)
{
std::string copy = filename;
#ifdef _WIN32
for (size_t i = 0; i < copy.size(); i++)
if (copy[i] == '/')
copy[i] = '\\';
#else
// Should we do the otherway around?
#endif
return copy;
}
void Launch(const char *filename)
{
#ifdef _WIN32
std::string win_filename = SanitizePath(filename);
SHELLEXECUTEINFO shex = { sizeof(shex) };
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
shex.lpVerb = "open";
shex.lpFile = win_filename.c_str();
shex.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&shex);
#else
// TODO: Insert GNOME/KDE code here.
#endif
}
void Explore(const char *path)
{
#ifdef _WIN32
std::string win_path = SanitizePath(path);
SHELLEXECUTEINFO shex = { sizeof(shex) };
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
shex.lpVerb = "explore";
shex.lpFile = win_path.c_str();
shex.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&shex);
#else
// TODO: Insert GNOME/KDE code here.
#endif
}
// Returns true if successful, or path already exists.
bool CreateDir(const char *path)
{
#ifdef _WIN32
if (::CreateDirectory(path, NULL))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
{
PanicAlert("%s already exists", path);
return true;
}
PanicAlert("Error creating directory %s: %i", path, error);
return false;
#else
if (mkdir(path, 0755) == 0)
return true;
int err = errno;
if (err == EEXIST)
{
PanicAlert("%s already exists", path);
return true;
}
PanicAlert("Error creating directory %s: %s", path, strerror(err));
return false;
#endif
}
// Create several dirs
bool CreateDirectoryStructure(const std::string& _rFullPath)
{
int PanicCounter = 10;
size_t Position = 0;
while(true)
{
// Find next sub path, support both \ and / directory separators
{
size_t nextPosition = _rFullPath.find(DIR_SEP_CHR, Position);
Position = nextPosition;
if (Position == std::string::npos)
return true;
Position++;
}
// Create next sub path
std::string SubPath = _rFullPath.substr(0, Position);
if (!SubPath.empty())
{
if (!File::IsDirectory(SubPath.c_str()))
{
File::CreateDir(SubPath.c_str());
LOG(WII_IPC_FILEIO, " CreateSubDir %s", SubPath.c_str());
}
}
// A safety check
PanicCounter--;
if (PanicCounter <= 0)
{
PanicAlert("CreateDirectoryStruct creates way to much dirs...");
return false;
}
}
}
bool DeleteDir(const char *filename)
{
if (!File::IsDirectory(filename))
return false;
#ifdef _WIN32
return ::RemoveDirectory (filename) ? true : false;
#else
if (rmdir(filename) == 0)
return true;
int err = errno;
PanicAlert("Error removing directory %s",strerror(err));
return false;
#endif
}
bool Rename(const char *srcFilename, const char *destFilename)
{
return (rename(srcFilename, destFilename) == 0);
}
bool Copy(const char *srcFilename, const char *destFilename)
{
#ifdef _WIN32
return (CopyFile(srcFilename, destFilename, FALSE) == TRUE) ? true : false;
#else
#define BSIZE 1024
int rnum, wnum, err;
char buffer[BSIZE];
FILE *output, *input;
if (! (input = fopen(srcFilename, "r"))) {
err = errno;
PanicAlert("Error copying from %s: %s", srcFilename, strerror(err));
return false;
}
if (! (output = fopen(destFilename, "w"))) {
err = errno;
PanicAlert("Error copying to %s: %s", destFilename, strerror(err));
return false;
}
while(! feof(input)) {
if((rnum = fread(buffer, sizeof(char), BSIZE, input)) != BSIZE) {
if(ferror(input) != 0){
PanicAlert("can't read source file\n");
return false;
}
}
if((wnum = fwrite(buffer, sizeof(char), rnum, output))!= rnum){
PanicAlert("can't write output file\n");
return false;
}
}
fclose(input);
fclose(output);
return true;
/*
std::ifstream ifs(srcFilename, std::ios::binary);
std::ofstream ofs(destFilename, std::ios::binary);
ofs << ifs.rdbuf();
ifs.close();
ofs.close();
return true;*/
#endif
}
std::string GetUserDirectory()
{
#ifdef _WIN32
char path[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path)))
{
return std::string(path);
}
return std::string("");
#else
char *dir = getenv("HOME");
if (!dir)
return std::string("");
return dir;
#endif
}
u64 GetSize(const char *filename)
{
if(!Exists(filename))
return 0;
struct stat buf;
if (stat(filename, &buf) == 0) {
return buf.st_size;
}
int err = errno;
PanicAlert("Error accessing %s: %s", filename, strerror(err));
return 0;
}
#ifdef _WIN32
static bool ReadFoundFile(const WIN32_FIND_DATA& ffd, FSTEntry& entry)
{
// ignore files starting with a .
if(strncmp(ffd.cFileName, ".", 1) == 0)
return false;
entry.virtualName = ffd.cFileName;
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
entry.isDirectory = true;
}
else
{
entry.isDirectory = false;
entry.size = ffd.nFileSizeLow;
}
return true;
}
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
{
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
std::string searchName = _Directory + "\\*";
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
u32 foundEntries = 0;
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
FSTEntry entry;
if(ReadFoundFile(ffd, entry))
{
entry.physicalName = _Directory + "\\" + entry.virtualName;
if(entry.isDirectory)
{
u32 childEntries = ScanDirectoryTree(entry.physicalName, entry);
entry.size = childEntries;
foundEntries += childEntries;
}
++foundEntries;
parentEntry.children.push_back(entry);
}
} while (FindNextFile(hFind, &ffd) != 0);
}
FindClose(hFind);
return foundEntries;
}
#else
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
{
PanicAlert("Scan directory not implemanted yet\n");
// TODO - Insert linux stuff here
return 0;
}
#endif
bool CreateEmptyFile(const char *filename)
{
FILE* pFile = fopen(filename, "wb");
if (pFile == NULL)
return false;
fclose(pFile);
return true;
}
bool DeleteDirRecursively(const std::string& _Directory)
{
#ifdef _WIN32
bool Result = false;
WIN32_FIND_DATA ffd;
std::string searchName = _Directory + "\\*";
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
// check for "." and ".."
if (((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == 0x00)) ||
((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == '.') && (ffd.cFileName[2] == 0x00)))
continue;
// build path
std::string newPath(_Directory);
newPath += '\\';
newPath += ffd.cFileName;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!File::DeleteDirRecursively(newPath))
goto error_jmp;
}
else
{
if (!File::Delete(newPath.c_str()))
goto error_jmp;
}
} while (FindNextFile(hFind, &ffd) != 0);
}
if (!File::DeleteDir(_Directory.c_str()))
goto error_jmp;
Result = true;
error_jmp:
FindClose(hFind);
return Result;
#else
// taken from http://www.dreamincode.net/code/snippet2700.htm
DIR *pdir = NULL;
pdir = opendir (_Directory.c_str());
struct dirent *pent = NULL;
if (pdir == NULL) {
return false;
}
char file[256];
int counter = 1;
while ((pent = readdir(pdir))) {
if (counter > 2) {
for (int i = 0; i < 256; i++) file[i] = '\0';
strcat(file, _Directory.c_str());
if (pent == NULL) {
return false;
}
strcat(file, pent->d_name);
if (IsDirectory(file) == true) {
DeleteDir(file);
} else {
remove(file);
}
}
counter++;
}
return DeleteDir(_Directory.c_str());
#endif
}
void GetCurrentDirectory(std::string& _rDirectory)
{
char tmpBuffer[MAX_PATH+1];
getcwd(tmpBuffer, MAX_PATH);
_rDirectory = tmpBuffer;
}
} // namespace
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "FileUtil.h"
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h> // for SHGetFolderPath
#include <shellapi.h>
#include <commdlg.h> // for GetSaveFileName
#include <io.h>
#include <direct.h> // getcwd
#else
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#endif
#include <fstream>
#include <sys/stat.h>
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif
namespace File
{
// =======================================================
// Remove any ending forward slashes from directory paths
// -------------
inline void StripTailDirSlashes(std::string& fname)
{
// Make sure it's not a blank string
if(fname.length() > 0)
{
while(fname.at(fname.length() - 1) == DIR_SEP_CHR)
fname.resize(fname.length() - 1);
}
}
// =============
bool Exists(const char *filename)
{
struct stat file_info;
std::string copy = filename;
StripTailDirSlashes(copy);
int result = stat(copy.c_str(), &file_info);
return (result == 0);
}
bool IsDirectory(const char *filename)
{
struct stat file_info;
std::string copy = filename;
StripTailDirSlashes(copy);
int result = stat(copy.c_str(), &file_info);
if (result == 0)
return S_ISDIR(file_info.st_mode);
else
return false;
}
bool Delete(const char *filename)
{
if (!Exists(filename))
return false;
if (IsDirectory(filename))
return false;
#ifdef _WIN32
DeleteFile(filename);
#else
unlink(filename);
#endif
return true;
}
std::string SanitizePath(const char *filename)
{
std::string copy = filename;
#ifdef _WIN32
for (size_t i = 0; i < copy.size(); i++)
if (copy[i] == '/')
copy[i] = '\\';
#else
// Should we do the otherway around?
#endif
return copy;
}
void Launch(const char *filename)
{
#ifdef _WIN32
std::string win_filename = SanitizePath(filename);
SHELLEXECUTEINFO shex = { sizeof(shex) };
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
shex.lpVerb = "open";
shex.lpFile = win_filename.c_str();
shex.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&shex);
#else
// TODO: Insert GNOME/KDE code here.
#endif
}
void Explore(const char *path)
{
#ifdef _WIN32
std::string win_path = SanitizePath(path);
SHELLEXECUTEINFO shex = { sizeof(shex) };
shex.fMask = SEE_MASK_NO_CONSOLE; // | SEE_MASK_ASYNC_OK;
shex.lpVerb = "explore";
shex.lpFile = win_path.c_str();
shex.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&shex);
#else
// TODO: Insert GNOME/KDE code here.
#endif
}
// Returns true if successful, or path already exists.
bool CreateDir(const char *path)
{
#ifdef _WIN32
if (::CreateDirectory(path, NULL))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
{
PanicAlert("%s already exists", path);
return true;
}
PanicAlert("Error creating directory %s: %i", path, error);
return false;
#else
if (mkdir(path, 0755) == 0)
return true;
int err = errno;
if (err == EEXIST)
{
PanicAlert("%s already exists", path);
return true;
}
PanicAlert("Error creating directory %s: %s", path, strerror(err));
return false;
#endif
}
// Create several dirs
bool CreateDirectoryStructure(const std::string& _rFullPath)
{
int PanicCounter = 10;
size_t Position = 0;
while(true)
{
// Find next sub path, support both \ and / directory separators
{
size_t nextPosition = _rFullPath.find(DIR_SEP_CHR, Position);
Position = nextPosition;
if (Position == std::string::npos)
return true;
Position++;
}
// Create next sub path
std::string SubPath = _rFullPath.substr(0, Position);
if (!SubPath.empty())
{
if (!File::IsDirectory(SubPath.c_str()))
{
File::CreateDir(SubPath.c_str());
LOG(WII_IPC_FILEIO, " CreateSubDir %s", SubPath.c_str());
}
}
// A safety check
PanicCounter--;
if (PanicCounter <= 0)
{
PanicAlert("CreateDirectoryStruct creates way to much dirs...");
return false;
}
}
}
bool DeleteDir(const char *filename)
{
if (!File::IsDirectory(filename))
return false;
#ifdef _WIN32
return ::RemoveDirectory (filename) ? true : false;
#else
if (rmdir(filename) == 0)
return true;
int err = errno;
PanicAlert("Error removing directory %s",strerror(err));
return false;
#endif
}
bool Rename(const char *srcFilename, const char *destFilename)
{
return (rename(srcFilename, destFilename) == 0);
}
bool Copy(const char *srcFilename, const char *destFilename)
{
#ifdef _WIN32
return (CopyFile(srcFilename, destFilename, FALSE) == TRUE) ? true : false;
#else
#define BSIZE 1024
int rnum, wnum, err;
char buffer[BSIZE];
FILE *output, *input;
if (! (input = fopen(srcFilename, "r"))) {
err = errno;
PanicAlert("Error copying from %s: %s", srcFilename, strerror(err));
return false;
}
if (! (output = fopen(destFilename, "w"))) {
err = errno;
PanicAlert("Error copying to %s: %s", destFilename, strerror(err));
return false;
}
while(! feof(input)) {
if((rnum = fread(buffer, sizeof(char), BSIZE, input)) != BSIZE) {
if(ferror(input) != 0){
PanicAlert("can't read source file\n");
return false;
}
}
if((wnum = fwrite(buffer, sizeof(char), rnum, output))!= rnum){
PanicAlert("can't write output file\n");
return false;
}
}
fclose(input);
fclose(output);
return true;
/*
std::ifstream ifs(srcFilename, std::ios::binary);
std::ofstream ofs(destFilename, std::ios::binary);
ofs << ifs.rdbuf();
ifs.close();
ofs.close();
return true;*/
#endif
}
std::string GetUserDirectory()
{
#ifdef _WIN32
char path[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path)))
{
return std::string(path);
}
return std::string("");
#else
char *dir = getenv("HOME");
if (!dir)
return std::string("");
return dir;
#endif
}
u64 GetSize(const char *filename)
{
if(!Exists(filename))
return 0;
struct stat buf;
if (stat(filename, &buf) == 0) {
return buf.st_size;
}
int err = errno;
PanicAlert("Error accessing %s: %s", filename, strerror(err));
return 0;
}
#ifdef _WIN32
static bool ReadFoundFile(const WIN32_FIND_DATA& ffd, FSTEntry& entry)
{
// ignore files starting with a .
if(strncmp(ffd.cFileName, ".", 1) == 0)
return false;
entry.virtualName = ffd.cFileName;
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
entry.isDirectory = true;
}
else
{
entry.isDirectory = false;
entry.size = ffd.nFileSizeLow;
}
return true;
}
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
{
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
std::string searchName = _Directory + "\\*";
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
u32 foundEntries = 0;
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
FSTEntry entry;
if(ReadFoundFile(ffd, entry))
{
entry.physicalName = _Directory + "\\" + entry.virtualName;
if(entry.isDirectory)
{
u32 childEntries = ScanDirectoryTree(entry.physicalName, entry);
entry.size = childEntries;
foundEntries += childEntries;
}
++foundEntries;
parentEntry.children.push_back(entry);
}
} while (FindNextFile(hFind, &ffd) != 0);
}
FindClose(hFind);
return foundEntries;
}
#else
u32 ScanDirectoryTree(const std::string& _Directory, FSTEntry& parentEntry)
{
PanicAlert("Scan directory not implemanted yet\n");
// TODO - Insert linux stuff here
return 0;
}
#endif
bool CreateEmptyFile(const char *filename)
{
FILE* pFile = fopen(filename, "wb");
if (pFile == NULL)
return false;
fclose(pFile);
return true;
}
bool DeleteDirRecursively(const std::string& _Directory)
{
#ifdef _WIN32
bool Result = false;
WIN32_FIND_DATA ffd;
std::string searchName = _Directory + "\\*";
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
// check for "." and ".."
if (((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == 0x00)) ||
((ffd.cFileName[0] == '.') && (ffd.cFileName[1] == '.') && (ffd.cFileName[2] == 0x00)))
continue;
// build path
std::string newPath(_Directory);
newPath += '\\';
newPath += ffd.cFileName;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!File::DeleteDirRecursively(newPath))
goto error_jmp;
}
else
{
if (!File::Delete(newPath.c_str()))
goto error_jmp;
}
} while (FindNextFile(hFind, &ffd) != 0);
}
if (!File::DeleteDir(_Directory.c_str()))
goto error_jmp;
Result = true;
error_jmp:
FindClose(hFind);
return Result;
#else
// taken from http://www.dreamincode.net/code/snippet2700.htm
DIR *pdir = NULL;
pdir = opendir (_Directory.c_str());
struct dirent *pent = NULL;
if (pdir == NULL) {
return false;
}
char file[256];
int counter = 1;
while ((pent = readdir(pdir))) {
if (counter > 2) {
for (int i = 0; i < 256; i++) file[i] = '\0';
strcat(file, _Directory.c_str());
if (pent == NULL) {
return false;
}
strcat(file, pent->d_name);
if (IsDirectory(file) == true) {
DeleteDir(file);
} else {
remove(file);
}
}
counter++;
}
return DeleteDir(_Directory.c_str());
#endif
}
void GetCurrentDirectory(std::string& _rDirectory)
{
char tmpBuffer[MAX_PATH+1];
getcwd(tmpBuffer, MAX_PATH);
_rDirectory = tmpBuffer;
}
} // namespace

View File

@ -1,136 +1,136 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Hash.h"
// uint32_t
// WARNING - may read one more byte!
// Implementation from Wikipedia.
u32 HashFletcher(const u8* data_u8, size_t length)
{
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
size_t len = (length + 1) / 2; /* Length in 16-bit words */
u32 sum1 = 0xffff, sum2 = 0xffff;
while (len)
{
size_t tlen = len > 360 ? 360 : len;
len -= tlen;
do {
sum1 += *data++;
sum2 += sum1;
}
while (--tlen);
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
}
/* Second reduction step to reduce sums to 16 bits */
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
return(sum2 << 16 | sum1);
}
// Implementation from Wikipedia
// Slightly slower than Fletcher above, but slighly more reliable.
#define MOD_ADLER 65521
// data: Pointer to the data to be summed; len is in bytes
u32 HashAdler32(const u8* data, size_t len)
{
u32 a = 1, b = 0;
while (len)
{
size_t tlen = len > 5550 ? 5550 : len;
len -= tlen;
do
{
a += *data++;
b += a;
}
while (--tlen);
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
}
// It can be shown that a <= 0x1013a here, so a single subtract will do.
if (a >= MOD_ADLER)
{
a -= MOD_ADLER;
}
// It can be shown that b can reach 0xfff87 here.
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
if (b >= MOD_ADLER)
{
b -= MOD_ADLER;
}
return((b << 16) | a);
}
// Another fast and decent hash
u32 HashFNV(const u8* ptr, int length)
{
u32 hash = 0x811c9dc5;
for (int i = 0; i < length; i++)
{
hash *= 1677761;
hash ^= ptr[i];
}
return(hash);
}
// Another fast and decent hash
u32 HashFNV1(const u8* ptr, int length)
{
u32 hash = 0x811c9dc5;
for (int i = 0; i < length; i++)
{
hash *= 1677761;
hash ^= ptr[i];
}
return(hash);
}
// Stupid hash - but can't go back now :)
// Don't use for new things. At least it's reasonably fast.
u32 HashEctor(const u8* ptr, int length)
{
u32 crc = 0;
for (int i = 0; i < length; i++)
{
crc ^= ptr[i];
crc = (crc << 3) | (crc >> 29);
}
return(crc);
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Hash.h"
// uint32_t
// WARNING - may read one more byte!
// Implementation from Wikipedia.
u32 HashFletcher(const u8* data_u8, size_t length)
{
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
size_t len = (length + 1) / 2; /* Length in 16-bit words */
u32 sum1 = 0xffff, sum2 = 0xffff;
while (len)
{
size_t tlen = len > 360 ? 360 : len;
len -= tlen;
do {
sum1 += *data++;
sum2 += sum1;
}
while (--tlen);
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
}
/* Second reduction step to reduce sums to 16 bits */
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
return(sum2 << 16 | sum1);
}
// Implementation from Wikipedia
// Slightly slower than Fletcher above, but slighly more reliable.
#define MOD_ADLER 65521
// data: Pointer to the data to be summed; len is in bytes
u32 HashAdler32(const u8* data, size_t len)
{
u32 a = 1, b = 0;
while (len)
{
size_t tlen = len > 5550 ? 5550 : len;
len -= tlen;
do
{
a += *data++;
b += a;
}
while (--tlen);
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
}
// It can be shown that a <= 0x1013a here, so a single subtract will do.
if (a >= MOD_ADLER)
{
a -= MOD_ADLER;
}
// It can be shown that b can reach 0xfff87 here.
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
if (b >= MOD_ADLER)
{
b -= MOD_ADLER;
}
return((b << 16) | a);
}
// Another fast and decent hash
u32 HashFNV(const u8* ptr, int length)
{
u32 hash = 0x811c9dc5;
for (int i = 0; i < length; i++)
{
hash *= 1677761;
hash ^= ptr[i];
}
return(hash);
}
// Another fast and decent hash
u32 HashFNV1(const u8* ptr, int length)
{
u32 hash = 0x811c9dc5;
for (int i = 0; i < length; i++)
{
hash *= 1677761;
hash ^= ptr[i];
}
return(hash);
}
// Stupid hash - but can't go back now :)
// Don't use for new things. At least it's reasonably fast.
u32 HashEctor(const u8* ptr, int length)
{
u32 crc = 0;
for (int i = 0; i < length; i++)
{
crc ^= ptr[i];
crc = (crc << 3) | (crc >> 29);
}
return(crc);
}

View File

@ -1,469 +1,469 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// see IniFile.h
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
#include "StringUtil.h"
#include "IniFile.h"
IniFile::IniFile()
{}
IniFile::~IniFile()
{}
Section::Section()
: lines(), name(""), comment("") {}
Section::Section(const std::string& _name)
: lines(), name(_name), comment("") {}
Section::Section(const Section& other)
{
name = other.name;
comment = other.comment;
lines = other.lines;
}
const Section* IniFile::GetSection(const char* sectionName) const
{
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
if (!strcmp(iter->name.c_str(), sectionName))
return (&(*iter));
return 0;
}
Section* IniFile::GetSection(const char* sectionName)
{
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
if (!strcmp(iter->name.c_str(), sectionName))
return (&(*iter));
return 0;
}
Section* IniFile::GetOrCreateSection(const char* sectionName)
{
Section* section = GetSection(sectionName);
if (!section)
{
sections.push_back(Section(sectionName));
section = &sections[sections.size() - 1];
}
return(section);
}
bool IniFile::DeleteSection(const char* sectionName)
{
Section* s = GetSection(sectionName);
if (!s)
{
return false;
}
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
if (&(*iter) == s)
{
sections.erase(iter);
return true;
}
}
return false;
}
void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const
{
// allow many types of commenting
// These MUST be signed! Do not change to size_t
int firstEquals = (int)line.find("=", 0);
int firstCommentChar = (int)line.find(";", 0);
if (firstCommentChar < 0){firstCommentChar = (int)line.find("#", firstEquals > 0 ? firstEquals : 0);}
if (firstCommentChar < 0){firstCommentChar = (int)line.find("//", firstEquals > 0 ? firstEquals : 0);}
// allow preserval of spacing before comment
if (firstCommentChar > 0)
{
while (line[firstCommentChar - 1] == ' ' || line[firstCommentChar - 1] == 9) // 9 == tab
{
firstCommentChar--;
}
}
if ((firstEquals >= 0) && ((firstCommentChar < 0) || (firstEquals < firstCommentChar)))
{
// Yes, a valid line!
*keyOut = StripSpaces(line.substr(0, firstEquals));
if (commentOut)
{
*commentOut = firstCommentChar > 0 ? line.substr(firstCommentChar) : std::string("");
}
if (valueOut)
{
*valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, firstCommentChar - firstEquals - 1)));
}
}
}
std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut)
{
for (std::vector<std::string>::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string& line = *iter;
std::string lineKey;
ParseLine(line, &lineKey, valueOut, commentOut);
if (!stricmp(lineKey.c_str(), key))
{
return &line;
}
}
return 0;
}
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
{
Section* section = GetOrCreateSection(sectionName);
std::string value, comment;
std::string* line = GetLine(section, key, &value, &comment);
if (line)
{
// Change the value - keep the key and comment
*line = StripSpaces(key) + " = " + newValue + comment;
}
else
{
// The key did not already exist in this section - let's add it.
section->lines.push_back(std::string(key) + " = " + newValue);
}
}
void IniFile::Set(const char* sectionName, const char* key, u32 newValue)
{
Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str());
}
void IniFile::Set(const char* sectionName, const char* key, int newValue)
{
Set(sectionName, key, StringFromInt(newValue).c_str());
}
void IniFile::Set(const char* sectionName, const char* key, bool newValue)
{
Set(sectionName, key, StringFromBool(newValue).c_str());
}
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
}
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
{
Section* section = GetSection(sectionName);
if (!section)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
std::string* line = GetLine(section, key, value, 0);
if (!line)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
return true;
}
bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseInt(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseUInt(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseBool(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::DeleteKey(const char* sectionName, const char* key)
{
Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
std::string* line = GetLine(section, key, 0, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
}
bool IniFile::Load(const char* filename)
{
sections.clear();
sections.push_back(Section(""));
//first section consists of the comments before the first real section
std::ifstream in;
in.open(filename, std::ios::in);
if (in.fail())
{
return false;
}
while (!in.eof())
{
char templine[512];
in.getline(templine, 512);
std::string line = templine;
if (in.eof())
{
break;
}
if (line.size() > 0)
{
if (line[0] == '[')
{
size_t endpos = line.find("]");
if (endpos != std::string::npos)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
if (endpos + 1 < line.size())
{
sections[sections.size() - 1].comment = line.substr(endpos + 1);
}
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
}
}
}
in.close();
return true;
}
bool IniFile::Save(const char* filename)
{
std::ofstream out;
out.open(filename, std::ios::out);
if (out.fail())
{
return false;
}
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
if (section.name != "")
{
out << "[" << section.name << "]" << section.comment << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
out.close();
return true;
}
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
{
const Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0, 0);
keys.push_back(key);
}
return true;
}
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
{
const Section* section = GetSection(sectionName);
if (!section)
return false;
lines.clear();
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string line = StripSpaces(*iter);
int commentPos = (int)line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != (int)std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
lines.push_back(line);
}
return true;
}
void IniFile::SortSections()
{
std::sort(sections.begin(), sections.end());
}
/*
int main()
{
IniFile ini;
ini.Load("my.ini");
ini.Set("Hej", "A", "amaskdfl");
ini.Set("Mossa", "A", "amaskdfl");
ini.Set("Aissa", "A", "amaskdfl");
//ini.Read("my.ini");
std::string x;
ini.Get("Hej", "B", &x, "boo");
ini.DeleteKey("Mossa", "A");
ini.DeleteSection("Mossa");
ini.SortSections();
ini.Save("my.ini");
//UpdateVars(ini);
return 0;
}
*/
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// see IniFile.h
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
#include "StringUtil.h"
#include "IniFile.h"
IniFile::IniFile()
{}
IniFile::~IniFile()
{}
Section::Section()
: lines(), name(""), comment("") {}
Section::Section(const std::string& _name)
: lines(), name(_name), comment("") {}
Section::Section(const Section& other)
{
name = other.name;
comment = other.comment;
lines = other.lines;
}
const Section* IniFile::GetSection(const char* sectionName) const
{
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
if (!strcmp(iter->name.c_str(), sectionName))
return (&(*iter));
return 0;
}
Section* IniFile::GetSection(const char* sectionName)
{
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
if (!strcmp(iter->name.c_str(), sectionName))
return (&(*iter));
return 0;
}
Section* IniFile::GetOrCreateSection(const char* sectionName)
{
Section* section = GetSection(sectionName);
if (!section)
{
sections.push_back(Section(sectionName));
section = &sections[sections.size() - 1];
}
return(section);
}
bool IniFile::DeleteSection(const char* sectionName)
{
Section* s = GetSection(sectionName);
if (!s)
{
return false;
}
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
if (&(*iter) == s)
{
sections.erase(iter);
return true;
}
}
return false;
}
void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const
{
// allow many types of commenting
// These MUST be signed! Do not change to size_t
int firstEquals = (int)line.find("=", 0);
int firstCommentChar = (int)line.find(";", 0);
if (firstCommentChar < 0){firstCommentChar = (int)line.find("#", firstEquals > 0 ? firstEquals : 0);}
if (firstCommentChar < 0){firstCommentChar = (int)line.find("//", firstEquals > 0 ? firstEquals : 0);}
// allow preserval of spacing before comment
if (firstCommentChar > 0)
{
while (line[firstCommentChar - 1] == ' ' || line[firstCommentChar - 1] == 9) // 9 == tab
{
firstCommentChar--;
}
}
if ((firstEquals >= 0) && ((firstCommentChar < 0) || (firstEquals < firstCommentChar)))
{
// Yes, a valid line!
*keyOut = StripSpaces(line.substr(0, firstEquals));
if (commentOut)
{
*commentOut = firstCommentChar > 0 ? line.substr(firstCommentChar) : std::string("");
}
if (valueOut)
{
*valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, firstCommentChar - firstEquals - 1)));
}
}
}
std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut)
{
for (std::vector<std::string>::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string& line = *iter;
std::string lineKey;
ParseLine(line, &lineKey, valueOut, commentOut);
if (!stricmp(lineKey.c_str(), key))
{
return &line;
}
}
return 0;
}
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
{
Section* section = GetOrCreateSection(sectionName);
std::string value, comment;
std::string* line = GetLine(section, key, &value, &comment);
if (line)
{
// Change the value - keep the key and comment
*line = StripSpaces(key) + " = " + newValue + comment;
}
else
{
// The key did not already exist in this section - let's add it.
section->lines.push_back(std::string(key) + " = " + newValue);
}
}
void IniFile::Set(const char* sectionName, const char* key, u32 newValue)
{
Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str());
}
void IniFile::Set(const char* sectionName, const char* key, int newValue)
{
Set(sectionName, key, StringFromInt(newValue).c_str());
}
void IniFile::Set(const char* sectionName, const char* key, bool newValue)
{
Set(sectionName, key, StringFromBool(newValue).c_str());
}
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
}
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
{
Section* section = GetSection(sectionName);
if (!section)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
std::string* line = GetLine(section, key, value, 0);
if (!line)
{
if (defaultValue)
{
*value = defaultValue;
}
return false;
}
return true;
}
bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseInt(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseUInt(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue)
{
std::string temp;
bool retval = Get(sectionName, key, &temp, 0);
if (retval && TryParseBool(temp.c_str(), value))
{
return true;
}
*value = defaultValue;
return false;
}
bool IniFile::DeleteKey(const char* sectionName, const char* key)
{
Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
std::string* line = GetLine(section, key, 0, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
}
bool IniFile::Load(const char* filename)
{
sections.clear();
sections.push_back(Section(""));
//first section consists of the comments before the first real section
std::ifstream in;
in.open(filename, std::ios::in);
if (in.fail())
{
return false;
}
while (!in.eof())
{
char templine[512];
in.getline(templine, 512);
std::string line = templine;
if (in.eof())
{
break;
}
if (line.size() > 0)
{
if (line[0] == '[')
{
size_t endpos = line.find("]");
if (endpos != std::string::npos)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
if (endpos + 1 < line.size())
{
sections[sections.size() - 1].comment = line.substr(endpos + 1);
}
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
}
}
}
in.close();
return true;
}
bool IniFile::Save(const char* filename)
{
std::ofstream out;
out.open(filename, std::ios::out);
if (out.fail())
{
return false;
}
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
if (section.name != "")
{
out << "[" << section.name << "]" << section.comment << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
out.close();
return true;
}
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
{
const Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0, 0);
keys.push_back(key);
}
return true;
}
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
{
const Section* section = GetSection(sectionName);
if (!section)
return false;
lines.clear();
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string line = StripSpaces(*iter);
int commentPos = (int)line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != (int)std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
lines.push_back(line);
}
return true;
}
void IniFile::SortSections()
{
std::sort(sections.begin(), sections.end());
}
/*
int main()
{
IniFile ini;
ini.Load("my.ini");
ini.Set("Hej", "A", "amaskdfl");
ini.Set("Mossa", "A", "amaskdfl");
ini.Set("Aissa", "A", "amaskdfl");
//ini.Read("my.ini");
std::string x;
ini.Get("Hej", "B", &x, "boo");
ini.DeleteKey("Mossa", "A");
ini.DeleteSection("Mossa");
ini.SortSections();
ini.Save("my.ini");
//UpdateVars(ini);
return 0;
}
*/

View File

@ -1,233 +1,233 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include "Common.h"
#include "MappedFile.h"
namespace Common
{
class CMappedFile
: public IMappedFile
{
public:
CMappedFile(void);
~CMappedFile(void);
bool Open(const char* _szFilename);
bool IsOpen(void);
void Close(void);
u64 GetSize(void);
u8* Lock(u64 _offset, u64 _size);
void Unlock(u8* ptr);
private:
u64 size;
typedef std::map<u8*, u8*>Lockmap;
Lockmap lockMap;
#ifdef _WIN32
HANDLE hFile;
HANDLE hFileMapping;
#elif POSIX
int fd;
typedef std::map<u8*, size_t>Sizemap;
Sizemap sizeMap;
#endif
int granularity;
};
CMappedFile::CMappedFile()
{
#ifdef _WIN32
hFile = INVALID_HANDLE_VALUE;
SYSTEM_INFO info;
GetSystemInfo(&info);
granularity = (int)info.dwAllocationGranularity;
#elif POSIX
fd = -1;
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
#endif
}
CMappedFile::~CMappedFile()
{
Close();
}
bool CMappedFile::Open(const char* filename)
{
Close();
#ifdef _WIN32
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return(false);
}
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == NULL)
{
CloseHandle(hFile);
hFile = 0;
return(false);
}
u32 high = 0;
u32 low = GetFileSize(hFile, (LPDWORD)&high);
size = (u64)low | ((u64)high << 32);
#elif POSIX
fd = open(filename, O_RDONLY);
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
#endif
return(true);
}
bool CMappedFile::IsOpen()
{
#ifdef _WIN32
return(hFile != INVALID_HANDLE_VALUE);
#elif POSIX
return(fd != -1);
#endif
}
u64 CMappedFile::GetSize()
{
return(size);
}
void CMappedFile::Close()
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
lockMap.clear();
hFile = INVALID_HANDLE_VALUE;
}
#elif POSIX
if (fd != -1)
{
lockMap.clear();
sizeMap.clear();
close(fd);
}
fd = -1;
#endif
}
u8* CMappedFile::Lock(u64 offset, u64 _size)
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
#elif POSIX
if (fd != -1)
#endif
{
u64 realOffset = offset & ~(granularity - 1);
s64 difference = offset - realOffset;
u64 fake_size = (difference + _size + granularity - 1) & ~(granularity - 1);
#ifdef _WIN32
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(_size));
if (realPtr == NULL)
{
return(NULL);
}
#elif POSIX
// TODO
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
if (!realPtr)
{
PanicAlert("Map Failed");
exit(0);
}
#endif
u8* fakePtr = realPtr + difference;
//add to map
lockMap[fakePtr] = realPtr;
#ifndef _WIN32
sizeMap[fakePtr] = _size + difference;
#endif
return(fakePtr);
}
else
{
return(0);
}
}
void CMappedFile::Unlock(u8* ptr)
{
if (ptr != 0)
{
Lockmap::iterator iter = lockMap.find(ptr);
if (iter != lockMap.end())
{
#ifdef _WIN32
UnmapViewOfFile((*iter).second);
#else
munmap((*iter).second, sizeMap[ptr]);
#endif
lockMap.erase(iter);
}
else
{
PanicAlert("CMappedFile : Unlock failed");
}
}
}
IMappedFile* IMappedFile::CreateMappedFileDEPRECATED(void)
{
return(new CMappedFile);
}
} // end of namespace Common
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include "Common.h"
#include "MappedFile.h"
namespace Common
{
class CMappedFile
: public IMappedFile
{
public:
CMappedFile(void);
~CMappedFile(void);
bool Open(const char* _szFilename);
bool IsOpen(void);
void Close(void);
u64 GetSize(void);
u8* Lock(u64 _offset, u64 _size);
void Unlock(u8* ptr);
private:
u64 size;
typedef std::map<u8*, u8*>Lockmap;
Lockmap lockMap;
#ifdef _WIN32
HANDLE hFile;
HANDLE hFileMapping;
#elif POSIX
int fd;
typedef std::map<u8*, size_t>Sizemap;
Sizemap sizeMap;
#endif
int granularity;
};
CMappedFile::CMappedFile()
{
#ifdef _WIN32
hFile = INVALID_HANDLE_VALUE;
SYSTEM_INFO info;
GetSystemInfo(&info);
granularity = (int)info.dwAllocationGranularity;
#elif POSIX
fd = -1;
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
#endif
}
CMappedFile::~CMappedFile()
{
Close();
}
bool CMappedFile::Open(const char* filename)
{
Close();
#ifdef _WIN32
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return(false);
}
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == NULL)
{
CloseHandle(hFile);
hFile = 0;
return(false);
}
u32 high = 0;
u32 low = GetFileSize(hFile, (LPDWORD)&high);
size = (u64)low | ((u64)high << 32);
#elif POSIX
fd = open(filename, O_RDONLY);
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
#endif
return(true);
}
bool CMappedFile::IsOpen()
{
#ifdef _WIN32
return(hFile != INVALID_HANDLE_VALUE);
#elif POSIX
return(fd != -1);
#endif
}
u64 CMappedFile::GetSize()
{
return(size);
}
void CMappedFile::Close()
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
lockMap.clear();
hFile = INVALID_HANDLE_VALUE;
}
#elif POSIX
if (fd != -1)
{
lockMap.clear();
sizeMap.clear();
close(fd);
}
fd = -1;
#endif
}
u8* CMappedFile::Lock(u64 offset, u64 _size)
{
#ifdef _WIN32
if (hFile != INVALID_HANDLE_VALUE)
#elif POSIX
if (fd != -1)
#endif
{
u64 realOffset = offset & ~(granularity - 1);
s64 difference = offset - realOffset;
u64 fake_size = (difference + _size + granularity - 1) & ~(granularity - 1);
#ifdef _WIN32
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(_size));
if (realPtr == NULL)
{
return(NULL);
}
#elif POSIX
// TODO
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
if (!realPtr)
{
PanicAlert("Map Failed");
exit(0);
}
#endif
u8* fakePtr = realPtr + difference;
//add to map
lockMap[fakePtr] = realPtr;
#ifndef _WIN32
sizeMap[fakePtr] = _size + difference;
#endif
return(fakePtr);
}
else
{
return(0);
}
}
void CMappedFile::Unlock(u8* ptr)
{
if (ptr != 0)
{
Lockmap::iterator iter = lockMap.find(ptr);
if (iter != lockMap.end())
{
#ifdef _WIN32
UnmapViewOfFile((*iter).second);
#else
munmap((*iter).second, sizeMap[ptr]);
#endif
lockMap.erase(iter);
}
else
{
PanicAlert("CMappedFile : Unlock failed");
}
}
}
IMappedFile* IMappedFile::CreateMappedFileDEPRECATED(void)
{
return(new CMappedFile);
}
} // end of namespace Common

View File

@ -1,44 +1,44 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <xmmintrin.h>
#include "Common.h"
#include "MathUtil.h"
static u32 saved_sse_state = _mm_getcsr();
static const u32 default_sse_state = _mm_getcsr();
void LoadDefaultSSEState()
{
_mm_setcsr(default_sse_state);
}
void LoadSSEState()
{
_mm_setcsr(saved_sse_state);
}
void SaveSSEState()
{
saved_sse_state = _mm_getcsr();
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <xmmintrin.h>
#include "Common.h"
#include "MathUtil.h"
static u32 saved_sse_state = _mm_getcsr();
static const u32 default_sse_state = _mm_getcsr();
void LoadDefaultSSEState()
{
_mm_setcsr(default_sse_state);
}
void LoadSSEState()
{
_mm_setcsr(saved_sse_state);
}
void SaveSSEState()
{
saved_sse_state = _mm_getcsr();
}

View File

@ -1,144 +1,144 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemArena.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#endif
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
const char* ram_temp_file = "/tmp/gc_mem.tmp";
void MemArena::GrabLowMemSpace(size_t size)
{
#ifdef _WIN32
hMemoryMapping = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
#else
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
ftruncate(fd, size);
return;
#endif
}
void MemArena::ReleaseSpace()
{
#ifdef _WIN32
CloseHandle(hMemoryMapping);
hMemoryMapping = 0;
#else
close(fd);
unlink(ram_temp_file);
#endif
}
void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem)
{
#ifdef _WIN32
return(MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size));
#else
void* ptr = mmap(0, size,
PROT_READ | PROT_WRITE,
MAP_SHARED
#ifdef __x86_64__
| (ensure_low_mem ? MAP_32BIT : 0)
#endif
, fd, offset);
if (!ptr)
{
PanicAlert("Failed to create view");
}
return(ptr);
#endif
}
void* MemArena::CreateViewAt(s64 offset, size_t size, void* base)
{
#ifdef _WIN32
return(MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base));
#else
return(mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset));
#endif
}
void MemArena::ReleaseView(void* view, size_t size)
{
#ifdef _WIN32
UnmapViewOfFile(view);
#else
munmap(view, size);
#endif
}
u8* MemArena::Find4GBBase()
{
#ifdef _M_X64
#ifdef _WIN32
// 64 bit
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
VirtualFree(base, 0, MEM_RELEASE);
return base;
#else
// Very precarious - mmap cannot return an error when trying to map already used pages.
// This makes the Windows approach above unusable on Linux, so we will simply pray...
return reinterpret_cast<u8*>(0x2300000000ULL);
#endif
#else
// 32 bit
#ifdef _WIN32
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
if (base) {
VirtualFree(base, 0, MEM_RELEASE);
}
return base;
#else
void* base = mmap(0, 0x31000000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
if (base == MAP_FAILED) {
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
return 0;
}
munmap(base, 0x31000000);
return static_cast<u8*>(base);
#endif
#endif
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemArena.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#endif
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
const char* ram_temp_file = "/tmp/gc_mem.tmp";
void MemArena::GrabLowMemSpace(size_t size)
{
#ifdef _WIN32
hMemoryMapping = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
#else
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
ftruncate(fd, size);
return;
#endif
}
void MemArena::ReleaseSpace()
{
#ifdef _WIN32
CloseHandle(hMemoryMapping);
hMemoryMapping = 0;
#else
close(fd);
unlink(ram_temp_file);
#endif
}
void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem)
{
#ifdef _WIN32
return(MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size));
#else
void* ptr = mmap(0, size,
PROT_READ | PROT_WRITE,
MAP_SHARED
#ifdef __x86_64__
| (ensure_low_mem ? MAP_32BIT : 0)
#endif
, fd, offset);
if (!ptr)
{
PanicAlert("Failed to create view");
}
return(ptr);
#endif
}
void* MemArena::CreateViewAt(s64 offset, size_t size, void* base)
{
#ifdef _WIN32
return(MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base));
#else
return(mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset));
#endif
}
void MemArena::ReleaseView(void* view, size_t size)
{
#ifdef _WIN32
UnmapViewOfFile(view);
#else
munmap(view, size);
#endif
}
u8* MemArena::Find4GBBase()
{
#ifdef _M_X64
#ifdef _WIN32
// 64 bit
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
VirtualFree(base, 0, MEM_RELEASE);
return base;
#else
// Very precarious - mmap cannot return an error when trying to map already used pages.
// This makes the Windows approach above unusable on Linux, so we will simply pray...
return reinterpret_cast<u8*>(0x2300000000ULL);
#endif
#else
// 32 bit
#ifdef _WIN32
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
if (base) {
VirtualFree(base, 0, MEM_RELEASE);
}
return base;
#else
void* base = mmap(0, 0x31000000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
if (base == MAP_FAILED) {
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
return 0;
}
munmap(base, 0x31000000);
return static_cast<u8*>(base);
#endif
#endif
}

View File

@ -1,135 +1,135 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemoryUtil.h"
#ifdef _WIN32
#include <windows.h>
#elif __GNUC__
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#endif
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
// MacOSX does not support MAP_VARIABLE
#ifndef MAP_VARIABLE
#define MAP_VARIABLE 0
#endif
// This is purposedely not a full wrapper for virtualalloc/mmap, but it
// provides exactly the primitive operations that Dolphin needs.
void* AllocateExecutableMemory(int size, bool low)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if ((u64)ptr >= 0x80000000)
{
PanicAlert("Executable memory ended up above 2GB!");
// If this happens, we have to implement a free ram search scheme. ector knows how.
}
return(ptr);
#else
void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE
#ifdef __x86_64__
| (low ? MAP_32BIT : 0)
#endif
, -1, 0); // | MAP_FIXED
// printf("Mapped executable memory at %p (size %i)\n", retval, size);
if (!retval)
{
PanicAlert("Failed to allocate executable memory, errno=%i", errno);
}
return(retval);
#endif
}
void* AllocateMemoryPages(int size)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
if (!ptr)
{
PanicAlert("Failed to allocate raw memory");
}
return(ptr);
#else
void* retval = mmap(0, size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
// printf("Mapped memory at %p (size %i)\n", retval, size);
if (!retval)
{
PanicAlert("Failed to allocate raw memory, errno=%i", errno);
}
return(retval);
#endif
}
void FreeMemoryPages(void* ptr, int size)
{
#ifdef _WIN32
if (ptr)
{
VirtualFree(ptr, 0, MEM_RELEASE);
ptr = NULL;
}
#else
munmap(ptr, size);
#endif
}
void WriteProtectMemory(void* ptr, int size, bool allowExecute)
{
#ifdef _WIN32
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, 0);
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
#endif
}
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute)
{
#ifdef _WIN32
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READONLY, 0);
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
#endif
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemoryUtil.h"
#ifdef _WIN32
#include <windows.h>
#elif __GNUC__
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#endif
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
// MacOSX does not support MAP_VARIABLE
#ifndef MAP_VARIABLE
#define MAP_VARIABLE 0
#endif
// This is purposedely not a full wrapper for virtualalloc/mmap, but it
// provides exactly the primitive operations that Dolphin needs.
void* AllocateExecutableMemory(int size, bool low)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if ((u64)ptr >= 0x80000000)
{
PanicAlert("Executable memory ended up above 2GB!");
// If this happens, we have to implement a free ram search scheme. ector knows how.
}
return(ptr);
#else
void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE
#ifdef __x86_64__
| (low ? MAP_32BIT : 0)
#endif
, -1, 0); // | MAP_FIXED
// printf("Mapped executable memory at %p (size %i)\n", retval, size);
if (!retval)
{
PanicAlert("Failed to allocate executable memory, errno=%i", errno);
}
return(retval);
#endif
}
void* AllocateMemoryPages(int size)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
if (!ptr)
{
PanicAlert("Failed to allocate raw memory");
}
return(ptr);
#else
void* retval = mmap(0, size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
// printf("Mapped memory at %p (size %i)\n", retval, size);
if (!retval)
{
PanicAlert("Failed to allocate raw memory, errno=%i", errno);
}
return(retval);
#endif
}
void FreeMemoryPages(void* ptr, int size)
{
#ifdef _WIN32
if (ptr)
{
VirtualFree(ptr, 0, MEM_RELEASE);
ptr = NULL;
}
#else
munmap(ptr, size);
#endif
}
void WriteProtectMemory(void* ptr, int size, bool allowExecute)
{
#ifdef _WIN32
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, 0);
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
#endif
}
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute)
{
#ifdef _WIN32
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READONLY, 0);
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
#endif
}

View File

@ -1,100 +1,100 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// =======================================================
// File description
// -------------
/* This file is a simpler version of Plugin_...cpp found in Core. This file only loads
the config and debugging windowses and works with all plugins. */
// =============
#include "Plugin.h"
namespace Common
{
DynamicLibrary CPlugin::m_hInstLib;
void(__cdecl * CPlugin::m_GetDllInfo) (PLUGIN_INFO * _PluginInfo) = 0;
//void(__cdecl * CPlugin::m_DllAbout) (HWND _hParent) = 0;
void(__cdecl * CPlugin::m_DllConfig) (HWND _hParent) = 0;
void(__cdecl * CPlugin::m_DllDebugger) (HWND _hParent, bool Show) = 0;
void
CPlugin::Release(void)
{
m_GetDllInfo = 0;
//m_DllAbout = 0;
m_DllConfig = 0;
m_DllDebugger = 0;
m_hInstLib.Unload();
}
bool
CPlugin::Load(const char* _szName)
{
if (m_hInstLib.Load(_szName))
{
m_GetDllInfo = (void (__cdecl*)(PLUGIN_INFO*)) m_hInstLib.Get("GetDllInfo");
m_DllConfig = (void (__cdecl*)(HWND)) m_hInstLib.Get("DllConfig");
m_DllDebugger = (void (__cdecl*)(HWND, bool)) m_hInstLib.Get("DllDebugger");
return(true);
}
return(false);
}
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
{
if (m_GetDllInfo != 0)
{
m_GetDllInfo(&_pluginInfo);
return(true);
}
return(false);
}
void CPlugin::Config(HWND _hwnd)
{
if (m_DllConfig != 0)
{
m_DllConfig(_hwnd);
}
}
//void CPlugin::About(HWND _hwnd)
//{
// if (m_DllAbout != 0)
// {
// m_DllAbout(_hwnd);
// }
//}
void CPlugin::Debug(HWND _hwnd, bool Show)
{
if (m_DllDebugger != 0)
{
m_DllDebugger(_hwnd, Show);
}
}
} // end of namespace Common
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// =======================================================
// File description
// -------------
/* This file is a simpler version of Plugin_...cpp found in Core. This file only loads
the config and debugging windowses and works with all plugins. */
// =============
#include "Plugin.h"
namespace Common
{
DynamicLibrary CPlugin::m_hInstLib;
void(__cdecl * CPlugin::m_GetDllInfo) (PLUGIN_INFO * _PluginInfo) = 0;
//void(__cdecl * CPlugin::m_DllAbout) (HWND _hParent) = 0;
void(__cdecl * CPlugin::m_DllConfig) (HWND _hParent) = 0;
void(__cdecl * CPlugin::m_DllDebugger) (HWND _hParent, bool Show) = 0;
void
CPlugin::Release(void)
{
m_GetDllInfo = 0;
//m_DllAbout = 0;
m_DllConfig = 0;
m_DllDebugger = 0;
m_hInstLib.Unload();
}
bool
CPlugin::Load(const char* _szName)
{
if (m_hInstLib.Load(_szName))
{
m_GetDllInfo = (void (__cdecl*)(PLUGIN_INFO*)) m_hInstLib.Get("GetDllInfo");
m_DllConfig = (void (__cdecl*)(HWND)) m_hInstLib.Get("DllConfig");
m_DllDebugger = (void (__cdecl*)(HWND, bool)) m_hInstLib.Get("DllDebugger");
return(true);
}
return(false);
}
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
{
if (m_GetDllInfo != 0)
{
m_GetDllInfo(&_pluginInfo);
return(true);
}
return(false);
}
void CPlugin::Config(HWND _hwnd)
{
if (m_DllConfig != 0)
{
m_DllConfig(_hwnd);
}
}
//void CPlugin::About(HWND _hwnd)
//{
// if (m_DllAbout != 0)
// {
// m_DllAbout(_hwnd);
// }
//}
void CPlugin::Debug(HWND _hwnd, bool Show)
{
if (m_DllDebugger != 0)
{
m_DllDebugger(_hwnd, Show);
}
}
} // end of namespace Common

View File

@ -1,396 +1,396 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdlib.h>
#include <stdio.h>
#include "StringUtil.h"
#include "TestFramework.h"
// faster than sscanf
bool AsciiToHex(const char* _szValue, u32& result)
{
u32 value = 0;
size_t finish = strlen(_szValue);
if (finish > 8)
finish = 8; // Max 32-bit values are supported.
for (size_t count = 0; count < finish; count++)
{
value <<= 4;
switch (_szValue[count])
{
case '0': break;
case '1': value += 1; break;
case '2': value += 2; break;
case '3': value += 3; break;
case '4': value += 4; break;
case '5': value += 5; break;
case '6': value += 6; break;
case '7': value += 7; break;
case '8': value += 8; break;
case '9': value += 9; break;
case 'A':
case 'a': value += 10; break;
case 'B':
case 'b': value += 11; break;
case 'C':
case 'c': value += 12; break;
case 'D':
case 'd': value += 13; break;
case 'E':
case 'e': value += 14; break;
case 'F':
case 'f': value += 15; break;
default:
return false;
break;
}
}
result = value;
return (true);
}
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
{
int writtenCount = vsnprintf(out, outsize, format, args);
if (writtenCount > 0 && writtenCount < outsize)
{
out[writtenCount] = '\0';
return true;
}
else
{
out[outsize - 1] = '\0';
return false;
}
}
// Expensive!
void StringFromFormatV(std::string* out, const char* format, va_list args)
{
int writtenCount = -1;
size_t newSize = strlen(format) + 16;
char* buf = 0;
while (writtenCount < 0)
{
delete [] buf;
buf = new char[newSize + 1];
writtenCount = vsnprintf(buf, newSize, format, args);
if (writtenCount > (int)newSize)
writtenCount = -1;
// ARGH! vsnprintf does no longer return -1 on truncation in newer libc!
// WORKAROUND! let's fake the old behaviour (even though it's less efficient).
// TODO: figure out why the fix causes an invalid read in strlen called from vsnprintf :(
// if (writtenCount >= (int)newSize)
// writtenCount = -1;
newSize *= 2;
}
buf[writtenCount] = '\0';
*out = buf;
delete[] buf;
}
std::string StringFromFormat(const char* format, ...)
{
std::string temp;
va_list args;
va_start(args, format);
StringFromFormatV(&temp, format, args);
va_end(args);
return(temp);
}
void ToStringFromFormat(std::string* out, const char* format, ...)
{
va_list args;
va_start(args, format);
StringFromFormatV(out, format, args);
va_end(args);
}
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string &str)
{
std::string s = str;
int i;
for (i = 0; i < (int)s.size(); i++)
{
if ((s[i] != ' ') && (s[i] != 9))
{
break;
}
}
s = s.substr(i);
for (i = (int)s.size() - 1; i > 0; i--)
{
if ((s[i] != ' ') && (s[i] != 9))
{
break;
}
}
return s.substr(0, i + 1);
}
// "\"hello\"" is turned to "hello"
// This one assumes that the string has already been space stripped in both
// ends, as done by StripSpaces above, for example.
std::string StripQuotes(const std::string& s)
{
if ((s[0] == '\"') && (s[s.size() - 1] == '\"'))
return s.substr(1, s.size() - 2);
else
return s;
}
// "\"hello\"" is turned to "hello"
// This one assumes that the string has already been space stripped in both
// ends, as done by StripSpaces above, for example.
std::string StripNewline(const std::string& s)
{
if (!s.size())
return s;
else if (s[s.size() - 1] == '\n')
return s.substr(0, s.size() - 1);
else
return s;
}
bool TryParseInt(const char* str, int* outVal)
{
const char* s = str;
int value = 0;
bool negativ = false;
if (*s == '-')
{
negativ = true;
s++;
}
while (*s)
{
char c = *s++;
if ((c < '0') || (c > '9'))
{
return false;
}
value = value * 10 + (c - '0');
}
if (negativ)
value = -value;
*outVal = value;
return true;
}
bool TryParseBool(const char* str, bool* output)
{
if ((str[0] == '1') || !strcmp(str, "true") || !strcmp(str, "True") || !strcmp(str, "TRUE"))
{
*output = true;
return true;
}
else if (str[0] == '0' || !strcmp(str, "false") || !strcmp(str, "False") || !strcmp(str, "FALSE"))
{
*output = false;
return true;
}
return false;
}
std::string StringFromInt(int value)
{
char temp[16];
sprintf(temp, "%i", value);
return std::string(temp);
}
std::string StringFromBool(bool value)
{
return value ? "True" : "False";
}
#ifdef _WIN32
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
if (_splitpath_s(full_path.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT) == 0)
{
if (_pPath)
{
*_pPath = std::string(drive) + std::string(dir);
}
if (_pFilename != 0)
{
*_pFilename = fname;
}
if (_pExtension != 0)
{
*_pExtension = ext;
}
return true;
}
return false;
}
#else
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
{
size_t last_slash = full_path.rfind('/');
if (last_slash == std::string::npos)
{
return false;
}
size_t last_dot = full_path.rfind('.');
if ((last_dot == std::string::npos) || (last_dot < last_slash))
{
return false;
}
if (_pPath)
{
*_pPath = full_path.substr(0, last_slash + 1);
}
if (_pFilename)
{
*_pFilename = full_path.substr(last_slash + 1, last_dot - (last_slash + 1));
}
if (_pExtension)
{
*_pExtension = full_path.substr(last_dot + 1);
_pExtension->insert(0, ".");
}
else if (_pFilename)
{
*_pFilename += full_path.substr(last_dot);
}
return true;
}
#endif
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
{
_CompleteFilename = _Path;
// check for seperator
if (_CompleteFilename[_CompleteFilename.size() - 1] != '\\')
{
_CompleteFilename += "\\";
}
// add the filename
_CompleteFilename += _Filename;
}
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output)
{
output.clear();
size_t offset = 0;
size_t delimIndex = 0;
delimIndex = str.find(delim, offset);
while (delimIndex != std::string::npos)
{
output.push_back(str.substr(offset, delimIndex - offset));
offset += delimIndex - offset + delim.length();
delimIndex = str.find(delim, offset);
}
output.push_back(str.substr(offset));
}
bool TryParseUInt(const std::string& str, u32* output)
{
if (!strcmp(str.substr(0, 2).c_str(), "0x") || !strcmp(str.substr(0, 2).c_str(), "0X"))
return sscanf(str.c_str() + 2, "%x", output) > 0;
else
return sscanf(str.c_str(), "%d", output) > 0;
}
int ChooseStringFrom(const char* str, const char* * items)
{
int i = 0;
while (items[i] != 0)
{
if (!strcmp(str, items[i]))
return i;
i++;
}
return -1;
}
// Thousand separator. Turns 12345678 into 12,345,678.
std::string ThS(int a, bool b)
{
char cbuf[20];
// determine treatment of signed or unsigned
if(b) sprintf(cbuf, "%u", a); else sprintf(cbuf, "%i", a);
std::string sbuf = cbuf;
for (u32 i = 0; i < sbuf.length(); ++i)
{
if((i & 3) == 3)
{
sbuf.insert(sbuf.length() - i, ",");
}
}
return sbuf;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <stdlib.h>
#include <stdio.h>
#include "StringUtil.h"
#include "TestFramework.h"
// faster than sscanf
bool AsciiToHex(const char* _szValue, u32& result)
{
u32 value = 0;
size_t finish = strlen(_szValue);
if (finish > 8)
finish = 8; // Max 32-bit values are supported.
for (size_t count = 0; count < finish; count++)
{
value <<= 4;
switch (_szValue[count])
{
case '0': break;
case '1': value += 1; break;
case '2': value += 2; break;
case '3': value += 3; break;
case '4': value += 4; break;
case '5': value += 5; break;
case '6': value += 6; break;
case '7': value += 7; break;
case '8': value += 8; break;
case '9': value += 9; break;
case 'A':
case 'a': value += 10; break;
case 'B':
case 'b': value += 11; break;
case 'C':
case 'c': value += 12; break;
case 'D':
case 'd': value += 13; break;
case 'E':
case 'e': value += 14; break;
case 'F':
case 'f': value += 15; break;
default:
return false;
break;
}
}
result = value;
return (true);
}
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
{
int writtenCount = vsnprintf(out, outsize, format, args);
if (writtenCount > 0 && writtenCount < outsize)
{
out[writtenCount] = '\0';
return true;
}
else
{
out[outsize - 1] = '\0';
return false;
}
}
// Expensive!
void StringFromFormatV(std::string* out, const char* format, va_list args)
{
int writtenCount = -1;
size_t newSize = strlen(format) + 16;
char* buf = 0;
while (writtenCount < 0)
{
delete [] buf;
buf = new char[newSize + 1];
writtenCount = vsnprintf(buf, newSize, format, args);
if (writtenCount > (int)newSize)
writtenCount = -1;
// ARGH! vsnprintf does no longer return -1 on truncation in newer libc!
// WORKAROUND! let's fake the old behaviour (even though it's less efficient).
// TODO: figure out why the fix causes an invalid read in strlen called from vsnprintf :(
// if (writtenCount >= (int)newSize)
// writtenCount = -1;
newSize *= 2;
}
buf[writtenCount] = '\0';
*out = buf;
delete[] buf;
}
std::string StringFromFormat(const char* format, ...)
{
std::string temp;
va_list args;
va_start(args, format);
StringFromFormatV(&temp, format, args);
va_end(args);
return(temp);
}
void ToStringFromFormat(std::string* out, const char* format, ...)
{
va_list args;
va_start(args, format);
StringFromFormatV(out, format, args);
va_end(args);
}
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string &str)
{
std::string s = str;
int i;
for (i = 0; i < (int)s.size(); i++)
{
if ((s[i] != ' ') && (s[i] != 9))
{
break;
}
}
s = s.substr(i);
for (i = (int)s.size() - 1; i > 0; i--)
{
if ((s[i] != ' ') && (s[i] != 9))
{
break;
}
}
return s.substr(0, i + 1);
}
// "\"hello\"" is turned to "hello"
// This one assumes that the string has already been space stripped in both
// ends, as done by StripSpaces above, for example.
std::string StripQuotes(const std::string& s)
{
if ((s[0] == '\"') && (s[s.size() - 1] == '\"'))
return s.substr(1, s.size() - 2);
else
return s;
}
// "\"hello\"" is turned to "hello"
// This one assumes that the string has already been space stripped in both
// ends, as done by StripSpaces above, for example.
std::string StripNewline(const std::string& s)
{
if (!s.size())
return s;
else if (s[s.size() - 1] == '\n')
return s.substr(0, s.size() - 1);
else
return s;
}
bool TryParseInt(const char* str, int* outVal)
{
const char* s = str;
int value = 0;
bool negativ = false;
if (*s == '-')
{
negativ = true;
s++;
}
while (*s)
{
char c = *s++;
if ((c < '0') || (c > '9'))
{
return false;
}
value = value * 10 + (c - '0');
}
if (negativ)
value = -value;
*outVal = value;
return true;
}
bool TryParseBool(const char* str, bool* output)
{
if ((str[0] == '1') || !strcmp(str, "true") || !strcmp(str, "True") || !strcmp(str, "TRUE"))
{
*output = true;
return true;
}
else if (str[0] == '0' || !strcmp(str, "false") || !strcmp(str, "False") || !strcmp(str, "FALSE"))
{
*output = false;
return true;
}
return false;
}
std::string StringFromInt(int value)
{
char temp[16];
sprintf(temp, "%i", value);
return std::string(temp);
}
std::string StringFromBool(bool value)
{
return value ? "True" : "False";
}
#ifdef _WIN32
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
if (_splitpath_s(full_path.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT) == 0)
{
if (_pPath)
{
*_pPath = std::string(drive) + std::string(dir);
}
if (_pFilename != 0)
{
*_pFilename = fname;
}
if (_pExtension != 0)
{
*_pExtension = ext;
}
return true;
}
return false;
}
#else
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
{
size_t last_slash = full_path.rfind('/');
if (last_slash == std::string::npos)
{
return false;
}
size_t last_dot = full_path.rfind('.');
if ((last_dot == std::string::npos) || (last_dot < last_slash))
{
return false;
}
if (_pPath)
{
*_pPath = full_path.substr(0, last_slash + 1);
}
if (_pFilename)
{
*_pFilename = full_path.substr(last_slash + 1, last_dot - (last_slash + 1));
}
if (_pExtension)
{
*_pExtension = full_path.substr(last_dot + 1);
_pExtension->insert(0, ".");
}
else if (_pFilename)
{
*_pFilename += full_path.substr(last_dot);
}
return true;
}
#endif
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
{
_CompleteFilename = _Path;
// check for seperator
if (_CompleteFilename[_CompleteFilename.size() - 1] != '\\')
{
_CompleteFilename += "\\";
}
// add the filename
_CompleteFilename += _Filename;
}
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output)
{
output.clear();
size_t offset = 0;
size_t delimIndex = 0;
delimIndex = str.find(delim, offset);
while (delimIndex != std::string::npos)
{
output.push_back(str.substr(offset, delimIndex - offset));
offset += delimIndex - offset + delim.length();
delimIndex = str.find(delim, offset);
}
output.push_back(str.substr(offset));
}
bool TryParseUInt(const std::string& str, u32* output)
{
if (!strcmp(str.substr(0, 2).c_str(), "0x") || !strcmp(str.substr(0, 2).c_str(), "0X"))
return sscanf(str.c_str() + 2, "%x", output) > 0;
else
return sscanf(str.c_str(), "%d", output) > 0;
}
int ChooseStringFrom(const char* str, const char* * items)
{
int i = 0;
while (items[i] != 0)
{
if (!strcmp(str, items[i]))
return i;
i++;
}
return -1;
}
// Thousand separator. Turns 12345678 into 12,345,678.
std::string ThS(int a, bool b)
{
char cbuf[20];
// determine treatment of signed or unsigned
if(b) sprintf(cbuf, "%u", a); else sprintf(cbuf, "%i", a);
std::string sbuf = cbuf;
for (u32 i = 0; i < sbuf.length(); ++i)
{
if((i & 3) == 3)
{
sbuf.insert(sbuf.length() - i, ",");
}
}
return sbuf;
}

View File

@ -1,38 +1,38 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "TestFramework.h"
namespace __test
{
int numTests;
int numTestsFailed;
}
int GetNumTests()
{
return(__test::numTests);
}
int GetNumTestsFailed()
{
return(__test::numTestsFailed);
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "TestFramework.h"
namespace __test
{
int numTests;
int numTestsFailed;
}
int GetNumTests()
{
return(__test::numTests);
}
int GetNumTestsFailed()
{
return(__test::numTestsFailed);
}

View File

@ -1,404 +1,404 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#elif __GNUC__
#include <unistd.h>
#include <pthread.h>
#else
#error unsupported platform
#endif
#include "Thread.h"
namespace Common
{
#ifdef _WIN32
CriticalSection::CriticalSection(int spincount)
{
if (spincount)
{
InitializeCriticalSectionAndSpinCount(&section, spincount);
}
else
{
InitializeCriticalSection(&section);
}
}
CriticalSection::~CriticalSection()
{
DeleteCriticalSection(&section);
}
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
bool CriticalSection::TryEnter()
{
return(TryEnterCriticalSection(&section) ? true : false);
}
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
}
Thread::Thread(ThreadFunc function, void* arg)
: m_hThread(NULL), m_threadId(0)
{
m_hThread = CreateThread(
0, // Security attributes
0, // Stack size
function,
arg,
0,
&m_threadId);
}
Thread::~Thread()
{
WaitForDeath();
}
void Thread::WaitForDeath()
{
if (m_hThread)
{
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
m_hThread = NULL;
}
}
void Thread::SetAffinity(int mask)
{
SetThreadAffinityMask(m_hThread, mask);
}
void Thread::SetCurrentThreadAffinity(int mask)
{
SetThreadAffinityMask(GetCurrentThread(), mask);
}
Event::Event()
{
m_hEvent = 0;
}
void Event::Init()
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
void Event::Shutdown()
{
CloseHandle(m_hEvent);
m_hEvent = 0;
}
void Event::Set()
{
SetEvent(m_hEvent);
}
void Event::Wait()
{
WaitForSingleObject(m_hEvent, INFINITE);
}
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} THREADNAME_INFO;
// Usage: SetThreadName (-1, "MainThread");
//
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
void SetCurrentThreadName(const TCHAR* szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
#ifdef UNICODE
//TODO: Find the proper way to do this.
char tname[256];
unsigned int i;
for (i = 0; i < _tcslen(szThreadName); i++)
{
tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
}
tname[i] = 0;
info.szName = tname;
#else
info.szName = szThreadName;
#endif
info.dwThreadID = -1; //dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
}
// TODO: check if ever inline
LONG SyncInterlockedIncrement(LONG *Dest)
{
return InterlockedIncrement(Dest);
}
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
{
return InterlockedExchangeAdd(Dest, Val);
}
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
{
return InterlockedExchange(Dest, Val);
}
#elif __GNUC__
CriticalSection::CriticalSection(int spincount_unused)
{
pthread_mutex_init(&mutex, 0);
}
CriticalSection::~CriticalSection()
{
pthread_mutex_destroy(&mutex);
}
void CriticalSection::Enter()
{
pthread_mutex_lock(&mutex);
}
bool CriticalSection::TryEnter()
{
return(!pthread_mutex_trylock(&mutex));
}
void CriticalSection::Leave()
{
pthread_mutex_unlock(&mutex);
}
Thread::Thread(ThreadFunc function, void* arg)
: thread_id(0)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024 * 1024);
pthread_create(&thread_id, &attr, function, arg);
}
Thread::~Thread()
{
WaitForDeath();
}
void Thread::WaitForDeath()
{
if (thread_id)
{
void* exit_status;
pthread_join(thread_id, &exit_status);
if (exit_status)
fprintf(stderr, "error %d joining thread\n", *(int *)exit_status);
thread_id = 0;
}
}
void Thread::SetAffinity(int mask)
{
// This is non-standard
#ifdef __linux__
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
{
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
}
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
#endif
}
void Thread::SetCurrentThreadAffinity(int mask)
{
#ifdef __linux__
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
for (size_t i = 0; i < sizeof(mask) * 8; i++)
{
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
}
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
#endif
}
void SleepCurrentThread(int ms)
{
usleep(1000 * ms);
}
void SetCurrentThreadName(const TCHAR* szThreadName)
{
// noop
}
Event::Event()
{
is_set_ = false;
}
void Event::Init()
{
pthread_cond_init(&event_, 0);
pthread_mutex_init(&mutex_, 0);
}
void Event::Shutdown()
{
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&event_);
}
void Event::Set()
{
pthread_mutex_lock(&mutex_);
if (!is_set_)
{
is_set_ = true;
pthread_cond_signal(&event_);
}
pthread_mutex_unlock(&mutex_);
}
void Event::Wait()
{
pthread_mutex_lock(&mutex_);
while (!is_set_)
{
pthread_cond_wait(&event_, &mutex_);
}
is_set_ = false;
pthread_mutex_unlock(&mutex_);
}
LONG SyncInterlockedIncrement(LONG *Dest)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_add_and_fetch(Dest, 1);
#else
register int result;
__asm__ __volatile__("lock; xadd %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (1), "m" (*Dest)
: "memory");
return result;
#endif
}
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_add_and_fetch(Dest, Val);
#else
register int result;
__asm__ __volatile__("lock; xadd %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (Val), "m" (*Dest)
: "memory");
return result;
#endif
}
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_lock_test_and_set(Dest, Val);
#else
register int result;
__asm__ __volatile__("lock; xchg %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (Val), "m" (*Dest)
: "memory");
return result;
#endif
}
#endif
} // end of namespace Common
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#elif __GNUC__
#include <unistd.h>
#include <pthread.h>
#else
#error unsupported platform
#endif
#include "Thread.h"
namespace Common
{
#ifdef _WIN32
CriticalSection::CriticalSection(int spincount)
{
if (spincount)
{
InitializeCriticalSectionAndSpinCount(&section, spincount);
}
else
{
InitializeCriticalSection(&section);
}
}
CriticalSection::~CriticalSection()
{
DeleteCriticalSection(&section);
}
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
bool CriticalSection::TryEnter()
{
return(TryEnterCriticalSection(&section) ? true : false);
}
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
}
Thread::Thread(ThreadFunc function, void* arg)
: m_hThread(NULL), m_threadId(0)
{
m_hThread = CreateThread(
0, // Security attributes
0, // Stack size
function,
arg,
0,
&m_threadId);
}
Thread::~Thread()
{
WaitForDeath();
}
void Thread::WaitForDeath()
{
if (m_hThread)
{
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
m_hThread = NULL;
}
}
void Thread::SetAffinity(int mask)
{
SetThreadAffinityMask(m_hThread, mask);
}
void Thread::SetCurrentThreadAffinity(int mask)
{
SetThreadAffinityMask(GetCurrentThread(), mask);
}
Event::Event()
{
m_hEvent = 0;
}
void Event::Init()
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
void Event::Shutdown()
{
CloseHandle(m_hEvent);
m_hEvent = 0;
}
void Event::Set()
{
SetEvent(m_hEvent);
}
void Event::Wait()
{
WaitForSingleObject(m_hEvent, INFINITE);
}
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} THREADNAME_INFO;
// Usage: SetThreadName (-1, "MainThread");
//
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
void SetCurrentThreadName(const TCHAR* szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
#ifdef UNICODE
//TODO: Find the proper way to do this.
char tname[256];
unsigned int i;
for (i = 0; i < _tcslen(szThreadName); i++)
{
tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
}
tname[i] = 0;
info.szName = tname;
#else
info.szName = szThreadName;
#endif
info.dwThreadID = -1; //dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
}
// TODO: check if ever inline
LONG SyncInterlockedIncrement(LONG *Dest)
{
return InterlockedIncrement(Dest);
}
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
{
return InterlockedExchangeAdd(Dest, Val);
}
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
{
return InterlockedExchange(Dest, Val);
}
#elif __GNUC__
CriticalSection::CriticalSection(int spincount_unused)
{
pthread_mutex_init(&mutex, 0);
}
CriticalSection::~CriticalSection()
{
pthread_mutex_destroy(&mutex);
}
void CriticalSection::Enter()
{
pthread_mutex_lock(&mutex);
}
bool CriticalSection::TryEnter()
{
return(!pthread_mutex_trylock(&mutex));
}
void CriticalSection::Leave()
{
pthread_mutex_unlock(&mutex);
}
Thread::Thread(ThreadFunc function, void* arg)
: thread_id(0)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024 * 1024);
pthread_create(&thread_id, &attr, function, arg);
}
Thread::~Thread()
{
WaitForDeath();
}
void Thread::WaitForDeath()
{
if (thread_id)
{
void* exit_status;
pthread_join(thread_id, &exit_status);
if (exit_status)
fprintf(stderr, "error %d joining thread\n", *(int *)exit_status);
thread_id = 0;
}
}
void Thread::SetAffinity(int mask)
{
// This is non-standard
#ifdef __linux__
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
{
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
}
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
#endif
}
void Thread::SetCurrentThreadAffinity(int mask)
{
#ifdef __linux__
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
for (size_t i = 0; i < sizeof(mask) * 8; i++)
{
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
}
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
#endif
}
void SleepCurrentThread(int ms)
{
usleep(1000 * ms);
}
void SetCurrentThreadName(const TCHAR* szThreadName)
{
// noop
}
Event::Event()
{
is_set_ = false;
}
void Event::Init()
{
pthread_cond_init(&event_, 0);
pthread_mutex_init(&mutex_, 0);
}
void Event::Shutdown()
{
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&event_);
}
void Event::Set()
{
pthread_mutex_lock(&mutex_);
if (!is_set_)
{
is_set_ = true;
pthread_cond_signal(&event_);
}
pthread_mutex_unlock(&mutex_);
}
void Event::Wait()
{
pthread_mutex_lock(&mutex_);
while (!is_set_)
{
pthread_cond_wait(&event_, &mutex_);
}
is_set_ = false;
pthread_mutex_unlock(&mutex_);
}
LONG SyncInterlockedIncrement(LONG *Dest)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_add_and_fetch(Dest, 1);
#else
register int result;
__asm__ __volatile__("lock; xadd %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (1), "m" (*Dest)
: "memory");
return result;
#endif
}
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_add_and_fetch(Dest, Val);
#else
register int result;
__asm__ __volatile__("lock; xadd %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (Val), "m" (*Dest)
: "memory");
return result;
#endif
}
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
{
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
return __sync_lock_test_and_set(Dest, Val);
#else
register int result;
__asm__ __volatile__("lock; xchg %0,%1"
: "=r" (result), "=m" (*Dest)
: "0" (Val), "m" (*Dest)
: "memory");
return result;
#endif
}
#endif
} // end of namespace Common

View File

@ -1,153 +1,153 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
#include "Common.h"
#include "Thunk.h"
#include "x64Emitter.h"
#include "MemoryUtil.h"
#include "ABI.h"
using namespace Gen;
#define THUNK_ARENA_SIZE 1024*1024*1
namespace {
static std::map<void *, const u8 *> thunks;
u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
static u8 *thunk_memory;
static u8 *thunk_code;
static const u8 *save_regs;
static const u8 *load_regs;
static u16 saved_mxcsr;
}
void Thunk_Init()
{
thunk_memory = (u8 *)AllocateExecutableMemory(THUNK_ARENA_SIZE);
thunk_code = thunk_memory;
GenContext ctx(&thunk_code);
save_regs = GetCodePtr();
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
MOVAPS(M(saved_fp_state + i * 16), (X64Reg)(XMM0 + i));
STMXCSR(M(&saved_mxcsr));
#ifdef _M_X64
MOV(64, M(saved_gpr_state + 0 ), R(RCX));
MOV(64, M(saved_gpr_state + 8 ), R(RDX));
MOV(64, M(saved_gpr_state + 16), R(R8) );
MOV(64, M(saved_gpr_state + 24), R(R9) );
MOV(64, M(saved_gpr_state + 32), R(R10));
MOV(64, M(saved_gpr_state + 40), R(R11));
#ifndef _WIN32
MOV(64, M(saved_gpr_state + 48), R(RSI));
MOV(64, M(saved_gpr_state + 56), R(RDI));
#endif
MOV(64, M(saved_gpr_state + 64), R(RBX));
#else
MOV(32, M(saved_gpr_state + 0 ), R(RCX));
MOV(32, M(saved_gpr_state + 4 ), R(RDX));
#endif
RET();
load_regs = GetCodePtr();
LDMXCSR(M(&saved_mxcsr));
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
MOVAPS((X64Reg)(XMM0 + i), M(saved_fp_state + i * 16));
#ifdef _M_X64
MOV(64, R(RCX), M(saved_gpr_state + 0 ));
MOV(64, R(RDX), M(saved_gpr_state + 8 ));
MOV(64, R(R8) , M(saved_gpr_state + 16));
MOV(64, R(R9) , M(saved_gpr_state + 24));
MOV(64, R(R10), M(saved_gpr_state + 32));
MOV(64, R(R11), M(saved_gpr_state + 40));
#ifndef _WIN32
MOV(64, R(RSI), M(saved_gpr_state + 48));
MOV(64, R(RDI), M(saved_gpr_state + 56));
#endif
MOV(64, R(RBX), M(saved_gpr_state + 64));
#else
MOV(32, R(RCX), M(saved_gpr_state + 0 ));
MOV(32, R(RDX), M(saved_gpr_state + 4 ));
#endif
RET();
}
void Thunk_Reset()
{
thunks.clear();
thunk_code = thunk_memory;
}
void Thunk_Shutdown()
{
Thunk_Reset();
FreeMemoryPages(thunk_memory, THUNK_ARENA_SIZE);
thunk_memory = 0;
thunk_code = 0;
}
void *ProtectFunction(void *function, int num_params)
{
std::map<void *, const u8 *>::iterator iter;
iter = thunks.find(function);
if (iter != thunks.end())
return (void *)iter->second;
if (!thunk_memory)
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
GenContext gen(&thunk_code);
const u8 *call_point = GetCodePtr();
// Make sure to align stack.
#ifdef _M_X64
#ifdef _WIN32
SUB(64, R(ESP), Imm8(0x28));
#else
SUB(64, R(ESP), Imm8(0x8));
#endif
CALL((void*)save_regs);
CALL((void*)function);
CALL((void*)load_regs);
#ifdef _WIN32
ADD(64, R(ESP), Imm8(0x28));
#else
ADD(64, R(ESP), Imm8(0x8));
#endif
RET();
#else
CALL((void*)save_regs);
// Since parameters are in the previous stack frame, not in registers, this takes some
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
// matter.
ABI_AlignStack(num_params * 4);
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
for (int i = 0; i < num_params; i++) {
// ESP is changing, so we do not need i
PUSH(32, MDisp(ESP, alignedSize - 4));
}
CALL(function);
ABI_RestoreStack(num_params * 4);
CALL((void*)load_regs);
RET();
#endif
thunks[function] = call_point;
return (void *)call_point;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
#include "Common.h"
#include "Thunk.h"
#include "x64Emitter.h"
#include "MemoryUtil.h"
#include "ABI.h"
using namespace Gen;
#define THUNK_ARENA_SIZE 1024*1024*1
namespace {
static std::map<void *, const u8 *> thunks;
u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
static u8 *thunk_memory;
static u8 *thunk_code;
static const u8 *save_regs;
static const u8 *load_regs;
static u16 saved_mxcsr;
}
void Thunk_Init()
{
thunk_memory = (u8 *)AllocateExecutableMemory(THUNK_ARENA_SIZE);
thunk_code = thunk_memory;
GenContext ctx(&thunk_code);
save_regs = GetCodePtr();
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
MOVAPS(M(saved_fp_state + i * 16), (X64Reg)(XMM0 + i));
STMXCSR(M(&saved_mxcsr));
#ifdef _M_X64
MOV(64, M(saved_gpr_state + 0 ), R(RCX));
MOV(64, M(saved_gpr_state + 8 ), R(RDX));
MOV(64, M(saved_gpr_state + 16), R(R8) );
MOV(64, M(saved_gpr_state + 24), R(R9) );
MOV(64, M(saved_gpr_state + 32), R(R10));
MOV(64, M(saved_gpr_state + 40), R(R11));
#ifndef _WIN32
MOV(64, M(saved_gpr_state + 48), R(RSI));
MOV(64, M(saved_gpr_state + 56), R(RDI));
#endif
MOV(64, M(saved_gpr_state + 64), R(RBX));
#else
MOV(32, M(saved_gpr_state + 0 ), R(RCX));
MOV(32, M(saved_gpr_state + 4 ), R(RDX));
#endif
RET();
load_regs = GetCodePtr();
LDMXCSR(M(&saved_mxcsr));
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
MOVAPS((X64Reg)(XMM0 + i), M(saved_fp_state + i * 16));
#ifdef _M_X64
MOV(64, R(RCX), M(saved_gpr_state + 0 ));
MOV(64, R(RDX), M(saved_gpr_state + 8 ));
MOV(64, R(R8) , M(saved_gpr_state + 16));
MOV(64, R(R9) , M(saved_gpr_state + 24));
MOV(64, R(R10), M(saved_gpr_state + 32));
MOV(64, R(R11), M(saved_gpr_state + 40));
#ifndef _WIN32
MOV(64, R(RSI), M(saved_gpr_state + 48));
MOV(64, R(RDI), M(saved_gpr_state + 56));
#endif
MOV(64, R(RBX), M(saved_gpr_state + 64));
#else
MOV(32, R(RCX), M(saved_gpr_state + 0 ));
MOV(32, R(RDX), M(saved_gpr_state + 4 ));
#endif
RET();
}
void Thunk_Reset()
{
thunks.clear();
thunk_code = thunk_memory;
}
void Thunk_Shutdown()
{
Thunk_Reset();
FreeMemoryPages(thunk_memory, THUNK_ARENA_SIZE);
thunk_memory = 0;
thunk_code = 0;
}
void *ProtectFunction(void *function, int num_params)
{
std::map<void *, const u8 *>::iterator iter;
iter = thunks.find(function);
if (iter != thunks.end())
return (void *)iter->second;
if (!thunk_memory)
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
GenContext gen(&thunk_code);
const u8 *call_point = GetCodePtr();
// Make sure to align stack.
#ifdef _M_X64
#ifdef _WIN32
SUB(64, R(ESP), Imm8(0x28));
#else
SUB(64, R(ESP), Imm8(0x8));
#endif
CALL((void*)save_regs);
CALL((void*)function);
CALL((void*)load_regs);
#ifdef _WIN32
ADD(64, R(ESP), Imm8(0x28));
#else
ADD(64, R(ESP), Imm8(0x8));
#endif
RET();
#else
CALL((void*)save_regs);
// Since parameters are in the previous stack frame, not in registers, this takes some
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
// matter.
ABI_AlignStack(num_params * 4);
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
for (int i = 0; i < num_params; i++) {
// ESP is changing, so we do not need i
PUSH(32, MDisp(ESP, alignedSize - 4));
}
CALL(function);
ABI_RestoreStack(num_params * 4);
CALL((void*)load_regs);
RET();
#endif
thunks[function] = call_point;
return (void *)call_point;
}

View File

@ -1,99 +1,99 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
#endif
#include <time.h>
#include "Common.h"
#include "Timer.h"
#ifdef __GNUC__
#include <sys/timeb.h>
u32 timeGetTime()
{
struct timeb t;
ftime(&t);
return((u32)(t.time * 1000 + t.millitm));
}
#endif
namespace Common
{
Timer::Timer(void)
: m_LastTime(0)
{
Update();
#ifdef _WIN32
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
#endif
}
void Timer::Update(void)
{
m_LastTime = timeGetTime();
//TODO(ector) - QPF
}
s64 Timer::GetTimeDifference(void)
{
return(timeGetTime() - m_LastTime);
}
void Timer::IncreaseResolution()
{
#ifdef _WIN32
timeBeginPeriod(1);
#endif
}
void Timer::RestoreResolution()
{
#ifdef _WIN32
timeEndPeriod(1);
#endif
}
#ifdef __GNUC__
void _time64(u64* t)
{
*t = 0; //TODO
}
#endif
u64 Timer::GetTimeSinceJan1970(void)
{
time_t ltime;
time(&ltime);
return((u64)ltime);
}
} // end of namespace Common
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
#endif
#include <time.h>
#include "Common.h"
#include "Timer.h"
#ifdef __GNUC__
#include <sys/timeb.h>
u32 timeGetTime()
{
struct timeb t;
ftime(&t);
return((u32)(t.time * 1000 + t.millitm));
}
#endif
namespace Common
{
Timer::Timer(void)
: m_LastTime(0)
{
Update();
#ifdef _WIN32
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
#endif
}
void Timer::Update(void)
{
m_LastTime = timeGetTime();
//TODO(ector) - QPF
}
s64 Timer::GetTimeDifference(void)
{
return(timeGetTime() - m_LastTime);
}
void Timer::IncreaseResolution()
{
#ifdef _WIN32
timeBeginPeriod(1);
#endif
}
void Timer::RestoreResolution()
{
#ifdef _WIN32
timeEndPeriod(1);
#endif
}
#ifdef __GNUC__
void _time64(u64* t)
{
*t = 0; //TODO
}
#endif
u64 Timer::GetTimeSinceJan1970(void)
{
time_t ltime;
time(&ltime);
return((u64)ltime);
}
} // end of namespace Common

View File

@ -1,123 +1,123 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "WaveFile.h"
enum {BUF_SIZE = 32*1024};
WaveFileWriter::WaveFileWriter()
{
conv_buffer = 0;
skip_silence = false;
}
WaveFileWriter::~WaveFileWriter()
{
delete [] conv_buffer;
Stop();
}
bool WaveFileWriter::Start(const char *filename)
{
if (!conv_buffer)
conv_buffer = new short[BUF_SIZE];
if (file)
return false;
file = fopen(filename, "wb");
if (!file)
return false;
Write4("RIFF");
Write(100 * 1000 * 1000); // write big value in case the file gets truncated
Write4("WAVE");
Write4("fmt ");
Write(16); // size of fmt block
Write(0x00020001); //two channels, uncompressed
const u32 sample_rate = 32000;
Write(sample_rate);
Write(sample_rate * 2 * 2); //two channels, 16bit
Write(0x00100004);
Write4("data");
Write(100 * 1000 * 1000 - 32);
// We are now at offset 44
if (ftell(file) != 44)
PanicAlert("wrong offset: %i", ftell(file));
return true;
}
void WaveFileWriter::Stop()
{
if (!file)
return;
// u32 file_size = (u32)ftell(file);
fseek(file, 4, SEEK_SET);
Write(audio_size + 36);
fseek(file, 40, SEEK_SET);
Write(audio_size);
fclose(file);
file = 0;
}
void WaveFileWriter::Write(u32 value)
{
fwrite(&value, 4, 1, file);
}
void WaveFileWriter::Write4(const char *ptr)
{
fwrite(ptr, 4, 1, file);
}
void WaveFileWriter::AddStereoSamples(const short *sample_data, int count)
{
if (!file)
PanicAlert("WaveFileWriter - file not open.");
if (skip_silence) {
bool all_zero = true;
for (int i = 0; i < count * 2; i++)
if (sample_data[i])
all_zero = false;
if (all_zero)
return;
}
fwrite(sample_data, count * 4, 1, file);
audio_size += count * 4;
}
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, int count)
{
if (!file)
PanicAlert("WaveFileWriter - file not open.");
if (count > BUF_SIZE * 2)
PanicAlert("WaveFileWriter - buffer too small (count = %i).", count);
if (skip_silence) {
bool all_zero = true;
for (int i = 0; i < count * 2; i++)
if (sample_data[i])
all_zero = false;
if (all_zero)
return;
}
for (int i = 0; i < count * 2; i++) {
conv_buffer[i] = Common::swap16((u16)sample_data[i]);
}
fwrite(conv_buffer, count * 4, 1, file);
audio_size += count * 4;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "WaveFile.h"
enum {BUF_SIZE = 32*1024};
WaveFileWriter::WaveFileWriter()
{
conv_buffer = 0;
skip_silence = false;
}
WaveFileWriter::~WaveFileWriter()
{
delete [] conv_buffer;
Stop();
}
bool WaveFileWriter::Start(const char *filename)
{
if (!conv_buffer)
conv_buffer = new short[BUF_SIZE];
if (file)
return false;
file = fopen(filename, "wb");
if (!file)
return false;
Write4("RIFF");
Write(100 * 1000 * 1000); // write big value in case the file gets truncated
Write4("WAVE");
Write4("fmt ");
Write(16); // size of fmt block
Write(0x00020001); //two channels, uncompressed
const u32 sample_rate = 32000;
Write(sample_rate);
Write(sample_rate * 2 * 2); //two channels, 16bit
Write(0x00100004);
Write4("data");
Write(100 * 1000 * 1000 - 32);
// We are now at offset 44
if (ftell(file) != 44)
PanicAlert("wrong offset: %i", ftell(file));
return true;
}
void WaveFileWriter::Stop()
{
if (!file)
return;
// u32 file_size = (u32)ftell(file);
fseek(file, 4, SEEK_SET);
Write(audio_size + 36);
fseek(file, 40, SEEK_SET);
Write(audio_size);
fclose(file);
file = 0;
}
void WaveFileWriter::Write(u32 value)
{
fwrite(&value, 4, 1, file);
}
void WaveFileWriter::Write4(const char *ptr)
{
fwrite(ptr, 4, 1, file);
}
void WaveFileWriter::AddStereoSamples(const short *sample_data, int count)
{
if (!file)
PanicAlert("WaveFileWriter - file not open.");
if (skip_silence) {
bool all_zero = true;
for (int i = 0; i < count * 2; i++)
if (sample_data[i])
all_zero = false;
if (all_zero)
return;
}
fwrite(sample_data, count * 4, 1, file);
audio_size += count * 4;
}
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, int count)
{
if (!file)
PanicAlert("WaveFileWriter - file not open.");
if (count > BUF_SIZE * 2)
PanicAlert("WaveFileWriter - buffer too small (count = %i).", count);
if (skip_silence) {
bool all_zero = true;
for (int i = 0; i < count * 2; i++)
if (sample_data[i])
all_zero = false;
if (all_zero)
return;
}
for (int i = 0; i < count * 2; i++) {
conv_buffer[i] = Common::swap16((u16)sample_data[i]);
}
fwrite(conv_buffer, count * 4, 1, file);
audio_size += count * 4;
}

View File

@ -1,18 +1,18 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "stdafx.h"
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "stdafx.h"

View File

@ -1,232 +1,232 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "x64Analyzer.h"
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
{
unsigned const char *startCodePtr = codePtr;
u8 rex = 0;
u8 codeByte = 0;
u8 codeByte2 = 0;
//Check for regular prefix
info.operandSize = 4;
info.zeroExtend = false;
info.signExtend = false;
info.hasImmediate = false;
info.isMemoryWrite = false;
int addressSize = 8;
u8 modRMbyte = 0;
u8 sibByte = 0;
bool hasModRM = false;
bool hasSIBbyte = false;
bool hasDisplacement = false;
int displacementSize = 0;
if (*codePtr == 0x66)
{
info.operandSize = 2;
codePtr++;
}
else if (*codePtr == 0x67)
{
addressSize = 4;
codePtr++;
}
//Check for REX prefix
if ((*codePtr & 0xF0) == 0x40)
{
rex = *codePtr;
if (rex & 8) //REX.W
{
info.operandSize = 8;
}
codePtr++;
}
codeByte = *codePtr++;
// Skip two-byte opcode byte
bool twoByte = false;
if(codeByte == 0x0F)
{
twoByte = true;
codeByte2 = *codePtr++;
}
if (!twoByte)
{
if ((codeByte & 0xF0) == 0x80 ||
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
{
modRMbyte = *codePtr++;
hasModRM = true;
}
}
else
{
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
(codeByte2 & 0xF0) == 0x30 ||
codeByte2 == 0x77 ||
(codeByte2 & 0xF0) == 0x80 ||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
(codeByte2 & 0xF8) == 0xC8)
{
// No mod R/M byte
}
else
{
modRMbyte = *codePtr++;
hasModRM = true;
}
}
if (hasModRM)
{
ModRM mrm(modRMbyte, rex);
info.regOperandReg = mrm.reg;
if (mrm.mod < 3)
{
if (mrm.rm == 4)
{
//SIB byte
sibByte = *codePtr++;
info.scaledReg = (sibByte >> 3) & 7;
info.otherReg = (sibByte & 7);
if (rex & 2) info.scaledReg += 8;
if (rex & 1) info.otherReg += 8;
hasSIBbyte = true;
}
else
{
//info.scaledReg =
}
}
if (mrm.mod == 1 || mrm.mod == 2)
{
hasDisplacement = true;
if (mrm.mod == 1)
displacementSize = 1;
else
displacementSize = 4;
}
}
if (displacementSize == 1)
info.displacement = (s32)(s8)*codePtr;
else
info.displacement = *((s32 *)codePtr);
codePtr += displacementSize;
if (accessType == 1)
{
info.isMemoryWrite = true;
//Write access
switch (codeByte)
{
case 0xC6: //move 8-bit immediate
{
info.hasImmediate = true;
info.immediate = *codePtr;
codePtr++; //move past immediate
}
break;
case 0xC7: //move 16 or 32-bit immediate, easiest case for writes
{
if (info.operandSize == 2)
{
info.hasImmediate = true;
info.immediate = *(u16*)codePtr;
codePtr += 2;
}
else if (info.operandSize == 4)
{
info.hasImmediate = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
else if (info.operandSize == 8)
{
info.zeroExtend = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
}
break;
case 0x89: //move reg to memory
break;
default:
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
return false;
}
}
else
{
// Memory read
//mov eax, dword ptr [rax] == 8b 00
switch (codeByte)
{
case 0x0F:
switch (codeByte2)
{
case 0xB6: //movzx on byte
info.zeroExtend = true;
info.operandSize = 1;
break;
case 0xB7: //movzx on short
info.zeroExtend = true;
info.operandSize = 2;
break;
case 0xBE: //movsx on byte
info.signExtend = true;
info.operandSize = 1;
break;
case 0xBF:
info.signExtend = true;
info.operandSize = 2;
break;
default:
return false;
}
break;
case 0x8a:
if (info.operandSize == 4)
{
info.operandSize = 1;
break;
}
else
return false;
case 0x8b:
break; //it's OK don't need to do anything
default:
return false;
}
}
info.instructionSize = (int)(codePtr - startCodePtr);
return true;
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "x64Analyzer.h"
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
{
unsigned const char *startCodePtr = codePtr;
u8 rex = 0;
u8 codeByte = 0;
u8 codeByte2 = 0;
//Check for regular prefix
info.operandSize = 4;
info.zeroExtend = false;
info.signExtend = false;
info.hasImmediate = false;
info.isMemoryWrite = false;
int addressSize = 8;
u8 modRMbyte = 0;
u8 sibByte = 0;
bool hasModRM = false;
bool hasSIBbyte = false;
bool hasDisplacement = false;
int displacementSize = 0;
if (*codePtr == 0x66)
{
info.operandSize = 2;
codePtr++;
}
else if (*codePtr == 0x67)
{
addressSize = 4;
codePtr++;
}
//Check for REX prefix
if ((*codePtr & 0xF0) == 0x40)
{
rex = *codePtr;
if (rex & 8) //REX.W
{
info.operandSize = 8;
}
codePtr++;
}
codeByte = *codePtr++;
// Skip two-byte opcode byte
bool twoByte = false;
if(codeByte == 0x0F)
{
twoByte = true;
codeByte2 = *codePtr++;
}
if (!twoByte)
{
if ((codeByte & 0xF0) == 0x80 ||
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
{
modRMbyte = *codePtr++;
hasModRM = true;
}
}
else
{
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
(codeByte2 & 0xF0) == 0x30 ||
codeByte2 == 0x77 ||
(codeByte2 & 0xF0) == 0x80 ||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
(codeByte2 & 0xF8) == 0xC8)
{
// No mod R/M byte
}
else
{
modRMbyte = *codePtr++;
hasModRM = true;
}
}
if (hasModRM)
{
ModRM mrm(modRMbyte, rex);
info.regOperandReg = mrm.reg;
if (mrm.mod < 3)
{
if (mrm.rm == 4)
{
//SIB byte
sibByte = *codePtr++;
info.scaledReg = (sibByte >> 3) & 7;
info.otherReg = (sibByte & 7);
if (rex & 2) info.scaledReg += 8;
if (rex & 1) info.otherReg += 8;
hasSIBbyte = true;
}
else
{
//info.scaledReg =
}
}
if (mrm.mod == 1 || mrm.mod == 2)
{
hasDisplacement = true;
if (mrm.mod == 1)
displacementSize = 1;
else
displacementSize = 4;
}
}
if (displacementSize == 1)
info.displacement = (s32)(s8)*codePtr;
else
info.displacement = *((s32 *)codePtr);
codePtr += displacementSize;
if (accessType == 1)
{
info.isMemoryWrite = true;
//Write access
switch (codeByte)
{
case 0xC6: //move 8-bit immediate
{
info.hasImmediate = true;
info.immediate = *codePtr;
codePtr++; //move past immediate
}
break;
case 0xC7: //move 16 or 32-bit immediate, easiest case for writes
{
if (info.operandSize == 2)
{
info.hasImmediate = true;
info.immediate = *(u16*)codePtr;
codePtr += 2;
}
else if (info.operandSize == 4)
{
info.hasImmediate = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
else if (info.operandSize == 8)
{
info.zeroExtend = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
}
break;
case 0x89: //move reg to memory
break;
default:
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
return false;
}
}
else
{
// Memory read
//mov eax, dword ptr [rax] == 8b 00
switch (codeByte)
{
case 0x0F:
switch (codeByte2)
{
case 0xB6: //movzx on byte
info.zeroExtend = true;
info.operandSize = 1;
break;
case 0xB7: //movzx on short
info.zeroExtend = true;
info.operandSize = 2;
break;
case 0xBE: //movsx on byte
info.signExtend = true;
info.operandSize = 1;
break;
case 0xBF:
info.signExtend = true;
info.operandSize = 2;
break;
default:
return false;
}
break;
case 0x8a:
if (info.operandSize == 4)
{
info.operandSize = 1;
break;
}
else
return false;
case 0x8b:
break; //it's OK don't need to do anything
default:
return false;
}
}
info.instructionSize = (int)(codePtr - startCodePtr);
return true;
}

File diff suppressed because it is too large Load Diff