summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt11
-rw-r--r--src/common/common.vcxproj188
-rw-r--r--src/common/common.vcxproj.filters35
-rw-r--r--src/common/src/atomic.h36
-rw-r--r--src/common/src/atomic_gcc.h72
-rw-r--r--src/common/src/atomic_win32.h76
-rw-r--r--src/common/src/common.h246
-rw-r--r--src/common/src/config.cpp118
-rw-r--r--src/common/src/config.h345
-rw-r--r--src/common/src/crc.cpp86
-rw-r--r--src/common/src/crc.h81
-rw-r--r--src/common/src/file_utils.cpp451
-rw-r--r--src/common/src/file_utils.h90
-rw-r--r--src/common/src/hash.cpp241
-rw-r--r--src/common/src/hash.h46
-rw-r--r--src/common/src/hash_container.h116
-rw-r--r--src/common/src/log.cpp152
-rw-r--r--src/common/src/log.h216
-rw-r--r--src/common/src/misc_utils.cpp91
-rw-r--r--src/common/src/misc_utils.h58
-rw-r--r--src/common/src/platform.h135
-rw-r--r--src/common/src/std_condition_variable.h152
-rw-r--r--src/common/src/std_mutex.h354
-rw-r--r--src/common/src/std_thread.h309
-rw-r--r--src/common/src/timer.cpp46
-rw-r--r--src/common/src/timer.h51
-rw-r--r--src/common/src/types.h119
-rw-r--r--src/common/src/x86_utils.cpp236
-rw-r--r--src/common/src/x86_utils.h92
-rw-r--r--src/common/src/xml.cpp487
-rw-r--r--src/common/src/xml.h41
31 files changed, 4777 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
new file mode 100644
index 000000000..ace0c409d
--- /dev/null
+++ b/src/common/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(SRCS src/config.cpp
+ src/crc.cpp
+ src/file_utils.cpp
+ src/hash.cpp
+ src/log.cpp
+ src/misc_utils.cpp
+ src/timer.cpp
+ src/x86_utils.cpp
+ src/xml.cpp)
+
+add_library(common STATIC ${SRCS})
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
new file mode 100644
index 000000000..c61ba6d9d
--- /dev/null
+++ b/src/common/common.vcxproj
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DFE335FC-755D-4BAA-8452-94434F8A1EDB}</ProjectGuid>
+ <RootNamespace>common</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\vsprops\Base.props" />
+ <Import Project="..\..\vsprops\CodeGen_Debug.props" />
+ <Import Project="..\..\vsprops\Optimization_Debug.props" />
+ <Import Project="..\..\vsprops\Externals.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\vsprops\Base.props" />
+ <Import Project="..\..\vsprops\CodeGen_Debug.props" />
+ <Import Project="..\..\vsprops\Optimization_Debug.props" />
+ <Import Project="..\..\vsprops\Externals.props" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\vsprops\Base.props" />
+ <Import Project="..\..\vsprops\CodeGen_Release.props" />
+ <Import Project="..\..\vsprops\Optimization_Release.props" />
+ <Import Project="..\..\vsprops\Externals.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\vsprops\Base.props" />
+ <Import Project="..\..\vsprops\CodeGen_Release.props" />
+ <Import Project="..\..\vsprops\Optimization_Release.props" />
+ <Import Project="..\..\vsprops\Externals.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <CustomBuildBeforeTargets>
+ </CustomBuildBeforeTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <CustomBuildBeforeTargets />
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <CustomBuildBeforeTargets>
+ </CustomBuildBeforeTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <CustomBuildBeforeTargets />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile />
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ <Message>
+ </Message>
+ <Outputs>
+ </Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile />
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ <Message>
+ </Message>
+ <Outputs>
+ </Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile />
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ <Message>
+ </Message>
+ <Outputs>
+ </Outputs>
+ </CustomBuildStep>
+ <ClCompile />
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile />
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ <Message>
+ </Message>
+ <Outputs>
+ </Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\config.cpp" />
+ <ClCompile Include="src\crc.cpp" />
+ <ClCompile Include="src\file_utils.cpp" />
+ <ClCompile Include="src\hash.cpp" />
+ <ClCompile Include="src\log.cpp" />
+ <ClCompile Include="src\misc_utils.cpp" />
+ <ClCompile Include="src\timer.cpp" />
+ <ClCompile Include="src\x86_utils.cpp" />
+ <ClCompile Include="src\xml.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\atomic.h" />
+ <ClInclude Include="src\atomic_gcc.h" />
+ <ClInclude Include="src\atomic_win32.h" />
+ <ClInclude Include="src\common.h" />
+ <ClInclude Include="src\config.h" />
+ <ClInclude Include="src\crc.h" />
+ <ClInclude Include="src\file_utils.h" />
+ <ClInclude Include="src\hash.h" />
+ <ClInclude Include="src\hash_container.h" />
+ <ClInclude Include="src\log.h" />
+ <ClInclude Include="src\misc_utils.h" />
+ <ClInclude Include="src\platform.h" />
+ <ClInclude Include="src\std_condition_variable.h" />
+ <ClInclude Include="src\std_mutex.h" />
+ <ClInclude Include="src\std_thread.h" />
+ <ClInclude Include="src\timer.h" />
+ <ClInclude Include="src\types.h" />
+ <ClInclude Include="src\x86_utils.h" />
+ <ClInclude Include="src\xml.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
new file mode 100644
index 000000000..9d2b5c513
--- /dev/null
+++ b/src/common/common.vcxproj.filters
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="src\crc.cpp" />
+ <ClCompile Include="src\log.cpp" />
+ <ClCompile Include="src\timer.cpp" />
+ <ClCompile Include="src\xml.cpp" />
+ <ClCompile Include="src\config.cpp" />
+ <ClCompile Include="src\misc_utils.cpp" />
+ <ClCompile Include="src\hash.cpp" />
+ <ClCompile Include="src\x86_utils.cpp" />
+ <ClCompile Include="src\file_utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\crc.h" />
+ <ClInclude Include="src\platform.h" />
+ <ClInclude Include="src\common.h" />
+ <ClInclude Include="src\types.h" />
+ <ClInclude Include="src\log.h" />
+ <ClInclude Include="src\timer.h" />
+ <ClInclude Include="src\x86_utils.h" />
+ <ClInclude Include="src\config.h" />
+ <ClInclude Include="src\xml.h" />
+ <ClInclude Include="src\misc_utils.h" />
+ <ClInclude Include="src\atomic.h" />
+ <ClInclude Include="src\atomic_win32.h" />
+ <ClInclude Include="src\atomic_gcc.h" />
+ <ClInclude Include="src\std_condition_variable.h" />
+ <ClInclude Include="src\std_mutex.h" />
+ <ClInclude Include="src\std_thread.h" />
+ <ClInclude Include="src\hash_container.h" />
+ <ClInclude Include="src\hash.h" />
+ <ClInclude Include="src\file_utils.h" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/common/src/atomic.h b/src/common/src/atomic.h
new file mode 100644
index 000000000..a6a03fee3
--- /dev/null
+++ b/src/common/src/atomic.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file atomic.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-11
+ * @brief Cross-platform atomic operations
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_ATOMIC_H_
+#define COMMON_ATOMIC_H_
+
+#include "platform.h"
+
+#ifdef _WIN32
+#include "atomic_win32.h"
+#else
+#include "atomic_gcc.h"
+#endif
+
+#endif // COMMON_ATOMIC_H_ \ No newline at end of file
diff --git a/src/common/src/atomic_gcc.h b/src/common/src/atomic_gcc.h
new file mode 100644
index 000000000..660926561
--- /dev/null
+++ b/src/common/src/atomic_gcc.h
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file atomic_gcc.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-06-28
+ * @brief Cross-platform atomic operations - GCC
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_ATOMIC_GCC_H_
+#define COMMON_ATOMIC_GCC_H_
+
+#include "types.h"
+
+namespace common {
+
+inline void AtomicAdd(volatile u32& target, u32 value) {
+ __sync_add_and_fetch(&target, value);
+}
+
+inline void AtomicAnd(volatile u32& target, u32 value) {
+ __sync_and_and_fetch(&target, value);
+}
+
+inline void AtomicDecrement(volatile u32& target) {
+ __sync_add_and_fetch(&target, -1);
+}
+
+inline void AtomicIncrement(volatile u32& target) {
+ __sync_add_and_fetch(&target, 1);
+}
+
+inline u32 AtomicLoad(volatile u32& src) {
+ return src;
+}
+
+inline u32 AtomicLoadAcquire(volatile u32& src) {
+ u32 result = src;
+ __asm__ __volatile__ ( "":::"memory" );
+ return result;
+}
+
+inline void AtomicOr(volatile u32& target, u32 value) {
+ __sync_or_and_fetch(&target, value);
+}
+
+inline void AtomicStore(volatile u32& dest, u32 value) {
+ dest = value;
+}
+
+inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
+ __sync_lock_test_and_set(&dest, value);
+}
+
+} // namespace
+
+#endif // COMMON_ATOMIC_GCC_H_ \ No newline at end of file
diff --git a/src/common/src/atomic_win32.h b/src/common/src/atomic_win32.h
new file mode 100644
index 000000000..9dc4506cd
--- /dev/null
+++ b/src/common/src/atomic_win32.h
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file atomic_win32.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-06-28
+ * @brief Cross-platform atomic operations - Windows/Visual C++
+ * @remark Taken from Dolphin Emulator (http://code.google.com/p/dolphin-emu/)
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_ATOMIC_WIN32_H_
+#define COMMON_ATOMIC_WIN32_H_
+
+#include "types.h"
+
+#include <intrin.h>
+#include <Windows.h>
+
+namespace common {
+
+inline void AtomicAdd(volatile u32& target, u32 value) {
+ InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value);
+}
+
+inline void AtomicAnd(volatile u32& target, u32 value) {
+ _InterlockedAnd((volatile LONG*)&target, (LONG)value);
+}
+
+inline void AtomicIncrement(volatile u32& target) {
+ InterlockedIncrement((volatile LONG*)&target);
+}
+
+inline void AtomicDecrement(volatile u32& target) {
+ InterlockedDecrement((volatile LONG*)&target);
+}
+
+inline u32 AtomicLoad(volatile u32& src) {
+ return src;
+}
+
+inline u32 AtomicLoadAcquire(volatile u32& src) {
+ u32 result = src;
+ _ReadBarrier();
+ return result;
+}
+
+inline void AtomicOr(volatile u32& target, u32 value) {
+ _InterlockedOr((volatile LONG*)&target, (LONG)value);
+}
+
+inline void AtomicStore(volatile u32& dest, u32 value) {
+ dest = value;
+}
+inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
+ _WriteBarrier();
+ dest = value;
+}
+
+} // namespace
+
+#endif // COMMON_ATOMIC_WIN32_H_ \ No newline at end of file
diff --git a/src/common/src/common.h b/src/common/src/common.h
new file mode 100644
index 000000000..f12cd461d
--- /dev/null
+++ b/src/common/src/common.h
@@ -0,0 +1,246 @@
+/*!
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * \file common.h
+ * \author ShizZy <shizzy247@gmail.com>
+ * \date 2012-02-04
+ * \brief Common header for using the common library
+ *
+ * \section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_COMMON_H_
+#define COMMON_COMMON_H_
+
+#include "platform.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Preprocessor stuff
+
+#define GEKKO_QUOTE_INPLACE(x) # x
+#define GEKKO_QUOTE(x) GEKKO_QUOTE_INPLACE(x)
+#define __FILE__LINE__ __FILE__ "(" GEKKO_QUOTE(__LINE__) ") : "
+#define GEKKO_TODO(x) __FILE__LINE__ x "\n"
+
+#if EMU_PLATFORM == PLATFORM_WINDOWS
+
+// All inline assembly is x86 right now!
+#ifdef EMU_ARCHITECTURE_X86
+#define USE_INLINE_ASM_X86
+#endif // EMU_ARCHITECTURE_X86
+
+#pragma warning( disable : 4786 ) //disable the truncated 255 character limit warning for debug identifiers
+
+#ifdef LEAK_DETECT
+#define _CRTDBG_MAP_ALLOC
+#define _INC_MALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif // LEAK_DETECT
+
+#define TODO( x ) message( __FILE__LINE__" TODO : " #x "\n" )
+#define todo( x ) message( __FILE__LINE__" TODO : " #x "\n" )
+
+#endif // PLATFORM_WINDOWS
+
+#define E_OK 0
+#define E_ERR 1
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes
+#include <xmmintrin.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// C Includes
+#include <cmath>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <csignal>
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ Includes
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+// OS-Specific Includes
+#if EMU_PLATFORM == PLATFORM_WINDOWS
+ #include <direct.h>
+ #include <windows.h>
+ #include <commctrl.h>
+ #include <commdlg.h>
+ #include <shlwapi.h>
+ #include <shlobj.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Big Endian bit Access (Bits numbered ascending from leftmost to rightmost)
+#define BIT_0 0x80000000
+#define BIT_1 0x40000000
+#define BIT_2 0x20000000
+#define BIT_3 0x10000000
+#define BIT_4 0x8000000
+#define BIT_5 0x4000000
+#define BIT_6 0x2000000
+#define BIT_7 0x1000000
+#define BIT_8 0x800000
+#define BIT_9 0x400000
+#define BIT_10 0x200000
+#define BIT_11 0x100000
+#define BIT_12 0x80000
+#define BIT_13 0x40000
+#define BIT_14 0x20000
+#define BIT_15 0x10000
+#define BIT_16 0x8000
+#define BIT_17 0x4000
+#define BIT_18 0x2000
+#define BIT_19 0x1000
+#define BIT_20 0x800
+#define BIT_21 0x400
+#define BIT_22 0x200
+#define BIT_23 0x100
+#define BIT_24 0x80
+#define BIT_25 0x40
+#define BIT_26 0x20
+#define BIT_27 0x10
+#define BIT_28 0x8
+#define BIT_29 0x4
+#define BIT_30 0x2
+#define BIT_31 0x1
+
+#define SIGNED_BIT8 ((u8) 1 << 7)
+#define SIGNED_BIT16 ((u16) 1 << 15)
+#define SIGNED_BIT32 ((u32) 1 << 31)
+#define SIGNED_BIT64 ((u64) 1 << 63)
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#ifdef _DEBUG
+ #ifndef _DEBUGSPEED
+ #define DEBUG_EMU
+ #define DEBUG_GX
+ #endif
+#endif
+
+#ifdef DEBUG_EMU
+#define ASSERT_T(cond,str) if((cond)) printf("#!\tERROR: ASSERTION FAILED: %s !\n", str);
+#define ASSERT_F(cond,str) if(!(cond)) printf("#!\tERROR: ASSERTION FAILED: %s !\n", str);
+#else
+#define ASSERT_T(cond,str)
+#define ASSERT_F(cond,str)
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+void DisplayError (char * Message, ...);
+
+#ifdef _MSC_VER
+# ifdef LEAK_DETECT
+# undef malloc
+# define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__, __LINE__)
+# define new DEBUG_NEW
+# define malloc(s) _malloc_dbg(s,_NORMAL_BLOCK,__FILE__,__LINE__)
+# define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
+# define free(p) _free_dbg(p, _NORMAL_BLOCK)
+# endif
+# define U64(a) a ## ui64
+# define S64(a) a ## si64
+#else //gcc
+# define U64(a) a ## ull
+# define S64(a) a ## sll
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "types.h"
+#include "log.h"
+#include "atomic.h"
+#include "misc_utils.h"
+#include "x86_utils.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+__inline static s16 toSHORT(u16 x)
+{
+ return *(s16*)&x;
+}
+
+__inline static f32 toFLOAT(u32 x)
+{
+ return *(f32*)&x;
+}
+
+__inline static f32 toFLOATS(s32 x)
+{
+ return *(f32*)&x;
+}
+
+__inline static f64 toDOUBLE(u64 x)
+{
+ return *(f64*)&x;
+}
+
+typedef void(*optable)(void);
+typedef void(EMU_FASTCALL *hwtable)(u32, u32*);
+
+////////////////////////////////////////////////////////////////////////////////
+// Fast Macros
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+#define CLAMP(X,min,max) (((X) > max) ? max : (((X) < min) ? min : (X)))
+
+__inline static u32 BSWAP24(u32 x)
+{
+ return (((x & 0xff0000) >> 16) | (x & 0xff00) | ((x & 0xff) << 16));
+}
+
+#if _MSC_VER > 1200
+
+#define BSWAP16(x) _byteswap_ushort(x)
+#define BSWAP32(x) _byteswap_ulong(x)
+#define BSWAP64(x) _byteswap_uint64(x)
+
+#else
+__inline static u16 BSWAP16(u16 x)
+{
+ return ((x)>>8) | ((x)<<8);
+}
+
+__inline static u32 BSWAP32(u32 x)
+{
+ return (BSWAP16((x)&0xffff)<<16) | (BSWAP16((x)>>16));
+}
+
+__inline static u64 BSWAP64(u64 x)
+{
+ return (u64)(((u64)BSWAP32((u32)(x&0xffffffff)))<<32) | (BSWAP32((u32)(x>>32)));
+}
+#endif
+
+
+#endif // COMMON_COMMON_H_
diff --git a/src/common/src/config.cpp b/src/common/src/config.cpp
new file mode 100644
index 000000000..c26789bf8
--- /dev/null
+++ b/src/common/src/config.cpp
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file config.cpp
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-19
+ * @brief Emulator configuration class - all config settings stored here
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "common.h"
+#include "config.h"
+#include "xml.h"
+
+namespace common {
+
+Config* g_config;
+
+Config::Config() {
+ ResolutionType default_res;
+ RendererConfig default_renderer_config;
+
+ default_renderer_config.enable_wireframe = false;
+ default_renderer_config.enable_shaders = true;
+ default_renderer_config.enable_texture_dumping = false;
+ default_renderer_config.enable_textures = true;
+ default_renderer_config.anti_aliasing_mode = 0;
+ default_renderer_config.anistropic_filtering_mode = 0;
+
+ default_res.width = 640;
+ default_res.height = 480;
+
+ set_program_dir("", MAX_PATH);
+ set_enable_multicore(true);
+ set_enable_idle_skipping(false);
+ set_enable_hle(true);
+ set_enable_auto_boot(true);
+ set_enable_cheats(false);
+ set_default_boot_file("", MAX_PATH);
+ memset(dvd_image_paths_, 0, sizeof(dvd_image_paths_));
+ set_enable_show_fps(true);
+ set_enable_dump_opcode0(false);
+ set_enable_pause_on_unknown_opcode(true);
+ set_enable_dump_gcm_reads(false);
+ set_enable_ipl(false);
+ set_powerpc_core(CPU_INTERPRETER);
+ set_powerpc_frequency(486);
+
+ memset(renderer_config_, 0, sizeof(renderer_config_));
+ set_renderer_config(RENDERER_OPENGL_3, default_renderer_config);
+ set_current_renderer(RENDERER_OPENGL_3);
+
+ set_enable_fullscreen(false);
+ set_window_resolution(default_res);
+ set_fullscreen_resolution(default_res);
+
+ memset(controller_ports_, 0, sizeof(controller_ports_));
+ memset(mem_slots_, 0, sizeof(mem_slots_));
+
+ memset(patches_, 0, sizeof(patches_));
+ memset(cheats_, 0, sizeof(patches_));
+}
+
+Config::~Config() {
+}
+
+ConfigManager::ConfigManager() {
+ set_program_dir("", MAX_PATH);
+}
+
+ConfigManager::~ConfigManager() {
+}
+
+/**
+ * @brief Reload a game-specific configuration
+ * @param id Game id (to load game specific configuration)
+ */
+void ConfigManager::ReloadGameConfig(const char* id) {
+ char full_filename[MAX_PATH];
+ sprintf(full_filename, "user/games/%s.xml", id);
+ common::LoadXMLConfig(*g_config, full_filename);
+}
+
+/// Reload the userconfig file
+void ConfigManager::ReloadUserConfig() {
+ common::LoadXMLConfig(*g_config, "userconf.xml");
+}
+
+/// Reload the sysconfig file
+void ConfigManager::ReloadSysConfig() {
+ common::LoadXMLConfig(*g_config, "sysconf.xml");
+}
+
+/// Reload all configurations
+void ConfigManager::ReloadConfig(const char* game_id) {
+ delete g_config;
+ g_config = new Config();
+ g_config->set_program_dir(program_dir_, MAX_PATH);
+ ReloadSysConfig();
+ ReloadUserConfig();
+ ReloadGameConfig(game_id);
+}
+
+} // namspace \ No newline at end of file
diff --git a/src/common/src/config.h b/src/common/src/config.h
new file mode 100644
index 000000000..843d0d312
--- /dev/null
+++ b/src/common/src/config.h
@@ -0,0 +1,345 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file config.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-11
+ * @brief Emulator configuration class - all config settings stored here
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_CONFIG_H_
+#define COMMON_CONFIG_H_
+
+#include "common.h"
+
+#define MAX_SEARCH_PATHS 16 ///< Maximum paths to search for files in
+
+/// If you need more than this... you're just lazy ;-)
+#define MAX_PATCHES_PER_GAME 128 ///< Maximum patches allowed per game
+
+namespace common {
+
+/// Class for storing emulator configuration(s)
+class Config {
+public:
+ Config();
+ ~Config();
+
+ /// Struct used for defining game-specific patches
+ struct Patch {
+ u32 address; ///< Address to patch
+ u32 data; ///< Data to write at the specified address
+ };
+
+ /// Struct used for configuring what is inserted in a memory slot
+ struct MemSlot {
+ u8 device; ///< Memory slot device (0 - memcard)
+ bool enable; ///< Enable (plugged in?)
+ };
+
+ enum Control {
+ BUTTON_A = 0,
+ BUTTON_B,
+ BUTTON_X,
+ BUTTON_Y,
+ TRIGGER_L,
+ TRIGGER_R,
+ BUTTON_Z,
+ BUTTON_START,
+ ANALOG_UP,
+ ANALOG_DOWN,
+ ANALOG_LEFT,
+ ANALOG_RIGHT,
+ C_UP,
+ C_DOWN,
+ C_LEFT,
+ C_RIGHT,
+ DPAD_UP,
+ DPAD_DOWN,
+ DPAD_LEFT,
+ DPAD_RIGHT,
+ NUM_CONTROLS
+ };
+
+ /// Struct used for defining a keyboard configuration for a GameCube controller
+ /// Reads/Writes from/to members should be atomic
+ struct KeyboardController {
+ bool enable; ///< Is the keyboard configation enabled?
+ int key_code[NUM_CONTROLS];
+ };
+
+ /// Struct used for defining a joypad configuration for a GameCube controller
+ /// We'll make another struct in case the user wants seperate joypad config
+ struct JoypadController {
+ bool enable; ///< Is the joypad configation enabled?
+ int key_code[NUM_CONTROLS];
+ };
+
+ /// Struct used for configuring what is inserted in a controller port
+ typedef struct {
+ u8 device; ///< Controller port device (0 - controller)
+ bool enable; ///< Enable (plugged in?)
+ KeyboardController keys; ///< Keyboard configuration for controller (if used)
+ JoypadController pads; ///< Joypad configuration for controller (if used)
+ } ControllerPort;
+
+ /// Enum for supported CPU types
+ enum CPUCoreType {
+ CPU_NULL = 0, ///< No CPU core
+ CPU_INTERPRETER, ///< Interpreter CPU core
+ CPU_DYNAREC, ///< Dynamic recompiler CPU core
+ NUMBER_OF_CPU_CONFIGS
+ };
+
+ /// Struct used for defining a renderer configuration
+ struct RendererConfig {
+ bool enable_wireframe;
+ bool enable_shaders;
+ bool enable_texture_dumping;
+ bool enable_textures;
+ int anti_aliasing_mode;
+ int anistropic_filtering_mode;
+ } ;
+
+ /// Struct used for configuring a screen resolution
+ struct ResolutionType {
+ int width;
+ int height;
+ };
+
+ /// Enum for supported video cores
+ enum RendererType {
+ RENDERER_NULL, ///< No video core
+ RENDERER_OPENGL_2, ///< OpenGL 2.0 core
+ RENDERER_OPENGL_3, ///< OpenGL 3.0 core (not implemented)
+ RENDERER_DIRECTX9, ///< DirectX9 core (not implemented)
+ RENDERER_DIRECTX10, ///< DirectX10 core (not implemented)
+ RENDERER_DIRECTX11, ///< DirectX11 core (not implemented)
+ RENDERER_SOFTWARE, ///< Software core (not implemented)
+ RENDERER_HARDWARE, ///< Hardware core (not implemented- this would be a driver)
+ NUMBER_OF_VIDEO_CONFIGS
+ };
+
+ char* program_dir() { return program_dir_; }
+ void set_program_dir(const char* val, size_t size) { strcpy(program_dir_, val); }
+
+ bool enable_multicore() { return enable_multicore_; }
+ bool enable_idle_skipping() {return enable_idle_skipping_; }
+ bool enable_hle() { return enable_hle_; }
+ bool enable_auto_boot() { return enable_auto_boot_; }
+ bool enable_cheats() { return enable_cheats_; }
+ void set_enable_multicore(bool val) { enable_multicore_ = val; }
+ void set_enable_idle_skipping(bool val) {enable_idle_skipping_ = val; }
+ void set_enable_hle(bool val) { enable_hle_ = val; }
+ void set_enable_auto_boot(bool val) { enable_auto_boot_ = val; }
+ void set_enable_cheats(bool val) { enable_cheats_ = val; }
+
+ char* default_boot_file() { return default_boot_file_; }
+ char* dvd_image_path(int path) { return dvd_image_paths_[path]; }
+ void set_default_boot_file(const char* val, size_t size) { strcpy(default_boot_file_, val); }
+ void set_dvd_image_path(int path, char* val, size_t size) { strcpy(dvd_image_paths_[path], val); }
+
+ bool enable_show_fps() { return enable_show_fps_; }
+ bool enable_dump_opcode0() { return enable_dump_opcode0_; }
+ bool enable_pause_on_unknown_opcode() { return enable_pause_on_unknown_opcode_; }
+ bool enable_dump_gcm_reads() { return enable_dump_gcm_reads_; }
+ void set_enable_show_fps(bool val) { enable_show_fps_ = val; }
+ void set_enable_dump_opcode0(bool val) { enable_dump_opcode0_ = val; }
+ void set_enable_pause_on_unknown_opcode(bool val) { enable_pause_on_unknown_opcode_ = val; }
+ void set_enable_dump_gcm_reads(bool val) { enable_dump_gcm_reads_ = val; }
+
+ bool enable_ipl() { return enable_ipl_; }
+ void set_enable_ipl(bool val) { enable_ipl_ = val; }
+
+ Patch patches(int patch) { return patches_[patch]; }
+ Patch cheats(int cheat) { return cheats_[cheat]; }
+ void set_patches(int patch, Patch val) { patches_[patch] = val; }
+ void set_cheats(int cheat, Patch val) { cheats_[cheat] = val; }
+
+ CPUCoreType powerpc_core() { return powerpc_core_; }
+ void set_powerpc_core(CPUCoreType val) { powerpc_core_ = val; }
+
+ int powerpc_frequency() { return powerpc_frequency_; }
+ void set_powerpc_frequency(int val) { powerpc_frequency_ = val; }
+
+ RendererType current_renderer() { return current_renderer_; }
+ void set_current_renderer(RendererType val) { current_renderer_ = val; }
+
+ RendererConfig renderer_config(RendererType val) { return renderer_config_[val]; }
+ RendererConfig current_renderer_config() { return renderer_config_[current_renderer_]; }
+ void set_renderer_config(RendererType renderer, RendererConfig config) {
+ renderer_config_[renderer] = config;
+ }
+
+ bool enable_fullscreen() { return enable_fullscreen_; }
+ void set_enable_fullscreen(bool val) { enable_fullscreen_ = val; }
+
+ ResolutionType window_resolution() { return window_resolution_; }
+ ResolutionType fullscreen_resolution() { return fullscreen_resolution_; }
+ void set_window_resolution(ResolutionType val) { window_resolution_ = val; }
+ void set_fullscreen_resolution(ResolutionType val) { fullscreen_resolution_ = val; }
+
+ // TODO: Should be const, but pending removal of some gekko_qt hacks
+ /*const */ControllerPort& controller_ports(int port) { return controller_ports_[port]; }
+ void set_controller_ports(int port, ControllerPort val) { controller_ports_[port] = val; }
+
+ MemSlot mem_slots(int slot) { return mem_slots_[slot]; }
+ void set_mem_slots(int slot, MemSlot val) { mem_slots_[slot] = val; }
+
+ /**
+ * @brief Gets a RenderType from a string (used from XML)
+ * @param renderer_str Renderer name string, see XML schema for list
+ * @return Corresponding RenderType
+ */
+ static inline RendererType StringToRenderType(const char* renderer_str) {
+ if (E_OK == _stricmp(renderer_str, "opengl2")) {
+ return RENDERER_OPENGL_2;
+ } else if (E_OK == _stricmp(renderer_str, "opengl3")) {
+ return RENDERER_OPENGL_3;
+ } else if (E_OK == _stricmp(renderer_str, "directx9")) {
+ return RENDERER_DIRECTX9;
+ } else if (E_OK == _stricmp(renderer_str, "directx10")) {
+ return RENDERER_DIRECTX10;
+ } else if (E_OK == _stricmp(renderer_str, "directx11")) {
+ return RENDERER_DIRECTX11;
+ } else if (E_OK == _stricmp(renderer_str, "software")) {
+ return RENDERER_SOFTWARE;
+ } else if (E_OK == _stricmp(renderer_str, "hardware")) {
+ return RENDERER_HARDWARE;
+ } else {
+ return RENDERER_NULL;
+ }
+ }
+
+ /**
+ * @brief Gets the renderer string from the type
+ * @param renderer Renderer to get string for
+ * @return Renderer string name
+ */
+ static std::string RenderTypeToString(RendererType renderer) {
+ switch (renderer) {
+ case RENDERER_OPENGL_2:
+ return "opengl2";
+ case RENDERER_OPENGL_3:
+ return "opengl3";
+ case RENDERER_DIRECTX9:
+ return "directx9";
+ case RENDERER_DIRECTX10:
+ return "directx10";
+ case RENDERER_DIRECTX11:
+ return "directx11";
+ case RENDERER_SOFTWARE:
+ return "software";
+ case RENDERER_HARDWARE:
+ return "hardware";
+ }
+ return "null";
+ }
+
+ /**
+ * @brief Gets the CPU string from the type
+ * @param cpu CPU to get string for
+ * @param cpu_str String result
+ * @param size Max size to write to string
+ */
+ static std::string CPUCoreTypeToString(CPUCoreType cpu) {
+ switch (cpu) {
+ case CPU_INTERPRETER:
+ return "interpreter";
+ case CPU_DYNAREC:
+ return "dynarec";
+ }
+ return "null";
+ }
+
+private:
+ char program_dir_[MAX_PATH];
+
+ bool enable_multicore_;
+ bool enable_idle_skipping_;
+ bool enable_hle_;
+ bool enable_auto_boot_;
+ bool enable_cheats_;
+
+ char default_boot_file_[MAX_PATH];
+ char dvd_image_paths_[MAX_SEARCH_PATHS][MAX_PATH];
+
+ bool enable_show_fps_;
+ bool enable_dump_opcode0_;
+ bool enable_pause_on_unknown_opcode_;
+ bool enable_dump_gcm_reads_;
+
+ bool enable_ipl_;
+
+ Patch patches_[MAX_PATCHES_PER_GAME];
+ Patch cheats_[MAX_PATCHES_PER_GAME];
+
+ CPUCoreType powerpc_core_;
+
+ int powerpc_frequency_;
+
+ bool enable_fullscreen_;
+
+ RendererType current_renderer_;
+
+ ResolutionType window_resolution_;
+ ResolutionType fullscreen_resolution_;
+
+ RendererConfig renderer_config_[NUMBER_OF_VIDEO_CONFIGS];
+
+ MemSlot mem_slots_[2];
+ ControllerPort controller_ports_[4];
+
+ DISALLOW_COPY_AND_ASSIGN(Config);
+};
+
+class ConfigManager {
+public:
+ ConfigManager();
+ ~ConfigManager();
+
+ /**
+ * @brief Reload a game-specific configuration
+ * @param id Game id (to load game specific configuration)
+ */
+ void ReloadGameConfig(const char* id);
+
+ /// Reload the userconfig file
+ void ReloadUserConfig();
+
+ // Reload the sysconfig file
+ void ReloadSysConfig();
+
+ /// Reload all configurations
+ void ReloadConfig(const char* game_id);
+
+ char* program_dir() { return program_dir_; }
+
+ void set_program_dir(const char* val, size_t size) { strcpy(program_dir_, val); }
+
+private:
+ char program_dir_[MAX_PATH]; ///< Program directory, used for loading config files
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigManager);
+};
+
+extern Config* g_config; ///< Global configuration for emulator
+
+} // namspace
+
+#endif // COMMON_CONFIG_H_
diff --git a/src/common/src/crc.cpp b/src/common/src/crc.cpp
new file mode 100644
index 000000000..a36dfdad8
--- /dev/null
+++ b/src/common/src/crc.cpp
@@ -0,0 +1,86 @@
+#include "common.h"
+#include "crc.h"
+
+u32 crc32_table[4][256];
+
+u32 Reflect(u32 ref, u8 Count)
+{
+ u32 value = 0;
+
+ // Swap bit 0 for bit 7
+ // bit 1 for bit 6, etc.
+ for(int i = 1; i < (Count + 1); i++)
+ {
+ if(ref & 1)
+ value |= 1 << (Count - i);
+ ref >>= 1;
+ }
+ return value;
+}
+
+void Init_CRC32_Table()
+{
+ // This is the official polynomial used by CRC-32
+ // in PKZip, WinZip and Ethernet.
+ u32 ulPolynomial = 0x04c11db7;
+
+ // 256 values representing ASCII character codes.
+ for(int x = 0; x < 4; x++)
+ {
+ for(int i = 0; i <= 0xFF; i++)
+ {
+ crc32_table[x][i]=Reflect(i, 8) << 24;
+ for (int j = 0; j < 8; j++)
+ crc32_table[x][i] = (crc32_table[x][i] << 1) ^ (crc32_table[x][i] & (1 << 31) ? (ulPolynomial + (x * 8)) : 0);
+ crc32_table[x][i] = Reflect(crc32_table[x][i], 32);
+ }
+ }
+}
+
+u32 GenerateCRC(u8 *StartAddr, u32 len)
+{
+ u32 ulCRC = -1;
+
+ // Perform the algorithm on each character
+ // in the string, using the lookup table values.
+ for(; len > 7; len-=8)
+ {
+ ulCRC ^= *(u32 *)StartAddr;
+ ulCRC = crc32_table[3][((ulCRC) & 0xFF)] ^
+ crc32_table[2][((ulCRC >> 8) & 0xFF)] ^
+ crc32_table[1][((ulCRC >> 16) & 0xFF)] ^
+ crc32_table[0][((ulCRC >> 24))];
+ ulCRC ^= *(u32 *)(StartAddr + 4);
+ ulCRC = crc32_table[3][((ulCRC) & 0xFF)] ^
+ crc32_table[2][((ulCRC >> 8) & 0xFF)] ^
+ crc32_table[1][((ulCRC >> 16) & 0xFF)] ^
+ crc32_table[0][((ulCRC >> 24))];
+ StartAddr+=8;
+ }
+
+ if(len > 3)
+ {
+ ulCRC ^= *(u32 *)StartAddr;
+ ulCRC = crc32_table[3][((ulCRC) & 0xFF)] ^
+ crc32_table[2][((ulCRC >> 8) & 0xFF)] ^
+ crc32_table[1][((ulCRC >> 16) & 0xFF)] ^
+ crc32_table[0][((ulCRC >> 24))];
+ StartAddr+=4;
+ len -= 4;
+ }
+
+ switch(len)
+ {
+ case 3:
+ ulCRC = crc32_table[0][(ulCRC & 0xFF) ^ *StartAddr] ^ (ulCRC >> 8);
+ StartAddr++;
+ case 2:
+ ulCRC = crc32_table[0][(ulCRC & 0xFF) ^ *StartAddr] ^ (ulCRC >> 8);
+ StartAddr++;
+ case 1:
+ ulCRC = crc32_table[0][(ulCRC & 0xFF) ^ *StartAddr] ^ (ulCRC >> 8);
+ StartAddr++;
+ }
+
+ return ulCRC;
+}
diff --git a/src/common/src/crc.h b/src/common/src/crc.h
new file mode 100644
index 000000000..2bb3210d8
--- /dev/null
+++ b/src/common/src/crc.h
@@ -0,0 +1,81 @@
+#ifndef COMMON_CRC_H_
+#define COMMON_CRC_H_
+
+#include "types.h"
+#include "platform.h"
+
+#define CRC_ROTL(crc) crc32_table[3][((crc) & 0xFF)] ^ crc32_table[2][((crc >> 8) & 0xFF)] ^ \
+ crc32_table[1][((crc >> 16) & 0xFF)] ^ crc32_table[0][((crc >> 24))]
+
+// Some definitions for using the X86 CRC32 instruction on different platforms. Keep in mind, you
+// should check for X86/X64 architecture support before using these, as well as for SSE 4.2 (see the
+// x86_utils module).
+
+#if defined(EMU_ARCHITECTURE_X86) || defined(EMU_ARCHITECTURE_X64)
+
+#if EMU_PLATFORM == PLATFORM_WINDOWS
+
+#include <nmmintrin.h>
+
+#ifdef EMU_ARCHITECTURE_X64
+static inline u64 InlineCrc32_U64(u64 crc, u64 value) {
+ return _mm_crc32_u64(crc, value);
+}
+#endif
+static inline u32 InlineCrc32_U32(u32 crc, u64 value) {
+ return _mm_crc32_u32(crc, static_cast<u32>(value));
+}
+
+static inline u32 InlineCrc32_U8(u32 crc, u8 value) {
+ return _mm_crc32_u8(crc, value);
+}
+
+#elif GCC_VERSION_AVAILABLE(4, 5) && defined(__SSE4_2__)
+
+extern inline unsigned int __attribute__((
+ __gnu_inline__, __always_inline__, __artificial__))
+InlineCrc32_U8(unsigned int __C, unsigned char __V) {
+ return __builtin_ia32_crc32qi(__C, __V);
+}
+#ifdef EMU_ARCHITECTURE_X64
+extern inline unsigned long long __attribute__((
+ __gnu_inline__, __always_inline__, __artificial__))
+InlineCrc32_U64(unsigned long long __C, unsigned long long __V) {
+ return __builtin_ia32_crc32di(__C, __V);
+}
+#else
+extern inline unsigned int __attribute__((
+ __gnu_inline__, __always_inline__, __artificial__))
+InlineCrc32_U32(unsigned int __C, unsigned int __V) {
+ return __builtin_ia32_crc32si (__C, __V);
+}
+#endif // EMU_ARCHITECTURE_X64
+
+#else
+
+// GCC 4.4.x and earlier: use inline asm, or msse4.2 flag not set
+
+static inline u64 InlineCrc32_U64(u64 crc, u64 value) {
+ asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
+ return crc;
+}
+
+static inline u32 InlineCrc32_U32(u32 crc, u64 value) {
+ asm("crc32l %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
+ return crc;
+}
+
+static inline u32 InlineCrc32_U8(u32 crc, u8 value) {
+ asm("crc32b %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
+ return crc;
+}
+#endif
+
+#endif // EMU_ARCHITECTURE_X86 or EMU_ARCHITECTURE_X64
+
+extern u32 crc32_table[4][256];
+
+void Init_CRC32_Table();
+u32 GenerateCRC(u8 *StartAddr, u32 Len);
+
+#endif // COMMON_CRC_H_
diff --git a/src/common/src/file_utils.cpp b/src/common/src/file_utils.cpp
new file mode 100644
index 000000000..6e792fcde
--- /dev/null
+++ b/src/common/src/file_utils.cpp
@@ -0,0 +1,451 @@
+/**
+* Copyright (C) 2005-2013 Gekko Emulator
+*
+* @file file_utils.cpp
+* @author ShizZy <shizzy247@gmail.com>
+* @date 2013-01-27
+* @brief Crossplatform file utility functions
+* @remark Borrowed from Dolphin Emulator
+*
+* @section LICENSE
+* 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; either version 2 of
+* the License, or (at your option) any later version.
+*
+* 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 for more details at
+* http://www.gnu.org/copyleft/gpl.html
+*
+* Official project repository can be found at:
+* http://code.google.com/p/gekko-gc-emu/
+*/
+
+#include "types.h"
+#include "file_utils.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/param.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFURL.h>
+#include <CoreFoundation/CFBundle.h>
+#endif
+
+#include <fstream>
+#include <sys/stat.h>
+
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif
+
+#ifdef BSD4_4
+#define stat64 stat
+#define fstat64 fstat
+#endif
+
+#ifdef _MSC_VER
+#define __strdup _strdup
+#define __getcwd _getcwd
+#define __chdir _chdir
+
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#define atoll _atoi64
+#define stat64 _stat64
+#define fstat64 _fstat64
+#define fileno _fileno
+
+#else
+#define __strdup strdup
+#define __getcwd getcwd
+#define __chdir chdir
+#endif
+
+namespace common {
+
+// Remove any ending forward slashes from directory paths
+// Modifies argument.
+static void StripTailDirSlashes(std::string &fname) {
+ if (fname.length() > 1) {
+ size_t i = fname.length() - 1;
+ while (fname[i] == '/') {
+ fname[i--] = '\0';
+ }
+ }
+}
+
+// Returns true if file filename exists
+bool FileExists(const std::string &filename) {
+ struct stat64 file_info;
+ std::string copy(filename);
+ StripTailDirSlashes(copy);
+ return (stat64(copy.c_str(), &file_info) == 0);
+}
+
+// Returns true if filename is a directory
+bool IsDirectory(const std::string &filename) {
+ struct stat64 file_info;
+ std::string copy(filename);
+ StripTailDirSlashes(copy);
+ if (stat64(copy.c_str(), &file_info) < 0) {
+ LOG_WARNING(TCOMMON, "IsDirectory: stat failed on %s", filename.c_str());
+ return false;
+ }
+ return S_ISDIR(file_info.st_mode);
+}
+
+// Deletes a given filename, return true on success
+// Doesn't supports deleting a directory
+bool DeleteFile(const std::string &filename) {
+ LOG_INFO(TCOMMON, "Delete: file %s", filename.c_str());
+ // Return true because we care about the file no
+ // being there, not the actual delete.
+ if (!FileExists(filename)) {
+ LOG_WARNING(TCOMMON, "Delete: %s does not exists", filename.c_str());
+ return true;
+ }
+ // We can't delete a directory
+ if (IsDirectory(filename)) {
+ LOG_WARNING(TCOMMON, "Delete failed: %s is a directory", filename.c_str());
+ return false;
+ }
+#ifdef _WIN32
+ if (!DeleteFile(filename.c_str())) {
+ LOG_WARNING(TCOMMON, "Delete: DeleteFile failed on %s", filename.c_str());
+ return false;
+ }
+#else
+ if (unlink(filename.c_str()) == -1) {
+ LOG_WARNING(TCOMMON, "Delete: unlink failed on %s", filename.c_str());
+ return false;
+ }
+#endif
+ return true;
+}
+
+// Returns true if successful, or path already exists.
+bool CreateDir(const std::string &path) {
+ LOG_INFO(TCOMMON, "CreateDir: directory %s", path.c_str());
+#ifdef _WIN32
+ if (::CreateDirectory(path.c_str(), NULL)) {
+ return true;
+ }
+ DWORD error = GetLastError();
+ if (error == ERROR_ALREADY_EXISTS)
+ {
+ LOG_WARNING(TCOMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
+ return true;
+ }
+ LOG_ERROR(TCOMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
+ return false;
+#else
+ if (mkdir(path.c_str(), 0755) == 0) {
+ return true;
+ }
+ int err = errno;
+ if (err == EEXIST) {
+ LOG_WARNING(TCOMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
+ return true;
+ }
+ LOG_ERROR(TCOMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
+ return false;
+#endif
+}
+
+// Creates the full path of fullPath returns true on success
+bool CreateFullPath(const std::string &fullPath) {
+ int panicCounter = 100;
+ LOG_INFO(TCOMMON, "CreateFullPath: path %s", fullPath.c_str());
+
+ if (FileExists(fullPath)) {
+ LOG_INFO(TCOMMON, "CreateFullPath: path exists %s", fullPath.c_str());
+ return true;
+ }
+
+ size_t position = 0;
+ while (1) {
+ // Find next sub path
+ position = fullPath.find('/', position);
+
+ // we're done, yay!
+ if (position == fullPath.npos) {
+ return true;
+ }
+ std::string subPath = fullPath.substr(0, position);
+ if (!IsDirectory(subPath)) CreateDir(subPath);
+
+ // A safety check
+ panicCounter--;
+ if (panicCounter <= 0) {
+ LOG_ERROR(TCOMMON, "CreateFullPath: directory structure too deep");
+ return false;
+ }
+ position++;
+ }
+}
+
+// Deletes a directory filename, returns true on success
+bool DeleteDir(const std::string &filename) {
+ LOG_INFO(TCOMMON, "DeleteDir: directory %s", filename.c_str());
+ // check if a directory
+ if (!IsDirectory(filename)) {
+ LOG_ERROR(TCOMMON, "DeleteDir: Not a directory %s", filename.c_str());
+ return false;
+ }
+#ifdef _WIN32
+ if (::RemoveDirectory(filename.c_str()))
+ return true;
+#else
+ if (rmdir(filename.c_str()) == 0)
+ return true;
+#endif
+ LOG_ERROR(TCOMMON, "DeleteDir: %s", filename.c_str());
+ return false;
+}
+
+// renames file srcFilename to destFilename, returns true on success
+bool RenameFile(const std::string &srcFilename, const std::string &destFilename) {
+ LOG_INFO(TCOMMON, "Rename: %s --> %s",
+ srcFilename.c_str(), destFilename.c_str());
+ if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
+ return true;
+ LOG_ERROR(TCOMMON, "Rename: failed %s --> %s", srcFilename.c_str(), destFilename.c_str());
+ return false;
+}
+
+// copies file srcFilename to destFilename, returns true on success
+bool CopyFile(const std::string &srcFilename, const std::string &destFilename) {
+ LOG_INFO(TCOMMON, "Copy: %s --> %s",
+ srcFilename.c_str(), destFilename.c_str());
+#ifdef _WIN32
+ if (::CopyFile(srcFilename.c_str(), destFilename.c_str(), FALSE))
+ return true;
+
+ LOG_ERROR(TCOMMON, "Copy: failed %s --> %s", srcFilename.c_str(), destFilename.c_str());
+ return false;
+#else
+ char buffer[1024];
+
+ // Open input file
+ FILE *input = fopen(srcFilename.c_str(), "rb");
+ if (!input) {
+ LOG_ERROR(TCOMMON, "Copy: input failed %s --> %s", srcFilename.c_str(),
+ destFilename.c_str());
+ return false;
+ }
+ // open output file
+ FILE *output = fopen(destFilename.c_str(), "wb");
+ if (!output) {
+ fclose(input);
+ LOG_ERROR(TCOMMON, "Copy: output failed %s --> %s", srcFilename.c_str(),
+ destFilename.c_str());
+ return false;
+ }
+ // copy loop
+ while (!feof(input)) {
+ // read input
+ int rnum = fread(buffer, sizeof(char), 1024, input);
+ if (rnum != 1024) {
+ if (ferror(input) != 0) {
+ LOG_ERROR(TCOMMON, "Copy: failed reading from source, %s --> %s",
+ srcFilename.c_str(), destFilename.c_str());
+ goto bail;
+ }
+ }
+ // write output
+ int wnum = fwrite(buffer, sizeof(char), rnum, output);
+ if (wnum != rnum) {
+ LOG_ERROR(TCOMMON, "Copy: failed writing to output, %s --> %s",
+ srcFilename.c_str(), destFilename.c_str());
+ goto bail;
+ }
+ }
+ // close flushs
+ fclose(input);
+ fclose(output);
+ return true;
+bail:
+ if (input)
+ fclose(input);
+ if (output)
+ fclose(output);
+ return false;
+#endif
+}
+
+// Returns the size of filename (64bit)
+u64 GetFileSize(const std::string &filename) {
+ if (!FileExists(filename)) {
+ LOG_WARNING(TCOMMON, "GetSize: failed %s: No such file", filename.c_str());
+ return 0;
+ }
+ if (IsDirectory(filename)) {
+ LOG_WARNING(TCOMMON, "GetSize: failed %s: is a directory", filename.c_str());
+ return 0;
+ }
+ struct stat64 buf;
+ if (stat64(filename.c_str(), &buf) == 0) {
+ LOG_DEBUG(TCOMMON, "GetSize: %s: %lld", filename.c_str(), (long long)buf.st_size);
+ return buf.st_size;
+ }
+ LOG_ERROR(TCOMMON, "GetSize: Stat failed %s", filename.c_str());
+ return 0;
+}
+
+// Overloaded GetSize, accepts file descriptor
+u64 GetFileSize(const int fd) {
+ struct stat64 buf;
+ if (fstat64(fd, &buf) != 0) {
+ LOG_ERROR(TCOMMON, "GetSize: stat failed %i", fd);
+ return 0;
+ }
+ return buf.st_size;
+}
+
+// Overloaded GetSize, accepts FILE*
+u64 GetFileSize(FILE *f) {
+ // can't use off_t here because it can be 32-bit
+ u64 pos = ftello(f);
+ if (fseeko(f, 0, SEEK_END) != 0) {
+ LOG_ERROR(TCOMMON, "GetSize: seek failed %p", f);
+ return 0;
+ }
+ u64 size = ftello(f);
+ if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
+ LOG_ERROR(TCOMMON, "GetSize: seek failed %p", f);
+ return 0;
+ }
+ return size;
+}
+
+// creates an empty file filename, returns true on success
+bool CreateEmptyFile(const std::string &filename) {
+ LOG_INFO(TCOMMON, "CreateEmptyFile: %s", filename.c_str());
+
+ FILE *pFile = fopen(filename.c_str(), "wb");
+ if (!pFile) {
+ LOG_ERROR(TCOMMON, "CreateEmptyFile: failed %s", filename.c_str());
+ return false;
+ }
+ fclose(pFile);
+ return true;
+}
+
+// Deletes the given directory and anything under it. Returns true on success.
+bool DeleteDirRecursively(const std::string &directory) {
+ LOG_INFO(TCOMMON, "DeleteDirRecursively: %s", directory.c_str());
+#ifdef _WIN32
+ // Find the first file in the directory.
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
+
+ if (hFind == INVALID_HANDLE_VALUE) {
+ FindClose(hFind);
+ return false;
+ }
+
+ // windows loop
+ do {
+ const std::string virtualName = ffd.cFileName;
+#else
+ struct dirent dirent, *result = NULL;
+ DIR *dirp = opendir(directory.c_str());
+ if (!dirp) {
+ return false;
+ }
+ // non windows loop
+ while (!readdir_r(dirp, &dirent, &result) && result) {
+ const std::string virtualName = result->d_name;
+#endif
+ // check for "." and ".."
+ if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
+ ((virtualName[0] == '.') && (virtualName[1] == '.') &&
+ (virtualName[2] == '\0'))) {
+ continue;
+ }
+ std::string newPath = directory + '/' + virtualName;
+ if (IsDirectory(newPath)) {
+ if (!DeleteDirRecursively(newPath))
+ return false;
+ } else {
+ if (!DeleteFile(newPath))
+ return false;
+ }
+
+#ifdef _WIN32
+ } while (FindNextFile(hFind, &ffd) != 0);
+ FindClose(hFind);
+#else
+ }
+ closedir(dirp);
+#endif
+ DeleteDir(directory);
+
+ return true;
+}
+
+// Returns the current directory
+std::string GetCurrentDir() {
+ char *dir;
+ // Get the current working directory (getcwd uses malloc)
+ if (!(dir = __getcwd(NULL, 0))) {
+
+ LOG_ERROR(TCOMMON, "GetCurrentDirectory failed:");
+ return NULL;
+ }
+ std::string strDir = dir;
+ free(dir);
+ return strDir;
+}
+
+// Sets the current directory to the given directory
+bool SetCurrentDir(const std::string &directory) {
+ return __chdir(directory.c_str()) == 0;
+}
+
+bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) {
+ FILE *f = fopen(filename, text_file ? "w" : "wb");
+ if (!f) {
+ return false;
+ }
+ size_t len = str.size();
+ if (len != fwrite(str.data(), 1, str.size(), f)) {
+ fclose(f);
+ return false;
+ }
+ fclose(f);
+ return true;
+}
+
+bool ReadFileToString(bool text_file, const char *filename, std::string &str) {
+ FILE *f = fopen(filename, text_file ? "r" : "rb");
+ if (!f) {
+ return false;
+ }
+ size_t len = (size_t)GetFileSize(f);
+ char *buf = new char[len + 1];
+ buf[fread(buf, 1, len, f)] = 0;
+ str = std::string(buf, len);
+ fclose(f);
+ delete [] buf;
+ return true;
+}
+
+} // namespace
diff --git a/src/common/src/file_utils.h b/src/common/src/file_utils.h
new file mode 100644
index 000000000..6b93710b9
--- /dev/null
+++ b/src/common/src/file_utils.h
@@ -0,0 +1,90 @@
+/**
+* Copyright (C) 2005-2013 Gekko Emulator
+*
+* @file file_utils.h
+* @author ShizZy <shizzy247@gmail.com>
+* @date 2013-01-27
+* @brief Crossplatform file utility functions
+* @remark Borrowed from Dolphin Emulator
+*
+* @section LICENSE
+* 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; either version 2 of
+* the License, or (at your option) any later version.
+*
+* 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 for more details at
+* http://www.gnu.org/copyleft/gpl.html
+*
+* Official project repository can be found at:
+* http://code.google.com/p/gekko-gc-emu/
+*/
+
+#ifndef COMMON_FILE_UTILS_H_
+#define COMMON_FILE_UTILS_H_
+
+#include <fstream>
+#include <cstdio>
+#include <string>
+#include <vector>
+#include <string.h>
+
+#include "common.h"
+
+namespace common {
+
+// Returns true if file filename exists
+bool FileExists(const std::string &filename);
+
+// Returns true if filename is a directory
+bool IsDirectory(const std::string &filename);
+
+// Returns the size of filename (64bit)
+u64 GetFileSize(const std::string &filename);
+
+// Overloaded GetSize, accepts file descriptor
+u64 GetFileSize(const int fd);
+
+// Overloaded GetSize, accepts FILE*
+u64 GetFileSize(FILE *f);
+
+// Returns true if successful, or path already exists.
+bool CreateDir(const std::string &filename);
+
+// Creates the full path of fullPath returns true on success
+bool CreateFullPath(const std::string &fullPath);
+
+// Deletes a given filename, return true on success
+// Doesn't supports deleting a directory
+bool DeleteFile(const std::string &filename);
+
+// Deletes a directory filename, returns true on success
+bool DeleteDir(const std::string &filename);
+
+// renames file srcFilename to destFilename, returns true on success
+bool RenameFile(const std::string &srcFilename, const std::string &destFilename);
+
+// copies file srcFilename to destFilename, returns true on success
+bool CopyFile(const std::string &srcFilename, const std::string &destFilename);
+
+// creates an empty file filename, returns true on success
+bool CreateEmptyFile(const std::string &filename);
+
+// deletes the given directory and anything under it. Returns true on success.
+bool DeleteDirRecursively(const std::string &directory);
+
+// Returns the current directory
+std::string GetCurrentDir();
+
+// Set the current directory to given directory
+bool SetCurrentDir(const std::string &directory);
+
+bool WriteStringToFile(bool text_file, const std::string &str, const char *filename);
+bool ReadFileToString(bool text_file, const char *filename, std::string &str);
+
+} // namespace
+
+#endif // COMMON_FILE_UTILS_H_
diff --git a/src/common/src/hash.cpp b/src/common/src/hash.cpp
new file mode 100644
index 000000000..738d3d353
--- /dev/null
+++ b/src/common/src/hash.cpp
@@ -0,0 +1,241 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file hash.cpp
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-12-05
+ * @brief General purpose hash function
+ * @remark Some functions borrowed from Dolphin Emulator
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "crc.h"
+#include "hash.h"
+#include "common.h"
+
+namespace common {
+
+/// Block mix - combine the key bits with the hash bits and scramble everything
+inline void bmix64(u64& h1, u64& h2, u64& k1, u64& k2, u64& c1, u64& c2) {
+ k1 *= c1;
+ k1 = _rotl64(k1,23);
+ k1 *= c2;
+ h1 ^= k1;
+ h1 += h2;
+
+ h2 = _rotl64(h2,41);
+
+ k2 *= c2;
+ k2 = _rotl64(k2,23);
+ k2 *= c1;
+ h2 ^= k2;
+ h2 += h1;
+
+ h1 = h1*3 + 0x52dce729;
+ h2 = h2*3 + 0x38495ab5;
+
+ c1 = c1*5 + 0x7b7d159c;
+ c2 = c2*5 + 0x6bce6396;
+}
+
+/// Finalization mix - avalanches all bits to within 0.05% bias
+inline u64 fmix64(u64 k) {
+ k ^= k >> 33;
+ k *= 0xff51afd7ed558ccd;
+ k ^= k >> 33;
+ k *= 0xc4ceb9fe1a85ec53;
+ k ^= k >> 33;
+ return k;
+}
+
+#define ROTL32(x,y) rotl32(x,y)
+
+inline uint32_t fmix ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+u32 __compute_murmur_hash3_32(const u8 *src, int len, u32 samples) {
+ u32 h = len;
+ u32 step = (len >> 2);
+ const u32 *data = (const u32*)src;
+ const u32 *end = data + step;
+ if (samples == 0) {
+ samples = std::max(step, 1u);
+ }
+ step = step / samples;
+ if(step < 1) {
+ step = 1;
+ }
+ u32 h1 = 0x2f6af274;
+ const u32 c1 = 0xcc9e2d51;
+ const u32 c2 = 0x1b873593;
+
+ while (data < end) {
+ u32 k1 = data[0];
+
+ k1 *= c1;
+ k1 = (k1 << 15) | (k1 >> (32 - 15));
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = (h1 << 15) | (h1 >> (32 - 13));
+ h1 = h1*5+0xe6546b64;
+
+ data += step;
+ }
+ const u8 * tail = (const u8*)(data);
+
+ u32 k1 = 0;
+
+ switch(len & 3) {
+ case 3:
+ k1 ^= tail[2] << 16;
+ case 2:
+ k1 ^= tail[1] << 8;
+ case 1:
+ k1 ^= tail[0];
+ k1 *= c1;
+ k1 = (k1 << 15) | (k1 >> (32 - 15));
+ k1 *= c2;
+ h1 ^= k1;
+ };
+ h1 ^= len;
+ h1 = fmix(h1);
+
+ return h1;
+}
+
+
+/// MurmurHash is a non-cryptographic hash function suitable for general hash-based lookup
+u64 __compute_murmur_hash3_64(const u8 *src, int len, u32 samples) {
+ const u8 * data = (const u8*)src;
+ const int nblocks = len / 16;
+ u32 step = (len / 8);
+ if(samples == 0) {
+ samples = std::max(step, 1u);
+ }
+ step = step / samples;
+ if(step < 1) {
+ step = 1;
+ }
+
+ u64 h1 = 0x9368e53c2f6af274;
+ u64 h2 = 0x586dcd208f7cd3fd;
+
+ u64 c1 = 0x87c37b91114253d5;
+ u64 c2 = 0x4cf5ad432745937f;
+
+ const u64* blocks = (const u64*)(data);
+
+ for (int i = 0; i < nblocks; i+=step) {
+ u64 k1 = blocks[(i * 2) + 0];
+ u64 k2 = blocks[(i * 2) + 1];
+
+ bmix64(h1,h2,k1,k2,c1,c2);
+ }
+ const u8* tail = (const u8*)(data + nblocks * 16);
+
+ u64 k1 = 0;
+ u64 k2 = 0;
+
+ switch (len & 15) {
+ case 15: k2 ^= u64(tail[14]) << 48;
+ case 14: k2 ^= u64(tail[13]) << 40;
+ case 13: k2 ^= u64(tail[12]) << 32;
+ case 12: k2 ^= u64(tail[11]) << 24;
+ case 11: k2 ^= u64(tail[10]) << 16;
+ case 10: k2 ^= u64(tail[ 9]) << 8;
+ case 9: k2 ^= u64(tail[ 8]) << 0;
+
+ case 8: k1 ^= u64(tail[ 7]) << 56;
+ case 7: k1 ^= u64(tail[ 6]) << 48;
+ case 6: k1 ^= u64(tail[ 5]) << 40;
+ case 5: k1 ^= u64(tail[ 4]) << 32;
+ case 4: k1 ^= u64(tail[ 3]) << 24;
+ case 3: k1 ^= u64(tail[ 2]) << 16;
+ case 2: k1 ^= u64(tail[ 1]) << 8;
+ case 1: k1 ^= u64(tail[ 0]) << 0;
+ bmix64(h1, h2, k1, k2, c1, c2);
+ };
+ h2 ^= len;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+
+ h1 += h2;
+
+ return h1;
+}
+
+/// CRC32 hash using the SSE4.2 instruction
+u64 __compute_crc32_sse4(const u8 *src, int len, u32 samples) {
+ u32 h = len;
+ u32 step = (len >> 2);
+ const u32 *data = (const u32*)src;
+ const u32 *end = data + step;
+ if (samples == 0) {
+ samples = std::max(step, 1u);
+ }
+ step = step / samples;
+ if(step < 1) {
+ step = 1;
+ }
+ while (data < end) {
+ h = InlineCrc32_U32(h, data[0]);
+ data += step;
+ }
+ const u8 *data2 = (const u8*)end;
+ return (u64)InlineCrc32_U32(h, u32(data2[0]));
+}
+
+/**
+ * Compute an efficient 64-bit hash (optimized for Intel hardware)
+ * @param src Source data buffer to compute hash for
+ * @param len Length of data buffer to compute hash for
+ * @param samples Number of samples to compute hash for
+ * @remark Borrowed from Dolphin Emulator
+ */
+Hash64 GetHash64(const u8 *src, int len, u32 samples) {
+#if defined(EMU_ARCHITECTURE_X86) || defined(EMU_ARCHITECTURE_X64)
+ // TODO(ShizZy): Move somewhere common so we dont need to instantiate this more than once
+ static X86Utils x86_utils;
+ if (x86_utils.IsExtensionSupported(X86Utils::kExtensionX86_SSE4_2)) {
+ return __compute_crc32_sse4(src, len, samples);
+ } else {
+
+#ifdef EMU_ARCHITECTURE_X64
+ return __compute_murmur_hash3_64(src, len, samples);
+#else
+ return __compute_murmur_hash3_32(src, len, samples);
+#endif
+ }
+#else
+ return __compute_murmur_hash3_32(src, len, samples);
+#endif
+}
+
+} // namespace
diff --git a/src/common/src/hash.h b/src/common/src/hash.h
new file mode 100644
index 000000000..37cbe823c
--- /dev/null
+++ b/src/common/src/hash.h
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file hash.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-12-05
+ * @brief General purpose hash function
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_HASH_H_
+#define COMMON_HASH_H_
+
+#include "types.h"
+
+namespace common {
+
+typedef u64 Hash64;
+
+/**
+ * Compute an efficient 64-bit hash (optimized for Intel hardware)
+ * @param src Source data buffer to compute hash for
+ * @param len Length of data buffer to compute hash for
+ * @param samples Number of samples to compute hash for
+ * @remark Borrowed from Dolphin Emulator
+ */
+Hash64 GetHash64(const u8 *src, int len, u32 samples);
+
+} // namespace
+
+
+#endif // COMMON_HASH_H_ \ No newline at end of file
diff --git a/src/common/src/hash_container.h b/src/common/src/hash_container.h
new file mode 100644
index 000000000..ab832f3c7
--- /dev/null
+++ b/src/common/src/hash_container.h
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file hash_container.h
+ * @author ShizZy <shizzy@6bit.net>
+ * @date 2012-11-29
+ * @brief Container object for storing a hash lookup
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_HASH_CONTAINER_H_
+#define COMMON_HASH_CONTAINER_H_
+
+#include <map>
+#include "common.h"
+
+/// Hash container generic interface - Don't use directly, use a derived class
+template <class HashType, class ValueType> class HashContainer {
+ /**
+ * Add (or update if already exists) a value at the specified hash in the container
+ * @param hash Hash to use
+ * @param value Value to update at given hash in the container
+ */
+ ValueType* Update(HashType hash, ValueType value);
+
+ /**
+ * Remove a hash entry in the hash container
+ * @param hash Hash value of entry to remove
+ */
+ void Remove(HashType hash);
+
+ /**
+ * Fetch the value at at the given hash from the hash container
+ * @param hash Hash value of entry to fetch
+ * @return Pointer to value stored at hash location on success (index was found), otherwise NULL
+ */
+ ValueType* FetchFromHash(HashType hash);
+
+ /**
+ * Fetch the value at at the given integer index from the hash container
+ * @param hash Hash value of entry to fetch
+ * @return Pointer to value stored at hash location on success (index was found), otherwise NULL
+ */
+ ValueType* FetchFromIndex(int index);
+
+ /**
+ * Get the size of the hash container
+ * @return Number of elements in the hash container
+ */
+ int Size();
+};
+
+/// Hash container implemented using STL map
+template <class HashType, class ValueType> class HashContainer_STLMap :
+ public HashContainer<HashType, ValueType> {
+
+public:
+ HashContainer_STLMap() {
+ }
+ ~HashContainer_STLMap() {
+ }
+
+ ValueType* Update(HashType hash, ValueType value) {
+ map_[hash] = value;
+ return &map_[hash];
+ }
+
+ void Remove(HashType hash) {
+ map_.erase(hash);
+ }
+
+ ValueType* FetchFromHash(HashType hash) {
+ typename std::map<HashType, ValueType>::iterator itr = map_.find(hash);
+ if (itr == map_.end()) {
+ return NULL;
+ }
+ return &itr->second;
+ }
+
+ ValueType* FetchFromIndex(int index) {
+ typename std::map<HashType, ValueType>::iterator itr = map_.begin();
+ int i = 0;
+ for (; i < index; ++i) {
+ ++itr;
+ }
+ if (i < index) {
+ return NULL;
+ }
+ return &itr->second;
+ }
+
+ int Size() {
+ return static_cast<int>(map_.size());
+ }
+
+private:
+ std::map<HashType, ValueType> map_;
+
+ DISALLOW_COPY_AND_ASSIGN(HashContainer_STLMap);
+};
+
+#endif // COMMON_HASH_CONTAINER_H_
diff --git a/src/common/src/log.cpp b/src/common/src/log.cpp
new file mode 100644
index 000000000..c365b2f70
--- /dev/null
+++ b/src/common/src/log.cpp
@@ -0,0 +1,152 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file log.cpp
+ * @author ShizZy <shizzy@6bit.net>
+ * @date 2012-02-11
+ * @brief Common logging routines used throughout the project
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "timer.h"
+
+namespace logger {
+
+LogContainer* g_logs[NUMBER_OF_LOGS]; ///< List of pointers to all logs
+
+/// LogContainer constructor
+LogContainer::LogContainer(const char* name, const char* desc, bool enable = false) {
+ strncpy(name_, name, 128);
+ strncpy(desc_, desc, 32);
+ level_ = LWARNING;
+}
+
+/// Asks the user a yes or no question
+SysUserResponse AskYesNo(const char* fmt, ...) {
+ char c;
+ va_list arg;
+
+ va_start(arg, fmt);
+ printf("\n** Question **\n");
+ vprintf(fmt, arg);
+ va_end(arg);
+
+ printf(" Response? (y/n) ");
+ while (1) {
+ c = getchar();
+ if (c == 'y' || c == 'Y') {
+ return SYS_USER_YES;
+ }
+ if (c == 'n' || c == 'N') {
+ return SYS_USER_NO;
+ }
+ }
+ return SYS_USER_NO;
+}
+
+//// Log routine used by everything
+void LogGeneric(LogLevel level, LogType type, const char *file, int line, bool append, const char* fmt, ...)
+{
+ char msg[kMaxMsgLength];
+ static const char level_to_char[8] = "-NECWID";
+ static char last_char = '\n';
+ static LogType last_type;
+
+ va_list arg;
+ va_start(arg, fmt);
+
+ if (type >= NUMBER_OF_LOGS) {
+ LOG_ERROR(TCOMMON, "Unknown logger type %d", type);
+ return;
+ }
+
+ // Format the log message
+ if (append) {
+ sprintf(msg, "%s", fmt);
+ } else {
+ // char time_str[16];
+ // u32 time_elapsed = common::GetTimeElapsed();
+ // common::TicksToFormattedString(time_elapsed, time_str);
+ sprintf(msg, "%c[%s] %s", level_to_char[(int)level], g_logs[type]->name(), fmt);
+ }
+
+ // If the last message didn't have a line break, print one
+ if ('\n' != last_char && '\r' != last_char && !append && last_type != TOS_REPORT &&
+ last_type != TOS_HLE) {
+ printf("\n");
+ }
+ last_char = msg[strlen(msg)-1];
+ last_type = type;
+
+ // Print the log message to stdout
+ vprintf(msg, arg);
+ va_end(arg);
+}
+
+/// Forces a controlled system crash rather before it catches fire (debug)
+void Crash() {
+ LOG_CRASH(TCOMMON, "*** SYSTEM CRASHED ***\n");
+ LOG_CRASH(TCOMMON, "Fatal error, system could not recover.\n");
+#ifdef _MSC_VER
+#ifdef USE_INLINE_ASM_X86
+ __asm int 3
+#endif
+#elif defined(__GNUC__)
+ asm("int $3");
+#else
+ LOG_CRASH(TCOMMON, "Exiting...\n");
+ exit(0);
+#endif
+}
+
+/// Initialize the logging system
+void Init() {
+ g_logs[TNULL] = new LogContainer("NULL", "Null");
+ g_logs[TAI] = new LogContainer("AI", "AudioInterface");
+ g_logs[TBOOT] = new LogContainer("BOOT", "Boot");
+ g_logs[TCOMMON] = new LogContainer("COMMON", "Common");
+ g_logs[TCONFIG] = new LogContainer("CONFIG", "Configuration");
+ g_logs[TCORE] = new LogContainer("CORE", "SysCore");
+ g_logs[TCP] = new LogContainer("CP", "CommandProcessor");
+ g_logs[TDI] = new LogContainer("DI", "DVDInterface");
+ g_logs[TDSP] = new LogContainer("DSP", "DSP");
+ g_logs[TDVD] = new LogContainer("DVD", "GCM/ISO");
+ g_logs[TEXI] = new LogContainer("EXI", "ExternalInterface");
+ g_logs[TGP] = new LogContainer("GP", "GraphicsProcessor");
+ g_logs[THLE] = new LogContainer("HLE", "HLE");
+ g_logs[THW] = new LogContainer("HW", "Hardware");
+ g_logs[TJOYPAD] = new LogContainer("JOYPAD", "Joypad");
+ g_logs[TMASTER] = new LogContainer("*", "Master Log");
+ g_logs[TMEM] = new LogContainer("MEM", "Memory");
+ g_logs[TMI] = new LogContainer("MI", "MemoryInterface");
+ g_logs[TOS_HLE] = new LogContainer("OSHLE", "OSHLE");
+ g_logs[TOS_REPORT] = new LogContainer("OSREPORT", "OSREPORT");
+ g_logs[TPE] = new LogContainer("PE", "PixelEngine");
+ g_logs[TPI] = new LogContainer("PI", "ProcessorInterface");
+ g_logs[TPOWERPC] = new LogContainer("PPC", "PowerPC");
+ g_logs[TSI] = new LogContainer("SI", "SerialInterface");
+ g_logs[TVI] = new LogContainer("VI", "VideoInterface");
+ g_logs[TVIDEO] = new LogContainer("VIDEO", "VideoCore");
+
+ LOG_NOTICE(TCOMMON, "%d logger(s) initalized ok", NUMBER_OF_LOGS);
+}
+
+} // namespace
diff --git a/src/common/src/log.h b/src/common/src/log.h
new file mode 100644
index 000000000..9ce3a30a3
--- /dev/null
+++ b/src/common/src/log.h
@@ -0,0 +1,216 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file log.h
+ * @author ShizZy <shizzy@6bit.net>
+ * @date 2012-02-11
+ * @brief Common logging routines used throughout the project
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_LOG_H_
+#define COMMON_LOG_H_
+
+#include "SDL.h" // Used for threading/mutexes
+
+#include "common.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Logging Macros
+
+#if defined(_DEBUG) || defined(DEBUG) || defined(LOGGING)
+/// Debug mode, show all logs
+#define MAX_LOG_LEVEL logger::LDEBUG
+#else
+/// Non debug mode, only show critical logs
+#define MAX_LOG_LEVEL logger::LWARNING
+#endif
+
+/// Logs a message ** Don't use directly **
+#define _LOG_GENERIC(level, type, ...) \
+ if (level <= MAX_LOG_LEVEL) { \
+ LogGeneric(level, type, __FILE__, __LINE__, false, __VA_ARGS__); \
+ }
+
+/// Used for appending to the last logged message
+#define LOG_APPEND(level, type, ...) \
+ if (logger::level <= MAX_LOG_LEVEL) { \
+ logger::LogGeneric(logger::level, logger::type, __FILE__, __LINE__, true, __VA_ARGS__); \
+ }
+
+/// Use this for printing an IMPORTANT notice to the logger
+#define LOG_NOTICE(type, ...) _LOG_GENERIC(logger::LNOTICE, logger::type, __VA_ARGS__)
+
+/// Use this for printing an error message to the logger
+#define LOG_ERROR(type, ...) _LOG_GENERIC(logger::LERROR, logger::type, __VA_ARGS__)
+
+/// Use this for printing a crash report to the logger
+#define LOG_CRASH(type, ...) _LOG_GENERIC(logger::LCRASH, logger::type, __VA_ARGS__)
+
+/// Use this for printing a warning to the logger
+#define LOG_WARNING(type, ...) _LOG_GENERIC(logger::LWARNING, logger::type, __VA_ARGS__)
+
+/// Use this for printing general information to the logger
+#define LOG_INFO(type, ...) _LOG_GENERIC(logger::LINFO, logger::type, __VA_ARGS__)
+
+#if defined(_DEBUG) || defined(DEBUG) || defined(LOGGING)
+
+/// Use this for printing a debug message to the logger
+#define LOG_DEBUG(type, ...) _LOG_GENERIC(logger::LDEBUG, logger::type, __VA_ARGS__)
+
+/// Used for debug-mode assertions
+#define _ASSERT_DBG(_type_, _cond_) \
+ if (!(_cond_)) { \
+ LOG_ERROR(_type_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n", \
+ __LINE__, __FILE__, __TIME__); \
+ if (!logger::AskYesNo("*** Assertion (see log)***\n")) logger::Crash(); \
+ }
+
+/// Used for message-specified debug-mode assertions
+#define _ASSERT_DBG_MSG(_type_, _cond_, ...) \
+ if (!(_cond_)) { \
+ LOG_ERROR(_type_, __VA_ARGS__); \
+ if (!logger::AskYesNo(__VA_ARGS__)) logger::Crash(); \
+ }
+#else
+#define _ASSERT_DBG(_type_, _cond_, ...)
+#define _ASSERT_DBG_MSG(_type_, _cond_, ...)
+#define LOG_DEBUG(type, ...)
+#endif
+
+/// Used for general purpose assertions, CRITICAL operations only
+#define _ASSERT_MSG(_type_, _cond_, ...) \
+ if (!(_cond_)) { \
+ if (!logger::AskYesNo(__VA_ARGS__)) logger::Crash(); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Logger
+
+namespace logger {
+
+const int kMaxMsgLength = 1024; ///< Maximum message length
+
+/// Used for handling responses to system functions that require them
+typedef enum {
+ SYS_USER_NO = 0, ///< User response for 'No'
+ SYS_USER_YES, ///< User response for 'Yes'
+ SYS_USER_OK, ///< User response for 'Okay'
+ SYS_USER_ABORT, ///< User response for 'Abort'
+ SYS_USER_RETRY, ///< User response for 'Retry'
+ SYS_USER_CANCEL, ///< User response for 'Cancel'
+} SysUserResponse;
+
+/// Level of logging
+typedef enum {
+ LNULL = 0, ///< Logs with this level won't get logged
+ LNOTICE, ///< Notice: A general message to the user
+ LERROR, ///< Error: For failure messages
+ LCRASH, ///< Crash: Used for crash reports
+ LWARNING, ///< Warning: For potentially bad things, but not fatal
+ LINFO, ///< Info: Information message
+ LDEBUG ///< Debug: Debug-only information
+} LogLevel;
+
+/// Type of logging
+typedef enum {
+ TNULL = 0,
+ TAI,
+ TBOOT,
+ TCOMMON,
+ TCONFIG,
+ TCORE,
+ TCP,
+ TDI,
+ TDSP,
+ TDVD,
+ TEXI,
+ TGP,
+ THLE,
+ THW,
+ TJOYPAD,
+ TMASTER,
+ TMEM,
+ TMI,
+ TOS_HLE,
+ TOS_REPORT,
+ TPE,
+ TPI,
+ TPOWERPC,
+ TSI,
+ TVI,
+ TVIDEO,
+ NUMBER_OF_LOGS ///< Number of logs - must be last
+} LogType;
+
+/// Used for implementing a logger for a subsystem
+class LogContainer
+{
+public:
+ LogContainer(const char* name, const char* desc, bool enable);
+ ~LogContainer() {}
+
+ const char* name() const { return name_; }
+ const char* desc() const { return desc_; }
+
+ bool enabled() const { return enabled_; }
+ void set_enabled(bool enabled) { enabled_ = enabled; }
+
+ LogLevel level() const { return level_; }
+ void set_level(LogLevel level) { level_ = level; }
+
+private:
+ char name_[32]; ///< Name of the logger (e.g. "SI")
+ char desc_[128]; ///< Description of the logger (e.g. "Serial Interface")
+ bool enabled_; ///< Whether or not the logger is enabled
+
+ LogLevel level_; ///< Level of the logger (e.g. Notice, Error, Warning, etc.)
+
+ SDL_mutex* listener_lock_; ///< Mutex for multithreaded access
+
+ DISALLOW_COPY_AND_ASSIGN(LogContainer);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function Prototypes
+
+/*!
+ * \brief Log routine used by everything
+ * \param level Log level to use
+ * \param type Log type to use
+ * \param file Filename of file where error occured
+ * \param line Linenumber of file where error occured
+ * \param fmt Formatted message
+ */
+void LogGeneric(LogLevel level, LogType type, const char *file, int line, bool append, const char* fmt, ...);
+
+/// Forces a controlled system crash rather before it catches fire (debug)
+void Crash();
+
+/*!
+ * \brief Asks the user a yes or no question
+ * \param fmt Question formatted message
+ * \return SysUserResponse response
+ */
+SysUserResponse AskYesNo(const char* fmt, ...);
+
+/// Initialize the logging system
+void Init();
+
+} // namespace log
+
+#endif // COMMON_LOG_H
diff --git a/src/common/src/misc_utils.cpp b/src/common/src/misc_utils.cpp
new file mode 100644
index 000000000..d2a50fb3e
--- /dev/null
+++ b/src/common/src/misc_utils.cpp
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file misc_utils.cpp
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-03-06
+ * @brief Miscellaneous functions/utilities that are used everywhere
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "misc_utils.h"
+
+namespace common {
+
+/// Make a string lowercase
+void LowerStr(char* str) {
+ for (int i = 0; str[i]; i++) {
+ str[i] = tolower(str[ i ]);
+ }
+}
+
+/// Make a string uppercase
+void UpperStr(char* str) {
+ for (int i=0; i < strlen(str); i++) {
+ if(str[i] >= 'a' && str[i] <= 'z') {
+ str[i] &= 0xDF;
+ }
+ }
+}
+
+/// Format a std::string using C-style sprintf formatting
+std::string FormatStr(const char* format, ...) {
+ va_list args;
+ char *buf = NULL;
+#if EMU_PLATFORM == PLATFORM_WINDOWS
+ int required = 0;
+
+ va_start(args, format);
+ required = _vscprintf(format, args);
+ buf = new char[required + 1];
+ vsnprintf(buf, required, format, args);
+ va_end(args);
+
+ buf[required] = '\0';
+ std::string temp = buf;
+ delete[] buf;
+#else
+ va_start(args, format);
+ vasprintf(&buf, format, args);
+ va_end(args);
+
+ std::string temp = buf;
+ free(buf);
+#endif
+ return temp;
+}
+
+/// Check if a file exists
+bool FileExists(char* filename) {
+ std::ifstream ifile(filename);
+ if (!ifile) {
+ return false;
+ }
+ ifile.close();
+ return true;
+}
+
+/// Gets the size of a file
+size_t FileSize(FILE* file) {
+ size_t pos = ftell(file);
+ fseek(file, 0L, SEEK_END);
+ size_t res = ftell(file);
+ fseek(file, pos, SEEK_SET);
+ return res;
+}
+
+} // namespace
diff --git a/src/common/src/misc_utils.h b/src/common/src/misc_utils.h
new file mode 100644
index 000000000..b003336cb
--- /dev/null
+++ b/src/common/src/misc_utils.h
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file misc_utils.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-03-06
+ * @brief Miscellaneous functions/utilities that are used everywhere
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "common.h"
+
+namespace common {
+
+/**
+ * @brief Make a string lowercase
+ * @param str String to make lowercase
+ */
+void LowerStr(char* str);
+
+/**
+ * @brief Make a string uppercase
+ * @param str String to make uppercase
+ */
+void UpperStr(char* str);
+
+/// Format a std::string using C-style sprintf formatting
+std::string FormatStr(const char* format, ...);
+
+/**
+ * @brief Check if a file exists on the users computer
+ * @param filename Filename of file to check for
+ * @return true on exists, false otherwise
+ */
+bool FileExists(char* filename);
+
+/**
+ * @brief Gets the size of a file
+ * @param file Pointer to file to get size of
+ * @return true Size of file, in bytes
+ */
+size_t FileSize(FILE* file);
+
+} // namespace
diff --git a/src/common/src/platform.h b/src/common/src/platform.h
new file mode 100644
index 000000000..efbf3824a
--- /dev/null
+++ b/src/common/src/platform.h
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file platform.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-11
+ * @brief Platform detection macros for portable compilation
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_PLATFORM_H_
+#define COMMON_PLATFORM_H_
+
+#include "types.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Platform definitions
+
+/// Enumeration for defining the supported platforms
+#define PLATFORM_NULL 0
+#define PLATFORM_WINDOWS 1
+#define PLATFORM_MACOSX 2
+#define PLATFORM_LINUX 3
+#define PLATFORM_ANDROID 4
+#define PLATFORM_IOS 5
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Platform detection
+extern char *kGekkoOS;
+
+#ifndef EMU_PLATFORM
+
+#if defined( __WIN32__ ) || defined( _WIN32 )
+#define EMU_PLATFORM PLATFORM_WINDOWS
+
+#elif defined( __APPLE__ ) || defined( __APPLE_CC__ )
+#define EMU_PLATFORM PLATFORM_MAXOSX
+
+#elif defined(__linux__)
+#define EMU_PLATFORM PLATFORM_LINUX
+
+#else // Assume linux otherwise
+#define EMU_PLATFORM PLATFORM_LINUX
+
+#endif
+
+#endif
+
+#if defined(__x86_64__) || defined(_M_X64) || defined(__alpha__) || defined(__ia64__)
+#define EMU_ARCHITECTURE_X64
+#else
+#define EMU_ARCHITECTURE_X86
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Compiler-Specific Definitions
+
+#if EMU_PLATFORM == PLATFORM_WINDOWS
+
+#define NOMINMAX
+#define EMU_FASTCALL __fastcall
+
+#else
+
+#define EMU_FASTCALL __attribute__((fastcall))
+#define __stdcall
+#define __cdecl
+
+#define LONG long
+#define BOOL bool
+#define DWORD u32
+
+#endif
+
+#if EMU_PLATFORM != PLATFORM_WINDOWS
+
+// TODO: Hacks..
+#include <limits.h>
+#define MAX_PATH PATH_MAX
+
+#include <strings.h>
+#define stricmp(str1, str2) strcasecmp(str1, str2)
+#define _stricmp(str1, str2) strcasecmp(str1, str2)
+#define _snprintf snprintf
+#define _getcwd getcwd
+#define _tzset tzset
+
+typedef void EXCEPTION_POINTERS;
+
+inline u32 _rotl(u32 x, int shift) {
+ shift &= 31;
+ if (0 == shift) {
+ return x;
+ }
+ return (x << shift) | (x >> (32 - shift));
+}
+
+inline u64 _rotl64(u64 x, u32 shift){
+ u32 n = shift % 64;
+ return (x << n) | (x >> (64 - n));
+}
+
+inline u32 _rotr(u32 x, int shift) {
+ shift &= 31;
+ if (0 == shift) {
+ return x;
+ }
+ return (x >> shift) | (x << (32 - shift));
+}
+
+inline u64 _rotr64(u64 x, u32 shift){
+ u32 n = shift % 64;
+ return (x >> n) | (x << (64 - n));
+}
+
+#endif
+
+#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
+
+#endif // COMMON_PLATFORM_H_
diff --git a/src/common/src/std_condition_variable.h b/src/common/src/std_condition_variable.h
new file mode 100644
index 000000000..e7088725c
--- /dev/null
+++ b/src/common/src/std_condition_variable.h
@@ -0,0 +1,152 @@
+#ifndef CONDITION_VARIABLE_H_
+#define CONDITION_VARIABLE_H_
+
+#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
+#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
+// GCC 4.4 provides <condition_variable>
+#include <condition_variable>
+#else
+
+// partial std::condition_variable implementation for win32/pthread
+
+#include "std_mutex.h"
+
+#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
+#define USE_RVALUE_REFERENCES
+#endif
+
+#if defined(_WIN32) && defined(_M_X64)
+#define USE_CONDITION_VARIABLES
+#elif defined(_WIN32)
+#define USE_EVENTS
+#endif
+
+namespace std
+{
+
+class condition_variable
+{
+#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
+ typedef CONDITION_VARIABLE native_type;
+#elif defined(_WIN32)
+ typedef HANDLE native_type;
+#else
+ typedef pthread_cond_t native_type;
+#endif
+
+public:
+
+#ifdef USE_EVENTS
+ typedef native_type native_handle_type;
+#else
+ typedef native_type* native_handle_type;
+#endif
+
+ condition_variable()
+ {
+#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
+ InitializeConditionVariable(&m_handle);
+#elif defined(_WIN32)
+ m_handle = CreateEvent(NULL, false, false, NULL);
+#else
+ pthread_cond_init(&m_handle, NULL);
+#endif
+ }
+
+ ~condition_variable()
+ {
+#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES)
+ CloseHandle(m_handle);
+#elif !defined(_WIN32)
+ pthread_cond_destroy(&m_handle);
+#endif
+ }
+
+ condition_variable(const condition_variable&) /*= delete*/;
+ condition_variable& operator=(const condition_variable&) /*= delete*/;
+
+ void notify_one()
+ {
+#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
+ WakeConditionVariable(&m_handle);
+#elif defined(_WIN32)
+ SetEvent(m_handle);
+#else
+ pthread_cond_signal(&m_handle);
+#endif
+ }
+
+ void notify_all()
+ {
+#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
+ WakeAllConditionVariable(&m_handle);
+#elif defined(_WIN32)
+ // TODO: broken
+ SetEvent(m_handle);
+#else
+ pthread_cond_broadcast(&m_handle);
+#endif
+ }
+
+ void wait(unique_lock<mutex>& lock)
+ {
+#ifdef _WIN32
+#ifdef USE_SRWLOCKS
+ SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0);
+#elif defined(USE_CONDITION_VARIABLES)
+ SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE);
+#else
+ // TODO: broken, the unlock and wait need to be atomic
+ lock.unlock();
+ WaitForSingleObject(m_handle, INFINITE);
+ lock.lock();
+#endif
+#else
+ pthread_cond_wait(&m_handle, lock.mutex()->native_handle());
+#endif
+ }
+
+ template <class Predicate>
+ void wait(unique_lock<mutex>& lock, Predicate pred)
+ {
+ while (!pred())
+ wait(lock);
+ }
+
+ //template <class Clock, class Duration>
+ //cv_status wait_until(unique_lock<mutex>& lock,
+ // const chrono::time_point<Clock, Duration>& abs_time);
+
+ //template <class Clock, class Duration, class Predicate>
+ // bool wait_until(unique_lock<mutex>& lock,
+ // const chrono::time_point<Clock, Duration>& abs_time,
+ // Predicate pred);
+
+ //template <class Rep, class Period>
+ //cv_status wait_for(unique_lock<mutex>& lock,
+ // const chrono::duration<Rep, Period>& rel_time);
+
+ //template <class Rep, class Period, class Predicate>
+ // bool wait_for(unique_lock<mutex>& lock,
+ // const chrono::duration<Rep, Period>& rel_time,
+ // Predicate pred);
+
+ native_handle_type native_handle()
+ {
+#ifdef USE_EVENTS
+ return m_handle;
+#else
+ return &m_handle;
+#endif
+ }
+
+private:
+ native_type m_handle;
+};
+
+}
+
+#endif
+#endif
diff --git a/src/common/src/std_mutex.h b/src/common/src/std_mutex.h
new file mode 100644
index 000000000..27c5833f8
--- /dev/null
+++ b/src/common/src/std_mutex.h
@@ -0,0 +1,354 @@
+#ifndef MUTEX_H_
+#define MUTEX_H_
+
+#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
+#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
+// GCC 4.4 provides <mutex>
+#include <mutex>
+#else
+
+// partial <mutex> implementation for win32/pthread
+
+#include <algorithm>
+
+#if defined(_WIN32)
+// WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#else
+// POSIX
+#include <pthread.h>
+
+#endif
+
+#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
+#define USE_RVALUE_REFERENCES
+#endif
+
+#if defined(_WIN32) && defined(_M_X64)
+#define USE_SRWLOCKS
+#endif
+
+namespace std
+{
+
+class recursive_mutex
+{
+#ifdef _WIN32
+ typedef CRITICAL_SECTION native_type;
+#else
+ typedef pthread_mutex_t native_type;
+#endif
+
+public:
+ typedef native_type* native_handle_type;
+
+ recursive_mutex(const recursive_mutex&) /*= delete*/;
+ recursive_mutex& operator=(const recursive_mutex&) /*= delete*/;
+
+ recursive_mutex()
+ {
+#ifdef _WIN32
+ InitializeCriticalSection(&m_handle);
+#else
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&m_handle, &attr);
+#endif
+ }
+
+ ~recursive_mutex()
+ {
+#ifdef _WIN32
+ DeleteCriticalSection(&m_handle);
+#else
+ pthread_mutex_destroy(&m_handle);
+#endif
+ }
+
+ void lock()
+ {
+#ifdef _WIN32
+ EnterCriticalSection(&m_handle);
+#else
+ pthread_mutex_lock(&m_handle);
+#endif
+ }
+
+ void unlock()
+ {
+#ifdef _WIN32
+ LeaveCriticalSection(&m_handle);
+#else
+ pthread_mutex_unlock(&m_handle);
+#endif
+ }
+
+ bool try_lock()
+ {
+#ifdef _WIN32
+ return (0 != TryEnterCriticalSection(&m_handle));
+#else
+ return !pthread_mutex_trylock(&m_handle);
+#endif
+ }
+
+ native_handle_type native_handle()
+ {
+ return &m_handle;
+ }
+
+private:
+ native_type m_handle;
+};
+
+#if !defined(_WIN32) || defined(USE_SRWLOCKS)
+
+class mutex
+{
+#ifdef _WIN32
+ typedef SRWLOCK native_type;
+#else
+ typedef pthread_mutex_t native_type;
+#endif
+
+public:
+ typedef native_type* native_handle_type;
+
+ mutex(const mutex&) /*= delete*/;
+ mutex& operator=(const mutex&) /*= delete*/;
+
+ mutex()
+ {
+#ifdef _WIN32
+ InitializeSRWLock(&m_handle);
+#else
+ pthread_mutex_init(&m_handle, NULL);
+#endif
+ }
+
+ ~mutex()
+ {
+#ifdef _WIN32
+#else
+ pthread_mutex_destroy(&m_handle);
+#endif
+ }
+
+ void lock()
+ {
+#ifdef _WIN32
+ AcquireSRWLockExclusive(&m_handle);
+#else
+ pthread_mutex_lock(&m_handle);
+#endif
+ }
+
+ void unlock()
+ {
+#ifdef _WIN32
+ ReleaseSRWLockExclusive(&m_handle);
+#else
+ pthread_mutex_unlock(&m_handle);
+#endif
+ }
+
+ bool try_lock()
+ {
+#ifdef _WIN32
+ // XXX TryAcquireSRWLockExclusive requires Windows 7!
+ // return (0 != TryAcquireSRWLockExclusive(&m_handle));
+ return false;
+#else
+ return !pthread_mutex_trylock(&m_handle);
+#endif
+ }
+
+ native_handle_type native_handle()
+ {
+ return &m_handle;
+ }
+
+private:
+ native_type m_handle;
+};
+
+#else
+typedef recursive_mutex mutex; // just use CriticalSections
+
+#endif
+
+enum defer_lock_t { defer_lock };
+enum try_to_lock_t { try_to_lock };
+enum adopt_lock_t { adopt_lock };
+
+template <class Mutex>
+class lock_guard
+{
+public:
+ typedef Mutex mutex_type;
+
+ explicit lock_guard(mutex_type& m)
+ : pm(m)
+ {
+ m.lock();
+ }
+
+ lock_guard(mutex_type& m, adopt_lock_t)
+ : pm(m)
+ {
+ }
+
+ ~lock_guard()
+ {
+ pm.unlock();
+ }
+
+ lock_guard(lock_guard const&) /*= delete*/;
+ lock_guard& operator=(lock_guard const&) /*= delete*/;
+
+private:
+ mutex_type& pm;
+};
+
+template <class Mutex>
+class unique_lock
+{
+public:
+ typedef Mutex mutex_type;
+
+ unique_lock()
+ : pm(NULL), owns(false)
+ {}
+
+ /*explicit*/ unique_lock(mutex_type& m)
+ : pm(&m), owns(true)
+ {
+ m.lock();
+ }
+
+ unique_lock(mutex_type& m, defer_lock_t)
+ : pm(&m), owns(false)
+ {}
+
+ unique_lock(mutex_type& m, try_to_lock_t)
+ : pm(&m), owns(m.try_lock())
+ {}
+
+ unique_lock(mutex_type& m, adopt_lock_t)
+ : pm(&m), owns(true)
+ {}
+
+ //template <class Clock, class Duration>
+ //unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
+
+ //template <class Rep, class Period>
+ //unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
+
+ ~unique_lock()
+ {
+ if (owns_lock())
+ mutex()->unlock();
+ }
+
+#ifdef USE_RVALUE_REFERENCES
+ unique_lock& operator=(const unique_lock&) /*= delete*/;
+
+ unique_lock& operator=(unique_lock&& other)
+ {
+#else
+ unique_lock& operator=(const unique_lock& u)
+ {
+ // ugly const_cast to get around lack of rvalue references
+ unique_lock& other = const_cast<unique_lock&>(u);
+#endif
+ swap(other);
+ return *this;
+ }
+
+#ifdef USE_RVALUE_REFERENCES
+ unique_lock(const unique_lock&) /*= delete*/;
+
+ unique_lock(unique_lock&& other)
+ : pm(NULL), owns(false)
+ {
+#else
+ unique_lock(const unique_lock& u)
+ : pm(NULL), owns(false)
+ {
+ // ugly const_cast to get around lack of rvalue references
+ unique_lock& other = const_cast<unique_lock&>(u);
+#endif
+ swap(other);
+ }
+
+ void lock()
+ {
+ mutex()->lock();
+ owns = true;
+ }
+
+ bool try_lock()
+ {
+ owns = mutex()->try_lock();
+ return owns;
+ }
+
+ //template <class Rep, class Period>
+ //bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
+ //template <class Clock, class Duration>
+ //bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
+
+ void unlock()
+ {
+ mutex()->unlock();
+ owns = false;
+ }
+
+ void swap(unique_lock& u)
+ {
+ std::swap(pm, u.pm);
+ std::swap(owns, u.owns);
+ }
+
+ mutex_type* release()
+ {
+ return mutex();
+ pm = NULL;
+ owns = false;
+ }
+
+ bool owns_lock() const
+ {
+ return owns;
+ }
+
+ //explicit operator bool () const
+ //{
+ // return owns_lock();
+ //}
+
+ mutex_type* mutex() const
+ {
+ return pm;
+ }
+
+private:
+ mutex_type* pm;
+ bool owns;
+};
+
+template <class Mutex>
+void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
+{
+ x.swap(y);
+}
+
+}
+
+#endif
+#endif
diff --git a/src/common/src/std_thread.h b/src/common/src/std_thread.h
new file mode 100644
index 000000000..0580221b2
--- /dev/null
+++ b/src/common/src/std_thread.h
@@ -0,0 +1,309 @@
+#ifndef STD_THREAD_H_
+#define STD_THREAD_H_
+
+#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
+#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
+// GCC 4.4 provides <thread>
+#ifndef _GLIBCXX_USE_SCHED_YIELD
+#define _GLIBCXX_USE_SCHED_YIELD
+#endif
+#include <thread>
+#else
+
+// partial std::thread implementation for win32/pthread
+
+#include <algorithm>
+
+#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
+#define USE_RVALUE_REFERENCES
+#endif
+
+#ifdef __APPLE__
+#import <Foundation/NSAutoreleasePool.h>
+#endif
+
+#if defined(_WIN32)
+// WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#if defined(_MSC_VER) && defined(_MT)
+// When linking with LIBCMT (the multithreaded C library), Microsoft recommends
+// using _beginthreadex instead of CreateThread.
+#define USE_BEGINTHREADEX
+#include <process.h>
+#endif
+
+#ifdef USE_BEGINTHREADEX
+#define THREAD_ID unsigned
+#define THREAD_RETURN unsigned __stdcall
+#else
+#define THREAD_ID DWORD
+#define THREAD_RETURN DWORD WINAPI
+#endif
+#define THREAD_HANDLE HANDLE
+
+#else
+// PTHREAD
+
+#include <unistd.h>
+
+#ifndef _POSIX_THREADS
+#error unsupported platform (no pthreads?)
+#endif
+
+#include <pthread.h>
+
+#define THREAD_ID pthread_t
+#define THREAD_HANDLE pthread_t
+#define THREAD_RETURN void*
+
+#endif
+
+namespace std
+{
+
+class thread
+{
+public:
+ typedef THREAD_HANDLE native_handle_type;
+
+ class id
+ {
+ friend class thread;
+ public:
+ id() : m_thread(0) {}
+ id(THREAD_ID _id) : m_thread(_id) {}
+
+ bool operator==(const id& rhs) const
+ {
+ return m_thread == rhs.m_thread;
+ }
+
+ bool operator!=(const id& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ bool operator<(const id& rhs) const
+ {
+ return m_thread < rhs.m_thread;
+ }
+
+ private:
+ THREAD_ID m_thread;
+ };
+
+ // no variadic template support in msvc
+ //template <typename C, typename... A>
+ //thread(C&& func, A&&... args);
+
+ template <typename C>
+ thread(C func)
+ {
+ StartThread(new Func<C>(func));
+ }
+
+ template <typename C, typename A>
+ thread(C func, A arg)
+ {
+ StartThread(new FuncArg<C, A>(func, arg));
+ }
+
+ thread() /*= default;*/ {}
+
+#ifdef USE_RVALUE_REFERENCES
+ thread(const thread&) /*= delete*/;
+
+ thread(thread&& other)
+ {
+#else
+ thread(const thread& t)
+ {
+ // ugly const_cast to get around lack of rvalue references
+ thread& other = const_cast<thread&>(t);
+#endif
+ swap(other);
+ }
+
+#ifdef USE_RVALUE_REFERENCES
+ thread& operator=(const thread&) /*= delete*/;
+
+ thread& operator=(thread&& other)
+ {
+#else
+ thread& operator=(const thread& t)
+ {
+ // ugly const_cast to get around lack of rvalue references
+ thread& other = const_cast<thread&>(t);
+#endif
+ if (joinable())
+ detach();
+ swap(other);
+ return *this;
+ }
+
+ ~thread()
+ {
+ if (joinable())
+ detach();
+ }
+
+ bool joinable() const
+ {
+ return m_id != id();
+ }
+
+ id get_id() const
+ {
+ return m_id;
+ }
+
+ native_handle_type native_handle()
+ {
+#ifdef _WIN32
+ return m_handle;
+#else
+ return m_id.m_thread;
+#endif
+ }
+
+ void join()
+ {
+#ifdef _WIN32
+ WaitForSingleObject(m_handle, INFINITE);
+ detach();
+#else
+ pthread_join(m_id.m_thread, NULL);
+ m_id = id();
+#endif
+ }
+
+ void detach()
+ {
+#ifdef _WIN32
+ CloseHandle(m_handle);
+#else
+ pthread_detach(m_id.m_thread);
+#endif
+ m_id = id();
+ }
+
+ void swap(thread& other)
+ {
+ std::swap(m_id, other.m_id);
+#ifdef _WIN32
+ std::swap(m_handle, other.m_handle);
+#endif
+ }
+
+ static unsigned hardware_concurrency()
+ {
+#ifdef _WIN32
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
+#else
+ return 0;
+#endif
+ }
+
+private:
+ id m_id;
+
+#ifdef _WIN32
+ native_handle_type m_handle;
+#endif
+
+ template <typename F>
+ void StartThread(F* param)
+ {
+#ifdef USE_BEGINTHREADEX
+ m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
+#elif defined(_WIN32)
+ m_handle = CreateThread(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
+#else
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 1024 * 1024);
+ if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete<F>, param))
+ m_id = id();
+#endif
+ }
+
+ template <typename C>
+ class Func
+ {
+ public:
+ Func(C _func) : func(_func) {}
+
+ void Run() { func(); }
+
+ private:
+ C const func;
+ };
+
+ template <typename C, typename A>
+ class FuncArg
+ {
+ public:
+ FuncArg(C _func, A _arg) : func(_func), arg(_arg) {}
+
+ void Run() { func(arg); }
+
+ private:
+ C const func;
+ A arg;
+ };
+
+ template <typename F>
+ static THREAD_RETURN RunAndDelete(void* param)
+ {
+#ifdef __APPLE__
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+#endif
+ static_cast<F*>(param)->Run();
+ delete static_cast<F*>(param);
+#ifdef __APPLE__
+ [pool release];
+#endif
+ return 0;
+ }
+};
+
+namespace this_thread
+{
+
+ inline void yield()
+ {
+#ifdef _WIN32
+ SwitchToThread();
+#else
+ sleep(0);
+#endif
+ }
+
+ inline thread::id get_id()
+ {
+#ifdef _WIN32
+ return GetCurrentThreadId();
+#else
+ return pthread_self();
+#endif
+ }
+
+} // namespace this_thread
+
+} // namespace std
+
+#undef USE_RVALUE_REFERENCES
+#undef USE_BEGINTHREADEX
+#undef THREAD_ID
+#undef THREAD_RETURN
+#undef THREAD_HANDLE
+
+#endif
+#endif
diff --git a/src/common/src/timer.cpp b/src/common/src/timer.cpp
new file mode 100644
index 000000000..c731ffb97
--- /dev/null
+++ b/src/common/src/timer.cpp
@@ -0,0 +1,46 @@
+/*!
+* Copyright (C) 2005-2012 Gekko Emulator
+*
+* \file timer.h
+* \author ShizZy <shizzy247@gmail.com>
+* \date 2012-02-11
+* \brief Common time and timer routines
+*
+ * \section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "SDL.h"
+
+#include "common.h"
+#include "timer.h"
+
+namespace common {
+
+/// Converts a ticks (miliseconds) u64 to a formatted string
+void TicksToFormattedString(u32 ticks, char* formatted_string) {
+ u32 hh = ticks / (1000 * 60 * 60);
+ ticks -= hh * (1000 * 60 * 60);
+
+ u32 mm = ticks / (1000 * 60);
+ ticks -= mm * (1000 * 60);
+
+ u32 ss = ticks / 1000;
+ ticks -= ss * 1000;
+
+ sprintf(formatted_string, "%02d:%02d:%03d", mm, ss, ticks);
+}
+
+} // namespace \ No newline at end of file
diff --git a/src/common/src/timer.h b/src/common/src/timer.h
new file mode 100644
index 000000000..dfbf87dfb
--- /dev/null
+++ b/src/common/src/timer.h
@@ -0,0 +1,51 @@
+/*!
+* Copyright (C) 2005-2012 Gekko Emulator
+*
+* \file timer.h
+* \author ShizZy <shizzy247@gmail.com>
+* \date 2012-02-11
+* \brief Common time and timer routines
+*
+ * \section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_TIMER_H_
+#define COMMON_TIMER_H_
+
+#include "types.h"
+
+namespace common {
+
+/*!
+ * \brief Gets Get the number of milliseconds since initialization
+ * \return Unsigned integer of ticks since software initialization
+ */
+static inline u32 GetTimeElapsed() {
+ return SDL_GetTicks();
+}
+
+/*!
+ * \brief Converts a ticks (miliseconds) u32 to a formatted string
+ * \param ticks Ticks (32-bit unsigned integer)
+ * \param formatted_string Pointer to formatted string result
+ */
+void TicksToFormattedString(u32 ticks, char* formatted_string);
+
+
+} // namespace
+
+
+#endif // COMMON_TIMER_H_ \ No newline at end of file
diff --git a/src/common/src/types.h b/src/common/src/types.h
new file mode 100644
index 000000000..d1e027957
--- /dev/null
+++ b/src/common/src/types.h
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file types.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-11
+ * @brief Common types used throughout the project
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_TYPES_H_
+#define COMMON_TYPES_H_
+
+#include <math.h>
+#include <xmmintrin.h> // data_types__m128.cpp
+
+typedef unsigned char u8; ///< 8-bit unsigned byte
+typedef unsigned short u16; ///< 16-bit unsigned short
+typedef unsigned int u32; ///< 32-bit unsigned word
+
+typedef signed char s8; ///< 8-bit signed byte
+typedef signed short s16; ///< 16-bit signed short
+typedef signed int s32; ///< 32-bit signed word
+
+typedef signed int x32; ///< S15.16 fixed point int
+
+typedef float f32; ///< 32-bit floating point
+typedef double f64; ///< 64-bit floating point
+
+#ifdef _MSC_VER
+
+typedef unsigned __int64 u64; ///< 64-bit unsigned int
+typedef signed __int64 s64; ///< 64-bit signed int
+
+#elif defined(__GNUC__)
+
+typedef signed long long s64; ///< 64-bit unsigned int
+typedef unsigned long long u64; ///< 64-bit signed int
+
+#define U64(a) a ## ull
+#define S64(a) a ## sll
+
+#endif
+
+/// Union for fast 16-bit type casting
+union t16 {
+ u8 _u8[2]; ///< 8-bit unsigned char(s)
+ u16 _u16; ///< 16-bit unsigned shorts(s)
+};
+
+/// Union for fast 32-bit type casting
+union t32 {
+ f32 _f32; ///< 32-bit floating point(s)
+ u32 _u32; ///< 32-bit unsigned int(s)
+ x32 _x32; ///< 32-bit fixed point(s)
+ u16 _u16[2]; ///< 16-bit unsigned shorts(s)
+ u8 _u8[4]; ///< 8-bit unsigned char(s)
+};
+
+/// Union for fast 64-bit type casting
+union t64 {
+ f64 _f64; ///< 64-bit floating point
+ u64 _u64; ///< 64-bit unsigned long
+ f32 _f32[2]; ///< 32-bit floating point(s)
+ u32 _u32[2]; ///< 32-bit unsigned int(s)
+ x32 _x32[2]; ///< 32-bit fixed point(s)
+ u16 _u16[4]; ///< 16-bit unsigned shorts(s)
+ u8 _u8[8]; ///< 8-bit unsigned char(s)
+};
+
+/// Union for fast 128-bit type casting
+union t128 {
+ struct
+ {
+ t64 ps0; ///< 64-bit paired single 0
+ t64 ps1; ///< 64-bit paired single 1
+ };
+ __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers)
+};
+
+/// Rectangle data structure
+class Rect {
+public:
+ Rect(int x0=0, int y0=0, int x1=0, int y1=0) {
+ x0_ = x0;
+ y0_ = y0;
+ x1_ = x1;
+ y1_ = y1;
+ }
+ ~Rect() { }
+
+ int x0_; ///< Rect top left X-coordinate
+ int y0_; ///< Rect top left Y-coordinate
+ int x1_; ///< Rect bottom left X-coordinate
+ int y1_; ///< Rect bottom right Y-coordinate
+
+ inline u32 width() const { return abs(x1_ - x0_); }
+ inline u32 height() const { return abs(y1_ - y0_); }
+
+ inline bool operator == (const Rect& val) const {
+ return (x0_ == val.x0_ && y0_ == val.y0_ && x1_ == val.x1_ && y1_ == val.y1_);
+ }
+};
+
+#endif // COMMON_TYPES_H_ \ No newline at end of file
diff --git a/src/common/src/x86_utils.cpp b/src/common/src/x86_utils.cpp
new file mode 100644
index 000000000..8af6b9868
--- /dev/null
+++ b/src/common/src/x86_utils.cpp
@@ -0,0 +1,236 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file x86_utils.cpp
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-12-23
+ * @brief Utilities for the x86 architecture
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include "common.h"
+#include "x86_utils.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>
+
+#if defined __FreeBSD__
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#else
+static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+#ifdef _LP64
+ // Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to
+ // restored at the end of the asm block.
+ __asm__ (
+ "cpuid;"
+ "movl %%ebx,%1;"
+ : "=a" (*eax),
+ "=S" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "a" (*eax)
+ : "rbx"
+ );
+#else
+ __asm__ (
+ "cpuid;"
+ "movl %%ebx,%1;"
+ : "=a" (*eax),
+ "=S" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "a" (*eax)
+ : "ebx"
+ );
+#endif
+}
+#endif
+
+static void __cpuid(int info[4], int x)
+{
+#if defined __FreeBSD__
+ do_cpuid((unsigned int)x, (unsigned int*)info);
+#else
+ 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
+}
+
+#endif
+
+namespace common {
+
+X86Utils::X86Utils() {
+ memset(this, 0, sizeof(*this));
+#ifdef _M_IX86
+
+#elif defined (_M_X64)
+ support_x64_os_ = true;
+ support_sse_ = true;
+ support_sse2_ = true;
+#endif
+ num_cores_ = 1;
+#ifdef _WIN32
+#ifdef _M_IX86
+ int f64 = 0;
+ IsWow64Process(GetCurrentProcess(), &f64);
+ support_x64_os_ = (f64 == 1) ? true : false;
+#endif
+#endif
+ // Assume CPU supports the CPUID instruction. Those that don't can barely
+ // boot modern OS:es anyway.
+ int cpu_id[4];
+ char cpu_string[32];
+ 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")) {
+ cpu_vendor_ = kVendorX86_Intel;
+ } else if (!strcmp(cpu_string, "AuthenticAMD")) {
+ cpu_vendor_ = kVendorX86_AMD;
+ } else {
+ cpu_vendor_ = kVendorX86_None;
+ }
+
+ // Detect family and other misc stuff.
+ bool ht = false;
+ support_hyper_threading_ = ht;
+ logical_cpu_count_ = 1;
+ if (max_std_fn >= 1) {
+ __cpuid(cpu_id, 0x00000001);
+ logical_cpu_count_ = (cpu_id[1] >> 16) & 0xFF;
+ ht = (cpu_id[3] >> 28) & 1;
+
+ if ((cpu_id[3] >> 25) & 1) support_sse_ = true;
+ if ((cpu_id[3] >> 26) & 1) support_sse2_ = true;
+ if ((cpu_id[2]) & 1) support_sse3_ = true;
+ if ((cpu_id[2] >> 9) & 1) support_ssse3_ = true;
+ if ((cpu_id[2] >> 19) & 1) support_sse4_1_ = true;
+ if ((cpu_id[2] >> 20) & 1) support_sse4_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));
+ }
+ num_cores_ = (logical_cpu_count_ == 0) ? 1 : logical_cpu_count_;
+
+ 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) {
+ if (ht) {
+ // New mechanism for modern Intel CPUs.
+ if (cpu_vendor_ == kVendorX86_Intel) {
+ __cpuid(cpu_id, 0x00000004);
+ int cores_x_package = ((cpu_id[0] >> 26) & 0x3F) + 1;
+ support_hyper_threading_ = (cores_x_package < logical_cpu_count_);
+ cores_x_package = ((logical_cpu_count_ % cores_x_package) == 0) ? cores_x_package : 1;
+ num_cores_ = (cores_x_package > 1) ? cores_x_package : num_cores_;
+ logical_cpu_count_ /= cores_x_package;
+ }
+ }
+ } else {
+ // Use AMD's new method.
+ num_cores_ = (cpu_id[2] & 0xFF) + 1;
+ }
+ }
+ LOG_NOTICE(TCOMMON, "CPU detected (%s)", this->Summary().c_str());
+}
+
+X86Utils::~X86Utils() {
+}
+
+/**
+ * Check if an X86 extension is supported by the current architecture
+ * @param extension ExtensionX86 extension support to check for
+ * @return True if the extension is supported, otherwise false
+ */
+bool X86Utils::IsExtensionSupported(X86Utils::ExtensionX86 extension) {
+ switch (extension) {
+ case kExtensionX86_SSE:
+ return support_sse_;
+ case kExtensionX86_SSE2:
+ return support_sse2_;
+ case kExtensionX86_SSE3:
+ return support_sse3_;
+ case kExtensionX86_SSSE3:
+ return support_ssse3_;
+ case kExtensionX86_SSE4_1:
+ return support_sse4_1_;
+ case kExtensionX86_SSE4_2:
+ return support_sse4_2_;
+ }
+ return false;
+}
+
+/**
+ * Gets a string summary of the X86 CPU information, suitable for printing
+ * @return String summary
+ */
+std::string X86Utils::Summary() {
+ const char* cpu_vendors[] = {
+ "Unknown", "Intel", "AMD"
+ };
+ std::string res;
+ res = FormatStr("%s, %d core%s", cpu_vendors[cpu_vendor_], num_cores_, (num_cores_ > 1) ? "s" : "");
+ if (support_sse4_2_) {
+ res += FormatStr(" (%i logical threads per physical core)", logical_cpu_count_);
+ }
+ if (support_sse_) res += ", SSE";
+ if (support_sse2_) res += ", SSE2";
+ if (support_sse3_) res += ", SSE3";
+ if (support_ssse3_) res += ", SSSE3";
+ if (support_sse4_1_) res += ", SSE4.1";
+ if (support_sse4_2_) res += ", SSE4.2";
+ if (support_hyper_threading_) res += ", HTT";
+ //if (bLongMode) res += ", 64-bit support";
+ return res;
+}
+
+} // namespace
diff --git a/src/common/src/x86_utils.h b/src/common/src/x86_utils.h
new file mode 100644
index 000000000..6dc8c0d92
--- /dev/null
+++ b/src/common/src/x86_utils.h
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file x86_utils.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-11
+ * @brief Utilities for the x86 architecture
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_X86_UTILS_
+#define COMMON_X86_UTILS_
+
+#include <string>
+#include "types.h"
+
+// Common namespace
+namespace common {
+
+class X86Utils {
+public:
+ /// Enumeration of X86 vendors
+ enum VendorX86 {
+ kVendorX86_None = 0,
+ kVendorX86_Intel,
+ kVendorX86_AMD,
+ kVendorX86_NumberOf
+ };
+
+ /// Enumeration of X86 extensions
+ enum ExtensionX86 {
+ kExtensionX86_None = 0,
+ kExtensionX86_SSE,
+ kExtensionX86_SSE2,
+ kExtensionX86_SSE3,
+ kExtensionX86_SSSE3,
+ kExtensionX86_SSE4_1,
+ kExtensionX86_SSE4_2,
+ kExtensionX86_NumberOf
+ };
+
+ X86Utils();
+ ~X86Utils();
+
+ /**
+ * Check if an X86 extension is supported by the current architecture
+ * @param extension ExtensionX86 extension support to check for
+ * @return True if the extension is supported, otherwise false
+ */
+ bool IsExtensionSupported(ExtensionX86 extension);
+
+ /**
+ * Gets a string summary of the X86 CPU information, suitable for printing
+ * @return String summary
+ */
+ std::string Summary();
+
+private:
+ bool support_x64_os_;
+ bool support_x64_cpu_;
+ bool support_hyper_threading_;
+
+ int num_cores_;
+ int logical_cpu_count_;
+
+ bool support_sse_;
+ bool support_sse2_;
+ bool support_sse3_;
+ bool support_ssse3_;
+ bool support_sse4_1_;
+ bool support_sse4_2_;
+
+ VendorX86 cpu_vendor_;
+};
+
+} // namespace
+
+#endif
diff --git a/src/common/src/xml.cpp b/src/common/src/xml.cpp
new file mode 100644
index 000000000..f4b913890
--- /dev/null
+++ b/src/common/src/xml.cpp
@@ -0,0 +1,487 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file xml.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-12
+ * @brief Used for parsing XML configurations
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <rapidxml.hpp>
+
+#include "common.h"
+#include "misc_utils.h"
+#include "config.h"
+#include "log.h"
+
+/// Gets a RapidXML boolean element value
+static bool GetXMLElementAsBool(rapidxml::xml_node<> *node, const char* element_name) {
+ rapidxml::xml_node<> *sub_node = node->first_node(element_name);
+ if (sub_node) {
+ return (E_OK == _stricmp(sub_node->value(), "true")) ? true : false;
+ }
+ return false;
+}
+
+/// Gets a RapidXML string element value
+static char* GetXMLElementAsString(rapidxml::xml_node<> *node, const char* element_name,
+ char* element_value) {
+ rapidxml::xml_node<> *sub_node = node->first_node(element_name);
+ if (sub_node) {
+ strcpy(element_value, sub_node->value());
+ return element_value;
+ }
+ return NULL;
+}
+
+/// Gets a RapidXML integer element value
+static int GetXMLElementAsInt(rapidxml::xml_node<> *node, const char* element_name) {
+ rapidxml::xml_node<> *sub_node = node->first_node(element_name);
+ if (sub_node) {
+ return atoi(sub_node->value());
+ }
+ return 0;
+}
+
+namespace common {
+
+/**
+ * @brief Parse the "General" XML group
+ * @param node RapidXML node for the "General" XML group
+ * @param config Config class object to parse data into
+ */
+void ParseGeneralNode(rapidxml::xml_node<> *node, Config& config) {
+ // Don't parse the node if it doesn't exist!
+ if (!node) {
+ return;
+ }
+ char temp_str[MAX_PATH];
+ config.set_enable_multicore(GetXMLElementAsBool(node, "EnableMultiCore"));
+ config.set_enable_idle_skipping(GetXMLElementAsBool(node, "EnableIdleSkipping"));
+ config.set_enable_hle(GetXMLElementAsBool(node, "EnableHLE"));
+ config.set_enable_auto_boot(GetXMLElementAsBool(node, "EnableAutoBoot"));
+ config.set_enable_cheats(GetXMLElementAsBool(node, "EnableCheats"));
+ config.set_default_boot_file(GetXMLElementAsString(node, "DefaultBootFile", temp_str), MAX_PATH);
+
+ // Parse all search paths in the DVDImagePaths node
+ rapidxml::xml_node<> *sub_node = node->first_node("DVDImagePaths");
+ if (sub_node) {
+ int i = 0;
+ for (rapidxml::xml_node<> *elem = sub_node->first_node("Path"); elem;
+ elem = elem->next_sibling()) {
+
+ config.set_dvd_image_path(i, elem->value(), MAX_PATH);
+ LOG_NOTICE(TCONFIG, "Adding %s to DVD image search paths...\n",
+ config.dvd_image_path(i));
+ i++;
+ // Stop if we have parsed the maximum paths
+ if (MAX_SEARCH_PATHS < i) {
+ LOG_WARNING(TCONFIG, "Maximum number of DVDImagePath search paths is %d, not parsing"
+ " any more!", MAX_SEARCH_PATHS);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * @brief Parse the "Debug" XML group
+ * @param node RapidXML node for the "Debug" XML group
+ * @param config Config class object to parse data into
+ */
+void ParseDebugNode(rapidxml::xml_node<> *node, Config& config) {
+ // Don't parse the node if it doesn't exist!
+ if (!node) {
+ return;
+ }
+ config.set_enable_show_fps(GetXMLElementAsBool(node, "EnableShowFPS"));
+ config.set_enable_dump_opcode0(GetXMLElementAsBool(node, "EnableDumpOpcode0"));
+ config.set_enable_pause_on_unknown_opcode(GetXMLElementAsBool(node,
+ "EnablePauseOnUnknownOpcode"));
+ config.set_enable_dump_gcm_reads(GetXMLElementAsBool(node, "EnableDumpGCMReads"));
+}
+
+/**
+ * @brief Parse the "Patches" and "Cheats" XML group
+ * @param node RapidXML node for the "Patches" or "Cheats" XML group
+ * @param config Config class object to parse data into
+ */
+void ParsePatchesNode(rapidxml::xml_node<> *node, Config& config, const char* node_name) {
+ int i = 0;
+ char node_name_str[8];
+
+ // Get lowercase section name
+ strcpy(node_name_str, node_name);
+
+ // TODO: not available on Unix
+ common::LowerStr(node_name_str);
+
+ // Parse all search patches in the Patches node
+ rapidxml::xml_node<> *sub_node = node->first_node(node_name);
+ if (sub_node) {
+ for (rapidxml::xml_node<> *elem = sub_node->first_node("Patch"); elem;
+ elem = elem->next_sibling()) {
+
+ // Get enable attribute (note: defaults to true)
+ rapidxml::xml_attribute<> *attr = elem->first_attribute("enable");
+ if (attr) {
+ if (E_OK == _stricmp(attr->value(), "false")) {
+ continue; // Patch is disabled, skip it
+ }
+ }
+ // Get address attribute
+ attr = elem->first_attribute("address");
+ if (!attr) {
+ LOG_ERROR(TCONFIG, "Patch without 'address' attribute illegal!");
+ continue;
+ } else {
+ u32 data = 0;
+ u32 address = 0;
+ {
+ // Convert address hexstring to unsigned int
+ std::stringstream ss;
+ ss << std::hex << attr->value();
+ ss >> address;
+ }
+ attr = elem->first_attribute("instr");
+
+ // Get "data" attribute if no "instr" attribute
+ if (!attr) {
+ attr = elem->first_attribute("data");
+ // Neither found - error
+ if (!attr) {
+ LOG_ERROR(TCONFIG, "Patch without 'instr' or 'data' attributes "
+ "illegal!");
+ continue;
+ } else {
+ // Found data, convert hexstring to unsigned int
+ std::stringstream ss;
+ ss << std::hex << attr->value();
+ ss >> data;
+ }
+ } else {
+ // Found instr
+ char instr_str[4];
+
+ // Convert to lowercase
+ strcpy(instr_str, attr->value());
+ // TODO: not available on Unix
+ common::LowerStr(instr_str);
+
+ // Convert instruction to equivalent PPC bytecode
+ // TODO(ShizZy): Pull this out to the PowerPC modules at some point
+ if (E_OK == _stricmp(instr_str, "blr")) {
+ data = 0x4E800020; // PowerPC BLR instruction bytecode
+ } else if (E_OK == _stricmp(instr_str, "nop")) {
+ data = 0x60000000; // PowerPC NOP instruction bytecode
+ } else {
+ LOG_ERROR(TCONFIG, "Patch with invalid 'instr' attribute illegal!");
+ continue;
+ }
+ }
+ Config::Patch patch = { address, data };
+
+ if (E_OK == _stricmp(node_name_str, "patches")) {
+ LOG_NOTICE(TCONFIG, "Adding patch addr=0x%08x data=0x%08x to patches...\n",
+ address, data, node_name_str);
+ config.set_patches(i, patch);
+ } else if (E_OK == _stricmp(node_name_str, "cheats")) {
+ LOG_NOTICE(TCONFIG, "Adding cheat addr=0x%08x data=0x%08x to cheats...\n",
+ address, data, node_name_str);
+ config.set_cheats(i, patch);
+ } else {
+ LOG_ERROR(TCONFIG, "Unexpected patch type %s, ignoring...", node_name_str);
+ }
+
+ // Stop if we have parsed the maximum patches
+ if (MAX_PATCHES_PER_GAME < ++i) {
+ LOG_WARNING(TCONFIG, "Maximum number of patches search paths is %d, not parsing"
+ " any more!", MAX_PATCHES_PER_GAME);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief Parse the "Boot" XML group
+ * @param node RapidXML node for the "Boot" XML group
+ * @param config Config class object to parse data into
+ */
+void ParseBootNode(rapidxml::xml_node<> *node, Config& config) {
+ // Don't parse the node if it doesn't exist!
+ if (!node) {
+ return;
+ }
+ config.set_enable_ipl(GetXMLElementAsBool(node, "EnableIPL"));
+
+ ParsePatchesNode(node, config, "Patches");
+ ParsePatchesNode(node, config, "Cheats");
+}
+
+/**
+ * @brief Parse the "Video" XML group
+ * @param node RapidXML node for the "Video" XML group
+ * @param config Config class object to parse data into
+ */
+void ParsePowerPCNode(rapidxml::xml_node<> *node, Config& config) {
+ // Don't parse the node if it doesn't exist!
+ if (!node) {
+ return;
+ }
+ rapidxml::xml_attribute<> *attr = node->first_attribute("core");
+
+ // Attribute not found - error
+ if (!attr) {
+ LOG_ERROR(TCONFIG, "PowerPC without 'core' attribute illegal!");
+ } else {
+ char core_str[12] = "null";
+
+ // Convert to lowercase
+ strcpy(core_str, attr->value());
+ // TODO: not available on Unix
+ common::LowerStr(core_str);
+
+ // Use interpreter core
+ if (E_OK == _stricmp(core_str, "interpreter")) {
+ config.set_powerpc_core(Config::CPU_INTERPRETER); // Interpreter selected
+ // Use dynarec core
+ } else if (E_OK == _stricmp(core_str, "dynarec")) {
+ config.set_powerpc_core(Config::CPU_DYNAREC); // Dynarec selected
+ // Unsupported type
+ } else {
+ LOG_ERROR(TCONFIG, "Invalid PowerPC type %s for attribute 'core' selected!",
+ core_str);
+ }
+ // Set frequency
+ attr = node->first_attribute("freq");
+ if (attr) {
+ config.set_powerpc_frequency(atoi(attr->value()));
+ }
+ LOG_NOTICE(TCONFIG, "Configured core=%s freq=%d", core_str, config.powerpc_frequency());
+ }
+}
+
+/**
+ * @brief Parse the "Video" XML group
+ * @param node RapidXML node for the "Video" XML group
+ * @param config Config class object to parse data into
+ */
+void ParseVideoNode(rapidxml::xml_node<> *node, Config& config) {
+ char res_str[512];
+ Config::ResolutionType res;
+
+ // Don't parse the node if it doesn't exist!
+ if (!node) {
+ return;
+ }
+ config.set_enable_fullscreen(GetXMLElementAsBool(node, "EnableFullscreen"));
+
+ // Set resolutions
+ GetXMLElementAsString(node, "WindowResolution", res_str);
+ sscanf(res_str, "%d_%d", &res.width, &res.height);
+ config.set_window_resolution(res);
+ GetXMLElementAsString(node, "FullscreenResolution", res_str);
+ sscanf(res_str, "%d_%d", &res.width, &res.height);
+ config.set_fullscreen_resolution(res);
+
+ // Parse all search renderer nodes
+ for (rapidxml::xml_node<> *elem = node->first_node("Renderer"); 1; ) {
+ Config::RendererConfig renderer_config;
+
+ rapidxml::xml_attribute<> *attr = elem->first_attribute("name");
+
+ Config::RendererType type = Config::StringToRenderType(attr->value());
+
+ renderer_config.enable_wireframe = GetXMLElementAsBool(elem, "EnableWireframe");
+ renderer_config.enable_shaders = GetXMLElementAsBool(elem, "EnableShaders");
+ renderer_config.enable_textures = GetXMLElementAsBool(elem, "EnableTextures");
+ renderer_config.enable_texture_dumping = GetXMLElementAsBool(elem, "EnableTextureDumping");
+ renderer_config.anti_aliasing_mode = GetXMLElementAsInt(elem, "AntiAliasingMode");
+ renderer_config.anistropic_filtering_mode = GetXMLElementAsInt(elem, "AnistropicFilteringMode");
+
+ config.set_renderer_config(type, renderer_config);
+
+ LOG_NOTICE(TCONFIG, "Renderer %s configured", attr->value());
+
+ break;
+ }
+}
+
+/**
+ * @brief Parse the "Devices" XML group
+ * @param node RapidXML node for the "Devices" XML group
+ * @param config Config class object to parse data into
+ */
+void ParseDevicesNode(rapidxml::xml_node<> *node, Config& config) {
+ // Don't parse the node if it doesn't exist!c
+ if (!node) {
+ return;
+ }
+ // Parse GameCube section
+ rapidxml::xml_node<> *gamecube_node = node->first_node("GameCube");
+ if (!gamecube_node) {
+ return;
+ }
+ // Parse all MemSlot nodes
+ for (rapidxml::xml_node<> *elem = gamecube_node->first_node("MemSlot"); elem;
+ elem = elem->next_sibling("MemSlot")) {
+ Config::MemSlot slot_config;
+
+ // Select MemSlot a or b
+ rapidxml::xml_attribute<> *attr = elem->first_attribute("slot");
+ int slot = (E_OK == _stricmp(attr->value(), "a")) ? 0 : 1;
+
+ // Enable
+ attr = elem->first_attribute("enable");
+ slot_config.enable = (E_OK == _stricmp(attr->value(), "true")) ? true : false;
+
+ // Select device
+ attr = elem->first_attribute("device");
+ slot_config.device = 0; // Only support memcards right now
+
+ LOG_NOTICE(TCONFIG, "Configured MemSlot[%d]=%s enabled=%s", slot, attr->value(),
+ slot_config.enable ? "true" : "false");
+
+ config.set_mem_slots(slot, slot_config);
+ }
+ // Parse all ControlerPort nodes
+ for (rapidxml::xml_node<> *elem = gamecube_node->first_node("ControllerPort"); elem;
+ elem = elem->next_sibling("ControllerPort")) {
+ Config::ControllerPort port_config;
+
+ // Select MemSlot a or b
+ rapidxml::xml_attribute<> *attr = elem->first_attribute("port");
+ int port = atoi(attr->value());
+
+ // Enable
+ attr = elem->first_attribute("enable");
+ port_config.enable = (E_OK == _stricmp(attr->value(), "true")) ? true : false;
+
+ // Select device
+ attr = elem->first_attribute("device");
+ port_config.device = 0; // Only support memcards right now
+
+ LOG_NOTICE(TCONFIG, "Configured ControllerPort[%d]=%s enabled=%s", port, attr->value(),
+ port_config.enable ? "true" : "false");
+
+ // Parse keyboard configuration - TODO: Move to EmuWindow (?)
+ rapidxml::xml_node<> *keyboard_node = elem->first_node("KeyboardController");
+ if (keyboard_node) {
+ attr = keyboard_node->first_attribute("enable");
+ port_config.keys.enable = (E_OK == _stricmp(attr->value(), "true")) ? true : false;
+ port_config.keys.key_code[Config::BUTTON_A] = GetXMLElementAsInt(keyboard_node, "AKey");
+ port_config.keys.key_code[Config::BUTTON_B] = GetXMLElementAsInt(keyboard_node, "BKey");
+ port_config.keys.key_code[Config::BUTTON_X] = GetXMLElementAsInt(keyboard_node, "XKey");
+ port_config.keys.key_code[Config::BUTTON_Y] = GetXMLElementAsInt(keyboard_node, "YKey");
+ port_config.keys.key_code[Config::TRIGGER_L] = GetXMLElementAsInt(keyboard_node, "LKey");
+ port_config.keys.key_code[Config::TRIGGER_R] = GetXMLElementAsInt(keyboard_node, "RKey");
+ port_config.keys.key_code[Config::BUTTON_Z] = GetXMLElementAsInt(keyboard_node, "ZKey");
+ port_config.keys.key_code[Config::BUTTON_START] = GetXMLElementAsInt(keyboard_node, "StartKey");
+ port_config.keys.key_code[Config::ANALOG_UP] = GetXMLElementAsInt(keyboard_node, "AnalogUpKey");
+ port_config.keys.key_code[Config::ANALOG_DOWN] = GetXMLElementAsInt(keyboard_node, "AnalogDownKey");
+ port_config.keys.key_code[Config::ANALOG_LEFT] = GetXMLElementAsInt(keyboard_node, "AnalogLeftKey");
+ port_config.keys.key_code[Config::ANALOG_RIGHT] = GetXMLElementAsInt(keyboard_node, "AnalogRightKey");
+ port_config.keys.key_code[Config::C_UP] = GetXMLElementAsInt(keyboard_node, "CUpKey");
+ port_config.keys.key_code[Config::C_DOWN] = GetXMLElementAsInt(keyboard_node, "CDownKey");
+ port_config.keys.key_code[Config::C_LEFT] = GetXMLElementAsInt(keyboard_node, "CLeftKey");
+ port_config.keys.key_code[Config::C_RIGHT] = GetXMLElementAsInt(keyboard_node, "CRightKey");
+ port_config.keys.key_code[Config::DPAD_UP] = GetXMLElementAsInt(keyboard_node, "DPadUpKey");
+ port_config.keys.key_code[Config::DPAD_DOWN] = GetXMLElementAsInt(keyboard_node, "DPadDownKey");
+ port_config.keys.key_code[Config::DPAD_LEFT] = GetXMLElementAsInt(keyboard_node, "DPadLeftKey");
+ port_config.keys.key_code[Config::DPAD_RIGHT] = GetXMLElementAsInt(keyboard_node, "DPadRightKey");
+ }
+
+ // Parse joypad configuration
+ rapidxml::xml_node<> *joypad_node = elem->first_node("JoypadController");
+ if (joypad_node) {
+ attr = joypad_node->first_attribute("enable");
+ port_config.pads.enable = (E_OK == _stricmp(attr->value(), "true")) ? true : false;
+ port_config.pads.key_code[Config::BUTTON_A] = GetXMLElementAsInt(joypad_node, "AKey");
+ port_config.pads.key_code[Config::BUTTON_B] = GetXMLElementAsInt(joypad_node, "BKey");
+ port_config.pads.key_code[Config::BUTTON_X] = GetXMLElementAsInt(joypad_node, "XKey");
+ port_config.pads.key_code[Config::BUTTON_Y] = GetXMLElementAsInt(joypad_node, "YKey");
+ port_config.pads.key_code[Config::TRIGGER_L] = GetXMLElementAsInt(joypad_node, "LKey");
+ port_config.pads.key_code[Config::TRIGGER_R] = GetXMLElementAsInt(joypad_node, "RKey");
+ port_config.pads.key_code[Config::BUTTON_Z] = GetXMLElementAsInt(joypad_node, "ZKey");
+ port_config.pads.key_code[Config::BUTTON_START] = GetXMLElementAsInt(joypad_node, "StartKey");
+ port_config.pads.key_code[Config::ANALOG_UP] = GetXMLElementAsInt(joypad_node, "AnalogUpKey");
+ port_config.pads.key_code[Config::ANALOG_DOWN] = GetXMLElementAsInt(joypad_node, "AnalogDownKey");
+ port_config.pads.key_code[Config::ANALOG_LEFT] = GetXMLElementAsInt(joypad_node, "AnalogLeftKey");
+ port_config.pads.key_code[Config::ANALOG_RIGHT] = GetXMLElementAsInt(joypad_node, "AnalogRightKey");
+ port_config.pads.key_code[Config::C_UP] = GetXMLElementAsInt(joypad_node, "CUpKey");
+ port_config.pads.key_code[Config::C_DOWN] = GetXMLElementAsInt(joypad_node, "CDownKey");
+ port_config.pads.key_code[Config::C_LEFT] = GetXMLElementAsInt(joypad_node, "CLeftKey");
+ port_config.pads.key_code[Config::C_RIGHT] = GetXMLElementAsInt(joypad_node, "CRightKey");
+ port_config.pads.key_code[Config::DPAD_UP] = GetXMLElementAsInt(joypad_node, "DPadUpKey");
+ port_config.pads.key_code[Config::DPAD_DOWN] = GetXMLElementAsInt(joypad_node, "DPadDownKey");
+ port_config.pads.key_code[Config::DPAD_LEFT] = GetXMLElementAsInt(joypad_node, "DPadLeftKey");
+ port_config.pads.key_code[Config::DPAD_RIGHT] = GetXMLElementAsInt(joypad_node, "DPadRightKey");
+ }
+ config.set_controller_ports(port, port_config);
+ }
+}
+
+/// Loads/parses an XML configuration file
+void LoadXMLConfig(Config& config, const char* filename) {
+ // Open the XML file
+ char full_filename[MAX_PATH];
+ strcpy(full_filename, config.program_dir());
+ strcat(full_filename, filename);
+ std::ifstream ifs(full_filename);
+
+ // Check that the file is valid
+ if (ifs.fail()) {
+ LOG_ERROR(TCONFIG, "XML configuration file %s failed to open!", filename);
+ return;
+ }
+ // Read and parse XML string
+ std::string xml_str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+ rapidxml::xml_document<> doc;
+ doc.parse<0>(const_cast<char *>(xml_str.c_str()));
+
+ // Try to load a system configuration
+ rapidxml::xml_node<> *node = doc.first_node("SysConfig");
+
+ // Try to load a game configuation
+ if (!node) {
+ node = doc.first_node("GameConfig");
+ }
+ // Try to load a user configuation
+ if (!node) {
+ node = doc.first_node("UserConfig");
+ }
+ // Not proper XML format
+ if (!node) {
+ LOG_ERROR(TCONFIG, "XML configuration file incorrect format %s!", filename)
+ return;
+ }
+ // Parse all sub nodes into the config
+ ParseGeneralNode(node->first_node("General"), config);
+ ParseDebugNode(node->first_node("Debug"), config);
+ ParseBootNode(node->first_node("Boot"), config);
+ ParsePowerPCNode(node->first_node("PowerPC"), config);
+ ParseVideoNode(node->first_node("Video"), config);
+ ParseDevicesNode(node->first_node("Devices"), config);
+}
+
+} // namespace
diff --git a/src/common/src/xml.h b/src/common/src/xml.h
new file mode 100644
index 000000000..30447649a
--- /dev/null
+++ b/src/common/src/xml.h
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2005-2012 Gekko Emulator
+ *
+ * @file xml.h
+ * @author ShizZy <shizzy247@gmail.com>
+ * @date 2012-02-12
+ * @brief Used for parsing XML configurations
+ *
+ * @section LICENSE
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 for more details at
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Official project repository can be found at:
+ * http://code.google.com/p/gekko-gc-emu/
+ */
+
+#ifndef COMMON_XML_H_
+#define COMMON_XML_H_
+
+#include "common.h"
+
+namespace common {
+
+/**
+ * @brief Loads/parses an XML configuration file
+ * @param config Reference to configuration object to populate
+ * @param filename Filename of XMl file to load
+ */
+void LoadXMLConfig(Config& config, const char* filename);
+
+} // namespace
+
+#endif // COMMON_XML_H_