mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
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:
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
}*/
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 = §ions[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 = §ions[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;
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(§ion, spincount);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeCriticalSection(§ion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CriticalSection::~CriticalSection()
|
||||
{
|
||||
DeleteCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Enter()
|
||||
{
|
||||
EnterCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
bool CriticalSection::TryEnter()
|
||||
{
|
||||
return(TryEnterCriticalSection(§ion) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Leave()
|
||||
{
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
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(§ion, spincount);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeCriticalSection(§ion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CriticalSection::~CriticalSection()
|
||||
{
|
||||
DeleteCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Enter()
|
||||
{
|
||||
EnterCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
bool CriticalSection::TryEnter()
|
||||
{
|
||||
return(TryEnterCriticalSection(§ion) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Leave()
|
||||
{
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(<ime);
|
||||
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(<ime);
|
||||
return((u64)ltime);
|
||||
}
|
||||
} // end of namespace Common
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
Reference in New Issue
Block a user