From 63e46abdb8764bc97e91bae862c8d461e61b1965 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 8 Apr 2014 19:25:03 -0400 Subject: got rid of 'src' folders in each sub-project --- src/common/atomic.h | 19 + src/common/atomic_gcc.h | 113 ++++ src/common/atomic_win32.h | 72 +++ src/common/break_points.cpp | 203 +++++++ src/common/break_points.h | 102 ++++ src/common/chunk_file.h | 874 ++++++++++++++++++++++++++++++ src/common/common.h | 171 ++++++ src/common/common_funcs.h | 245 +++++++++ src/common/common_paths.h | 79 +++ src/common/common_types.h | 125 +++++ src/common/console_listener.cpp | 337 ++++++++++++ src/common/console_listener.h | 41 ++ src/common/cpu_detect.h | 81 +++ src/common/debug_interface.h | 39 ++ src/common/emu_window.h | 102 ++++ src/common/extended_trace.cpp | 433 +++++++++++++++ src/common/extended_trace.h | 53 ++ src/common/fifo_queue.h | 115 ++++ src/common/file_search.cpp | 106 ++++ src/common/file_search.h | 28 + src/common/file_util.cpp | 910 ++++++++++++++++++++++++++++++++ src/common/file_util.h | 224 ++++++++ src/common/fixed_size_queue.h | 75 +++ src/common/hash.cpp | 520 ++++++++++++++++++ src/common/hash.h | 20 + src/common/linear_disk_cache.h | 191 +++++++ src/common/log.h | 155 ++++++ src/common/log_manager.cpp | 200 +++++++ src/common/log_manager.h | 169 ++++++ src/common/math_util.cpp | 212 ++++++++ src/common/math_util.h | 200 +++++++ src/common/mem_arena.cpp | 477 +++++++++++++++++ src/common/mem_arena.h | 81 +++ src/common/memory_util.cpp | 197 +++++++ src/common/memory_util.h | 25 + src/common/misc.cpp | 37 ++ src/common/msg_handler.cpp | 107 ++++ src/common/msg_handler.h | 73 +++ src/common/platform.h | 142 +++++ src/common/scm_rev.h | 4 + src/common/src/atomic.h | 19 - src/common/src/atomic_gcc.h | 113 ---- src/common/src/atomic_win32.h | 72 --- src/common/src/break_points.cpp | 203 ------- src/common/src/break_points.h | 102 ---- src/common/src/chunk_file.h | 874 ------------------------------ src/common/src/common.h | 171 ------ src/common/src/common_funcs.h | 245 --------- src/common/src/common_paths.h | 79 --- src/common/src/common_types.h | 125 ----- src/common/src/console_listener.cpp | 337 ------------ src/common/src/console_listener.h | 41 -- src/common/src/cpu_detect.h | 81 --- src/common/src/debug_interface.h | 39 -- src/common/src/emu_window.h | 102 ---- src/common/src/extended_trace.cpp | 433 --------------- src/common/src/extended_trace.h | 53 -- src/common/src/fifo_queue.h | 115 ---- src/common/src/file_search.cpp | 106 ---- src/common/src/file_search.h | 28 - src/common/src/file_util.cpp | 910 -------------------------------- src/common/src/file_util.h | 224 -------- src/common/src/fixed_size_queue.h | 75 --- src/common/src/hash.cpp | 520 ------------------ src/common/src/hash.h | 20 - src/common/src/linear_disk_cache.h | 191 ------- src/common/src/log.h | 155 ------ src/common/src/log_manager.cpp | 200 ------- src/common/src/log_manager.h | 169 ------ src/common/src/math_util.cpp | 212 -------- src/common/src/math_util.h | 200 ------- src/common/src/mem_arena.cpp | 477 ----------------- src/common/src/mem_arena.h | 81 --- src/common/src/memory_util.cpp | 197 ------- src/common/src/memory_util.h | 25 - src/common/src/misc.cpp | 37 -- src/common/src/msg_handler.cpp | 107 ---- src/common/src/msg_handler.h | 73 --- src/common/src/platform.h | 142 ----- src/common/src/scm_rev.h | 4 - src/common/src/std_condition_variable.h | 170 ------ src/common/src/std_mutex.h | 365 ------------- src/common/src/std_thread.h | 317 ----------- src/common/src/string_util.cpp | 531 ------------------- src/common/src/string_util.h | 111 ---- src/common/src/swap.h | 535 ------------------- src/common/src/thread.cpp | 133 ----- src/common/src/thread.h | 156 ------ src/common/src/thunk.h | 46 -- src/common/src/timer.cpp | 226 -------- src/common/src/timer.h | 46 -- src/common/src/utf8.cpp | 463 ---------------- src/common/src/utf8.h | 67 --- src/common/src/version.cpp | 45 -- src/common/std_condition_variable.h | 170 ++++++ src/common/std_mutex.h | 365 +++++++++++++ src/common/std_thread.h | 317 +++++++++++ src/common/string_util.cpp | 531 +++++++++++++++++++ src/common/string_util.h | 111 ++++ src/common/swap.h | 535 +++++++++++++++++++ src/common/thread.cpp | 133 +++++ src/common/thread.h | 156 ++++++ src/common/thunk.h | 46 ++ src/common/timer.cpp | 226 ++++++++ src/common/timer.h | 46 ++ src/common/utf8.cpp | 463 ++++++++++++++++ src/common/utf8.h | 67 +++ src/common/version.cpp | 45 ++ 108 files changed, 10568 insertions(+), 10568 deletions(-) create mode 100644 src/common/atomic.h create mode 100644 src/common/atomic_gcc.h create mode 100644 src/common/atomic_win32.h create mode 100644 src/common/break_points.cpp create mode 100644 src/common/break_points.h create mode 100644 src/common/chunk_file.h create mode 100644 src/common/common.h create mode 100644 src/common/common_funcs.h create mode 100644 src/common/common_paths.h create mode 100644 src/common/common_types.h create mode 100644 src/common/console_listener.cpp create mode 100644 src/common/console_listener.h create mode 100644 src/common/cpu_detect.h create mode 100644 src/common/debug_interface.h create mode 100644 src/common/emu_window.h create mode 100644 src/common/extended_trace.cpp create mode 100644 src/common/extended_trace.h create mode 100644 src/common/fifo_queue.h create mode 100644 src/common/file_search.cpp create mode 100644 src/common/file_search.h create mode 100644 src/common/file_util.cpp create mode 100644 src/common/file_util.h create mode 100644 src/common/fixed_size_queue.h create mode 100644 src/common/hash.cpp create mode 100644 src/common/hash.h create mode 100644 src/common/linear_disk_cache.h create mode 100644 src/common/log.h create mode 100644 src/common/log_manager.cpp create mode 100644 src/common/log_manager.h create mode 100644 src/common/math_util.cpp create mode 100644 src/common/math_util.h create mode 100644 src/common/mem_arena.cpp create mode 100644 src/common/mem_arena.h create mode 100644 src/common/memory_util.cpp create mode 100644 src/common/memory_util.h create mode 100644 src/common/misc.cpp create mode 100644 src/common/msg_handler.cpp create mode 100644 src/common/msg_handler.h create mode 100644 src/common/platform.h create mode 100644 src/common/scm_rev.h delete mode 100644 src/common/src/atomic.h delete mode 100644 src/common/src/atomic_gcc.h delete mode 100644 src/common/src/atomic_win32.h delete mode 100644 src/common/src/break_points.cpp delete mode 100644 src/common/src/break_points.h delete mode 100644 src/common/src/chunk_file.h delete mode 100644 src/common/src/common.h delete mode 100644 src/common/src/common_funcs.h delete mode 100644 src/common/src/common_paths.h delete mode 100644 src/common/src/common_types.h delete mode 100644 src/common/src/console_listener.cpp delete mode 100644 src/common/src/console_listener.h delete mode 100644 src/common/src/cpu_detect.h delete mode 100644 src/common/src/debug_interface.h delete mode 100644 src/common/src/emu_window.h delete mode 100644 src/common/src/extended_trace.cpp delete mode 100644 src/common/src/extended_trace.h delete mode 100644 src/common/src/fifo_queue.h delete mode 100644 src/common/src/file_search.cpp delete mode 100644 src/common/src/file_search.h delete mode 100644 src/common/src/file_util.cpp delete mode 100644 src/common/src/file_util.h delete mode 100644 src/common/src/fixed_size_queue.h delete mode 100644 src/common/src/hash.cpp delete mode 100644 src/common/src/hash.h delete mode 100644 src/common/src/linear_disk_cache.h delete mode 100644 src/common/src/log.h delete mode 100644 src/common/src/log_manager.cpp delete mode 100644 src/common/src/log_manager.h delete mode 100644 src/common/src/math_util.cpp delete mode 100644 src/common/src/math_util.h delete mode 100644 src/common/src/mem_arena.cpp delete mode 100644 src/common/src/mem_arena.h delete mode 100644 src/common/src/memory_util.cpp delete mode 100644 src/common/src/memory_util.h delete mode 100644 src/common/src/misc.cpp delete mode 100644 src/common/src/msg_handler.cpp delete mode 100644 src/common/src/msg_handler.h delete mode 100644 src/common/src/platform.h delete mode 100644 src/common/src/scm_rev.h delete mode 100644 src/common/src/std_condition_variable.h delete mode 100644 src/common/src/std_mutex.h delete mode 100644 src/common/src/std_thread.h delete mode 100644 src/common/src/string_util.cpp delete mode 100644 src/common/src/string_util.h delete mode 100644 src/common/src/swap.h delete mode 100644 src/common/src/thread.cpp delete mode 100644 src/common/src/thread.h delete mode 100644 src/common/src/thunk.h delete mode 100644 src/common/src/timer.cpp delete mode 100644 src/common/src/timer.h delete mode 100644 src/common/src/utf8.cpp delete mode 100644 src/common/src/utf8.h delete mode 100644 src/common/src/version.cpp create mode 100644 src/common/std_condition_variable.h create mode 100644 src/common/std_mutex.h create mode 100644 src/common/std_thread.h create mode 100644 src/common/string_util.cpp create mode 100644 src/common/string_util.h create mode 100644 src/common/swap.h create mode 100644 src/common/thread.cpp create mode 100644 src/common/thread.h create mode 100644 src/common/thunk.h create mode 100644 src/common/timer.cpp create mode 100644 src/common/timer.h create mode 100644 src/common/utf8.cpp create mode 100644 src/common/utf8.h create mode 100644 src/common/version.cpp (limited to 'src/common') diff --git a/src/common/atomic.h b/src/common/atomic.h new file mode 100644 index 00000000..883bc14f --- /dev/null +++ b/src/common/atomic.h @@ -0,0 +1,19 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_H_ +#define _ATOMIC_H_ + +#ifdef _WIN32 + +#include "atomic_win32.h" + +#else + +// GCC-compatible compiler assumed! +#include "atomic_gcc.h" + +#endif + +#endif diff --git a/src/common/atomic_gcc.h b/src/common/atomic_gcc.h new file mode 100644 index 00000000..2eb38697 --- /dev/null +++ b/src/common/atomic_gcc.h @@ -0,0 +1,113 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_GCC_H_ +#define _ATOMIC_GCC_H_ + +#include "common.h" + +// Atomic operations are performed in a single step by the CPU. It is +// impossible for other threads to see the operation "half-done." +// +// Some atomic operations can be combined with different types of memory +// barriers called "Acquire semantics" and "Release semantics", defined below. +// +// Acquire semantics: Future memory accesses cannot be relocated to before the +// operation. +// +// Release semantics: Past memory accesses cannot be relocated to after the +// operation. +// +// These barriers affect not only the compiler, but also the CPU. + +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; // 32-bit reads are always atomic. +} +inline u32 AtomicLoadAcquire(volatile u32& src) { + //keep the compiler from caching any memory references + u32 result = src; // 32-bit reads are always atomic. + //__sync_synchronize(); // TODO: May not be necessary. + // Compiler instruction only. x86 loads always have acquire semantics. + __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; // 32-bit writes are always atomic. +} +inline void AtomicStoreRelease(volatile u32& dest, u32 value) { + __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. +} + +} + +// Old code kept here for reference in case we need the parts with __asm__ __volatile__. +#if 0 +LONG SyncInterlockedIncrement(LONG *Dest) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_add_and_fetch(Dest, 1); +#else + register int result; + __asm__ __volatile__("lock; xadd %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (1), "m" (*Dest) + : "memory"); + return result; +#endif +} + +LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_add_and_fetch(Dest, Val); +#else + register int result; + __asm__ __volatile__("lock; xadd %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); + return result; +#endif +} + +LONG SyncInterlockedExchange(LONG *Dest, LONG Val) +{ +#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) + return __sync_lock_test_and_set(Dest, Val); +#else + register int result; + __asm__ __volatile__("lock; xchg %0,%1" + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); + return result; +#endif +} +#endif + +#endif diff --git a/src/common/atomic_win32.h b/src/common/atomic_win32.h new file mode 100644 index 00000000..760b16d4 --- /dev/null +++ b/src/common/atomic_win32.h @@ -0,0 +1,72 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _ATOMIC_WIN32_H_ +#define _ATOMIC_WIN32_H_ + +#include "common.h" +#include +#include + +// Atomic operations are performed in a single step by the CPU. It is +// impossible for other threads to see the operation "half-done." +// +// Some atomic operations can be combined with different types of memory +// barriers called "Acquire semantics" and "Release semantics", defined below. +// +// Acquire semantics: Future memory accesses cannot be relocated to before the +// operation. +// +// Release semantics: Past memory accesses cannot be relocated to after the +// operation. +// +// These barriers affect not only the compiler, but also the CPU. +// +// NOTE: Acquire and Release are not differentiated right now. They perform a +// full memory barrier instead of a "one-way" memory barrier. The newest +// Windows SDK has Acquire and Release versions of some Interlocked* functions. + +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; // 32-bit reads are always atomic. +} +inline u32 AtomicLoadAcquire(volatile u32& src) { + u32 result = src; // 32-bit reads are always atomic. + _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. + 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; // 32-bit writes are always atomic. +} +inline void AtomicStoreRelease(volatile u32& dest, u32 value) { + _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. + dest = value; // 32-bit writes are always atomic. +} + +} + +#endif diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp new file mode 100644 index 00000000..787263f7 --- /dev/null +++ b/src/common/break_points.cpp @@ -0,0 +1,203 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "debug_interface.h" +#include "break_points.h" + +#include +#include + +bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + if (i->iAddress == _iAddress) + return true; + return false; +} + +bool BreakPoints::IsTempBreakPoint(u32 _iAddress) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + if (i->iAddress == _iAddress && i->bTemporary) + return true; + return false; +} + +BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const +{ + TBreakPointsStr bps; + for (TBreakPoints::const_iterator i = m_BreakPoints.begin(); + i != m_BreakPoints.end(); ++i) + { + if (!i->bTemporary) + { + std::stringstream bp; + bp << std::hex << i->iAddress << " " << (i->bOn ? "n" : ""); + bps.push_back(bp.str()); + } + } + + return bps; +} + +void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) +{ + for (TBreakPointsStr::const_iterator i = bps.begin(); i != bps.end(); ++i) + { + TBreakPoint bp; + std::stringstream bpstr; + bpstr << std::hex << *i; + bpstr >> bp.iAddress; + bp.bOn = i->find("n") != i->npos; + bp.bTemporary = false; + Add(bp); + } +} + +void BreakPoints::Add(const TBreakPoint& bp) +{ + if (!IsAddressBreakPoint(bp.iAddress)) + { + m_BreakPoints.push_back(bp); + //if (jit) + // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + } +} + +void BreakPoints::Add(u32 em_address, bool temp) +{ + if (!IsAddressBreakPoint(em_address)) // only add new addresses + { + TBreakPoint pt; // breakpoint settings + pt.bOn = true; + pt.bTemporary = temp; + pt.iAddress = em_address; + + m_BreakPoints.push_back(pt); + + //if (jit) + // jit->GetBlockCache()->InvalidateICache(em_address, 4); + } +} + +void BreakPoints::Remove(u32 em_address) +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + { + if (i->iAddress == em_address) + { + m_BreakPoints.erase(i); + //if (jit) + // jit->GetBlockCache()->InvalidateICache(em_address, 4); + return; + } + } +} + +void BreakPoints::Clear() +{ + //if (jit) + //{ + // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), + // [](const TBreakPoint& bp) + // { + // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + // } + // ); + //} + + m_BreakPoints.clear(); +} + +MemChecks::TMemChecksStr MemChecks::GetStrings() const +{ + TMemChecksStr mcs; + for (TMemChecks::const_iterator i = m_MemChecks.begin(); + i != m_MemChecks.end(); ++i) + { + std::stringstream mc; + mc << std::hex << i->StartAddress; + mc << " " << (i->bRange ? i->EndAddress : i->StartAddress) << " " << + (i->bRange ? "n" : "") << (i->OnRead ? "r" : "") << + (i->OnWrite ? "w" : "") << (i->Log ? "l" : "") << (i->Break ? "p" : ""); + mcs.push_back(mc.str()); + } + + return mcs; +} + +void MemChecks::AddFromStrings(const TMemChecksStr& mcs) +{ + for (TMemChecksStr::const_iterator i = mcs.begin(); i != mcs.end(); ++i) + { + TMemCheck mc; + std::stringstream mcstr; + mcstr << std::hex << *i; + mcstr >> mc.StartAddress; + mc.bRange = i->find("n") != i->npos; + mc.OnRead = i->find("r") != i->npos; + mc.OnWrite = i->find("w") != i->npos; + mc.Log = i->find("l") != i->npos; + mc.Break = i->find("p") != i->npos; + if (mc.bRange) + mcstr >> mc.EndAddress; + else + mc.EndAddress = mc.StartAddress; + Add(mc); + } +} + +void MemChecks::Add(const TMemCheck& _rMemoryCheck) +{ + if (GetMemCheck(_rMemoryCheck.StartAddress) == 0) + m_MemChecks.push_back(_rMemoryCheck); +} + +void MemChecks::Remove(u32 _Address) +{ + for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) + { + if (i->StartAddress == _Address) + { + m_MemChecks.erase(i); + return; + } + } +} + +TMemCheck *MemChecks::GetMemCheck(u32 address) +{ + for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) + { + if (i->bRange) + { + if (address >= i->StartAddress && address <= i->EndAddress) + return &(*i); + } + else if (i->StartAddress == address) + return &(*i); + } + + // none found + return 0; +} + +void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, + bool write, int size, u32 pc) +{ + if ((write && OnWrite) || (!write && OnRead)) + { + if (Log) + { + INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", + pc, debug_interface->getDescription(pc).c_str(), + write ? "Write" : "Read", size*8, size*2, iValue, addr, + debug_interface->getDescription(addr).c_str() + ); + } + if (Break) + debug_interface->breakNow(); + } +} diff --git a/src/common/break_points.h b/src/common/break_points.h new file mode 100644 index 00000000..dc771ba0 --- /dev/null +++ b/src/common/break_points.h @@ -0,0 +1,102 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _DEBUGGER_BREAKPOINTS_H +#define _DEBUGGER_BREAKPOINTS_H + +#include +#include + +#include "common.h" + +class DebugInterface; + +struct TBreakPoint +{ + u32 iAddress; + bool bOn; + bool bTemporary; +}; + +struct TMemCheck +{ + TMemCheck() { + numHits = 0; + StartAddress = EndAddress = 0; + bRange = OnRead = OnWrite = Log = Break = false; + } + u32 StartAddress; + u32 EndAddress; + + bool bRange; + + bool OnRead; + bool OnWrite; + + bool Log; + bool Break; + + u32 numHits; + + void Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, + bool write, int size, u32 pc); +}; + +// Code breakpoints. +class BreakPoints +{ +public: + typedef std::vector TBreakPoints; + typedef std::vector TBreakPointsStr; + + const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } + + TBreakPointsStr GetStrings() const; + void AddFromStrings(const TBreakPointsStr& bps); + + // is address breakpoint + bool IsAddressBreakPoint(u32 _iAddress); + bool IsTempBreakPoint(u32 _iAddress); + + // Add BreakPoint + void Add(u32 em_address, bool temp=false); + void Add(const TBreakPoint& bp); + + // Remove Breakpoint + void Remove(u32 _iAddress); + void Clear(); + + void DeleteByAddress(u32 _Address); + +private: + TBreakPoints m_BreakPoints; + u32 m_iBreakOnCount; +}; + + +// Memory breakpoints +class MemChecks +{ +public: + typedef std::vector TMemChecks; + typedef std::vector TMemChecksStr; + + TMemChecks m_MemChecks; + + const TMemChecks& GetMemChecks() { return m_MemChecks; } + + TMemChecksStr GetStrings() const; + void AddFromStrings(const TMemChecksStr& mcs); + + void Add(const TMemCheck& _rMemoryCheck); + + // memory breakpoint + TMemCheck *GetMemCheck(u32 address); + void Remove(u32 _Address); + + void Clear() { m_MemChecks.clear(); }; +}; + +#endif + diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h new file mode 100644 index 00000000..68c2943a --- /dev/null +++ b/src/common/chunk_file.h @@ -0,0 +1,874 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _POINTERWRAP_H_ +#define _POINTERWRAP_H_ + +// Extremely simple serialization framework. + +// (mis)-features: +// + Super fast +// + Very simple +// + Same code is used for serialization and deserializaition (in most cases) +// - Zero backwards/forwards compatibility +// - Serialization code for anything complex has to be manually written. + +#include +#include +#include +#include +#include +#include +#ifndef __SYMBIAN32__ +#if defined(IOS) || defined(MACGNUSTD) +#include +#else +#include +#endif +#endif + +#include "common.h" +#include "file_util.h" +//#include "../ext/snappy/snappy-c.h" + +#if defined(IOS) || defined(MACGNUSTD) +namespace std { + using tr1::is_pointer; +} +#endif +#ifdef __SYMBIAN32__ +namespace std { + template + struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; + }; + template const bool bool_constant::value; + template struct is_pointer : public bool_constant {}; + template struct is_pointer : public bool_constant {}; +} +#endif + +template +struct LinkedListItem : public T +{ + LinkedListItem *next; +}; + +class PointerWrap; + +class PointerWrapSection +{ +public: + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { + } + ~PointerWrapSection(); + + bool operator == (const int &v) const { return ver_ == v; } + bool operator != (const int &v) const { return ver_ != v; } + bool operator <= (const int &v) const { return ver_ <= v; } + bool operator >= (const int &v) const { return ver_ >= v; } + bool operator < (const int &v) const { return ver_ < v; } + bool operator > (const int &v) const { return ver_ > v; } + + operator bool() const { + return ver_ > 0; + } + +private: + PointerWrap &p_; + int ver_; + const char *title_; +}; + +// Wrapper class +class PointerWrap +{ + // This makes it a compile error if you forget to define DoState() on non-POD. + // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... +#ifdef _MSC_VER + template::value, bool isPointer = std::is_pointer::value> +#else + template::value> +#endif + struct DoHelper + { + static void DoArray(PointerWrap *p, T *x, int count) + { + for (int i = 0; i < count; ++i) + p->Do(x[i]); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoClass(x); + } + }; + + template + struct DoHelper + { + static void DoArray(PointerWrap *p, T *x, int count) + { + p->DoVoid((void *)x, sizeof(T) * count); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoVoid((void *)&x, sizeof(x)); + } + }; + +public: + enum Mode { + MODE_READ = 1, // load + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + }; + + enum Error { + ERROR_NONE = 0, + ERROR_WARNING = 1, + ERROR_FAILURE = 2, + }; + + u8 **ptr; + Mode mode; + Error error; + +public: + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} + + PointerWrapSection Section(const char *title, int ver) { + return Section(title, ver, ver); + } + + // The returned object can be compared against the version that was loaded. + // This can be used to support versions as old as minVer. + // Version = 0 means the section was not found. + PointerWrapSection Section(const char *title, int minVer, int ver) { + char marker[16] = {0}; + int foundVersion = ver; + + strncpy(marker, title, sizeof(marker)); + if (!ExpectVoid(marker, sizeof(marker))) + { + // Might be before we added name markers for safety. + if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) + DoMarker(title); + // Wasn't found, but maybe we can still load the state. + else + foundVersion = 0; + } + else + Do(foundVersion); + + if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { + WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + return PointerWrapSection(*this, foundVersion, title); + } + + void SetMode(Mode mode_) {mode = mode_;} + Mode GetMode() const {return mode;} + u8 **GetPPtr() {return ptr;} + void SetError(Error error_) + { + if (error < error_) + error = error_; + if (error > ERROR_WARNING) + mode = PointerWrap::MODE_MEASURE; + } + + bool ExpectVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; + default: break; // throw an error? + } + (*ptr) += size; + return true; + } + + void DoVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: memcpy(data, *ptr, size); break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; + default: break; // throw an error? + } + (*ptr) += size; + } + + template + void Do(std::map &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMap(x, dv); + } + + template + void Do(std::map &x) + { + T dv = T(); + DoMap(x, dv); + } + + template + void DoMap(std::map &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x[first] = second; + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::map::iterator itr = x.begin(); + while (number > 0) + { + K first = itr->first; + Do(first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + template + void Do(std::multimap &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMultimap(x, dv); + } + + template + void Do(std::multimap &x) + { + T dv = T(); + DoMultimap(x, dv); + } + + template + void DoMultimap(std::multimap &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x.insert(std::make_pair(first, second)); + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::multimap::iterator itr = x.begin(); + while (number > 0) + { + Do(itr->first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + // Store vectors. + template + void Do(std::vector &x) + { + T *dv = NULL; + DoVector(x, dv); + } + + template + void Do(std::vector &x) + { + T dv = T(); + DoVector(x, dv); + } + + + template + void DoPOD(std::vector &x) + { + T dv = T(); + DoVectorPOD(x, dv); + } + + template + void Do(std::vector &x, T &default_val) + { + DoVector(x, default_val); + } + + template + void DoVector(std::vector &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + template + void DoVectorPOD(std::vector &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + // Store deques. + template + void Do(std::deque &x) + { + T *dv = NULL; + DoDeque(x, dv); + } + + template + void Do(std::deque &x) + { + T dv = T(); + DoDeque(x, dv); + } + + template + void DoDeque(std::deque &x, T &default_val) + { + u32 deq_size = (u32)x.size(); + Do(deq_size); + x.resize(deq_size, default_val); + u32 i; + for(i = 0; i < deq_size; i++) + Do(x[i]); + } + + // Store STL lists. + template + void Do(std::list &x) + { + T *dv = NULL; + Do(x, dv); + } + + template + void Do(std::list &x) + { + T dv = T(); + DoList(x, dv); + } + + template + void Do(std::list &x, T &default_val) + { + DoList(x, default_val); + } + + template + void DoList(std::list &x, T &default_val) + { + u32 list_size = (u32)x.size(); + Do(list_size); + x.resize(list_size, default_val); + + typename std::list::iterator itr, end; + for (itr = x.begin(), end = x.end(); itr != end; ++itr) + Do(*itr); + } + + + // Store STL sets. + template + void Do(std::set &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (*it != NULL) + delete *it; + } + } + DoSet(x); + } + + template + void Do(std::set &x) + { + DoSet(x); + } + + template + void DoSet(std::set &x) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + + switch (mode) + { + case MODE_READ: + { + x.clear(); + while (number-- > 0) + { + T it = T(); + Do(it); + x.insert(it); + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::set::iterator itr = x.begin(); + while (number-- > 0) + Do(*itr++); + } + break; + + default: + ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); + } + } + + // Store strings. + void Do(std::string &x) + { + int stringLen = (int)x.length() + 1; + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (char*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; + } + (*ptr) += stringLen; + } + + void Do(std::wstring &x) + { + int stringLen = sizeof(wchar_t)*((int)x.length() + 1); + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (wchar_t*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; + } + (*ptr) += stringLen; + } + + template + void DoClass(T &x) { + x.DoState(*this); + } + + template + void DoClass(T *&x) { + if (mode == MODE_READ) + { + if (x != NULL) + delete x; + x = new T(); + } + x->DoState(*this); + } + + template + void DoArray(T *x, int count) { + DoHelper::DoArray(this, x, count); + } + + template + void Do(T &x) { + DoHelper::Do(this, x); + } + + template + void DoPOD(T &x) { + DoHelper::Do(this, x); + } + + template + void DoPointer(T* &x, T*const base) { + // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range + s32 offset = x - base; + Do(offset); + if (mode == MODE_READ) + x = base + offset; + } + + template* (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> + void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) + { + LinkedListItem* list_cur = list_start; + LinkedListItem* prev = 0; + + while (true) + { + u8 shouldExist = (list_cur ? 1 : 0); + Do(shouldExist); + if (shouldExist == 1) + { + LinkedListItem* cur = list_cur ? list_cur : TNew(); + TDo(*this, (T*)cur); + if (!list_cur) + { + if (mode == MODE_READ) + { + cur->next = 0; + list_cur = cur; + if (prev) + prev->next = cur; + else + list_start = cur; + } + else + { + TFree(cur); + continue; + } + } + } + else + { + if (mode == MODE_READ) + { + if (prev) + prev->next = 0; + if (list_end) + *list_end = prev; + if (list_cur) + { + if (list_start == list_cur) + list_start = 0; + do + { + LinkedListItem* next = list_cur->next; + TFree(list_cur); + list_cur = next; + } + while (list_cur); + } + } + break; + } + prev = list_cur; + list_cur = list_cur->next; + } + } + + void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) + { + u32 cookie = arbitraryNumber; + Do(cookie); + if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) + { + PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + SetError(ERROR_FAILURE); + } + } +}; + +inline PointerWrapSection::~PointerWrapSection() { + if (ver_ > 0) { + p_.DoMarker(title_); + } +} + + +class CChunkFileReader +{ +public: + enum Error { + ERROR_NONE, + ERROR_BAD_FILE, + ERROR_BROKEN_STATE, + }; + + // Load file template + template + static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) + { + INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); + _failureReason->clear(); + _failureReason->append("LoadStateWrongVersion"); + + if (!File::Exists(_rFilename)) { + _failureReason->clear(); + _failureReason->append("LoadStateDoesntExist"); + ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); + return ERROR_BAD_FILE; + } + + // Check file size + const u64 fileSize = File::GetSize(_rFilename); + static const u64 headerSize = sizeof(SChunkHeader); + if (fileSize < headerSize) + { + ERROR_LOG(COMMON,"ChunkReader: File too small"); + return ERROR_BAD_FILE; + } + + File::IOFile pFile(_rFilename, "rb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); + return ERROR_BAD_FILE; + } + + // read the header + SChunkHeader header; + if (!pFile.ReadArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Bad header size"); + return ERROR_BAD_FILE; + } + + // Check revision + if (header.Revision != _Revision) + { + ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", + header.Revision, _Revision); + return ERROR_BAD_FILE; + } + + if (strcmp(header.GitVersion, _VersionString) != 0) + { + WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", + header.GitVersion); + } + + // get size + const int sz = (int)(fileSize - headerSize); + if (header.ExpectedSize != sz) + { + ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", + sz, header.ExpectedSize); + return ERROR_BAD_FILE; + } + + // read the state + u8* buffer = new u8[sz]; + if (!pFile.ReadBytes(buffer, sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Error reading file"); + return ERROR_BAD_FILE; + } + + u8 *ptr = buffer; + u8 *buf = buffer; + if (header.Compress) { + u8 *uncomp_buffer = new u8[header.UncompressedSize]; + size_t uncomp_size = header.UncompressedSize; + snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); + if ((int)uncomp_size != header.UncompressedSize) { + ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); + } + ptr = uncomp_buffer; + buf = uncomp_buffer; + delete [] buffer; + } + + PointerWrap p(&ptr, PointerWrap::MODE_READ); + _class.DoState(p); + delete[] buf; + + INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + // Save file template + template + static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) + { + INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); + + File::IOFile pFile(_rFilename, "wb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); + return ERROR_BAD_FILE; + } + + bool compress = true; + + // Get data + u8 *ptr = 0; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + + u8 * buffer = new u8[sz]; + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Create header + SChunkHeader header; + header.Compress = compress ? 1 : 0; + header.Revision = _Revision; + header.ExpectedSize = (int)sz; + header.UncompressedSize = (int)sz; + strncpy(header.GitVersion, _VersionString, 32); + header.GitVersion[31] = '\0'; + + // Write to file + if (compress) { + size_t comp_len = snappy_max_compressed_length(sz); + u8 *compressed_buffer = new u8[comp_len]; + snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); + delete [] buffer; + header.ExpectedSize = (int)comp_len; + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { + ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); + return ERROR_BAD_FILE; + } else { + INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); + } + delete [] compressed_buffer; + } else { + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&buffer[0], sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); + return ERROR_BAD_FILE; + } + delete [] buffer; + } + + INFO_LOG(COMMON,"ChunkReader: Done writing %s", + _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + template + static Error Verify(T& _class) + { + u8 *ptr = 0; + + // Step 1: Measure the space required. + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + std::vector buffer(sz); + + // Step 2: Dump the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Step 3: Verify the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_VERIFY); + _class.DoState(p); + + return ERROR_NONE; + } + +private: + struct SChunkHeader + { + int Revision; + int Compress; + int ExpectedSize; + int UncompressedSize; + char GitVersion[32]; + }; +}; + +#endif // _POINTERWRAP_H_ diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 00000000..3b71d9b3 --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,171 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +// DO NOT EVER INCLUDE directly _or indirectly_ from this file +// since it slows down the build a lot. + +#include +#include +#include + +// SVN version number +extern const char *scm_rev_str; +extern const char *netplay_dolphin_ver; + +// Force enable logging in the right modes. For some reason, something had changed +// so that debugfast no longer logged. +#if defined(_DEBUG) || defined(DEBUGFAST) +#undef LOGGING +#define LOGGING 1 +#endif + +#define STACKALIGN + +#if __cplusplus >= 201103 || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) +#define HAVE_CXX11_SYNTAX 1 +#endif + +#if HAVE_CXX11_SYNTAX +// An inheritable class to disallow the copy constructor and operator= functions +class NonCopyable +{ +protected: + NonCopyable() {} + NonCopyable(const NonCopyable&&) {} + void operator=(const NonCopyable&&) {} +private: + NonCopyable(NonCopyable&); + NonCopyable& operator=(NonCopyable& other); +}; +#endif + +#include "log.h" +#include "common_types.h" +#include "msg_handler.h" +#include "common_funcs.h" +#include "common_paths.h" +#include "platform.h" + +#ifdef __APPLE__ +// The Darwin ABI requires that stack frames be aligned to 16-byte boundaries. +// This is only needed on i386 gcc - x86_64 already aligns to 16 bytes. +#if defined __i386__ && defined __GNUC__ +#undef STACKALIGN +#define STACKALIGN __attribute__((__force_align_arg_pointer__)) +#endif + +#elif defined _WIN32 + +// Check MSC ver + #if !defined _MSC_VER || _MSC_VER <= 1000 + #error needs at least version 1000 of MSC + #endif + + #define NOMINMAX + +// Memory leak checks + #define CHECK_HEAP_INTEGRITY() + +// Alignment + #define MEMORY_ALIGNED16(x) __declspec(align(16)) x + #define MEMORY_ALIGNED32(x) __declspec(align(32)) x + #define MEMORY_ALIGNED64(x) __declspec(align(64)) x + #define MEMORY_ALIGNED128(x) __declspec(align(128)) x + #define MEMORY_ALIGNED16_DECL(x) __declspec(align(16)) x + #define MEMORY_ALIGNED64_DECL(x) __declspec(align(64)) x + +// Since they are always around on windows + #define HAVE_WX 1 + #define HAVE_OPENAL 1 + + #define HAVE_PORTAUDIO 1 + +// Debug definitions + #if defined(_DEBUG) + #include + #undef CHECK_HEAP_INTEGRITY + #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} + // If you want to see how much a pain in the ass singletons are, for example: + // {614} normal block at 0x030C5310, 188 bytes long. + // Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 + struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } }; + //CrtDebugBreak breakAt(614); + #endif // end DEBUG/FAST + +#endif + +// Windows compatibility +#ifndef _WIN32 +#include +#define MAX_PATH PATH_MAX +#ifdef _LP64 +#define _M_X64 1 +#else +#define _M_IX86 1 +#endif +#define __forceinline inline __attribute__((always_inline)) +#define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x +#define MEMORY_ALIGNED32(x) __attribute__((aligned(32))) x +#define MEMORY_ALIGNED64(x) __attribute__((aligned(64))) x +#define MEMORY_ALIGNED128(x) __attribute__((aligned(128))) x +#define MEMORY_ALIGNED16_DECL(x) __attribute__((aligned(16))) x +#define MEMORY_ALIGNED64_DECL(x) __attribute__((aligned(64))) x +#endif + +#ifdef _MSC_VER +#define __strdup _strdup +#define __getcwd _getcwd +#define __chdir _chdir +#else +#define __strdup strdup +#define __getcwd getcwd +#define __chdir chdir +#endif + +// Dummy macro for marking translatable strings that can not be immediately translated. +// wxWidgets does not have a true dummy macro for this. +#define _trans(a) a + +#if defined _M_GENERIC +# define _M_SSE 0x0 +#elif defined __GNUC__ +# if defined __SSE4_2__ +# define _M_SSE 0x402 +# elif defined __SSE4_1__ +# define _M_SSE 0x401 +# elif defined __SSSE3__ +# define _M_SSE 0x301 +# elif defined __SSE3__ +# define _M_SSE 0x300 +# endif +#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008 +# define _M_SSE 0x402 +#endif + +// Host communication. +enum HOST_COMM +{ + // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on + WM_USER_STOP = 10, + WM_USER_CREATE, + WM_USER_SETCURSOR, +}; + +// Used for notification on emulation state +enum EMUSTATE_CHANGE +{ + EMUSTATE_CHANGE_PLAY = 1, + EMUSTATE_CHANGE_PAUSE, + EMUSTATE_CHANGE_STOP +}; + +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#endif // _COMMON_H_ diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h new file mode 100644 index 00000000..7ca0b350 --- /dev/null +++ b/src/common/common_funcs.h @@ -0,0 +1,245 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMONFUNCS_H_ +#define _COMMONFUNCS_H_ + +#ifdef _WIN32 +#define SLEEP(x) Sleep(x) +#else +#include +#define SLEEP(x) usleep(x*1000) +#endif + +template struct CompileTimeAssert; +template<> struct CompileTimeAssert {}; + +#define b2(x) ( (x) | ( (x) >> 1) ) +#define b4(x) ( b2(x) | ( b2(x) >> 2) ) +#define b8(x) ( b4(x) | ( b4(x) >> 4) ) +#define b16(x) ( b8(x) | ( b8(x) >> 8) ) +#define b32(x) (b16(x) | (b16(x) >>16) ) +#define ROUND_UP_POW2(x) (b32(x - 1) + 1) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC +#include +static __inline __m128i __attribute__((__always_inline__)) +_mm_shuffle_epi8(__m128i a, __m128i mask) +{ + __m128i result; + __asm__("pshufb %1, %0" + : "=x" (result) + : "xm" (mask), "0" (a)); + return result; +} +#endif + +#ifndef _WIN32 + +#include +#ifdef __linux__ +#include +#elif defined __FreeBSD__ +#include +#endif + +// go to debugger mode + #ifdef GEKKO + #define Crash() + #elif defined _M_GENERIC + #define Crash() { exit(1); } + #else + #define Crash() {asm ("int $3");} + #endif + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +// GCC 4.8 defines all the rotate functions now +// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit +#ifndef _rotl +inline u32 _rotl(u32 x, int shift) { + shift &= 31; + if (!shift) return x; + return (x << shift) | (x >> (32 - shift)); +} + +inline u32 _rotr(u32 x, int shift) { + shift &= 31; + if (!shift) return x; + return (x >> shift) | (x << (32 - shift)); +} +#endif + +inline u64 _rotl64(u64 x, unsigned int shift){ + unsigned int n = shift % 64; + return (x << n) | (x >> (64 - n)); +} + +inline u64 _rotr64(u64 x, unsigned int shift){ + unsigned int n = shift % 64; + return (x >> n) | (x << (64 - n)); +} + +#else // WIN32 +// Function Cross-Compatibility + #define strcasecmp _stricmp + #define strncasecmp _strnicmp + #define unlink _unlink + #define snprintf _snprintf + #define vscprintf _vscprintf + +// Locale Cross-Compatibility + #define locale_t _locale_t + #define freelocale _free_locale + #define newlocale(mask, locale, base) _create_locale(mask, locale) + + #define LC_GLOBAL_LOCALE ((locale_t)-1) + #define LC_ALL_MASK LC_ALL + #define LC_COLLATE_MASK LC_COLLATE + #define LC_CTYPE_MASK LC_CTYPE + #define LC_MONETARY_MASK LC_MONETARY + #define LC_NUMERIC_MASK LC_NUMERIC + #define LC_TIME_MASK LC_TIME + + inline locale_t uselocale(locale_t new_locale) + { + // Retrieve the current per thread locale setting + bool bIsPerThread = (_configthreadlocale(0) == _ENABLE_PER_THREAD_LOCALE); + + // Retrieve the current thread-specific locale + locale_t old_locale = bIsPerThread ? _get_current_locale() : LC_GLOBAL_LOCALE; + + if(new_locale == LC_GLOBAL_LOCALE) + { + // Restore the global locale + _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); + } + else if(new_locale != NULL) + { + // Configure the thread to set the locale only for this thread + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + + // Set all locale categories + for(int i = LC_MIN; i <= LC_MAX; i++) + setlocale(i, new_locale->locinfo->lc_category[i].locale); + } + + return old_locale; + } + +// 64 bit offsets for windows + #define fseeko _fseeki64 + #define ftello _ftelli64 + #define atoll _atoi64 + #define stat64 _stat64 + #define fstat64 _fstat64 + #define fileno _fileno + + #if _M_IX86 + #define Crash() {__asm int 3} + #else +extern "C" { + __declspec(dllimport) void __stdcall DebugBreak(void); +} + #define Crash() {DebugBreak();} + #endif // M_IX86 +#endif // WIN32 ndef + +// Dolphin's min and max functions +#undef min +#undef max + +template +inline T min(const T& a, const T& b) {return a > b ? b : a;} +template +inline T max(const T& a, const T& b) {return a > b ? a : b;} + +// Generic function to get last error message. +// Call directly after the command or use the error num. +// This function might change the error code. +// Defined in Misc.cpp. +const char* GetLastErrorMsg(); + +namespace Common +{ +inline u8 swap8(u8 _data) {return _data;} +inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} + +#ifdef ANDROID +#undef swap16 +#undef swap32 +#undef swap64 +#endif + +#ifdef _WIN32 +inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} +inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} +inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} +#elif _M_ARM +inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} +inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} +inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} +#elif __linux__ +inline u16 swap16(u16 _data) {return bswap_16(_data);} +inline u32 swap32(u32 _data) {return bswap_32(_data);} +inline u64 swap64(u64 _data) {return bswap_64(_data);} +#elif __APPLE__ +inline __attribute__((always_inline)) u16 swap16(u16 _data) + {return (_data >> 8) | (_data << 8);} +inline __attribute__((always_inline)) u32 swap32(u32 _data) + {return __builtin_bswap32(_data);} +inline __attribute__((always_inline)) u64 swap64(u64 _data) + {return __builtin_bswap64(_data);} +#elif __FreeBSD__ +inline u16 swap16(u16 _data) {return bswap16(_data);} +inline u32 swap32(u32 _data) {return bswap32(_data);} +inline u64 swap64(u64 _data) {return bswap64(_data);} +#else +// Slow generic implementation. +inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} +inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} +inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} +#endif + +inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} +inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} +inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} + +template +void swap(u8*); + +template <> +inline void swap<1>(u8* data) +{} + +template <> +inline void swap<2>(u8* data) +{ + *reinterpret_cast(data) = swap16(data); +} + +template <> +inline void swap<4>(u8* data) +{ + *reinterpret_cast(data) = swap32(data); +} + +template <> +inline void swap<8>(u8* data) +{ + *reinterpret_cast(data) = swap64(data); +} + +template +inline T FromBigEndian(T data) +{ + //static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); + + swap(reinterpret_cast(&data)); + return data; +} + +} // Namespace Common + +#endif // _COMMONFUNCS_H_ diff --git a/src/common/common_paths.h b/src/common/common_paths.h new file mode 100644 index 00000000..9ccb87d8 --- /dev/null +++ b/src/common/common_paths.h @@ -0,0 +1,79 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _COMMON_PATHS_H_ +#define _COMMON_PATHS_H_ + +// Make sure we pick up USER_DIR if set in config.h +#include "common.h" + +// Directory seperators, do we need this? +#define DIR_SEP "/" +#define DIR_SEP_CHR '/' + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// The user data dir +#define ROOT_DIR "." +#ifdef _WIN32 + #define USERDATA_DIR "user" + #define EMU_DATA_DIR "emu" +#else + #define USERDATA_DIR "user" + #ifdef USER_DIR + #define EMU_DATA_DIR USER_DIR + #else + #define EMU_DATA_DIR ".emu" + #endif +#endif + +// Shared data dirs (Sys and shared User for linux) +#ifdef _WIN32 + #define SYSDATA_DIR "sys" +#else + #ifdef DATA_DIR + #define SYSDATA_DIR DATA_DIR "sys" + #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP + #else + #define SYSDATA_DIR "sys" + #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP + #endif +#endif + +// Dirs in both User and Sys +#define EUR_DIR "EUR" +#define USA_DIR "USA" +#define JAP_DIR "JAP" + +// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) +#define CONFIG_DIR "config" +#define GAMECONFIG_DIR "game_config" +#define MAPS_DIR "maps" +#define CACHE_DIR "cache" +#define SHADERCACHE_DIR "shader_cache" +#define STATESAVES_DIR "state_saves" +#define SCREENSHOTS_DIR "screenShots" +#define DUMP_DIR "dump" +#define DUMP_TEXTURES_DIR "textures" +#define DUMP_FRAMES_DIR "frames" +#define DUMP_AUDIO_DIR "audio" +#define LOGS_DIR "logs" +#define SHADERS_DIR "shaders" +#define SYSCONF_DIR "sysconf" + +// Filenames +// Files in the directory returned by GetUserPath(D_CONFIG_IDX) +#define EMU_CONFIG "emu.ini" +#define DEBUGGER_CONFIG "debugger.ini" +#define LOGGER_CONFIG "logger.ini" + +// Files in the directory returned by GetUserPath(D_LOGS_IDX) +#define MAIN_LOG "emu.log" + +// Files in the directory returned by GetUserPath(D_SYSCONF_IDX) +#define SYSCONF "SYSCONF" + +#endif // _COMMON_PATHS_H_ diff --git a/src/common/common_types.h b/src/common/common_types.h new file mode 100644 index 00000000..af1cd0e2 --- /dev/null +++ b/src/common/common_types.h @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file common_types.h + * @author ShizZy + * @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/ + */ + +#pragma once + +#include +#include // data_types__m128.cpp + +#ifdef _WIN32 + +#include + +typedef unsigned __int8 u8; ///< 8-bit unsigned byte +typedef unsigned __int16 u16; ///< 16-bit unsigned short +typedef unsigned __int32 u32; ///< 32-bit unsigned word +typedef unsigned __int64 u64; ///< 64-bit unsigned int + +typedef signed __int8 s8; ///< 8-bit signed byte +typedef signed __int16 s16; ///< 16-bit signed short +typedef signed __int32 s32; ///< 32-bit signed word +typedef signed __int64 s64; ///< 64-bit signed int + +#else + +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 unsigned long long u64; ///< 64-bit unsigned int + +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 long long s64; ///< 64-bit signed int + +// For using windows lock code +#define TCHAR char +#define LONG int + +#endif // _WIN32 + +typedef float f32; ///< 32-bit floating point +typedef double f64; ///< 64-bit floating point + +#include "swap.h" + +/// 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) + s32 _s32; ///< 32-bit signed int(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) + s32 _s32[2]; ///< 32-bit signed int(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_); + } +}; diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp new file mode 100644 index 00000000..270ad9ce --- /dev/null +++ b/src/common/console_listener.cpp @@ -0,0 +1,337 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include // min +#include // System: To be able to add strings with "+" +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include "common.h" +#include "log_manager.h" // Common +#include "console_listener.h" // Common + +ConsoleListener::ConsoleListener() +{ +#ifdef _WIN32 + hConsole = NULL; + bUseColor = true; +#else + bUseColor = isatty(fileno(stdout)); +#endif +} + +ConsoleListener::~ConsoleListener() +{ + Close(); +} + +// 100, 100, "Dolphin Log Console" +// Open console window - width and height is the size of console window +// Name is the window title +void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title) +{ +#ifdef _WIN32 + if (!GetConsoleWindow()) + { + // Open the console window and create the window handle for GetStdHandle() + AllocConsole(); + // Hide + if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE); + // Save the window handle that AllocConsole() created + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + // Set the console window title + SetConsoleTitle(UTF8ToTStr(Title).c_str()); + // Set letter space + LetterSpace(80, 4000); + //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); + } + else + { + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + } +#endif +} + +void ConsoleListener::UpdateHandle() +{ +#ifdef _WIN32 + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +#endif +} + +// Close the console window and close the eventual file handle +void ConsoleListener::Close() +{ +#ifdef _WIN32 + if (hConsole == NULL) + return; + FreeConsole(); + hConsole = NULL; +#else + fflush(NULL); +#endif +} + +bool ConsoleListener::IsOpen() +{ +#ifdef _WIN32 + return (hConsole != NULL); +#else + return true; +#endif +} + +/* + LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are + dependent on each other, that's the reason for the additional checks. +*/ +void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) +{ +#ifdef _WIN32 + BOOL SB, SW; + if (BufferFirst) + { + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + // Change the screen buffer window size + SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + } + else + { + // Change the screen buffer window size + SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + } +#endif +} +void ConsoleListener::LetterSpace(int Width, int Height) +{ +#ifdef _WIN32 + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + + // + int OldBufferWidth = ConInfo.dwSize.X; + int OldBufferHeight = ConInfo.dwSize.Y; + int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); + int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); + // + int NewBufferWidth = Width; + int NewBufferHeight = Height; + int NewScreenWidth = NewBufferWidth - 1; + int NewScreenHeight = OldScreenHeight; + + // Width + BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1)); + // Height + BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); + + // Resize the window too + //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); +#endif +} +#ifdef _WIN32 +COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) +{ + COORD Ret = {0, 0}; + // Full rows + int Step = (int)floor((float)BytesRead / (float)BufferWidth); + Ret.Y += Step; + // Partial row + Ret.X = BytesRead - (BufferWidth * Step); + return Ret; +} +#endif +void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) +{ +#ifdef _WIN32 + // Check size + if (Width < 8 || Height < 12) return; + + bool DBef = true; + bool DAft = true; + std::string SLog = ""; + + const HWND hWnd = GetConsoleWindow(); + const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y; + + // --------------------------------------------------------------------- + // Save the current text + // ------------------------ + DWORD cCharsRead = 0; + COORD coordScreen = { 0, 0 }; + + static const int MAX_BYTES = 1024 * 16; + + std::vector> Str; + std::vector> Attr; + + // ReadConsoleOutputAttribute seems to have a limit at this level + static const int ReadBufferSize = MAX_BYTES - 32; + + DWORD cAttrRead = ReadBufferSize; + DWORD BytesRead = 0; + while (BytesRead < BufferSize) + { + Str.resize(Str.size() + 1); + if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + + Attr.resize(Attr.size() + 1); + if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + // Break on error + if (cAttrRead == 0) break; + BytesRead += cAttrRead; + coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X); + } + // Letter space + int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f); + int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f); + int LBufWidth = LWidth + 1; + int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth); + // Change screen buffer size + LetterSpace(LBufWidth, LBufHeight); + + + ClearScreen(true); + coordScreen.Y = 0; + coordScreen.X = 0; + DWORD cCharsWritten = 0; + + int BytesWritten = 0; + DWORD cAttrWritten = 0; + for (size_t i = 0; i < Attr.size(); i++) + { + if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + BytesWritten += cAttrWritten; + coordScreen = GetCoordinates(BytesWritten, LBufWidth); + } + + const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; + COORD Coo = GetCoordinates(OldCursor, LBufWidth); + SetConsoleCursorPosition(hConsole, Coo); + + if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str()); + + // Resize the window too + if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); +#endif +} + +void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) +{ +#if defined(_WIN32) + /* + const int MAX_BYTES = 1024*10; + char Str[MAX_BYTES]; + va_list ArgPtr; + int Cnt; + va_start(ArgPtr, Text); + Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); + va_end(ArgPtr); + */ + DWORD cCharsWritten; + WORD Color; + + switch (Level) + { + case NOTICE_LEVEL: // light green + Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case ERROR_LEVEL: // light red + Color = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case WARNING_LEVEL: // light yellow + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case INFO_LEVEL: // cyan + Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; + break; + case DEBUG_LEVEL: // gray + Color = FOREGROUND_INTENSITY; + break; + default: // off-white + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + } + if (strlen(Text) > 10) + { + // First 10 chars white + SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); + Text += 10; + } + SetConsoleTextAttribute(hConsole, Color); + WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); +#else + char ColorAttr[16] = ""; + char ResetAttr[16] = ""; + + if (bUseColor) + { + strcpy(ResetAttr, "\033[0m"); + switch (Level) + { + case NOTICE_LEVEL: // light green + strcpy(ColorAttr, "\033[92m"); + break; + case ERROR_LEVEL: // light red + strcpy(ColorAttr, "\033[91m"); + break; + case WARNING_LEVEL: // light yellow + strcpy(ColorAttr, "\033[93m"); + break; + default: + break; + } + } + fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); +#endif +} +// Clear console screen +void ConsoleListener::ClearScreen(bool Cursor) +{ +#if defined(_WIN32) + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleScreenBufferInfo(hConsole, &csbi); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + // Write space to the entire console + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); + // Reset cursor + if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); +#endif +} + + diff --git a/src/common/console_listener.h b/src/common/console_listener.h new file mode 100644 index 00000000..a2936050 --- /dev/null +++ b/src/common/console_listener.h @@ -0,0 +1,41 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _CONSOLELISTENER_H +#define _CONSOLELISTENER_H + +#include "log_manager.h" + +#ifdef _WIN32 +#include +#endif + +class ConsoleListener : public LogListener +{ +public: + ConsoleListener(); + ~ConsoleListener(); + + void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console"); + void UpdateHandle(); + void Close(); + bool IsOpen(); + void LetterSpace(int Width, int Height); + void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst); + void PixelSpace(int Left, int Top, int Width, int Height, bool); +#ifdef _WIN32 + COORD GetCoordinates(int BytesRead, int BufferWidth); +#endif + void Log(LogTypes::LOG_LEVELS, const char *Text); + void ClearScreen(bool Cursor = true); + +private: +#ifdef _WIN32 + HWND GetHwnd(void); + HANDLE hConsole; +#endif + bool bUseColor; +}; + +#endif // _CONSOLELISTENER_H diff --git a/src/common/cpu_detect.h b/src/common/cpu_detect.h new file mode 100644 index 00000000..e93cf333 --- /dev/null +++ b/src/common/cpu_detect.h @@ -0,0 +1,81 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +// Detect the cpu, so we'll know which optimizations to use +#ifndef _CPUDETECT_H_ +#define _CPUDETECT_H_ + +#include + +enum CPUVendor +{ + VENDOR_INTEL = 0, + VENDOR_AMD = 1, + VENDOR_ARM = 2, + VENDOR_OTHER = 3, +}; + +struct CPUInfo +{ + CPUVendor vendor; + + char cpu_string[0x21]; + char brand_string[0x41]; + bool OS64bit; + bool CPU64bit; + bool Mode64bit; + + bool HTT; + int num_cores; + int logical_cpu_count; + + bool bSSE; + bool bSSE2; + bool bSSE3; + bool bSSSE3; + bool bPOPCNT; + bool bSSE4_1; + bool bSSE4_2; + bool bLZCNT; + bool bSSE4A; + bool bAVX; + bool bAES; + bool bLAHFSAHF64; + bool bLongMode; + + // ARM specific CPUInfo + bool bSwp; + bool bHalf; + bool bThumb; + bool bFastMult; + bool bVFP; + bool bEDSP; + bool bThumbEE; + bool bNEON; + bool bVFPv3; + bool bTLS; + bool bVFPv4; + bool bIDIVa; + bool bIDIVt; + bool bArmV7; // enable MOVT, MOVW etc + + // ARMv8 specific + bool bFP; + bool bASIMD; + + // Call Detect() + explicit CPUInfo(); + + // Turn the cpu info into a string we can show + std::string Summarize(); + +private: + // Detects the various cpu features + void Detect(); +}; + +extern CPUInfo cpu_info; + +#endif // _CPUDETECT_H_ diff --git a/src/common/debug_interface.h b/src/common/debug_interface.h new file mode 100644 index 00000000..49cc54a8 --- /dev/null +++ b/src/common/debug_interface.h @@ -0,0 +1,39 @@ +#ifndef _DEBUGINTERFACE_H +#define _DEBUGINTERFACE_H + +#include +#include + +class DebugInterface +{ +protected: + virtual ~DebugInterface() {} + +public: + virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} + virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} + virtual int getInstructionSize(int /*instruction*/) {return 1;} + virtual bool isAlive() {return true;} + virtual bool isBreakpoint(unsigned int /*address*/) {return false;} + virtual void setBreakpoint(unsigned int /*address*/){} + virtual void clearBreakpoint(unsigned int /*address*/){} + virtual void clearAllBreakpoints() {} + virtual void toggleBreakpoint(unsigned int /*address*/){} + virtual bool isMemCheck(unsigned int /*address*/) {return false;} + virtual void toggleMemCheck(unsigned int /*address*/){} + virtual unsigned int readMemory(unsigned int /*address*/){return 0;} + virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} + virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} + virtual unsigned int readInstruction(unsigned int /*address*/){return 0;} + virtual unsigned int getPC() {return 0;} + virtual void setPC(unsigned int /*address*/) {} + virtual void step() {} + virtual void runToBreakpoint() {} + virtual void breakNow() {} + virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} + virtual void showJitResults(unsigned int /*address*/) {}; + virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} + virtual std::string getDescription(unsigned int /*address*/) = 0; +}; + +#endif diff --git a/src/common/emu_window.h b/src/common/emu_window.h new file mode 100644 index 00000000..f4936705 --- /dev/null +++ b/src/common/emu_window.h @@ -0,0 +1,102 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file emu_window.h + * @author Neobrain + * @date 2012-06-01 + * @brief Interface for implementing an emulator window manager + * + * @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 CORE_EMUWINDOW_H_ +#define CORE_EMUWINDOW_H_ + +#include "common.h" + +//namespace input_common +//{ +//class KeyboardInput; +//} + +// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, +// QGLWidget, GLFW, etc...) +class EmuWindow +{ + +public: + /// Data structure to store an emuwindow configuration + struct Config{ + bool fullscreen; + int res_width; + int res_height; + }; + + /// Swap buffers to display the next frame + virtual void SwapBuffers() = 0; + + /// Polls window events + virtual void PollEvents() = 0; + + /// Makes the graphics context current for the caller thread + virtual void MakeCurrent() = 0; + + /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread + virtual void DoneCurrent() = 0; + + /** + * @brief Called from KeyboardInput constructor to notify EmuWindow about its presence + * @param controller_interface Pointer to a running KeyboardInput interface + */ + //void set_controller_interface(input_common::KeyboardInput* controller_interface) { + // controller_interface_ = controller_interface; + //} + //input_common::KeyboardInput* controller_interface() { return controller_interface_; } + + Config config() { return config_; } + void set_config(Config val) { config_ = val; } + + int client_area_width() { return client_area_width_; } + void set_client_area_width(int val) { client_area_width_ = val; } + + int client_area_height() { return client_area_height_; } + void set_client_area_height(int val) { client_area_height_ = val; } + + std::string window_title() { return window_title_; } + void set_window_title(std::string val) { window_title_ = val; } + +protected: + EmuWindow() : client_area_width_(640), client_area_height_(480) { + char window_title[255]; + sprintf(window_title, "citra [%s|%s] - %s", + "null-cpu", + "null-renderer", + __DATE__); + window_title_ = window_title; + } + virtual ~EmuWindow() {} + + std::string window_title_; ///< Current window title, should be used by window impl. + + int client_area_width_; ///< Current client width, should be set by window impl. + int client_area_height_; ///< Current client height, should be set by window impl. + +private: + Config config_; ///< Internal configuration + +}; + +#endif // CORE_EMUWINDOW_H_ diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp new file mode 100644 index 00000000..9f717dba --- /dev/null +++ b/src/common/extended_trace.cpp @@ -0,0 +1,433 @@ +// -------------------------------------------------------------------------------------- +// +// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com +// For companies(Austin,TX): If you would like to get my resume, send an email. +// +// The source is free, but if you want to use it, mention my name and e-mail address +// +// History: +// 1.0 Initial version Zoltan Csizmadia +// 1.1 WhineCube version Masken +// 1.2 Dolphin version Masken +// +// -------------------------------------------------------------------------------------- + +#if defined(WIN32) + +#include +#include +#include "extended_trace.h" +#include "string_util.h" +using namespace std; + +#include +#include + +#define BUFFERSIZE 0x200 +#pragma warning(disable:4996) + +// Unicode safe char* -> TCHAR* conversion +void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) +{ +#if defined(UNICODE)||defined(_UNICODE) + ULONG index = 0; + PCSTR lpAct = lpszIn; + + for( ; ; lpAct++ ) + { + lpszOut[index++] = (TCHAR)(*lpAct); + if ( *lpAct == 0 ) + break; + } +#else + // This is trivial :) + strcpy( lpszOut, lpszIn ); +#endif +} + +// Let's figure out the path for the symbol files +// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath +// Note: There is no size check for lpszSymbolPath! +static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath ) +{ + CHAR lpszPath[BUFFERSIZE]; + + // Creating the default path + // ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + strcpy( lpszSymbolPath, "." ); + + // environment variable _NT_SYMBOL_PATH + if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + } + + // environment variable _NT_ALTERNATE_SYMBOL_PATH + if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + } + + // environment variable SYSTEMROOT + if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszPath ); + strcat( lpszSymbolPath, ";" ); + + // SYSTEMROOT\System32 + strcat( lpszSymbolPath, lpszPath ); + strcat( lpszSymbolPath, "\\System32" ); + } + + // Add user defined path + if ( lpszIniPath != NULL ) + if ( lpszIniPath[0] != '\0' ) + { + strcat( lpszSymbolPath, ";" ); + strcat( lpszSymbolPath, lpszIniPath ); + } +} + +// Uninitialize the loaded symbol files +BOOL UninitSymInfo() { + return SymCleanup( GetCurrentProcess() ); +} + +// Initializes the symbol files +BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) +{ + CHAR lpszSymbolPath[BUFFERSIZE]; + DWORD symOptions = SymGetOptions(); + + symOptions |= SYMOPT_LOAD_LINES; + symOptions &= ~SYMOPT_UNDNAME; + SymSetOptions( symOptions ); + InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); + + return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE); +} + +// Get the module name from a given address +static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) +{ + BOOL ret = FALSE; + IMAGEHLP_MODULE moduleInfo; + + ::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); + moduleInfo.SizeOfStruct = sizeof(moduleInfo); + + if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) + { + // Got it! + PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule ); + ret = TRUE; + } + else + // Not found :( + _tcscpy( lpszModule, _T("?") ); + + return ret; +} + +// Get function prototype and parameter info from ip address and stack address +static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) +{ + BOOL ret = FALSE; + DWORD dwSymSize = 10000; + TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); + CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; + LPTSTR lpszParamSep = NULL; + LPTSTR lpszParsed = lpszUnDSymbol; + PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize ); + + ::ZeroMemory( pSym, dwSymSize ); + pSym->SizeOfStruct = dwSymSize; + pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL); + + // Set the default to unknown + _tcscpy( lpszSymbol, _T("?") ); + + // Get symbol info for IP +#ifndef _M_X64 + DWORD dwDisp = 0; + if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) +#else + //makes it compile but hell im not sure if this works... + DWORD64 dwDisp = 0; + if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) +#endif + { + // Make the symbol readable for humans + UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, + UNDNAME_COMPLETE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_SPECIAL_SYMS | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_ACCESS_SPECIFIERS ); + + // Symbol information is ANSI string + PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol ); + + // I am just smarter than the symbol file :) + if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("mainCRTStartup()")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)")); + else + if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 ) + _tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()")); + + lpszSymbol[0] = _T('\0'); + + // Let's go through the stack, and modify the function prototype, and insert the actual + // parameter values from the stack + if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL) + { + ULONG index = 0; + for( ; ; index++ ) + { + lpszParamSep = _tcschr( lpszParsed, _T(',') ); + if ( lpszParamSep == NULL ) + break; + + *lpszParamSep = _T('\0'); + + _tcscat( lpszSymbol, lpszParsed ); + _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) ); + + lpszParsed = lpszParamSep + 1; + } + + lpszParamSep = _tcschr( lpszParsed, _T(')') ); + if ( lpszParamSep != NULL ) + { + *lpszParamSep = _T('\0'); + + _tcscat( lpszSymbol, lpszParsed ); + _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) ); + + lpszParsed = lpszParamSep + 1; + } + } + + _tcscat( lpszSymbol, lpszParsed ); + + ret = TRUE; + } + GlobalFree( pSym ); + + return ret; +} + +// Get source file name and line number from IP address +// The output format is: "sourcefile(linenumber)" or +// "modulename!address" or +// "address" +static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ) +{ + BOOL ret = FALSE; + IMAGEHLP_LINE lineInfo; + DWORD dwDisp; + TCHAR lpszFileName[BUFFERSIZE] = _T(""); + TCHAR lpModuleInfo[BUFFERSIZE] = _T(""); + + _tcscpy( lpszSourceInfo, _T("?(?)") ); + + ::ZeroMemory( &lineInfo, sizeof( lineInfo ) ); + lineInfo.SizeOfStruct = sizeof( lineInfo ); + + if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) ) + { + // Got it. Let's use "sourcefile(linenumber)" format + PCSTR2LPTSTR( lineInfo.FileName, lpszFileName ); + TCHAR fname[_MAX_FNAME]; + TCHAR ext[_MAX_EXT]; + _tsplitpath(lpszFileName, NULL, NULL, fname, ext); + _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber ); + ret = TRUE; + } + else + { + // There is no source file information. :( + // Let's use the "modulename!address" format + GetModuleNameFromAddress( address, lpModuleInfo ); + + if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0')) + // There is no modulename information. :(( + // Let's use the "address" format + _stprintf( lpszSourceInfo, _T("0x%08X"), address ); + else + _stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address ); + + ret = FALSE; + } + + return ret; +} + +void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) +{ + TCHAR symInfo[BUFFERSIZE] = _T("?"); + TCHAR srcInfo[BUFFERSIZE] = _T("?"); + + GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); + GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); + etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); +} + +void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) +{ + STACKFRAME callStack; + BOOL bResult; + CONTEXT context; + HANDLE hProcess = GetCurrentProcess(); + + // If it's not this thread, let's suspend it, and resume it at the end + if ( hThread != GetCurrentThread() ) + if ( SuspendThread( hThread ) == -1 ) + { + // whaaat ?! + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &context, sizeof(context) ); + context.ContextFlags = CONTEXT_FULL; + + if ( !GetThreadContext( hThread, &context ) ) + { + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &callStack, sizeof(callStack) ); +#ifndef _M_X64 + callStack.AddrPC.Offset = context.Eip; + callStack.AddrStack.Offset = context.Esp; + callStack.AddrFrame.Offset = context.Ebp; +#else + callStack.AddrPC.Offset = context.Rip; + callStack.AddrStack.Offset = context.Rsp; + callStack.AddrFrame.Offset = context.Rbp; +#endif + callStack.AddrPC.Mode = AddrModeFlat; + callStack.AddrStack.Mode = AddrModeFlat; + callStack.AddrFrame.Mode = AddrModeFlat; + + etfprint(file, "Call stack info: \n"); + etfprint(file, lpszMessage); + + PrintFunctionAndSourceInfo(file, callStack); + + for( ULONG index = 0; ; index++ ) + { + bResult = StackWalk( + IMAGE_FILE_MACHINE_I386, + hProcess, + hThread, + &callStack, + NULL, + NULL, + SymFunctionTableAccess, + SymGetModuleBase, + NULL); + + if ( index == 0 ) + continue; + + if( !bResult || callStack.AddrFrame.Offset == 0 ) + break; + + PrintFunctionAndSourceInfo(file, callStack); + + } + + if ( hThread != GetCurrentThread() ) + ResumeThread( hThread ); +} + +void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) +{ + STACKFRAME callStack; + BOOL bResult; + TCHAR symInfo[BUFFERSIZE] = _T("?"); + TCHAR srcInfo[BUFFERSIZE] = _T("?"); + HANDLE hProcess = GetCurrentProcess(); + + // If it's not this thread, let's suspend it, and resume it at the end + if ( hThread != GetCurrentThread() ) + if ( SuspendThread( hThread ) == -1 ) + { + // whaaat ?! + etfprint(file, "Call stack info failed\n"); + return; + } + + ::ZeroMemory( &callStack, sizeof(callStack) ); + callStack.AddrPC.Offset = eip; + callStack.AddrStack.Offset = esp; + callStack.AddrFrame.Offset = ebp; + callStack.AddrPC.Mode = AddrModeFlat; + callStack.AddrStack.Mode = AddrModeFlat; + callStack.AddrFrame.Mode = AddrModeFlat; + + etfprint(file, "Call stack info: \n"); + etfprint(file, lpszMessage); + + PrintFunctionAndSourceInfo(file, callStack); + + for( ULONG index = 0; ; index++ ) + { + bResult = StackWalk( + IMAGE_FILE_MACHINE_I386, + hProcess, + hThread, + &callStack, + NULL, + NULL, + SymFunctionTableAccess, + SymGetModuleBase, + NULL); + + if ( index == 0 ) + continue; + + if( !bResult || callStack.AddrFrame.Offset == 0 ) + break; + + PrintFunctionAndSourceInfo(file, callStack); + } + + if ( hThread != GetCurrentThread() ) + ResumeThread( hThread ); +} + +char g_uefbuf[2048]; + +void etfprintf(FILE *file, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int len = vsprintf(g_uefbuf, format, ap); + fwrite(g_uefbuf, 1, len, file); + va_end(ap); +} + +void etfprint(FILE *file, const std::string &text) +{ + size_t len = text.length(); + fwrite(text.data(), 1, len, file); +} + +#endif //WIN32 diff --git a/src/common/extended_trace.h b/src/common/extended_trace.h new file mode 100644 index 00000000..1552e901 --- /dev/null +++ b/src/common/extended_trace.h @@ -0,0 +1,53 @@ +// ----------------------------------------------------------------------------------------- +// +// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com +// For companies(Austin,TX): If you would like to get my resume, send an email. +// +// The source is free, but if you want to use it, mention my name and e-mail address +// +// History: +// 1.0 Initial version Zoltan Csizmadia +// 1.1 WhineCube version Masken +// 1.2 Dolphin version Masken +// +// ---------------------------------------------------------------------------------------- + +#ifndef _EXTENDEDTRACE_H_INCLUDED_ +#define _EXTENDEDTRACE_H_INCLUDED_ + +#if defined(WIN32) + +#include +#include + +#include + +#pragma comment( lib, "imagehlp.lib" ) + +#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath ) +#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() +#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file) +#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp) +// class File; + +BOOL InitSymInfo( PCSTR ); +BOOL UninitSymInfo(); +void StackTrace(HANDLE, char const* msg, FILE *file); +void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp); + +// functions by Masken +void etfprintf(FILE *file, const char *format, ...); +void etfprint(FILE *file, const std::string &text); +#define UEFBUFSIZE 2048 +extern char g_uefbuf[UEFBUFSIZE]; + +#else // not WIN32 + +#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) +#define EXTENDEDTRACEUNINITIALIZE() ((void)0) +#define STACKTRACE(file) ((void)0) +#define STACKTRACE2(file, eip, esp, ebp) ((void)0) + +#endif // WIN32 + +#endif // _EXTENDEDTRACE_H_INCLUDED_ diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h new file mode 100644 index 00000000..57efcd83 --- /dev/null +++ b/src/common/fifo_queue.h @@ -0,0 +1,115 @@ + +#ifndef _FIFO_QUEUE_H_ +#define _FIFO_QUEUE_H_ + +// a simple lockless thread-safe, +// single reader, single writer queue + +#include "atomic.h" + +namespace Common +{ + +template +class FifoQueue +{ +public: + FifoQueue() : m_size(0) + { + m_write_ptr = m_read_ptr = new ElementPtr(); + } + + ~FifoQueue() + { + // this will empty out the whole queue + delete m_read_ptr; + } + + u32 Size() const + { + return m_size; + } + + bool Empty() const + { + //return (m_read_ptr == m_write_ptr); + return (0 == m_size); + } + + T& Front() const + { + return *m_read_ptr->current; + } + + template + void Push(Arg&& t) + { + // create the element, add it to the queue + m_write_ptr->current = new T(std::forward(t)); + // set the next pointer to a new element ptr + // then advance the write pointer + m_write_ptr = m_write_ptr->next = new ElementPtr(); + Common::AtomicIncrement(m_size); + } + + void Pop() + { + Common::AtomicDecrement(m_size); + ElementPtr *const tmpptr = m_read_ptr; + // advance the read pointer + m_read_ptr = m_read_ptr->next; + // set the next element to NULL to stop the recursive deletion + tmpptr->next = NULL; + delete tmpptr; // this also deletes the element + } + + bool Pop(T& t) + { + if (Empty()) + return false; + + t = std::move(Front()); + Pop(); + + return true; + } + + // not thread-safe + void Clear() + { + m_size = 0; + delete m_read_ptr; + m_write_ptr = m_read_ptr = new ElementPtr(); + } + +private: + // stores a pointer to element + // and a pointer to the next ElementPtr + class ElementPtr + { + public: + ElementPtr() : current(NULL), next(NULL) {} + + ~ElementPtr() + { + if (current) + { + delete current; + // recusion ftw + if (next) + delete next; + } + } + + T *volatile current; + ElementPtr *volatile next; + }; + + ElementPtr *volatile m_write_ptr; + ElementPtr *volatile m_read_ptr; + volatile u32 m_size; +}; + +} + +#endif diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp new file mode 100644 index 00000000..59f64010 --- /dev/null +++ b/src/common/file_search.cpp @@ -0,0 +1,106 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "common_paths.h" +#ifndef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include + +#include "file_search.h" + +#include "string_util.h" + + +CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories) +{ + // Reverse the loop order for speed? + for (size_t j = 0; j < _rSearchStrings.size(); j++) + { + for (size_t i = 0; i < _rDirectories.size(); i++) + { + FindFiles(_rSearchStrings[j], _rDirectories[i]); + } + } +} + + +void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) +{ + std::string GCMSearchPath; + BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); +#ifdef _WIN32 + WIN32_FIND_DATA findData; + HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); + + if (FindFirst != INVALID_HANDLE_VALUE) + { + bool bkeepLooping = true; + + while (bkeepLooping) + { + if (findData.cFileName[0] != '.') + { + std::string strFilename; + BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); + m_FileNames.push_back(strFilename); + } + + bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false; + } + } + FindClose(FindFirst); + + +#else + // TODO: super lame/broken + + auto end_match(_searchString); + + // assuming we have a "*.blah"-like pattern + if (!end_match.empty() && end_match[0] == '*') + end_match.erase(0, 1); + + // ugly + if (end_match == ".*") + end_match.clear(); + + DIR* dir = opendir(_strPath.c_str()); + + if (!dir) + return; + + while (auto const dp = readdir(dir)) + { + std::string found(dp->d_name); + + if ((found != ".") && (found != "..") + && (found.size() >= end_match.size()) + && std::equal(end_match.rbegin(), end_match.rend(), found.rbegin())) + { + std::string full_name; + if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR) + full_name = _strPath + found; + else + full_name = _strPath + DIR_SEP + found; + + m_FileNames.push_back(full_name); + } + } + + closedir(dir); +#endif +} + +const CFileSearch::XStringVector& CFileSearch::GetFileNames() const +{ + return m_FileNames; +} diff --git a/src/common/file_search.h b/src/common/file_search.h new file mode 100644 index 00000000..2a9ff801 --- /dev/null +++ b/src/common/file_search.h @@ -0,0 +1,28 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FILESEARCH_H_ +#define _FILESEARCH_H_ + +#include +#include + +class CFileSearch +{ +public: + typedef std::vectorXStringVector; + + CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories); + const XStringVector& GetFileNames() const; + +private: + + void FindFiles(const std::string& _searchString, const std::string& _strPath); + + XStringVector m_FileNames; +}; + +#endif // _FILESEARCH_H_ + diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp new file mode 100644 index 00000000..8b47cb3e --- /dev/null +++ b/src/common/file_util.cpp @@ -0,0 +1,910 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "common_paths.h" +#include "file_util.h" +#include "string_util.h" + +#ifdef _WIN32 +#include +#include // for SHGetFolderPath +#include +#include // for GetSaveFileName +#include +#include // getcwd +#else +#include +#include +#include +#include +#include +#endif + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#include +#include + +#include "string_util.h" + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#endif + +#ifdef BSD4_4 +#define stat64 stat +#define fstat64 fstat +#endif + +// This namespace has various generic functions related to files and paths. +// The code still needs a ton of cleanup. +// REMEMBER: strdup considered harmful! +namespace File +{ + +// 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] == DIR_SEP_CHR) + fname[i--] = '\0'; + } + return; +} + +// Returns true if file filename exists +bool Exists(const std::string &filename) +{ + struct stat64 file_info; + + std::string copy(filename); + StripTailDirSlashes(copy); + +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else + int result = stat64(copy.c_str(), &file_info); +#endif + + return (result == 0); +} + +// Returns true if filename is a directory +bool IsDirectory(const std::string &filename) +{ + struct stat64 file_info; + + std::string copy(filename); + StripTailDirSlashes(copy); + +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else + int result = stat64(copy.c_str(), &file_info); +#endif + + if (result < 0) { + WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } + + return S_ISDIR(file_info.st_mode); +} + +// Deletes a given filename, return true on success +// Doesn't supports deleting a directory +bool Delete(const std::string &filename) +{ + INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); + + // Return true because we care about the file no + // being there, not the actual delete. + if (!Exists(filename)) + { + WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); + return true; + } + + // We can't delete a directory + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); + return false; + } + +#ifdef _WIN32 + if (!DeleteFile(UTF8ToTStr(filename).c_str())) + { + WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } +#else + if (unlink(filename.c_str()) == -1) { + WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } +#endif + + return true; +} + +// Returns true if successful, or path already exists. +bool CreateDir(const std::string &path) +{ + INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); +#ifdef _WIN32 + if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) + return true; + DWORD error = GetLastError(); + if (error == ERROR_ALREADY_EXISTS) + { + WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); + return true; + } + ERROR_LOG(COMMON, "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) + { + WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); + return true; + } + + ERROR_LOG(COMMON, "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; + INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); + + if (File::Exists(fullPath)) + { + INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); + return true; + } + + size_t position = 0; + while (true) + { + // Find next sub path + position = fullPath.find(DIR_SEP_CHR, position); + + // we're done, yay! + if (position == fullPath.npos) + return true; + + // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") + std::string const subPath(fullPath.substr(0, position + 1)); + if (!File::IsDirectory(subPath)) + File::CreateDir(subPath); + + // A safety check + panicCounter--; + if (panicCounter <= 0) + { + ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); + return false; + } + position++; + } +} + + +// Deletes a directory filename, returns true on success +bool DeleteDir(const std::string &filename) +{ + INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); + + // check if a directory + if (!File::IsDirectory(filename)) + { + ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); + return false; + } + +#ifdef _WIN32 + if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) + return true; +#else + if (rmdir(filename.c_str()) == 0) + return true; +#endif + ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); + + return false; +} + +// renames file srcFilename to destFilename, returns true on success +bool Rename(const std::string &srcFilename, const std::string &destFilename) +{ + INFO_LOG(COMMON, "Rename: %s --> %s", + srcFilename.c_str(), destFilename.c_str()); + if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) + return true; + ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; +} + +// copies file srcFilename to destFilename, returns true on success +bool Copy(const std::string &srcFilename, const std::string &destFilename) +{ + INFO_LOG(COMMON, "Copy: %s --> %s", + srcFilename.c_str(), destFilename.c_str()); +#ifdef _WIN32 + if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) + return true; + + ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; +#else + + // buffer size +#define BSIZE 1024 + + char buffer[BSIZE]; + + // Open input file + FILE *input = fopen(srcFilename.c_str(), "rb"); + if (!input) + { + ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; + } + + // open output file + FILE *output = fopen(destFilename.c_str(), "wb"); + if (!output) + { + fclose(input); + ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + return false; + } + + // copy loop + while (!feof(input)) + { + // read input + int rnum = fread(buffer, sizeof(char), BSIZE, input); + if (rnum != BSIZE) + { + if (ferror(input) != 0) + { + ERROR_LOG(COMMON, + "Copy: failed reading from source, %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + goto bail; + } + } + + // write output + int wnum = fwrite(buffer, sizeof(char), rnum, output); + if (wnum != rnum) + { + ERROR_LOG(COMMON, + "Copy: failed writing to output, %s --> %s: %s", + srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); + goto bail; + } + } + // close files + 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 GetSize(const std::string &filename) +{ + if (!Exists(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); + return 0; + } + + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); + return 0; + } + + struct stat64 buf; +#ifdef _WIN32 + if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) +#else + if (stat64(filename.c_str(), &buf) == 0) +#endif + { + DEBUG_LOG(COMMON, "GetSize: %s: %lld", + filename.c_str(), (long long)buf.st_size); + return buf.st_size; + } + + ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", + filename.c_str(), GetLastErrorMsg()); + return 0; +} + +// Overloaded GetSize, accepts file descriptor +u64 GetSize(const int fd) +{ + struct stat64 buf; + if (fstat64(fd, &buf) != 0) { + ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", + fd, GetLastErrorMsg()); + return 0; + } + return buf.st_size; +} + +// Overloaded GetSize, accepts FILE* +u64 GetSize(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) { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", + f, GetLastErrorMsg()); + return 0; + } + u64 size = ftello(f); + if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", + f, GetLastErrorMsg()); + return 0; + } + return size; +} + +// creates an empty file filename, returns true on success +bool CreateEmptyFile(const std::string &filename) +{ + INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); + + if (!File::IOFile(filename, "wb")) + { + ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", + filename.c_str(), GetLastErrorMsg()); + return false; + } + + return true; +} + + +// Scans the directory tree gets, starting from _Directory and adds the +// results into parentEntry. Returns the number of files+directories found +u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) +{ + INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); + // How many files + directories we found + u32 foundEntries = 0; +#ifdef _WIN32 + // Find the first file in the directory. + WIN32_FIND_DATA ffd; + + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return foundEntries; + } + // windows loop + do + { + FSTEntry entry; + const std::string virtualName(TStrToUTF8(ffd.cFileName)); +#else + struct dirent dirent, *result = NULL; + + DIR *dirp = opendir(directory.c_str()); + if (!dirp) + return 0; + + // non windows loop + while (!readdir_r(dirp, &dirent, &result) && result) + { + FSTEntry entry; + 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; + entry.virtualName = virtualName; + entry.physicalName = directory; + entry.physicalName += DIR_SEP + entry.virtualName; + + if (IsDirectory(entry.physicalName.c_str())) + { + entry.isDirectory = true; + // is a directory, lets go inside + entry.size = ScanDirectoryTree(entry.physicalName, entry); + foundEntries += (u32)entry.size; + } + else + { // is a file + entry.isDirectory = false; + entry.size = GetSize(entry.physicalName.c_str()); + } + ++foundEntries; + // Push into the tree + parentEntry.children.push_back(entry); +#ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + } + closedir(dirp); +#endif + // Return number of entries found. + return foundEntries; +} + + +// Deletes the given directory and anything under it. Returns true on success. +bool DeleteDirRecursively(const std::string &directory) +{ + INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); +#ifdef _WIN32 + // Find the first file in the directory. + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return false; + } + + // windows loop + do + { + const std::string virtualName(TStrToUTF8(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 + DIR_SEP_CHR + virtualName; + if (IsDirectory(newPath)) + { + if (!DeleteDirRecursively(newPath)) + { + #ifndef _WIN32 + closedir(dirp); + #endif + + return false; + } + } + else + { + if (!File::Delete(newPath)) + { + #ifndef _WIN32 + closedir(dirp); + #endif + + return false; + } + } + +#ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + } + closedir(dirp); +#endif + File::DeleteDir(directory); + + return true; +} + +// Create directory and copy contents (does not overwrite existing files) +void CopyDir(const std::string &source_path, const std::string &dest_path) +{ +#ifndef _WIN32 + if (source_path == dest_path) return; + if (!File::Exists(source_path)) return; + if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); + + struct dirent dirent, *result = NULL; + DIR *dirp = opendir(source_path.c_str()); + if (!dirp) return; + + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtualName(result->d_name); + // check for "." and ".." + if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || + ((virtualName[0] == '.') && (virtualName[1] == '.') && + (virtualName[2] == '\0'))) + continue; + + std::string source, dest; + source = source_path + virtualName; + dest = dest_path + virtualName; + if (IsDirectory(source)) + { + source += '/'; + dest += '/'; + if (!File::Exists(dest)) File::CreateFullPath(dest); + CopyDir(source, dest); + } + else if (!File::Exists(dest)) File::Copy(source, dest); + } + closedir(dirp); +#endif +} + +// Returns the current directory +std::string GetCurrentDir() +{ + char *dir; + // Get the current working directory (getcwd uses malloc) + if (!(dir = __getcwd(NULL, 0))) { + + ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", + GetLastErrorMsg()); + 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; +} + +#if defined(__APPLE__) +std::string GetBundleDirectory() +{ + CFURLRef BundleRef; + char AppBundlePath[MAXPATHLEN]; + // Get the main bundle for the app + BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); + CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); + CFRelease(BundleRef); + CFRelease(BundlePath); + + return AppBundlePath; +} +#endif + +#ifdef _WIN32 +std::string& GetExeDirectory() +{ + static std::string DolphinPath; + if (DolphinPath.empty()) + { + TCHAR Dolphin_exe_Path[2048]; + GetModuleFileName(NULL, Dolphin_exe_Path, 2048); + DolphinPath = TStrToUTF8(Dolphin_exe_Path); + DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); + } + return DolphinPath; +} +#endif + +std::string GetSysDirectory() +{ + std::string sysDir; + +#if defined (__APPLE__) + sysDir = GetBundleDirectory(); + sysDir += DIR_SEP; + sysDir += SYSDATA_DIR; +#else + sysDir = SYSDATA_DIR; +#endif + sysDir += DIR_SEP; + + INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); + return sysDir; +} + +// Returns a string with a Dolphin data dir or file in the user's home +// directory. To be used in "multi-user" mode (that is, installed). +const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) +{ + static std::string paths[NUM_PATH_INDICES]; + + // Set up all paths and files on the first run + if (paths[D_USER_IDX].empty()) + { +#ifdef _WIN32 + paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; +#else + if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; + else + paths[D_USER_IDX] = std::string(getenv("HOME") ? + getenv("HOME") : getenv("PWD") ? + getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; +#endif + + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; + paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + } + + if (!newPath.empty()) + { + if (!File::IsDirectory(newPath)) + { + WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); + return paths[DirIDX]; + } + else + { + paths[DirIDX] = newPath; + } + + switch (DirIDX) + { + case D_ROOT_IDX: + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; + paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; + break; + + case D_USER_IDX: + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; + paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + break; + + case D_CONFIG_IDX: + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + break; + + case D_DUMP_IDX: + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + break; + + case D_LOGS_IDX: + paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; + } + } + + return paths[DirIDX]; +} + +//std::string GetThemeDir(const std::string& theme_name) +//{ +// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; +// +//#if !defined(_WIN32) +// // If theme does not exist in user's dir load from shared directory +// if (!File::Exists(dir)) +// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; +//#endif +// +// return dir; +//} + +bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) +{ + return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); +} + +bool ReadFileToString(bool text_file, const char *filename, std::string &str) +{ + File::IOFile file(filename, text_file ? "r" : "rb"); + auto const f = file.GetHandle(); + + if (!f) + return false; + + str.resize(static_cast(GetSize(f))); + return file.ReadArray(&str[0], str.size()); +} + +IOFile::IOFile() + : m_file(NULL), m_good(true) +{} + +IOFile::IOFile(std::FILE* file) + : m_file(file), m_good(true) +{} + +IOFile::IOFile(const std::string& filename, const char openmode[]) + : m_file(NULL), m_good(true) +{ + Open(filename, openmode); +} + +IOFile::~IOFile() +{ + Close(); +} + +IOFile::IOFile(IOFile&& other) + : m_file(NULL), m_good(true) +{ + Swap(other); +} + +IOFile& IOFile::operator=(IOFile&& other) +{ + Swap(other); + return *this; +} + +void IOFile::Swap(IOFile& other) +{ + std::swap(m_file, other.m_file); + std::swap(m_good, other.m_good); +} + +bool IOFile::Open(const std::string& filename, const char openmode[]) +{ + Close(); +#ifdef _WIN32 + _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); +#else + m_file = fopen(filename.c_str(), openmode); +#endif + + m_good = IsOpen(); + return m_good; +} + +bool IOFile::Close() +{ + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; + + m_file = NULL; + return m_good; +} + +std::FILE* IOFile::ReleaseHandle() +{ + std::FILE* const ret = m_file; + m_file = NULL; + return ret; +} + +void IOFile::SetHandle(std::FILE* file) +{ + Close(); + Clear(); + m_file = file; +} + +u64 IOFile::GetSize() +{ + if (IsOpen()) + return File::GetSize(m_file); + else + return 0; +} + +bool IOFile::Seek(s64 off, int origin) +{ + if (!IsOpen() || 0 != fseeko(m_file, off, origin)) + m_good = false; + + return m_good; +} + +u64 IOFile::Tell() +{ + if (IsOpen()) + return ftello(m_file); + else + return -1; +} + +bool IOFile::Flush() +{ + if (!IsOpen() || 0 != std::fflush(m_file)) + m_good = false; + + return m_good; +} + +bool IOFile::Resize(u64 size) +{ + if (!IsOpen() || 0 != +#ifdef _WIN32 + // ector: _chsize sucks, not 64-bit safe + // F|RES: changed to _chsize_s. i think it is 64-bit safe + _chsize_s(_fileno(m_file), size) +#else + // TODO: handle 64bit and growing + ftruncate(fileno(m_file), size) +#endif + ) + m_good = false; + + return m_good; +} + +} // namespace diff --git a/src/common/file_util.h b/src/common/file_util.h new file mode 100644 index 00000000..f4ef949d --- /dev/null +++ b/src/common/file_util.h @@ -0,0 +1,224 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FILEUTIL_H_ +#define _FILEUTIL_H_ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "string_util.h" + +// User directory indices for GetUserPath +enum { + D_USER_IDX, + D_ROOT_IDX, + D_CONFIG_IDX, + D_GAMECONFIG_IDX, + D_MAPS_IDX, + D_CACHE_IDX, + D_SHADERCACHE_IDX, + D_SHADERS_IDX, + D_STATESAVES_IDX, + D_SCREENSHOTS_IDX, + D_HIRESTEXTURES_IDX, + D_DUMP_IDX, + D_DUMPFRAMES_IDX, + D_DUMPAUDIO_IDX, + D_DUMPTEXTURES_IDX, + D_DUMPDSP_IDX, + D_LOGS_IDX, + D_SYSCONF_IDX, + F_EMUCONFIG_IDX, + F_DEBUGGERCONFIG_IDX, + F_LOGGERCONFIG_IDX, + F_MAINLOG_IDX, + F_RAMDUMP_IDX, + F_ARAMDUMP_IDX, + F_SYSCONF_IDX, + NUM_PATH_INDICES +}; + +namespace File +{ + +// FileSystem tree node/ +struct FSTEntry +{ + bool isDirectory; + u64 size; // file length or number of entries from children + std::string physicalName; // name on disk + std::string virtualName; // name in FST names table + std::vector children; +}; + +// Returns true if file filename exists +bool Exists(const std::string &filename); + +// Returns true if filename is a directory +bool IsDirectory(const std::string &filename); + +// Returns the size of filename (64bit) +u64 GetSize(const std::string &filename); + +// Overloaded GetSize, accepts file descriptor +u64 GetSize(const int fd); + +// Overloaded GetSize, accepts FILE* +u64 GetSize(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 Delete(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 Rename(const std::string &srcFilename, const std::string &destFilename); + +// copies file srcFilename to destFilename, returns true on success +bool Copy(const std::string &srcFilename, const std::string &destFilename); + +// creates an empty file filename, returns true on success +bool CreateEmptyFile(const std::string &filename); + +// Scans the directory tree gets, starting from _Directory and adds the +// results into parentEntry. Returns the number of files+directories found +u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry); + +// 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(); + +// Create directory and copy contents (does not overwrite existing files) +void CopyDir(const std::string &source_path, const std::string &dest_path); + +// Set the current directory to given directory +bool SetCurrentDir(const std::string &directory); + +// Returns a pointer to a string with a Dolphin data dir in the user's home +// directory. To be used in "multi-user" mode (that is, installed). +const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); + +// probably doesn't belong here +//std::string GetThemeDir(const std::string& theme_name); + +// Returns the path to where the sys file are +std::string GetSysDirectory(); + +#ifdef __APPLE__ +std::string GetBundleDirectory(); +#endif + +#ifdef _WIN32 +std::string &GetExeDirectory(); +#endif + +bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); +bool ReadFileToString(bool text_file, const char *filename, std::string &str); + +// simple wrapper for cstdlib file functions to +// hopefully will make error checking easier +// and make forgetting an fclose() harder +class IOFile : public NonCopyable +{ +public: + IOFile(); + IOFile(std::FILE* file); + IOFile(const std::string& filename, const char openmode[]); + + ~IOFile(); + + IOFile(IOFile&& other); + IOFile& operator=(IOFile&& other); + + void Swap(IOFile& other); + + bool Open(const std::string& filename, const char openmode[]); + bool Close(); + + template + bool ReadArray(T* data, size_t length) + { + if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) + m_good = false; + + return m_good; + } + + template + bool WriteArray(const T* data, size_t length) + { + if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + m_good = false; + + return m_good; + } + + bool ReadBytes(void* data, size_t length) + { + return ReadArray(reinterpret_cast(data), length); + } + + bool WriteBytes(const void* data, size_t length) + { + return WriteArray(reinterpret_cast(data), length); + } + + bool IsOpen() { return NULL != m_file; } + + // m_good is set to false when a read, write or other function fails + bool IsGood() { return m_good; } + operator void*() { return m_good ? m_file : NULL; } + + std::FILE* ReleaseHandle(); + + std::FILE* GetHandle() { return m_file; } + + void SetHandle(std::FILE* file); + + bool Seek(s64 off, int origin); + u64 Tell(); + u64 GetSize(); + bool Resize(u64 size); + bool Flush(); + + // clear error state + void Clear() { m_good = true; std::clearerr(m_file); } + + std::FILE* m_file; + bool m_good; +private: + IOFile(IOFile&); + IOFile& operator=(IOFile& other); +}; + +} // namespace + +// To deal with Windows being dumb at unicode: +template +void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) +{ +#ifdef _WIN32 + fstream.open(UTF8ToTStr(filename).c_str(), openmode); +#else + fstream.open(filename.c_str(), openmode); +#endif +} + +#endif diff --git a/src/common/fixed_size_queue.h b/src/common/fixed_size_queue.h new file mode 100644 index 00000000..1f507f4a --- /dev/null +++ b/src/common/fixed_size_queue.h @@ -0,0 +1,75 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _FIXED_SIZE_QUEUE_H_ +#define _FIXED_SIZE_QUEUE_H_ + +// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the +// real STL classes. + +// Not fully featured, no safety checking yet. Add features as needed. + +// TODO: "inline" storage? + +template +class fixed_size_queue.h +{ + T *storage; + int head; + int tail; + int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. + + // Make copy constructor private for now. + fixed_size_queue.h(fixed_size_queue.h &other) { } + +public: + fixed_size_queue.h() + { + storage = new T[N]; + clear(); + } + + ~fixed_size_queue.h() + { + delete [] storage; + } + + void clear() { + head = 0; + tail = 0; + count = 0; + } + + void push(T t) { + storage[tail] = t; + tail++; + if (tail == N) + tail = 0; + count++; + } + + void pop() { + head++; + if (head == N) + head = 0; + count--; + } + + T pop_front() { + const T &temp = storage[head]; + pop(); + return temp; + } + + T &front() { return storage[head]; } + const T &front() const { return storage[head]; } + + size_t size() const { + return count; + } +}; + +#endif // _FIXED_SIZE_QUEUE_H_ + diff --git a/src/common/hash.cpp b/src/common/hash.cpp new file mode 100644 index 00000000..5303f07b --- /dev/null +++ b/src/common/hash.cpp @@ -0,0 +1,520 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "hash.h" +#if _M_SSE >= 0x402 +#include "cpu_detect.h" +#include +#endif + +static u64 (*ptrHashFunction)(const u8 *src, int len, u32 samples) = &GetMurmurHash3; + +// uint32_t +// WARNING - may read one more byte! +// Implementation from Wikipedia. +u32 HashFletcher(const u8* data_u8, size_t length) +{ + const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */ + size_t len = (length + 1) / 2; /* Length in 16-bit words */ + u32 sum1 = 0xffff, sum2 = 0xffff; + + while (len) + { + size_t tlen = len > 360 ? 360 : len; + len -= tlen; + + do { + sum1 += *data++; + sum2 += sum1; + } + while (--tlen); + + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + } + + // Second reduction step to reduce sums to 16 bits + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + return(sum2 << 16 | sum1); +} + + +// Implementation from Wikipedia +// Slightly slower than Fletcher above, but slightly more reliable. +#define MOD_ADLER 65521 +// data: Pointer to the data to be summed; len is in bytes +u32 HashAdler32(const u8* data, size_t len) +{ + u32 a = 1, b = 0; + + while (len) + { + size_t tlen = len > 5550 ? 5550 : len; + len -= tlen; + + do + { + a += *data++; + b += a; + } + while (--tlen); + + a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + } + + // It can be shown that a <= 0x1013a here, so a single subtract will do. + if (a >= MOD_ADLER) + { + a -= MOD_ADLER; + } + + // It can be shown that b can reach 0xfff87 here. + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + + if (b >= MOD_ADLER) + { + b -= MOD_ADLER; + } + + return((b << 16) | a); +} + +// Stupid hash - but can't go back now :) +// Don't use for new things. At least it's reasonably fast. +u32 HashEctor(const u8* ptr, int length) +{ + u32 crc = 0; + + for (int i = 0; i < length; i++) + { + crc ^= ptr[i]; + crc = (crc << 3) | (crc >> 29); + } + + return(crc); +} + + +#ifdef _M_X64 + +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +inline u64 getblock(const u64 * p, int i) +{ + return p[i]; +} + +//---------- +// 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; +} + +u64 GetMurmurHash3(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 = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + + u64 h1 = 0x9368e53c2f6af274; + u64 h2 = 0x586dcd208f7cd3fd; + + u64 c1 = 0x87c37b91114253d5; + u64 c2 = 0x4cf5ad432745937f; + + + //---------- + // body + + const u64 * blocks = (const u64 *)(data); + + for(int i = 0; i < nblocks; i+=Step) + { + u64 k1 = getblock(blocks,i*2+0); + u64 k2 = getblock(blocks,i*2+1); + + bmix64(h1,h2,k1,k2,c1,c2); + } + + //---------- + // tail + + 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); + }; + + //---------- + // finalization + + h2 ^= len; + + h1 += h2; + h2 += h1; + + h1 = fmix64(h1); + h2 = fmix64(h2); + + h1 += h2; + + return h1; +} + + +// CRC32 hash using the SSE4.2 instruction +u64 GetCRC32(const u8 *src, int len, u32 samples) +{ +#if _M_SSE >= 0x402 + u64 h = len; + u32 Step = (len / 8); + const u64 *data = (const u64 *)src; + const u64 *end = data + Step; + if(samples == 0) samples = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + while(data < end) + { + h = _mm_crc32_u64(h, data[0]); + data += Step; + } + + const u8 *data2 = (const u8*)end; + return _mm_crc32_u64(h, u64(data2[0])); +#else + return 0; +#endif +} + + +/* + * NOTE: This hash function is used for custom texture loading/dumping, so + * it should not be changed, which would require all custom textures to be + * recalculated for their new hash values. If the hashing function is + * changed, make sure this one is still used when the legacy parameter is + * true. + */ +u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) +{ + const u64 m = 0xc6a4a7935bd1e995; + u64 h = len * m; + const int r = 47; + u32 Step = (len / 8); + const u64 *data = (const u64 *)src; + const u64 *end = data + Step; + if(samples == 0) samples = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + while(data < end) + { + u64 k = data[0]; + data+=Step; + k *= m; + k ^= k >> r; + k *= m; + h ^= k; + h *= m; + } + + const u8 * data2 = (const u8*)end; + + switch(len & 7) + { + case 7: h ^= u64(data2[6]) << 48; + case 6: h ^= u64(data2[5]) << 40; + case 5: h ^= u64(data2[4]) << 32; + case 4: h ^= u64(data2[3]) << 24; + case 3: h ^= u64(data2[2]) << 16; + case 2: h ^= u64(data2[1]) << 8; + case 1: h ^= u64(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} +#else +// CRC32 hash using the SSE4.2 instruction +u64 GetCRC32(const u8 *src, int len, u32 samples) +{ +#if _M_SSE >= 0x402 + u32 h = len; + u32 Step = (len/4); + const u32 *data = (const u32 *)src; + const u32 *end = data + Step; + if(samples == 0) samples = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + while(data < end) + { + h = _mm_crc32_u32(h, data[0]); + data += Step; + } + + const u8 *data2 = (const u8*)end; + return (u64)_mm_crc32_u32(h, u32(data2[0])); +#else + return 0; +#endif +} + +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +inline u32 getblock(const u32 * p, int i) +{ + return p[i]; +} + +//---------- +// Finalization mix - force all bits of a hash block to avalanche + +// avalanches all bits to within 0.25% bias + +inline u32 fmix32(u32 h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2) +{ + k1 *= c1; + k1 = _rotl(k1,11); + k1 *= c2; + h1 ^= k1; + h1 += h2; + + h2 = _rotl(h2,17); + + k2 *= c2; + k2 = _rotl(k2,11); + k2 *= c1; + h2 ^= k2; + h2 += h1; + + h1 = h1*3+0x52dce729; + h2 = h2*3+0x38495ab5; + + c1 = c1*5+0x7b7d159c; + c2 = c2*5+0x6bce6396; +} + +//---------- + +u64 GetMurmurHash3(const u8* src, int len, u32 samples) +{ + const u8 * data = (const u8*)src; + u32 out[2]; + const int nblocks = len / 8; + u32 Step = (len / 4); + if(samples == 0) samples = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + + u32 h1 = 0x8de1c3ac; + u32 h2 = 0xbab98226; + + u32 c1 = 0x95543787; + u32 c2 = 0x2ad7eb25; + + //---------- + // body + + const u32 * blocks = (const u32 *)(data + nblocks*8); + + for(int i = -nblocks; i < 0; i+=Step) + { + u32 k1 = getblock(blocks,i*2+0); + u32 k2 = getblock(blocks,i*2+1); + + bmix32(h1,h2,k1,k2,c1,c2); + } + + //---------- + // tail + + const u8 * tail = (const u8*)(data + nblocks*8); + + u32 k1 = 0; + u32 k2 = 0; + + switch(len & 7) + { + case 7: k2 ^= tail[6] << 16; + case 6: k2 ^= tail[5] << 8; + case 5: k2 ^= tail[4] << 0; + case 4: k1 ^= tail[3] << 24; + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0] << 0; + bmix32(h1,h2,k1,k2,c1,c2); + }; + + //---------- + // finalization + + h2 ^= len; + + h1 += h2; + h2 += h1; + + h1 = fmix32(h1); + h2 = fmix32(h2); + + h1 += h2; + h2 += h1; + + out[0] = h1; + out[1] = h2; + + return *((u64 *)&out); +} + +/* + * FIXME: The old 32-bit version of this hash made different hashes than the + * 64-bit version. Until someone can make a new version of the 32-bit one that + * makes identical hashes, this is just a c/p of the 64-bit one. + */ +u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) +{ + const u64 m = 0xc6a4a7935bd1e995ULL; + u64 h = len * m; + const int r = 47; + u32 Step = (len / 8); + const u64 *data = (const u64 *)src; + const u64 *end = data + Step; + if(samples == 0) samples = max(Step, 1u); + Step = Step / samples; + if(Step < 1) Step = 1; + while(data < end) + { + u64 k = data[0]; + data+=Step; + k *= m; + k ^= k >> r; + k *= m; + h ^= k; + h *= m; + } + + const u8 * data2 = (const u8*)end; + + switch(len & 7) + { + case 7: h ^= u64(data2[6]) << 48; + case 6: h ^= u64(data2[5]) << 40; + case 5: h ^= u64(data2[4]) << 32; + case 4: h ^= u64(data2[3]) << 24; + case 3: h ^= u64(data2[2]) << 16; + case 2: h ^= u64(data2[1]) << 8; + case 1: h ^= u64(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} +#endif + +u64 GetHash64(const u8 *src, int len, u32 samples) +{ + return ptrHashFunction(src, len, samples); +} + +// sets the hash function used for the texture cache +void SetHash64Function(bool useHiresTextures) +{ + if (useHiresTextures) + { + ptrHashFunction = &GetHashHiresTexture; + } +#if _M_SSE >= 0x402 + else if (cpu_info.bSSE4_2 && !useHiresTextures) // sse crc32 version + { + ptrHashFunction = &GetCRC32; + } +#endif + else + { + ptrHashFunction = &GetMurmurHash3; + } +} + + + diff --git a/src/common/hash.h b/src/common/hash.h new file mode 100644 index 00000000..addfa4b5 --- /dev/null +++ b/src/common/hash.h @@ -0,0 +1,20 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _HASH_H_ +#define _HASH_H_ + +#include "common.h" + +u32 HashFletcher(const u8* data_u8, size_t length); // FAST. Length & 1 == 0. +u32 HashAdler32(const u8* data, size_t len); // Fairly accurate, slightly slower +u32 HashFNV(const u8* ptr, int length); // Another fast and decent hash +u32 HashEctor(const u8* ptr, int length); // JUNK. DO NOT USE FOR NEW THINGS +u64 GetCRC32(const u8 *src, int len, u32 samples); // SSE4.2 version of CRC32 +u64 GetHashHiresTexture(const u8 *src, int len, u32 samples); +u64 GetMurmurHash3(const u8 *src, int len, u32 samples); +u64 GetHash64(const u8 *src, int len, u32 samples); +void SetHash64Function(bool useHiresTextures); +#endif // _HASH_H_ diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h new file mode 100644 index 00000000..da5d6b9b --- /dev/null +++ b/src/common/linear_disk_cache.h @@ -0,0 +1,191 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _LINEAR_DISKCACHE +#define _LINEAR_DISKCACHE + +#include "common.h" +#include + +// defined in Version.cpp +extern const char *scm_rev_git_str; + +// On disk format: +//header{ +// u32 'DCAC'; +// u32 version; // svn_rev +// u16 sizeof(key_type); +// u16 sizeof(value_type); +//} + +//key_value_pair{ +// u32 value_size; +// key_type key; +// value_type[value_size] value; +//} + +template +class LinearDiskCacheReader +{ +public: + virtual void Read(const K &key, const V *value, u32 value_size) = 0; +}; + +// Dead simple unsorted key-value store with append functionality. +// No random read functionality, all reading is done in OpenAndRead. +// Keys and values can contain any characters, including \0. +// +// Suitable for caching generated shader bytecode between executions. +// Not tuned for extreme performance but should be reasonably fast. +// Does not support keys or values larger than 2GB, which should be reasonable. +// Keys must have non-zero length; values can have zero length. + +// K and V are some POD type +// K : the key type +// V : value array type +template +class LinearDiskCache +{ +public: + // return number of read entries + u32 OpenAndRead(const char *filename, LinearDiskCacheReader &reader) + { + using std::ios_base; + + // close any currently opened file + Close(); + m_num_entries = 0; + + // try opening for reading/writing + OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); + + m_file.seekg(0, std::ios::end); + std::fstream::pos_type end_pos = m_file.tellg(); + m_file.seekg(0, std::ios::beg); + std::fstream::pos_type start_pos = m_file.tellg(); + std::streamoff file_size = end_pos - start_pos; + + if (m_file.is_open() && ValidateHeader()) + { + // good header, read some key/value pairs + K key; + + V *value = NULL; + u32 value_size; + u32 entry_number; + + std::fstream::pos_type last_pos = m_file.tellg(); + + while (Read(&value_size)) + { + std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; + if (next_extent > file_size) + break; + + delete[] value; + value = new V[value_size]; + + // read key/value and pass to reader + if (Read(&key) && + Read(value, value_size) && + Read(&entry_number) && + entry_number == m_num_entries+1) + { + reader.Read(key, value, value_size); + } + else + { + break; + } + + m_num_entries++; + last_pos = m_file.tellg(); + } + m_file.seekp(last_pos); + m_file.clear(); + + delete[] value; + return m_num_entries; + } + + // failed to open file for reading or bad header + // close and recreate file + Close(); + m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); + WriteHeader(); + return 0; + } + + void Sync() + { + m_file.flush(); + } + + void Close() + { + if (m_file.is_open()) + m_file.close(); + // clear any error flags + m_file.clear(); + } + + // Appends a key-value pair to the store. + void Append(const K &key, const V *value, u32 value_size) + { + // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) + Write(&value_size); + Write(&key); + Write(value, value_size); + m_num_entries++; + Write(&m_num_entries); + } + +private: + void WriteHeader() + { + Write(&m_header); + } + + bool ValidateHeader() + { + char file_header[sizeof(Header)]; + + return (Read(file_header, sizeof(Header)) + && !memcmp((const char*)&m_header, file_header, sizeof(Header))); + } + + template + bool Write(const D *data, u32 count = 1) + { + return m_file.write((const char*)data, count * sizeof(D)).good(); + } + + template + bool Read(const D *data, u32 count = 1) + { + return m_file.read((char*)data, count * sizeof(D)).good(); + } + + struct Header + { + Header() + : id(*(u32*)"DCAC") + , key_t_size(sizeof(K)) + , value_t_size(sizeof(V)) + { + memcpy(ver, scm_rev_git_str, 40); + } + + const u32 id; + const u16 key_t_size, value_t_size; + char ver[40]; + + } m_header; + + std::fstream m_file; + u32 m_num_entries; +}; + +#endif // _LINEAR_DISKCACHE diff --git a/src/common/log.h b/src/common/log.h new file mode 100644 index 00000000..432a307f --- /dev/null +++ b/src/common/log.h @@ -0,0 +1,155 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _LOG_H_ +#define _LOG_H_ + +#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. +#define ERROR_LEVEL 2 // Critical errors +#define WARNING_LEVEL 3 // Something is suspicious. +#define INFO_LEVEL 4 // General information. +#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. + +namespace LogTypes +{ + +enum LOG_TYPE { + ACTIONREPLAY, + AUDIO, + AUDIO_INTERFACE, + BOOT, + COMMANDPROCESSOR, + COMMON, + CONSOLE, + DISCIO, + FILEMON, + DSPHLE, + DSPLLE, + DSP_MAIL, + DSPINTERFACE, + DVDINTERFACE, + DYNA_REC, + EXPANSIONINTERFACE, + GDB_STUB, + ARM11, + GPFIFO, + OSHLE, + MASTER_LOG, + MEMMAP, + MEMCARD_MANAGER, + OSREPORT, + PAD, + PROCESSORINTERFACE, + PIXELENGINE, + SERIALINTERFACE, + SP1, + STREAMINGINTERFACE, + VIDEO, + VIDEOINTERFACE, + LOADER, + FILESYS, + WII_IPC_DVD, + WII_IPC_ES, + WII_IPC_FILEIO, + WII_IPC_HID, + WII_IPC_HLE, + WII_IPC_NET, + WII_IPC_WC24, + WII_IPC_SSL, + RENDER, + LCD, + HW, + TIME, + NETPLAY, + + NUMBER_OF_LOGS // Must be last +}; + +// FIXME: should this be removed? +enum LOG_LEVELS { + LNOTICE = NOTICE_LEVEL, + LERROR = ERROR_LEVEL, + LWARNING = WARNING_LEVEL, + LINFO = INFO_LEVEL, + LDEBUG = DEBUG_LEVEL, +}; + +#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS +#define LOGTYPES_TYPE LogTypes::LOG_TYPE + +} // namespace + +void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, + const char *file, int line, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 5, 6))) +#endif + ; + +#if defined LOGGING || defined _DEBUG || defined DEBUGFAST +#define MAX_LOGLEVEL DEBUG_LEVEL +#else +#ifndef MAX_LOGLEVEL +#define MAX_LOGLEVEL WARNING_LEVEL +#endif // loglevel +#endif // logging + +#ifdef GEKKO +#define GENERIC_LOG(t, v, ...) +#else +// Let the compiler optimize this out +#define GENERIC_LOG(t, v, ...) { \ + if (v <= MAX_LOGLEVEL) \ + GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ + } +#endif + +#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) +#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) +#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) +#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0) +#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0) + +#if MAX_LOGLEVEL >= DEBUG_LEVEL +#define _dbg_assert_(_t_, _a_) \ + if (!(_a_)) {\ + ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \ + __LINE__, __FILE__, __TIME__); \ + if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \ + } +#define _dbg_assert_msg_(_t_, _a_, ...)\ + if (!(_a_)) {\ + ERROR_LOG(_t_, __VA_ARGS__); \ + if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ + } +#define _dbg_update_() Host_UpdateLogDisplay(); + +#else // not debug +#define _dbg_update_() ; + +#ifndef _dbg_assert_ +#define _dbg_assert_(_t_, _a_) {} +#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} +#endif // dbg_assert +#endif // MAX_LOGLEVEL DEBUG + +#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_) + +#ifndef GEKKO +#ifdef _WIN32 +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) {\ + if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ + } +#else // not win32 +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) {\ + if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ + } +#endif // WIN32 +#else // GEKKO +#define _assert_msg_(_t_, _a_, _fmt_, ...) +#endif + +#endif // _LOG_H_ diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp new file mode 100644 index 00000000..b5b03484 --- /dev/null +++ b/src/common/log_manager.cpp @@ -0,0 +1,200 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#ifdef ANDROID +#include "Host.h" +#endif +#include "log_manager.h" +#include "console_listener.h" +#include "timer.h" +#include "thread.h" +#include "file_util.h" + +void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (LogManager::GetInstance()) + LogManager::GetInstance()->Log(level, type, + file, line, fmt, args); + va_end(args); +} + +LogManager *LogManager::m_logManager = NULL; + +LogManager::LogManager() +{ + // create log files + m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); + m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); + m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); + m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); + m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); + m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); + m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); + m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); + m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt"); + m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt"); + m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); + m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); + m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); + m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); + m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); + m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); + m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); + m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); + m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); + m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); + m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11"); + m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); + m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); + m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); + m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); + m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); + m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); + m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT"); + m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); + m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); + m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing"); + m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader"); + m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); + m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); + m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); + m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); + m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); + m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); + m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); + m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); + m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); + m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); + m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); + m_Log[LogTypes::HW] = new LogContainer("HARDWARE", "HARDWARE"); + m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); + m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); + m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + + m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); + m_consoleLog = new ConsoleListener(); + m_debuggerLog = new DebuggerLogListener(); + + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_Log[i]->SetEnable(true); + m_Log[i]->AddListener(m_fileLog); + m_Log[i]->AddListener(m_consoleLog); +#ifdef _MSC_VER + if (IsDebuggerPresent()) + m_Log[i]->AddListener(m_debuggerLog); +#endif + } +} + +LogManager::~LogManager() +{ + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog); + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog); + m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog); + } + + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + delete m_Log[i]; + + delete m_fileLog; + delete m_consoleLog; + delete m_debuggerLog; +} + +void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char *format, va_list args) +{ + char temp[MAX_MSGLEN]; + char msg[MAX_MSGLEN * 2]; + LogContainer *log = m_Log[type]; + + if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) + return; + + CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); + + static const char level_to_char[7] = "-NEWID"; + sprintf(msg, "%s %s:%u %c[%s]: %s\n", + Common::Timer::GetTimeFormatted().c_str(), + file, line, level_to_char[(int)level], + log->GetShortName(), temp); +#ifdef ANDROID + Host_SysMessage(msg); +#endif + printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this + log->Trigger(level, msg); +} + +void LogManager::Init() +{ + m_logManager = new LogManager(); +} + +void LogManager::Shutdown() +{ + delete m_logManager; + m_logManager = NULL; +} + +LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable) + : m_enable(enable) +{ + strncpy(m_fullName, fullName, 128); + strncpy(m_shortName, shortName, 32); + m_level = LogTypes::LWARNING; +} + +// LogContainer +void LogContainer::AddListener(LogListener *listener) +{ + std::lock_guard lk(m_listeners_lock); + m_listeners.insert(listener); +} + +void LogContainer::RemoveListener(LogListener *listener) +{ + std::lock_guard lk(m_listeners_lock); + m_listeners.erase(listener); +} + +void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) +{ + std::lock_guard lk(m_listeners_lock); + + std::set::const_iterator i; + for (i = m_listeners.begin(); i != m_listeners.end(); ++i) + { + (*i)->Log(level, msg); + } +} + +FileLogListener::FileLogListener(const char *filename) +{ + OpenFStream(m_logfile, filename, std::ios::app); + SetEnable(true); +} + +void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) +{ + if (!IsEnabled() || !IsValid()) + return; + + std::lock_guard lk(m_log_lock); + m_logfile << msg << std::flush; +} + +void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) +{ +#if _MSC_VER + ::OutputDebugStringA(msg); +#endif +} diff --git a/src/common/log_manager.h b/src/common/log_manager.h new file mode 100644 index 00000000..579198ff --- /dev/null +++ b/src/common/log_manager.h @@ -0,0 +1,169 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _LOGMANAGER_H_ +#define _LOGMANAGER_H_ + +#include "log.h" +#include "string_util.h" +#include "thread.h" +#include "file_util.h" + +#include +#include + +#define MAX_MESSAGES 8000 +#define MAX_MSGLEN 1024 + + +// pure virtual interface +class LogListener +{ +public: + virtual ~LogListener() {} + + virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0; +}; + +class FileLogListener : public LogListener +{ +public: + FileLogListener(const char *filename); + + void Log(LogTypes::LOG_LEVELS, const char *msg); + + bool IsValid() { return !m_logfile.fail(); } + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + + const char* GetName() const { return "file"; } + +private: + std::mutex m_log_lock; + std::ofstream m_logfile; + bool m_enable; +}; + +class DebuggerLogListener : public LogListener +{ +public: + void Log(LogTypes::LOG_LEVELS, const char *msg); +}; + +class LogContainer +{ +public: + LogContainer(const char* shortName, const char* fullName, bool enable = false); + + const char* GetShortName() const { return m_shortName; } + const char* GetFullName() const { return m_fullName; } + + void AddListener(LogListener* listener); + void RemoveListener(LogListener* listener); + + void Trigger(LogTypes::LOG_LEVELS, const char *msg); + + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + + LogTypes::LOG_LEVELS GetLevel() const { return m_level; } + + void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } + + bool HasListeners() const { return !m_listeners.empty(); } + +private: + char m_fullName[128]; + char m_shortName[32]; + bool m_enable; + LogTypes::LOG_LEVELS m_level; + std::mutex m_listeners_lock; + std::set m_listeners; +}; + +class ConsoleListener; + +class LogManager : NonCopyable +{ +private: + LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; + FileLogListener *m_fileLog; + ConsoleListener *m_consoleLog; + DebuggerLogListener *m_debuggerLog; + static LogManager *m_logManager; // Singleton. Ugh. + + LogManager(); + ~LogManager(); +public: + + static u32 GetMaxLevel() { return MAX_LOGLEVEL; } + + void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char *file, int line, const char *fmt, va_list args); + + void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) + { + m_Log[type]->SetLevel(level); + } + + void SetEnable(LogTypes::LOG_TYPE type, bool enable) + { + m_Log[type]->SetEnable(enable); + } + + bool IsEnabled(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->IsEnabled(); + } + + const char* GetShortName(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->GetShortName(); + } + + const char* GetFullName(LogTypes::LOG_TYPE type) const + { + return m_Log[type]->GetFullName(); + } + + void AddListener(LogTypes::LOG_TYPE type, LogListener *listener) + { + m_Log[type]->AddListener(listener); + } + + void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener) + { + m_Log[type]->RemoveListener(listener); + } + + FileLogListener *GetFileListener() const + { + return m_fileLog; + } + + ConsoleListener *GetConsoleListener() const + { + return m_consoleLog; + } + + DebuggerLogListener *GetDebuggerListener() const + { + return m_debuggerLog; + } + + static LogManager* GetInstance() + { + return m_logManager; + } + + static void SetInstance(LogManager *logManager) + { + m_logManager = logManager; + } + + static void Init(); + static void Shutdown(); +}; + +#endif // _LOGMANAGER_H_ diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp new file mode 100644 index 00000000..da90f8d7 --- /dev/null +++ b/src/common/math_util.cpp @@ -0,0 +1,212 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "math_util.h" + +#include +#include + +namespace MathUtil +{ + +u32 ClassifyDouble(double dvalue) +{ + // TODO: Optimize the below to be as fast as possible. + IntDouble value; + value.d = dvalue; + u64 sign = value.i & DOUBLE_SIGN; + u64 exp = value.i & DOUBLE_EXP; + if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) + { + // Nice normalized number. + return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; + } + else + { + u64 mantissa = value.i & DOUBLE_FRAC; + if (mantissa) + { + if (exp) + { + return PPC_FPCLASS_QNAN; + } + else + { + // Denormalized number. + return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + } + } + else if (exp) + { + //Infinite + return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; + } + else + { + //Zero + return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; + } + } +} + +u32 ClassifyFloat(float fvalue) +{ + // TODO: Optimize the below to be as fast as possible. + IntFloat value; + value.f = fvalue; + u32 sign = value.i & FLOAT_SIGN; + u32 exp = value.i & FLOAT_EXP; + if (exp > FLOAT_ZERO && exp < FLOAT_EXP) + { + // Nice normalized number. + return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; + } + else + { + u32 mantissa = value.i & FLOAT_FRAC; + if (mantissa) + { + if (exp) + { + return PPC_FPCLASS_QNAN; // Quiet NAN + } + else + { + // Denormalized number. + return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + } + } + else if (exp) + { + // Infinite + return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; + } + else + { + //Zero + return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; + } + } +} + + +} // namespace + +inline void MatrixMul(int n, const float *a, const float *b, float *result) +{ + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) + { + float temp = 0; + for (int k = 0; k < n; ++k) + { + temp += a[i * n + k] * b[k * n + j]; + } + result[i * n + j] = temp; + } + } +} + +// Calculate sum of a float list +float MathFloatVectorSum(const std::vector& Vec) +{ + return std::accumulate(Vec.begin(), Vec.end(), 0.0f); +} + +void Matrix33::LoadIdentity(Matrix33 &mtx) +{ + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[4] = 1.0f; + mtx.data[8] = 1.0f; +} + +void Matrix33::RotateX(Matrix33 &mtx, float rad) +{ + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1; + mtx.data[4] = c; + mtx.data[5] = -s; + mtx.data[7] = s; + mtx.data[8] = c; +} +void Matrix33::RotateY(Matrix33 &mtx, float rad) +{ + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = c; + mtx.data[2] = s; + mtx.data[4] = 1; + mtx.data[6] = -s; + mtx.data[8] = c; +} + +void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result) +{ + MatrixMul(3, a.data, b.data, result.data); +} + +void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3]) +{ + for (int i = 0; i < 3; ++i) { + result[i] = 0; + for (int k = 0; k < 3; ++k) { + result[i] += a.data[i * 3 + k] * vec[k]; + } + } +} + +void Matrix44::LoadIdentity(Matrix44 &mtx) +{ + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[5] = 1.0f; + mtx.data[10] = 1.0f; + mtx.data[15] = 1.0f; +} + +void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33) +{ + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + mtx.data[i * 4 + j] = m33.data[i * 3 + j]; + } + } + + for (int i = 0; i < 3; ++i) + { + mtx.data[i * 4 + 3] = 0; + mtx.data[i + 12] = 0; + } + mtx.data[15] = 1.0f; +} + +void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16]) +{ + for(int i = 0; i < 16; ++i) { + mtx.data[i] = mtxArray[i]; + } +} + +void Matrix44::Translate(Matrix44 &mtx, const float vec[3]) +{ + LoadIdentity(mtx); + mtx.data[3] = vec[0]; + mtx.data[7] = vec[1]; + mtx.data[11] = vec[2]; +} + +void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) +{ + MatrixMul(4, a.data, b.data, result.data); +} + diff --git a/src/common/math_util.h b/src/common/math_util.h new file mode 100644 index 00000000..4410c5e0 --- /dev/null +++ b/src/common/math_util.h @@ -0,0 +1,200 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _MATH_UTIL_H_ +#define _MATH_UTIL_H_ + +#include "common.h" + +#include + +namespace MathUtil +{ + +static const u64 DOUBLE_SIGN = 0x8000000000000000ULL, + DOUBLE_EXP = 0x7FF0000000000000ULL, + DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL, + DOUBLE_ZERO = 0x0000000000000000ULL; + +static const u32 FLOAT_SIGN = 0x80000000, + FLOAT_EXP = 0x7F800000, + FLOAT_FRAC = 0x007FFFFF, + FLOAT_ZERO = 0x00000000; + +union IntDouble { + double d; + u64 i; +}; +union IntFloat { + float f; + u32 i; +}; + +inline bool IsNAN(double d) +{ + IntDouble x; x.d = d; + return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + +inline bool IsQNAN(double d) +{ + IntDouble x; x.d = d; + return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) && + ((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) ); +} + +inline bool IsSNAN(double d) +{ + IntDouble x; x.d = d; + return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) ); +} + +inline float FlushToZero(float f) +{ + IntFloat x; x.f = f; + if ((x.i & FLOAT_EXP) == 0) + x.i &= FLOAT_SIGN; // turn into signed zero + return x.f; +} + +inline double FlushToZeroAsFloat(double d) +{ + IntDouble x; x.d = d; + if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL) + x.i &= DOUBLE_SIGN; // turn into signed zero + return x.d; +} + +enum PPCFpClass +{ + PPC_FPCLASS_QNAN = 0x11, + PPC_FPCLASS_NINF = 0x9, + PPC_FPCLASS_NN = 0x8, + PPC_FPCLASS_ND = 0x18, + PPC_FPCLASS_NZ = 0x12, + PPC_FPCLASS_PZ = 0x2, + PPC_FPCLASS_PD = 0x14, + PPC_FPCLASS_PN = 0x4, + PPC_FPCLASS_PINF = 0x5, +}; + +// Uses PowerPC conventions for the return value, so it can be easily +// used directly in CPU emulation. +u32 ClassifyDouble(double dvalue); +// More efficient float version. +u32 ClassifyFloat(float fvalue); + +template +struct Rectangle +{ + T left; + T top; + T right; + T bottom; + + Rectangle() + { } + + Rectangle(T theLeft, T theTop, T theRight, T theBottom) + : left(theLeft), top(theTop), right(theRight), bottom(theBottom) + { } + + bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } + + T GetWidth() const { return abs(right - left); } + T GetHeight() const { return abs(bottom - top); } + + // If the rectangle is in a coordinate system with a lower-left origin, use + // this Clamp. + void ClampLL(T x1, T y1, T x2, T y2) + { + if (left < x1) left = x1; + if (right > x2) right = x2; + if (top > y1) top = y1; + if (bottom < y2) bottom = y2; + } + + // If the rectangle is in a coordinate system with an upper-left origin, + // use this Clamp. + void ClampUL(T x1, T y1, T x2, T y2) + { + if (left < x1) left = x1; + if (right > x2) right = x2; + if (top < y1) top = y1; + if (bottom > y2) bottom = y2; + } +}; + +} // namespace MathUtil + +inline float pow2f(float x) {return x * x;} +inline double pow2(double x) {return x * x;} + +float MathFloatVectorSum(const std::vector&); + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) + +// Rounds down. 0 -> undefined +inline u64 Log2(u64 val) +{ +#if defined(__GNUC__) + return 63 - __builtin_clzll(val); + +#elif defined(_MSC_VER) && defined(_M_X64) + unsigned long result = -1; + _BitScanReverse64(&result, val); + return result; + +#else + u64 result = -1; + while (val != 0) + { + val >>= 1; + ++result; + } + return result; +#endif +} + +// Tiny matrix/vector library. +// Used for things like Free-Look in the gfx backend. + +class Matrix33 +{ +public: + static void LoadIdentity(Matrix33 &mtx); + + // set mtx to be a rotation matrix around the x axis + static void RotateX(Matrix33 &mtx, float rad); + // set mtx to be a rotation matrix around the y axis + static void RotateY(Matrix33 &mtx, float rad); + + // set result = a x b + static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); + static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); + + float data[9]; +}; + +class Matrix44 +{ +public: + static void LoadIdentity(Matrix44 &mtx); + static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); + static void Set(Matrix44 &mtx, const float mtxArray[16]); + + static void Translate(Matrix44 &mtx, const float vec[3]); + + static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); + + float data[16]; +}; + +#endif // _MATH_UTIL_H_ diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp new file mode 100644 index 00000000..1a6fcf44 --- /dev/null +++ b/src/common/mem_arena.cpp @@ -0,0 +1,477 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "memory_util.h" +#include "mem_arena.h" + +#ifdef _WIN32 +//#include "CommonWindows.h" +#else +#include +#include +#include +#include +#include +#ifdef ANDROID +#include +#include +#endif +#endif + +#ifdef IOS +void* globalbase = NULL; +#endif + +#ifdef ANDROID + +// Hopefully this ABI will never change... + + +#define ASHMEM_DEVICE "/dev/ashmem" + +/* +* ashmem_create_region - creates a new ashmem region and returns the file +* descriptor, or <0 on error +* +* `name' is an optional label to give the region (visible in /proc/pid/maps) +* `size' is the size of the region, in page-aligned bytes +*/ +int ashmem_create_region(const char *name, size_t size) +{ + int fd, ret; + + fd = open(ASHMEM_DEVICE, O_RDWR); + if (fd < 0) + return fd; + + if (name) { + char buf[ASHMEM_NAME_LEN]; + + strncpy(buf, name, sizeof(buf)); + ret = ioctl(fd, ASHMEM_SET_NAME, buf); + if (ret < 0) + goto error; + } + + ret = ioctl(fd, ASHMEM_SET_SIZE, size); + if (ret < 0) + goto error; + + return fd; + +error: + ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret); + close(fd); + return ret; +} + +int ashmem_set_prot_region(int fd, int prot) +{ + return ioctl(fd, ASHMEM_SET_PROT_MASK, prot); +} + +int ashmem_pin_region(int fd, size_t offset, size_t len) +{ + struct ashmem_pin pin = { offset, len }; + return ioctl(fd, ASHMEM_PIN, &pin); +} + +int ashmem_unpin_region(int fd, size_t offset, size_t len) +{ + struct ashmem_pin pin = { offset, len }; + return ioctl(fd, ASHMEM_UNPIN, &pin); +} +#endif // Android + + + +#ifndef _WIN32 +// do not make this "static" +#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) +std::string ram_temp_file = "/home/user/gc_mem.tmp"; +#else +std::string ram_temp_file = "/tmp/gc_mem.tmp"; +#endif +#elif !defined(_XBOX) +SYSTEM_INFO sysInfo; +#endif + + +// Windows mappings need to be on 64K boundaries, due to Alpha legacy. +#ifdef _WIN32 +size_t roundup(size_t x) { +#ifndef _XBOX + int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; +#else + int gran = 0x10000; // 64k in 360 +#endif + return (x + gran - 1) & ~(gran - 1); +} +#else +size_t roundup(size_t x) { + return x; +} +#endif + + +void MemArena::GrabLowMemSpace(size_t size) +{ +#ifdef _WIN32 +#ifndef _XBOX + hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); + GetSystemInfo(&sysInfo); +#endif +#elif defined(ANDROID) + // Use ashmem so we don't have to allocate a file on disk! + fd = ashmem_create_region("PPSSPP_RAM", size); + // Note that it appears that ashmem is pinned by default, so no need to pin. + if (fd < 0) + { + ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); + return; + } +#else + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); + if (fd < 0) + { + ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno)); + return; + } + // delete immediately, we keep the fd so it still lives + unlink(ram_temp_file.c_str()); + if (ftruncate(fd, size) != 0) + { + ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size); + } + return; +#endif +} + + +void MemArena::ReleaseSpace() +{ +#ifdef _WIN32 + CloseHandle(hMemoryMapping); + hMemoryMapping = 0; +#elif defined(__SYMBIAN32__) + memmap->Close(); + delete memmap; +#else + close(fd); +#endif +} + + +void *MemArena::CreateView(s64 offset, size_t size, void *base) +{ +#ifdef _WIN32 +#ifdef _XBOX + size = roundup(size); + // use 64kb pages + void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + return ptr; +#else + size = roundup(size); + void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); + return ptr; +#endif +#else + void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | + // Do not sync memory to underlying file. Linux has this by default. +#ifdef BLACKBERRY + MAP_NOSYNCFILE | +#elif defined(__FreeBSD__) + MAP_NOSYNC | +#endif + ((base == 0) ? 0 : MAP_FIXED), fd, offset); + + if (retval == MAP_FAILED) + { + NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd); + return 0; + } + return retval; +#endif +} + + +void MemArena::ReleaseView(void* view, size_t size) +{ +#ifdef _WIN32 +#ifndef _XBOX + UnmapViewOfFile(view); +#endif +#elif defined(__SYMBIAN32__) + memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); +#else + munmap(view, size); +#endif +} + +#ifndef __SYMBIAN32__ +u8* MemArena::Find4GBBase() +{ +#ifdef _M_X64 +#ifdef _WIN32 + // 64 bit + u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE); + VirtualFree(base, 0, MEM_RELEASE); + return base; +#else + // Very precarious - mmap cannot return an error when trying to map already used pages. + // This makes the Windows approach above unusable on Linux, so we will simply pray... + return reinterpret_cast(0x2300000000ULL); +#endif + +#else // 32 bit + +#ifdef _WIN32 + u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE); + if (base) { + VirtualFree(base, 0, MEM_RELEASE); + } + return base; +#else +#ifdef IOS + void* base = NULL; + if (globalbase == NULL){ + base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0); + if (base == MAP_FAILED) { + PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno)); + return 0; + } + munmap(base, 0x08000000); + globalbase = base; + } + else{ base = globalbase; } +#else + void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0); + if (base == MAP_FAILED) { + PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); + return 0; + } + munmap(base, 0x10000000); +#endif + return static_cast(base); +#endif +#endif +} +#endif + + +// yeah, this could also be done in like two bitwise ops... +#define SKIP(a_flags, b_flags) +// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) +// continue; +// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) +// continue; + +static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { + // OK, we know where to find free space. Now grab it! + // We just mimic the popular BAT setup. + size_t position = 0; + size_t last_position = 0; + +#if defined(_XBOX) + void *ptr; +#endif + + // Zero all the pointers to be sure. + for (int i = 0; i < num_views; i++) + { + if (views[i].out_ptr_low) + *views[i].out_ptr_low = 0; + if (views[i].out_ptr) + *views[i].out_ptr = 0; + } + + int i; + for (i = 0; i < num_views; i++) + { + const MemoryView &view = views[i]; + if (view.size == 0) + continue; + SKIP(flags, view.flags); + if (view.flags & MV_MIRROR_PREVIOUS) { + position = last_position; + } + else { +#ifdef __SYMBIAN32__ + *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); + arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + } + *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); +#elif defined(_XBOX) + *(view.out_ptr_low) = (u8*)(base + view.virtual_address); + //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); + } + *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); +#else + *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size); + if (!*view.out_ptr_low) + goto bail; + } +#ifdef _M_X64 + *view.out_ptr = (u8*)arena->CreateView( + position, view.size, base + view.virtual_address); +#else + if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical. + // No need to create multiple identical views. + *view.out_ptr = *views[i - 1].out_ptr; + } + else { + *view.out_ptr = (u8*)arena->CreateView( + position, view.size, base + (view.virtual_address & 0x3FFFFFFF)); + if (!*view.out_ptr) + goto bail; + } +#endif + +#endif + last_position = position; + position += roundup(view.size); + } + + return true; + +bail: + // Argh! ERROR! Free what we grabbed so far so we can try again. + for (int j = 0; j <= i; j++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if (views[j].out_ptr_low && *views[j].out_ptr_low) + { + arena->ReleaseView(*views[j].out_ptr_low, views[j].size); + *views[j].out_ptr_low = NULL; + } + if (*views[j].out_ptr) + { +#ifdef _M_X64 + arena->ReleaseView(*views[j].out_ptr, views[j].size); +#else + if (!(views[j].flags & MV_MIRROR_PREVIOUS)) + { + arena->ReleaseView(*views[j].out_ptr, views[j].size); + } +#endif + *views[j].out_ptr = NULL; + } + } + return false; +} + +u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) +{ + size_t total_mem = 0; + int base_attempts = 0; + + for (int i = 0; i < num_views; i++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) + total_mem += roundup(views[i].size); + } + // Grab some pagefile backed memory out of the void ... +#ifndef __SYMBIAN32__ + arena->GrabLowMemSpace(total_mem); +#endif + + // Now, create views in high memory where there's plenty of space. +#ifdef _M_X64 + u8 *base = MemArena::Find4GBBase(); + // This really shouldn't fail - in 64-bit, there will always be enough + // address space. + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } +#elif defined(_XBOX) + // Reserve 256MB + u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return 0; + } +#elif defined(_WIN32) + // Try a whole range of possible bases. Return once we got a valid one. + u32 max_base_addr = 0x7FFF0000 - 0x10000000; + u8 *base = NULL; + + for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) + { + base_attempts++; + base = (u8 *)base_addr; + if (Memory_TryBase(base, views, num_views, flags, arena)) + { + INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); + base_attempts = 0; + break; + } + } +#elif defined(__SYMBIAN32__) + arena->memmap = new RChunk(); + arena->memmap->CreateDisconnectedLocal(0, 0, 0x10000000); + if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } + u8* base = arena->memmap->Base(); +#else + // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. + u8 *base = MemArena::Find4GBBase(); + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + return 0; + } +#endif + if (base_attempts) + PanicAlert("No possible memory base pointer found!"); + return base; +} + +void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) +{ + for (int i = 0; i < num_views; i++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if (views[i].out_ptr_low && *views[i].out_ptr_low) + arena->ReleaseView(*views[i].out_ptr_low, views[i].size); + if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) + arena->ReleaseView(*views[i].out_ptr, views[i].size); + *views[i].out_ptr = NULL; + if (views[i].out_ptr_low) + *views[i].out_ptr_low = NULL; + } +} diff --git a/src/common/mem_arena.h b/src/common/mem_arena.h new file mode 100644 index 00000000..8bdf9f18 --- /dev/null +++ b/src/common/mem_arena.h @@ -0,0 +1,81 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _MEMARENA_H_ +#define _MEMARENA_H_ + +#ifdef _WIN32 +#include +#endif + +#ifdef __SYMBIAN32__ +#include +#endif + +#include "common.h" + +// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. +// Multiple views can mirror the same section of the block, which makes it very convient for emulating +// memory mirrors. + +class MemArena +{ +public: + void GrabLowMemSpace(size_t size); + void ReleaseSpace(); + void *CreateView(s64 offset, size_t size, void *base = 0); + void ReleaseView(void *view, size_t size); + +#ifdef __SYMBIAN32__ + RChunk* memmap; +#else + // This only finds 1 GB in 32-bit + static u8 *Find4GBBase(); +#endif +private: + +#ifdef _WIN32 + HANDLE hMemoryMapping; +#else + int fd; +#endif +}; + +enum { + MV_MIRROR_PREVIOUS = 1, + // MV_FAKE_VMEM = 2, + // MV_WII_ONLY = 4, + MV_IS_PRIMARY_RAM = 0x100, + MV_IS_EXTRA1_RAM = 0x200, + MV_IS_EXTRA2_RAM = 0x400, +}; + +struct MemoryView +{ + u8 **out_ptr_low; + u8 **out_ptr; + u32 virtual_address; + u32 size; + u32 flags; +}; + +// Uses a memory arena to set up an emulator-friendly memory map according to +// a passed-in list of MemoryView structures. +u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena); +void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena); + +#endif // _MEMARENA_H_ diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp new file mode 100644 index 00000000..cc6e77b3 --- /dev/null +++ b/src/common/memory_util.cpp @@ -0,0 +1,197 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#include "common.h" +#include "memory_util.h" +#include "string_util.h" + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) +#include +#define PAGE_MASK (getpagesize() - 1) +#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) +#endif + +// This is purposely not a full wrapper for virtualalloc/mmap, but it +// provides exactly the primitive operations that Dolphin needs. + +void* AllocateExecutableMemory(size_t size, bool low) +{ +#if defined(_WIN32) + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + static char *map_hint = 0; +#if defined(__x86_64__) && !defined(MAP_32BIT) + // This OS has no flag to enforce allocation below the 4 GB boundary, + // but if we hint that we want a low address it is very likely we will + // get one. + // An older version of this code used MAP_FIXED, but that has the side + // effect of discarding already mapped pages that happen to be in the + // requested virtual memory range (such as the emulated RAM, sometimes). + if (low && (!map_hint)) + map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ +#endif + void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANON | MAP_PRIVATE +#if defined(__x86_64__) && defined(MAP_32BIT) + | (low ? MAP_32BIT : 0) +#endif + , -1, 0); +#endif /* defined(_WIN32) */ + + // printf("Mapped executable memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + +#if defined(__FreeBSD__) + if (ptr == MAP_FAILED) + { + ptr = NULL; +#else + if (ptr == NULL) + { +#endif + PanicAlert("Failed to allocate executable memory"); + } +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) + else + { + if (low) + { + map_hint += size; + map_hint = (char*)round_page(map_hint); /* round up to the next page */ + // printf("Next map will (hopefully) be at %p\n", map_hint); + } + } +#endif + +#if defined(_M_X64) + if ((u64)ptr >= 0x80000000 && low == true) + PanicAlert("Executable memory ended up above 2GB!"); +#endif + + return ptr; +} + +void* AllocateMemoryPages(size_t size) +{ +#ifdef _WIN32 + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +#else + void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + + // printf("Mapped memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + + if (ptr == NULL) + PanicAlert("Failed to allocate raw memory"); + + return ptr; +} + +void* AllocateAlignedMemory(size_t size,size_t alignment) +{ +#ifdef _WIN32 + void* ptr = _aligned_malloc(size,alignment); +#else + void* ptr = NULL; +#ifdef ANDROID + ptr = memalign(alignment, size); +#else + if (posix_memalign(&ptr, alignment, size) != 0) + ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); +#endif +#endif + + // printf("Mapped memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + + if (ptr == NULL) + PanicAlert("Failed to allocate aligned memory"); + + return ptr; +} + +void FreeMemoryPages(void* ptr, size_t size) +{ + if (ptr) + { +#ifdef _WIN32 + + if (!VirtualFree(ptr, 0, MEM_RELEASE)) + PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); + ptr = NULL; // Is this our responsibility? + +#else + munmap(ptr, size); +#endif + } +} + +void FreeAlignedMemory(void* ptr) +{ + if (ptr) + { +#ifdef _WIN32 + _aligned_free(ptr); +#else + free(ptr); +#endif + } +} + +void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +#ifdef _WIN32 + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) + PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); +#else + mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); +#endif +} + +void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) +{ +#ifdef _WIN32 + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) + PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); +#else + mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); +#endif +} + +std::string MemUsage() +{ +#ifdef _WIN32 +#pragma comment(lib, "psapi") + DWORD processID = GetCurrentProcessId(); + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + std::string Ret; + + // Print information about the memory usage of the process. + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + if (NULL == hProcess) return "MemUsage Error"; + + if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) + Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); + + CloseHandle(hProcess); + return Ret; +#else + return ""; +#endif +} diff --git a/src/common/memory_util.h b/src/common/memory_util.h new file mode 100644 index 00000000..49b2589d --- /dev/null +++ b/src/common/memory_util.h @@ -0,0 +1,25 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +#ifndef _MEMORYUTIL_H +#define _MEMORYUTIL_H + +#ifndef _WIN32 +#include +#endif +#include + +void* AllocateExecutableMemory(size_t size, bool low = true); +void* AllocateMemoryPages(size_t size); +void FreeMemoryPages(void* ptr, size_t size); +void* AllocateAlignedMemory(size_t size,size_t alignment); +void FreeAlignedMemory(void* ptr); +void WriteProtectMemory(void* ptr, size_t size, bool executable = false); +void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); +std::string MemUsage(); + +inline int GetPageSize() { return 4096; } + +#endif diff --git a/src/common/misc.cpp b/src/common/misc.cpp new file mode 100644 index 00000000..93580547 --- /dev/null +++ b/src/common/misc.cpp @@ -0,0 +1,37 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" + +#ifdef _WIN32 +#include +#endif + +// Neither Android nor OS X support TLS +#if defined(__APPLE__) || (ANDROID && __clang__) +#define __thread +#endif + +// Generic function to get last error message. +// Call directly after the command or use the error num. +// This function might change the error code. +const char* GetLastErrorMsg() +{ + static const size_t buff_size = 255; + +#ifdef _WIN32 + static __declspec(thread) char err_str[buff_size] = {}; + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + err_str, buff_size, NULL); +#else + static __thread char err_str[buff_size] = {}; + + // Thread safe (XSI-compliant) + strerror_r(errno, err_str, buff_size); +#endif + + return err_str; +} diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp new file mode 100644 index 00000000..8e9fe218 --- /dev/null +++ b/src/common/msg_handler.cpp @@ -0,0 +1,107 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include // System + +#include "common.h" // Local +#include "string_util.h" + +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); +static MsgAlertHandler msg_handler = DefaultMsgHandler; +static bool AlertEnabled = true; + +std::string DefaultStringTranslator(const char* text); +static StringTranslator str_translator = DefaultStringTranslator; + +// Select which of these functions that are used for message boxes. If +// wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp +void RegisterMsgAlertHandler(MsgAlertHandler handler) +{ + msg_handler = handler; +} + +// Select translation function. For wxWidgets use wxStringTranslator in Main.cpp +void RegisterStringTranslator(StringTranslator translator) +{ + str_translator = translator; +} + +// enable/disable the alert handler +void SetEnableAlert(bool enable) +{ + AlertEnabled = enable; +} + +// This is the first stop for gui alerts where the log is updated and the +// correct window is shown +bool MsgAlert(bool yes_no, int Style, const char* format, ...) +{ + // Read message and write it to the log + std::string caption; + char buffer[2048]; + + static std::string info_caption; + static std::string warn_caption; + static std::string ques_caption; + static std::string crit_caption; + + if (!info_caption.length()) + { + info_caption = str_translator(_trans("Information")); + ques_caption = str_translator(_trans("Question")); + warn_caption = str_translator(_trans("Warning")); + crit_caption = str_translator(_trans("Critical")); + } + + switch(Style) + { + case INFORMATION: + caption = info_caption; + break; + case QUESTION: + caption = ques_caption; + break; + case WARNING: + caption = warn_caption; + break; + case CRITICAL: + caption = crit_caption; + break; + } + + va_list args; + va_start(args, format); + CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); + va_end(args); + + ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); + + // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored + if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) + return msg_handler(caption.c_str(), buffer, yes_no, Style); + + return true; +} + +// Default non library dependent panic alert +bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) +{ +//#ifdef _WIN32 +// int STYLE = MB_ICONINFORMATION; +// if (Style == QUESTION) STYLE = MB_ICONQUESTION; +// if (Style == WARNING) STYLE = MB_ICONWARNING; +// +// return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); +//#else + printf("%s\n", text); + return true; +//#endif +} + +// Default (non) translator +std::string DefaultStringTranslator(const char* text) +{ + return text; +} + diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h new file mode 100644 index 00000000..bde2808f --- /dev/null +++ b/src/common/msg_handler.h @@ -0,0 +1,73 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _MSGHANDLER_H_ +#define _MSGHANDLER_H_ + +#include + +// Message alerts +enum MSG_TYPE +{ + INFORMATION, + QUESTION, + WARNING, + CRITICAL +}; + +typedef bool (*MsgAlertHandler)(const char* caption, const char* text, + bool yes_no, int Style); +typedef std::string (*StringTranslator)(const char* text); + +void RegisterMsgAlertHandler(MsgAlertHandler handler); +void RegisterStringTranslator(StringTranslator translator); + +extern bool MsgAlert(bool yes_no, int Style, const char* format, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) +#endif + ; +void SetEnableAlert(bool enable); + +#ifndef GEKKO +#ifdef _WIN32 + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) + // Use these macros (that do the same thing) if the message should be translated. + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) +#else + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) + // Use these macros (that do the same thing) if the message should be translated. + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) +#endif +#else +// GEKKO + #define SuccessAlert(format, ...) ; + #define PanicAlert(format, ...) ; + #define PanicYesNo(format, ...) ; + #define AskYesNo(format, ...) ; + #define CriticalAlert(format, ...) ; + #define SuccessAlertT(format, ...) ; + #define PanicAlertT(format, ...) ; + #define PanicYesNoT(format, ...) ; + #define AskYesNoT(format, ...) ; + #define CriticalAlertT(format, ...) ; +#endif + +#endif // _MSGHANDLER_H_ diff --git a/src/common/platform.h b/src/common/platform.h new file mode 100644 index 00000000..84c6b636 --- /dev/null +++ b/src/common/platform.h @@ -0,0 +1,142 @@ +/** + * Copyright (C) 2005-2012 Gekko Emulator + * + * @file platform.h + * @author ShizZy + * @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 "common_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 + +#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 + +#include + +#define NOMINMAX +#define EMU_FASTCALL __fastcall + +inline struct tm* localtime_r(const time_t *clock, struct tm *result) { + if (localtime_s(result, clock) == 0) + return result; + return NULL; +} + +#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 +#define MAX_PATH PATH_MAX + +#include +#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/scm_rev.h b/src/common/scm_rev.h new file mode 100644 index 00000000..69962c58 --- /dev/null +++ b/src/common/scm_rev.h @@ -0,0 +1,4 @@ +#define SCM_REV_STR "a7b06698ff012aa7b1094414e796ffae1ca1eb4d" +#define SCM_DESC_STR "a7b0669" +#define SCM_BRANCH_STR "master" +#define SCM_IS_MASTER 1 diff --git a/src/common/src/atomic.h b/src/common/src/atomic.h deleted file mode 100644 index 883bc14f..00000000 --- a/src/common/src/atomic.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_H_ -#define _ATOMIC_H_ - -#ifdef _WIN32 - -#include "atomic_win32.h" - -#else - -// GCC-compatible compiler assumed! -#include "atomic_gcc.h" - -#endif - -#endif diff --git a/src/common/src/atomic_gcc.h b/src/common/src/atomic_gcc.h deleted file mode 100644 index 2eb38697..00000000 --- a/src/common/src/atomic_gcc.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_GCC_H_ -#define _ATOMIC_GCC_H_ - -#include "common.h" - -// Atomic operations are performed in a single step by the CPU. It is -// impossible for other threads to see the operation "half-done." -// -// Some atomic operations can be combined with different types of memory -// barriers called "Acquire semantics" and "Release semantics", defined below. -// -// Acquire semantics: Future memory accesses cannot be relocated to before the -// operation. -// -// Release semantics: Past memory accesses cannot be relocated to after the -// operation. -// -// These barriers affect not only the compiler, but also the CPU. - -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; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - //keep the compiler from caching any memory references - u32 result = src; // 32-bit reads are always atomic. - //__sync_synchronize(); // TODO: May not be necessary. - // Compiler instruction only. x86 loads always have acquire semantics. - __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; // 32-bit writes are always atomic. -} -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. -} - -} - -// Old code kept here for reference in case we need the parts with __asm__ __volatile__. -#if 0 -LONG SyncInterlockedIncrement(LONG *Dest) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_add_and_fetch(Dest, 1); -#else - register int result; - __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (1), "m" (*Dest) - : "memory"); - return result; -#endif -} - -LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_add_and_fetch(Dest, Val); -#else - register int result; - __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); - return result; -#endif -} - -LONG SyncInterlockedExchange(LONG *Dest, LONG Val) -{ -#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__)) - return __sync_lock_test_and_set(Dest, Val); -#else - register int result; - __asm__ __volatile__("lock; xchg %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); - return result; -#endif -} -#endif - -#endif diff --git a/src/common/src/atomic_win32.h b/src/common/src/atomic_win32.h deleted file mode 100644 index 760b16d4..00000000 --- a/src/common/src/atomic_win32.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _ATOMIC_WIN32_H_ -#define _ATOMIC_WIN32_H_ - -#include "common.h" -#include -#include - -// Atomic operations are performed in a single step by the CPU. It is -// impossible for other threads to see the operation "half-done." -// -// Some atomic operations can be combined with different types of memory -// barriers called "Acquire semantics" and "Release semantics", defined below. -// -// Acquire semantics: Future memory accesses cannot be relocated to before the -// operation. -// -// Release semantics: Past memory accesses cannot be relocated to after the -// operation. -// -// These barriers affect not only the compiler, but also the CPU. -// -// NOTE: Acquire and Release are not differentiated right now. They perform a -// full memory barrier instead of a "one-way" memory barrier. The newest -// Windows SDK has Acquire and Release versions of some Interlocked* functions. - -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; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - u32 result = src; // 32-bit reads are always atomic. - _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. - 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; // 32-bit writes are always atomic. -} -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. - dest = value; // 32-bit writes are always atomic. -} - -} - -#endif diff --git a/src/common/src/break_points.cpp b/src/common/src/break_points.cpp deleted file mode 100644 index 787263f7..00000000 --- a/src/common/src/break_points.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "debug_interface.h" -#include "break_points.h" - -#include -#include - -bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - if (i->iAddress == _iAddress) - return true; - return false; -} - -bool BreakPoints::IsTempBreakPoint(u32 _iAddress) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - if (i->iAddress == _iAddress && i->bTemporary) - return true; - return false; -} - -BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const -{ - TBreakPointsStr bps; - for (TBreakPoints::const_iterator i = m_BreakPoints.begin(); - i != m_BreakPoints.end(); ++i) - { - if (!i->bTemporary) - { - std::stringstream bp; - bp << std::hex << i->iAddress << " " << (i->bOn ? "n" : ""); - bps.push_back(bp.str()); - } - } - - return bps; -} - -void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) -{ - for (TBreakPointsStr::const_iterator i = bps.begin(); i != bps.end(); ++i) - { - TBreakPoint bp; - std::stringstream bpstr; - bpstr << std::hex << *i; - bpstr >> bp.iAddress; - bp.bOn = i->find("n") != i->npos; - bp.bTemporary = false; - Add(bp); - } -} - -void BreakPoints::Add(const TBreakPoint& bp) -{ - if (!IsAddressBreakPoint(bp.iAddress)) - { - m_BreakPoints.push_back(bp); - //if (jit) - // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); - } -} - -void BreakPoints::Add(u32 em_address, bool temp) -{ - if (!IsAddressBreakPoint(em_address)) // only add new addresses - { - TBreakPoint pt; // breakpoint settings - pt.bOn = true; - pt.bTemporary = temp; - pt.iAddress = em_address; - - m_BreakPoints.push_back(pt); - - //if (jit) - // jit->GetBlockCache()->InvalidateICache(em_address, 4); - } -} - -void BreakPoints::Remove(u32 em_address) -{ - for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - { - if (i->iAddress == em_address) - { - m_BreakPoints.erase(i); - //if (jit) - // jit->GetBlockCache()->InvalidateICache(em_address, 4); - return; - } - } -} - -void BreakPoints::Clear() -{ - //if (jit) - //{ - // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), - // [](const TBreakPoint& bp) - // { - // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); - // } - // ); - //} - - m_BreakPoints.clear(); -} - -MemChecks::TMemChecksStr MemChecks::GetStrings() const -{ - TMemChecksStr mcs; - for (TMemChecks::const_iterator i = m_MemChecks.begin(); - i != m_MemChecks.end(); ++i) - { - std::stringstream mc; - mc << std::hex << i->StartAddress; - mc << " " << (i->bRange ? i->EndAddress : i->StartAddress) << " " << - (i->bRange ? "n" : "") << (i->OnRead ? "r" : "") << - (i->OnWrite ? "w" : "") << (i->Log ? "l" : "") << (i->Break ? "p" : ""); - mcs.push_back(mc.str()); - } - - return mcs; -} - -void MemChecks::AddFromStrings(const TMemChecksStr& mcs) -{ - for (TMemChecksStr::const_iterator i = mcs.begin(); i != mcs.end(); ++i) - { - TMemCheck mc; - std::stringstream mcstr; - mcstr << std::hex << *i; - mcstr >> mc.StartAddress; - mc.bRange = i->find("n") != i->npos; - mc.OnRead = i->find("r") != i->npos; - mc.OnWrite = i->find("w") != i->npos; - mc.Log = i->find("l") != i->npos; - mc.Break = i->find("p") != i->npos; - if (mc.bRange) - mcstr >> mc.EndAddress; - else - mc.EndAddress = mc.StartAddress; - Add(mc); - } -} - -void MemChecks::Add(const TMemCheck& _rMemoryCheck) -{ - if (GetMemCheck(_rMemoryCheck.StartAddress) == 0) - m_MemChecks.push_back(_rMemoryCheck); -} - -void MemChecks::Remove(u32 _Address) -{ - for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) - { - if (i->StartAddress == _Address) - { - m_MemChecks.erase(i); - return; - } - } -} - -TMemCheck *MemChecks::GetMemCheck(u32 address) -{ - for (TMemChecks::iterator i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) - { - if (i->bRange) - { - if (address >= i->StartAddress && address <= i->EndAddress) - return &(*i); - } - else if (i->StartAddress == address) - return &(*i); - } - - // none found - return 0; -} - -void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, - bool write, int size, u32 pc) -{ - if ((write && OnWrite) || (!write && OnRead)) - { - if (Log) - { - INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", - pc, debug_interface->getDescription(pc).c_str(), - write ? "Write" : "Read", size*8, size*2, iValue, addr, - debug_interface->getDescription(addr).c_str() - ); - } - if (Break) - debug_interface->breakNow(); - } -} diff --git a/src/common/src/break_points.h b/src/common/src/break_points.h deleted file mode 100644 index dc771ba0..00000000 --- a/src/common/src/break_points.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _DEBUGGER_BREAKPOINTS_H -#define _DEBUGGER_BREAKPOINTS_H - -#include -#include - -#include "common.h" - -class DebugInterface; - -struct TBreakPoint -{ - u32 iAddress; - bool bOn; - bool bTemporary; -}; - -struct TMemCheck -{ - TMemCheck() { - numHits = 0; - StartAddress = EndAddress = 0; - bRange = OnRead = OnWrite = Log = Break = false; - } - u32 StartAddress; - u32 EndAddress; - - bool bRange; - - bool OnRead; - bool OnWrite; - - bool Log; - bool Break; - - u32 numHits; - - void Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, - bool write, int size, u32 pc); -}; - -// Code breakpoints. -class BreakPoints -{ -public: - typedef std::vector TBreakPoints; - typedef std::vector TBreakPointsStr; - - const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } - - TBreakPointsStr GetStrings() const; - void AddFromStrings(const TBreakPointsStr& bps); - - // is address breakpoint - bool IsAddressBreakPoint(u32 _iAddress); - bool IsTempBreakPoint(u32 _iAddress); - - // Add BreakPoint - void Add(u32 em_address, bool temp=false); - void Add(const TBreakPoint& bp); - - // Remove Breakpoint - void Remove(u32 _iAddress); - void Clear(); - - void DeleteByAddress(u32 _Address); - -private: - TBreakPoints m_BreakPoints; - u32 m_iBreakOnCount; -}; - - -// Memory breakpoints -class MemChecks -{ -public: - typedef std::vector TMemChecks; - typedef std::vector TMemChecksStr; - - TMemChecks m_MemChecks; - - const TMemChecks& GetMemChecks() { return m_MemChecks; } - - TMemChecksStr GetStrings() const; - void AddFromStrings(const TMemChecksStr& mcs); - - void Add(const TMemCheck& _rMemoryCheck); - - // memory breakpoint - TMemCheck *GetMemCheck(u32 address); - void Remove(u32 _Address); - - void Clear() { m_MemChecks.clear(); }; -}; - -#endif - diff --git a/src/common/src/chunk_file.h b/src/common/src/chunk_file.h deleted file mode 100644 index 68c2943a..00000000 --- a/src/common/src/chunk_file.h +++ /dev/null @@ -1,874 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _POINTERWRAP_H_ -#define _POINTERWRAP_H_ - -// Extremely simple serialization framework. - -// (mis)-features: -// + Super fast -// + Very simple -// + Same code is used for serialization and deserializaition (in most cases) -// - Zero backwards/forwards compatibility -// - Serialization code for anything complex has to be manually written. - -#include -#include -#include -#include -#include -#include -#ifndef __SYMBIAN32__ -#if defined(IOS) || defined(MACGNUSTD) -#include -#else -#include -#endif -#endif - -#include "common.h" -#include "file_util.h" -//#include "../ext/snappy/snappy-c.h" - -#if defined(IOS) || defined(MACGNUSTD) -namespace std { - using tr1::is_pointer; -} -#endif -#ifdef __SYMBIAN32__ -namespace std { - template - struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; - }; - template const bool bool_constant::value; - template struct is_pointer : public bool_constant {}; - template struct is_pointer : public bool_constant {}; -} -#endif - -template -struct LinkedListItem : public T -{ - LinkedListItem *next; -}; - -class PointerWrap; - -class PointerWrapSection -{ -public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } - ~PointerWrapSection(); - - bool operator == (const int &v) const { return ver_ == v; } - bool operator != (const int &v) const { return ver_ != v; } - bool operator <= (const int &v) const { return ver_ <= v; } - bool operator >= (const int &v) const { return ver_ >= v; } - bool operator < (const int &v) const { return ver_ < v; } - bool operator > (const int &v) const { return ver_ > v; } - - operator bool() const { - return ver_ > 0; - } - -private: - PointerWrap &p_; - int ver_; - const char *title_; -}; - -// Wrapper class -class PointerWrap -{ - // This makes it a compile error if you forget to define DoState() on non-POD. - // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... -#ifdef _MSC_VER - template::value, bool isPointer = std::is_pointer::value> -#else - template::value> -#endif - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - for (int i = 0; i < count; ++i) - p->Do(x[i]); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoClass(x); - } - }; - - template - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - p->DoVoid((void *)x, sizeof(T) * count); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoVoid((void *)&x, sizeof(x)); - } - }; - -public: - enum Mode { - MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare - }; - - enum Error { - ERROR_NONE = 0, - ERROR_WARNING = 1, - ERROR_FAILURE = 2, - }; - - u8 **ptr; - Mode mode; - Error error; - -public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} - - PointerWrapSection Section(const char *title, int ver) { - return Section(title, ver, ver); - } - - // The returned object can be compared against the version that was loaded. - // This can be used to support versions as old as minVer. - // Version = 0 means the section was not found. - PointerWrapSection Section(const char *title, int minVer, int ver) { - char marker[16] = {0}; - int foundVersion = ver; - - strncpy(marker, title, sizeof(marker)); - if (!ExpectVoid(marker, sizeof(marker))) - { - // Might be before we added name markers for safety. - if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) - DoMarker(title); - // Wasn't found, but maybe we can still load the state. - else - foundVersion = 0; - } - else - Do(foundVersion); - - if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { - WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); - SetError(ERROR_FAILURE); - return PointerWrapSection(*this, -1, title); - } - return PointerWrapSection(*this, foundVersion, title); - } - - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} - void SetError(Error error_) - { - if (error < error_) - error = error_; - if (error > ERROR_WARNING) - mode = PointerWrap::MODE_MEASURE; - } - - bool ExpectVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; - default: break; // throw an error? - } - (*ptr) += size; - return true; - } - - void DoVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: memcpy(data, *ptr, size); break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; - default: break; // throw an error? - } - (*ptr) += size; - } - - template - void Do(std::map &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMap(x, dv); - } - - template - void Do(std::map &x) - { - T dv = T(); - DoMap(x, dv); - } - - template - void DoMap(std::map &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x[first] = second; - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::map::iterator itr = x.begin(); - while (number > 0) - { - K first = itr->first; - Do(first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - template - void Do(std::multimap &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMultimap(x, dv); - } - - template - void Do(std::multimap &x) - { - T dv = T(); - DoMultimap(x, dv); - } - - template - void DoMultimap(std::multimap &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x.insert(std::make_pair(first, second)); - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::multimap::iterator itr = x.begin(); - while (number > 0) - { - Do(itr->first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - // Store vectors. - template - void Do(std::vector &x) - { - T *dv = NULL; - DoVector(x, dv); - } - - template - void Do(std::vector &x) - { - T dv = T(); - DoVector(x, dv); - } - - - template - void DoPOD(std::vector &x) - { - T dv = T(); - DoVectorPOD(x, dv); - } - - template - void Do(std::vector &x, T &default_val) - { - DoVector(x, default_val); - } - - template - void DoVector(std::vector &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - template - void DoVectorPOD(std::vector &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - // Store deques. - template - void Do(std::deque &x) - { - T *dv = NULL; - DoDeque(x, dv); - } - - template - void Do(std::deque &x) - { - T dv = T(); - DoDeque(x, dv); - } - - template - void DoDeque(std::deque &x, T &default_val) - { - u32 deq_size = (u32)x.size(); - Do(deq_size); - x.resize(deq_size, default_val); - u32 i; - for(i = 0; i < deq_size; i++) - Do(x[i]); - } - - // Store STL lists. - template - void Do(std::list &x) - { - T *dv = NULL; - Do(x, dv); - } - - template - void Do(std::list &x) - { - T dv = T(); - DoList(x, dv); - } - - template - void Do(std::list &x, T &default_val) - { - DoList(x, default_val); - } - - template - void DoList(std::list &x, T &default_val) - { - u32 list_size = (u32)x.size(); - Do(list_size); - x.resize(list_size, default_val); - - typename std::list::iterator itr, end; - for (itr = x.begin(), end = x.end(); itr != end; ++itr) - Do(*itr); - } - - - // Store STL sets. - template - void Do(std::set &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (*it != NULL) - delete *it; - } - } - DoSet(x); - } - - template - void Do(std::set &x) - { - DoSet(x); - } - - template - void DoSet(std::set &x) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - - switch (mode) - { - case MODE_READ: - { - x.clear(); - while (number-- > 0) - { - T it = T(); - Do(it); - x.insert(it); - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::set::iterator itr = x.begin(); - while (number-- > 0) - Do(*itr++); - } - break; - - default: - ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); - } - } - - // Store strings. - void Do(std::string &x) - { - int stringLen = (int)x.length() + 1; - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (char*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; - } - (*ptr) += stringLen; - } - - void Do(std::wstring &x) - { - int stringLen = sizeof(wchar_t)*((int)x.length() + 1); - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (wchar_t*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; - } - (*ptr) += stringLen; - } - - template - void DoClass(T &x) { - x.DoState(*this); - } - - template - void DoClass(T *&x) { - if (mode == MODE_READ) - { - if (x != NULL) - delete x; - x = new T(); - } - x->DoState(*this); - } - - template - void DoArray(T *x, int count) { - DoHelper::DoArray(this, x, count); - } - - template - void Do(T &x) { - DoHelper::Do(this, x); - } - - template - void DoPOD(T &x) { - DoHelper::Do(this, x); - } - - template - void DoPointer(T* &x, T*const base) { - // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range - s32 offset = x - base; - Do(offset); - if (mode == MODE_READ) - x = base + offset; - } - - template* (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> - void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) - { - LinkedListItem* list_cur = list_start; - LinkedListItem* prev = 0; - - while (true) - { - u8 shouldExist = (list_cur ? 1 : 0); - Do(shouldExist); - if (shouldExist == 1) - { - LinkedListItem* cur = list_cur ? list_cur : TNew(); - TDo(*this, (T*)cur); - if (!list_cur) - { - if (mode == MODE_READ) - { - cur->next = 0; - list_cur = cur; - if (prev) - prev->next = cur; - else - list_start = cur; - } - else - { - TFree(cur); - continue; - } - } - } - else - { - if (mode == MODE_READ) - { - if (prev) - prev->next = 0; - if (list_end) - *list_end = prev; - if (list_cur) - { - if (list_start == list_cur) - list_start = 0; - do - { - LinkedListItem* next = list_cur->next; - TFree(list_cur); - list_cur = next; - } - while (list_cur); - } - } - break; - } - prev = list_cur; - list_cur = list_cur->next; - } - } - - void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) - { - u32 cookie = arbitraryNumber; - Do(cookie); - if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) - { - PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); - SetError(ERROR_FAILURE); - } - } -}; - -inline PointerWrapSection::~PointerWrapSection() { - if (ver_ > 0) { - p_.DoMarker(title_); - } -} - - -class CChunkFileReader -{ -public: - enum Error { - ERROR_NONE, - ERROR_BAD_FILE, - ERROR_BROKEN_STATE, - }; - - // Load file template - template - static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) - { - INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); - _failureReason->clear(); - _failureReason->append("LoadStateWrongVersion"); - - if (!File::Exists(_rFilename)) { - _failureReason->clear(); - _failureReason->append("LoadStateDoesntExist"); - ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); - return ERROR_BAD_FILE; - } - - // Check file size - const u64 fileSize = File::GetSize(_rFilename); - static const u64 headerSize = sizeof(SChunkHeader); - if (fileSize < headerSize) - { - ERROR_LOG(COMMON,"ChunkReader: File too small"); - return ERROR_BAD_FILE; - } - - File::IOFile pFile(_rFilename, "rb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); - return ERROR_BAD_FILE; - } - - // read the header - SChunkHeader header; - if (!pFile.ReadArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Bad header size"); - return ERROR_BAD_FILE; - } - - // Check revision - if (header.Revision != _Revision) - { - ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", - header.Revision, _Revision); - return ERROR_BAD_FILE; - } - - if (strcmp(header.GitVersion, _VersionString) != 0) - { - WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", - header.GitVersion); - } - - // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) - { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); - return ERROR_BAD_FILE; - } - - // read the state - u8* buffer = new u8[sz]; - if (!pFile.ReadBytes(buffer, sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Error reading file"); - return ERROR_BAD_FILE; - } - - u8 *ptr = buffer; - u8 *buf = buffer; - if (header.Compress) { - u8 *uncomp_buffer = new u8[header.UncompressedSize]; - size_t uncomp_size = header.UncompressedSize; - snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); - if ((int)uncomp_size != header.UncompressedSize) { - ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); - } - ptr = uncomp_buffer; - buf = uncomp_buffer; - delete [] buffer; - } - - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); - delete[] buf; - - INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - // Save file template - template - static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - - File::IOFile pFile(_rFilename, "wb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); - return ERROR_BAD_FILE; - } - - bool compress = true; - - // Get data - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - - u8 * buffer = new u8[sz]; - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Create header - SChunkHeader header; - header.Compress = compress ? 1 : 0; - header.Revision = _Revision; - header.ExpectedSize = (int)sz; - header.UncompressedSize = (int)sz; - strncpy(header.GitVersion, _VersionString, 32); - header.GitVersion[31] = '\0'; - - // Write to file - if (compress) { - size_t comp_len = snappy_max_compressed_length(sz); - u8 *compressed_buffer = new u8[comp_len]; - snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); - delete [] buffer; - header.ExpectedSize = (int)comp_len; - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { - ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); - return ERROR_BAD_FILE; - } else { - INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); - } - delete [] compressed_buffer; - } else { - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&buffer[0], sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); - return ERROR_BAD_FILE; - } - delete [] buffer; - } - - INFO_LOG(COMMON,"ChunkReader: Done writing %s", - _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - template - static Error Verify(T& _class) - { - u8 *ptr = 0; - - // Step 1: Measure the space required. - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector buffer(sz); - - // Step 2: Dump the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Step 3: Verify the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_VERIFY); - _class.DoState(p); - - return ERROR_NONE; - } - -private: - struct SChunkHeader - { - int Revision; - int Compress; - int ExpectedSize; - int UncompressedSize; - char GitVersion[32]; - }; -}; - -#endif // _POINTERWRAP_H_ diff --git a/src/common/src/common.h b/src/common/src/common.h deleted file mode 100644 index 3b71d9b3..00000000 --- a/src/common/src/common.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMON_H_ -#define _COMMON_H_ - -// DO NOT EVER INCLUDE directly _or indirectly_ from this file -// since it slows down the build a lot. - -#include -#include -#include - -// SVN version number -extern const char *scm_rev_str; -extern const char *netplay_dolphin_ver; - -// Force enable logging in the right modes. For some reason, something had changed -// so that debugfast no longer logged. -#if defined(_DEBUG) || defined(DEBUGFAST) -#undef LOGGING -#define LOGGING 1 -#endif - -#define STACKALIGN - -#if __cplusplus >= 201103 || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) -#define HAVE_CXX11_SYNTAX 1 -#endif - -#if HAVE_CXX11_SYNTAX -// An inheritable class to disallow the copy constructor and operator= functions -class NonCopyable -{ -protected: - NonCopyable() {} - NonCopyable(const NonCopyable&&) {} - void operator=(const NonCopyable&&) {} -private: - NonCopyable(NonCopyable&); - NonCopyable& operator=(NonCopyable& other); -}; -#endif - -#include "log.h" -#include "common_types.h" -#include "msg_handler.h" -#include "common_funcs.h" -#include "common_paths.h" -#include "platform.h" - -#ifdef __APPLE__ -// The Darwin ABI requires that stack frames be aligned to 16-byte boundaries. -// This is only needed on i386 gcc - x86_64 already aligns to 16 bytes. -#if defined __i386__ && defined __GNUC__ -#undef STACKALIGN -#define STACKALIGN __attribute__((__force_align_arg_pointer__)) -#endif - -#elif defined _WIN32 - -// Check MSC ver - #if !defined _MSC_VER || _MSC_VER <= 1000 - #error needs at least version 1000 of MSC - #endif - - #define NOMINMAX - -// Memory leak checks - #define CHECK_HEAP_INTEGRITY() - -// Alignment - #define MEMORY_ALIGNED16(x) __declspec(align(16)) x - #define MEMORY_ALIGNED32(x) __declspec(align(32)) x - #define MEMORY_ALIGNED64(x) __declspec(align(64)) x - #define MEMORY_ALIGNED128(x) __declspec(align(128)) x - #define MEMORY_ALIGNED16_DECL(x) __declspec(align(16)) x - #define MEMORY_ALIGNED64_DECL(x) __declspec(align(64)) x - -// Since they are always around on windows - #define HAVE_WX 1 - #define HAVE_OPENAL 1 - - #define HAVE_PORTAUDIO 1 - -// Debug definitions - #if defined(_DEBUG) - #include - #undef CHECK_HEAP_INTEGRITY - #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} - // If you want to see how much a pain in the ass singletons are, for example: - // {614} normal block at 0x030C5310, 188 bytes long. - // Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 - struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } }; - //CrtDebugBreak breakAt(614); - #endif // end DEBUG/FAST - -#endif - -// Windows compatibility -#ifndef _WIN32 -#include -#define MAX_PATH PATH_MAX -#ifdef _LP64 -#define _M_X64 1 -#else -#define _M_IX86 1 -#endif -#define __forceinline inline __attribute__((always_inline)) -#define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x -#define MEMORY_ALIGNED32(x) __attribute__((aligned(32))) x -#define MEMORY_ALIGNED64(x) __attribute__((aligned(64))) x -#define MEMORY_ALIGNED128(x) __attribute__((aligned(128))) x -#define MEMORY_ALIGNED16_DECL(x) __attribute__((aligned(16))) x -#define MEMORY_ALIGNED64_DECL(x) __attribute__((aligned(64))) x -#endif - -#ifdef _MSC_VER -#define __strdup _strdup -#define __getcwd _getcwd -#define __chdir _chdir -#else -#define __strdup strdup -#define __getcwd getcwd -#define __chdir chdir -#endif - -// Dummy macro for marking translatable strings that can not be immediately translated. -// wxWidgets does not have a true dummy macro for this. -#define _trans(a) a - -#if defined _M_GENERIC -# define _M_SSE 0x0 -#elif defined __GNUC__ -# if defined __SSE4_2__ -# define _M_SSE 0x402 -# elif defined __SSE4_1__ -# define _M_SSE 0x401 -# elif defined __SSSE3__ -# define _M_SSE 0x301 -# elif defined __SSE3__ -# define _M_SSE 0x300 -# endif -#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008 -# define _M_SSE 0x402 -#endif - -// Host communication. -enum HOST_COMM -{ - // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on - WM_USER_STOP = 10, - WM_USER_CREATE, - WM_USER_SETCURSOR, -}; - -// Used for notification on emulation state -enum EMUSTATE_CHANGE -{ - EMUSTATE_CHANGE_PLAY = 1, - EMUSTATE_CHANGE_PAUSE, - EMUSTATE_CHANGE_STOP -}; - -// This should be used in the private: declarations for a class -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -#endif // _COMMON_H_ diff --git a/src/common/src/common_funcs.h b/src/common/src/common_funcs.h deleted file mode 100644 index 7ca0b350..00000000 --- a/src/common/src/common_funcs.h +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMONFUNCS_H_ -#define _COMMONFUNCS_H_ - -#ifdef _WIN32 -#define SLEEP(x) Sleep(x) -#else -#include -#define SLEEP(x) usleep(x*1000) -#endif - -template struct CompileTimeAssert; -template<> struct CompileTimeAssert {}; - -#define b2(x) ( (x) | ( (x) >> 1) ) -#define b4(x) ( b2(x) | ( b2(x) >> 2) ) -#define b8(x) ( b4(x) | ( b4(x) >> 4) ) -#define b16(x) ( b8(x) | ( b8(x) >> 8) ) -#define b32(x) (b16(x) | (b16(x) >>16) ) -#define ROUND_UP_POW2(x) (b32(x - 1) + 1) - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC -#include -static __inline __m128i __attribute__((__always_inline__)) -_mm_shuffle_epi8(__m128i a, __m128i mask) -{ - __m128i result; - __asm__("pshufb %1, %0" - : "=x" (result) - : "xm" (mask), "0" (a)); - return result; -} -#endif - -#ifndef _WIN32 - -#include -#ifdef __linux__ -#include -#elif defined __FreeBSD__ -#include -#endif - -// go to debugger mode - #ifdef GEKKO - #define Crash() - #elif defined _M_GENERIC - #define Crash() { exit(1); } - #else - #define Crash() {asm ("int $3");} - #endif - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -// GCC 4.8 defines all the rotate functions now -// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit -#ifndef _rotl -inline u32 _rotl(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x << shift) | (x >> (32 - shift)); -} - -inline u32 _rotr(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x >> shift) | (x << (32 - shift)); -} -#endif - -inline u64 _rotl64(u64 x, unsigned int shift){ - unsigned int n = shift % 64; - return (x << n) | (x >> (64 - n)); -} - -inline u64 _rotr64(u64 x, unsigned int shift){ - unsigned int n = shift % 64; - return (x >> n) | (x << (64 - n)); -} - -#else // WIN32 -// Function Cross-Compatibility - #define strcasecmp _stricmp - #define strncasecmp _strnicmp - #define unlink _unlink - #define snprintf _snprintf - #define vscprintf _vscprintf - -// Locale Cross-Compatibility - #define locale_t _locale_t - #define freelocale _free_locale - #define newlocale(mask, locale, base) _create_locale(mask, locale) - - #define LC_GLOBAL_LOCALE ((locale_t)-1) - #define LC_ALL_MASK LC_ALL - #define LC_COLLATE_MASK LC_COLLATE - #define LC_CTYPE_MASK LC_CTYPE - #define LC_MONETARY_MASK LC_MONETARY - #define LC_NUMERIC_MASK LC_NUMERIC - #define LC_TIME_MASK LC_TIME - - inline locale_t uselocale(locale_t new_locale) - { - // Retrieve the current per thread locale setting - bool bIsPerThread = (_configthreadlocale(0) == _ENABLE_PER_THREAD_LOCALE); - - // Retrieve the current thread-specific locale - locale_t old_locale = bIsPerThread ? _get_current_locale() : LC_GLOBAL_LOCALE; - - if(new_locale == LC_GLOBAL_LOCALE) - { - // Restore the global locale - _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); - } - else if(new_locale != NULL) - { - // Configure the thread to set the locale only for this thread - _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); - - // Set all locale categories - for(int i = LC_MIN; i <= LC_MAX; i++) - setlocale(i, new_locale->locinfo->lc_category[i].locale); - } - - return old_locale; - } - -// 64 bit offsets for windows - #define fseeko _fseeki64 - #define ftello _ftelli64 - #define atoll _atoi64 - #define stat64 _stat64 - #define fstat64 _fstat64 - #define fileno _fileno - - #if _M_IX86 - #define Crash() {__asm int 3} - #else -extern "C" { - __declspec(dllimport) void __stdcall DebugBreak(void); -} - #define Crash() {DebugBreak();} - #endif // M_IX86 -#endif // WIN32 ndef - -// Dolphin's min and max functions -#undef min -#undef max - -template -inline T min(const T& a, const T& b) {return a > b ? b : a;} -template -inline T max(const T& a, const T& b) {return a > b ? a : b;} - -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -// Defined in Misc.cpp. -const char* GetLastErrorMsg(); - -namespace Common -{ -inline u8 swap8(u8 _data) {return _data;} -inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} - -#ifdef ANDROID -#undef swap16 -#undef swap32 -#undef swap64 -#endif - -#ifdef _WIN32 -inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} -inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} -inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} -#elif _M_ARM -inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} -inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} -inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} -#elif __linux__ -inline u16 swap16(u16 _data) {return bswap_16(_data);} -inline u32 swap32(u32 _data) {return bswap_32(_data);} -inline u64 swap64(u64 _data) {return bswap_64(_data);} -#elif __APPLE__ -inline __attribute__((always_inline)) u16 swap16(u16 _data) - {return (_data >> 8) | (_data << 8);} -inline __attribute__((always_inline)) u32 swap32(u32 _data) - {return __builtin_bswap32(_data);} -inline __attribute__((always_inline)) u64 swap64(u64 _data) - {return __builtin_bswap64(_data);} -#elif __FreeBSD__ -inline u16 swap16(u16 _data) {return bswap16(_data);} -inline u32 swap32(u32 _data) {return bswap32(_data);} -inline u64 swap64(u64 _data) {return bswap64(_data);} -#else -// Slow generic implementation. -inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} -inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} -inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} -#endif - -inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} -inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} -inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} - -template -void swap(u8*); - -template <> -inline void swap<1>(u8* data) -{} - -template <> -inline void swap<2>(u8* data) -{ - *reinterpret_cast(data) = swap16(data); -} - -template <> -inline void swap<4>(u8* data) -{ - *reinterpret_cast(data) = swap32(data); -} - -template <> -inline void swap<8>(u8* data) -{ - *reinterpret_cast(data) = swap64(data); -} - -template -inline T FromBigEndian(T data) -{ - //static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); - - swap(reinterpret_cast(&data)); - return data; -} - -} // Namespace Common - -#endif // _COMMONFUNCS_H_ diff --git a/src/common/src/common_paths.h b/src/common/src/common_paths.h deleted file mode 100644 index 9ccb87d8..00000000 --- a/src/common/src/common_paths.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _COMMON_PATHS_H_ -#define _COMMON_PATHS_H_ - -// Make sure we pick up USER_DIR if set in config.h -#include "common.h" - -// Directory seperators, do we need this? -#define DIR_SEP "/" -#define DIR_SEP_CHR '/' - -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - -// The user data dir -#define ROOT_DIR "." -#ifdef _WIN32 - #define USERDATA_DIR "user" - #define EMU_DATA_DIR "emu" -#else - #define USERDATA_DIR "user" - #ifdef USER_DIR - #define EMU_DATA_DIR USER_DIR - #else - #define EMU_DATA_DIR ".emu" - #endif -#endif - -// Shared data dirs (Sys and shared User for linux) -#ifdef _WIN32 - #define SYSDATA_DIR "sys" -#else - #ifdef DATA_DIR - #define SYSDATA_DIR DATA_DIR "sys" - #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP - #else - #define SYSDATA_DIR "sys" - #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP - #endif -#endif - -// Dirs in both User and Sys -#define EUR_DIR "EUR" -#define USA_DIR "USA" -#define JAP_DIR "JAP" - -// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) -#define CONFIG_DIR "config" -#define GAMECONFIG_DIR "game_config" -#define MAPS_DIR "maps" -#define CACHE_DIR "cache" -#define SHADERCACHE_DIR "shader_cache" -#define STATESAVES_DIR "state_saves" -#define SCREENSHOTS_DIR "screenShots" -#define DUMP_DIR "dump" -#define DUMP_TEXTURES_DIR "textures" -#define DUMP_FRAMES_DIR "frames" -#define DUMP_AUDIO_DIR "audio" -#define LOGS_DIR "logs" -#define SHADERS_DIR "shaders" -#define SYSCONF_DIR "sysconf" - -// Filenames -// Files in the directory returned by GetUserPath(D_CONFIG_IDX) -#define EMU_CONFIG "emu.ini" -#define DEBUGGER_CONFIG "debugger.ini" -#define LOGGER_CONFIG "logger.ini" - -// Files in the directory returned by GetUserPath(D_LOGS_IDX) -#define MAIN_LOG "emu.log" - -// Files in the directory returned by GetUserPath(D_SYSCONF_IDX) -#define SYSCONF "SYSCONF" - -#endif // _COMMON_PATHS_H_ diff --git a/src/common/src/common_types.h b/src/common/src/common_types.h deleted file mode 100644 index af1cd0e2..00000000 --- a/src/common/src/common_types.h +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file common_types.h - * @author ShizZy - * @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/ - */ - -#pragma once - -#include -#include // data_types__m128.cpp - -#ifdef _WIN32 - -#include - -typedef unsigned __int8 u8; ///< 8-bit unsigned byte -typedef unsigned __int16 u16; ///< 16-bit unsigned short -typedef unsigned __int32 u32; ///< 32-bit unsigned word -typedef unsigned __int64 u64; ///< 64-bit unsigned int - -typedef signed __int8 s8; ///< 8-bit signed byte -typedef signed __int16 s16; ///< 16-bit signed short -typedef signed __int32 s32; ///< 32-bit signed word -typedef signed __int64 s64; ///< 64-bit signed int - -#else - -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 unsigned long long u64; ///< 64-bit unsigned int - -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 long long s64; ///< 64-bit signed int - -// For using windows lock code -#define TCHAR char -#define LONG int - -#endif // _WIN32 - -typedef float f32; ///< 32-bit floating point -typedef double f64; ///< 64-bit floating point - -#include "swap.h" - -/// 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) - s32 _s32; ///< 32-bit signed int(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) - s32 _s32[2]; ///< 32-bit signed int(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_); - } -}; diff --git a/src/common/src/console_listener.cpp b/src/common/src/console_listener.cpp deleted file mode 100644 index 270ad9ce..00000000 --- a/src/common/src/console_listener.cpp +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include // min -#include // System: To be able to add strings with "+" -#include -#include -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -#include "common.h" -#include "log_manager.h" // Common -#include "console_listener.h" // Common - -ConsoleListener::ConsoleListener() -{ -#ifdef _WIN32 - hConsole = NULL; - bUseColor = true; -#else - bUseColor = isatty(fileno(stdout)); -#endif -} - -ConsoleListener::~ConsoleListener() -{ - Close(); -} - -// 100, 100, "Dolphin Log Console" -// Open console window - width and height is the size of console window -// Name is the window title -void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title) -{ -#ifdef _WIN32 - if (!GetConsoleWindow()) - { - // Open the console window and create the window handle for GetStdHandle() - AllocConsole(); - // Hide - if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE); - // Save the window handle that AllocConsole() created - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - // Set the console window title - SetConsoleTitle(UTF8ToTStr(Title).c_str()); - // Set letter space - LetterSpace(80, 4000); - //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); - } - else - { - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - } -#endif -} - -void ConsoleListener::UpdateHandle() -{ -#ifdef _WIN32 - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); -#endif -} - -// Close the console window and close the eventual file handle -void ConsoleListener::Close() -{ -#ifdef _WIN32 - if (hConsole == NULL) - return; - FreeConsole(); - hConsole = NULL; -#else - fflush(NULL); -#endif -} - -bool ConsoleListener::IsOpen() -{ -#ifdef _WIN32 - return (hConsole != NULL); -#else - return true; -#endif -} - -/* - LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are - dependent on each other, that's the reason for the additional checks. -*/ -void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) -{ -#ifdef _WIN32 - BOOL SB, SW; - if (BufferFirst) - { - // Change screen buffer size - COORD Co = {BufferWidth, BufferHeight}; - SB = SetConsoleScreenBufferSize(hConsole, Co); - // Change the screen buffer window size - SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom - SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); - } - else - { - // Change the screen buffer window size - SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom - SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); - // Change screen buffer size - COORD Co = {BufferWidth, BufferHeight}; - SB = SetConsoleScreenBufferSize(hConsole, Co); - } -#endif -} -void ConsoleListener::LetterSpace(int Width, int Height) -{ -#ifdef _WIN32 - // Get console info - CONSOLE_SCREEN_BUFFER_INFO ConInfo; - GetConsoleScreenBufferInfo(hConsole, &ConInfo); - - // - int OldBufferWidth = ConInfo.dwSize.X; - int OldBufferHeight = ConInfo.dwSize.Y; - int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); - int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); - // - int NewBufferWidth = Width; - int NewBufferHeight = Height; - int NewScreenWidth = NewBufferWidth - 1; - int NewScreenHeight = OldScreenHeight; - - // Width - BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1)); - // Height - BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); - - // Resize the window too - //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); -#endif -} -#ifdef _WIN32 -COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) -{ - COORD Ret = {0, 0}; - // Full rows - int Step = (int)floor((float)BytesRead / (float)BufferWidth); - Ret.Y += Step; - // Partial row - Ret.X = BytesRead - (BufferWidth * Step); - return Ret; -} -#endif -void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) -{ -#ifdef _WIN32 - // Check size - if (Width < 8 || Height < 12) return; - - bool DBef = true; - bool DAft = true; - std::string SLog = ""; - - const HWND hWnd = GetConsoleWindow(); - const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - // Get console info - CONSOLE_SCREEN_BUFFER_INFO ConInfo; - GetConsoleScreenBufferInfo(hConsole, &ConInfo); - DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y; - - // --------------------------------------------------------------------- - // Save the current text - // ------------------------ - DWORD cCharsRead = 0; - COORD coordScreen = { 0, 0 }; - - static const int MAX_BYTES = 1024 * 16; - - std::vector> Str; - std::vector> Attr; - - // ReadConsoleOutputAttribute seems to have a limit at this level - static const int ReadBufferSize = MAX_BYTES - 32; - - DWORD cAttrRead = ReadBufferSize; - DWORD BytesRead = 0; - while (BytesRead < BufferSize) - { - Str.resize(Str.size() + 1); - if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); - - Attr.resize(Attr.size() + 1); - if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); - - // Break on error - if (cAttrRead == 0) break; - BytesRead += cAttrRead; - coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X); - } - // Letter space - int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f); - int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f); - int LBufWidth = LWidth + 1; - int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth); - // Change screen buffer size - LetterSpace(LBufWidth, LBufHeight); - - - ClearScreen(true); - coordScreen.Y = 0; - coordScreen.X = 0; - DWORD cCharsWritten = 0; - - int BytesWritten = 0; - DWORD cAttrWritten = 0; - for (size_t i = 0; i < Attr.size(); i++) - { - if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); - if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); - - BytesWritten += cAttrWritten; - coordScreen = GetCoordinates(BytesWritten, LBufWidth); - } - - const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; - COORD Coo = GetCoordinates(OldCursor, LBufWidth); - SetConsoleCursorPosition(hConsole, Coo); - - if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str()); - - // Resize the window too - if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); -#endif -} - -void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) -{ -#if defined(_WIN32) - /* - const int MAX_BYTES = 1024*10; - char Str[MAX_BYTES]; - va_list ArgPtr; - int Cnt; - va_start(ArgPtr, Text); - Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); - va_end(ArgPtr); - */ - DWORD cCharsWritten; - WORD Color; - - switch (Level) - { - case NOTICE_LEVEL: // light green - Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; - break; - case ERROR_LEVEL: // light red - Color = FOREGROUND_RED | FOREGROUND_INTENSITY; - break; - case WARNING_LEVEL: // light yellow - Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; - break; - case INFO_LEVEL: // cyan - Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; - break; - case DEBUG_LEVEL: // gray - Color = FOREGROUND_INTENSITY; - break; - default: // off-white - Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - break; - } - if (strlen(Text) > 10) - { - // First 10 chars white - SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); - Text += 10; - } - SetConsoleTextAttribute(hConsole, Color); - WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); -#else - char ColorAttr[16] = ""; - char ResetAttr[16] = ""; - - if (bUseColor) - { - strcpy(ResetAttr, "\033[0m"); - switch (Level) - { - case NOTICE_LEVEL: // light green - strcpy(ColorAttr, "\033[92m"); - break; - case ERROR_LEVEL: // light red - strcpy(ColorAttr, "\033[91m"); - break; - case WARNING_LEVEL: // light yellow - strcpy(ColorAttr, "\033[93m"); - break; - default: - break; - } - } - fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); -#endif -} -// Clear console screen -void ConsoleListener::ClearScreen(bool Cursor) -{ -#if defined(_WIN32) - COORD coordScreen = { 0, 0 }; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; - - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - GetConsoleScreenBufferInfo(hConsole, &csbi); - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - // Write space to the entire console - FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); - GetConsoleScreenBufferInfo(hConsole, &csbi); - FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); - // Reset cursor - if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); -#endif -} - - diff --git a/src/common/src/console_listener.h b/src/common/src/console_listener.h deleted file mode 100644 index a2936050..00000000 --- a/src/common/src/console_listener.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _CONSOLELISTENER_H -#define _CONSOLELISTENER_H - -#include "log_manager.h" - -#ifdef _WIN32 -#include -#endif - -class ConsoleListener : public LogListener -{ -public: - ConsoleListener(); - ~ConsoleListener(); - - void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console"); - void UpdateHandle(); - void Close(); - bool IsOpen(); - void LetterSpace(int Width, int Height); - void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst); - void PixelSpace(int Left, int Top, int Width, int Height, bool); -#ifdef _WIN32 - COORD GetCoordinates(int BytesRead, int BufferWidth); -#endif - void Log(LogTypes::LOG_LEVELS, const char *Text); - void ClearScreen(bool Cursor = true); - -private: -#ifdef _WIN32 - HWND GetHwnd(void); - HANDLE hConsole; -#endif - bool bUseColor; -}; - -#endif // _CONSOLELISTENER_H diff --git a/src/common/src/cpu_detect.h b/src/common/src/cpu_detect.h deleted file mode 100644 index e93cf333..00000000 --- a/src/common/src/cpu_detect.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -// Detect the cpu, so we'll know which optimizations to use -#ifndef _CPUDETECT_H_ -#define _CPUDETECT_H_ - -#include - -enum CPUVendor -{ - VENDOR_INTEL = 0, - VENDOR_AMD = 1, - VENDOR_ARM = 2, - VENDOR_OTHER = 3, -}; - -struct CPUInfo -{ - CPUVendor vendor; - - char cpu_string[0x21]; - char brand_string[0x41]; - bool OS64bit; - bool CPU64bit; - bool Mode64bit; - - bool HTT; - int num_cores; - int logical_cpu_count; - - bool bSSE; - bool bSSE2; - bool bSSE3; - bool bSSSE3; - bool bPOPCNT; - bool bSSE4_1; - bool bSSE4_2; - bool bLZCNT; - bool bSSE4A; - bool bAVX; - bool bAES; - bool bLAHFSAHF64; - bool bLongMode; - - // ARM specific CPUInfo - bool bSwp; - bool bHalf; - bool bThumb; - bool bFastMult; - bool bVFP; - bool bEDSP; - bool bThumbEE; - bool bNEON; - bool bVFPv3; - bool bTLS; - bool bVFPv4; - bool bIDIVa; - bool bIDIVt; - bool bArmV7; // enable MOVT, MOVW etc - - // ARMv8 specific - bool bFP; - bool bASIMD; - - // Call Detect() - explicit CPUInfo(); - - // Turn the cpu info into a string we can show - std::string Summarize(); - -private: - // Detects the various cpu features - void Detect(); -}; - -extern CPUInfo cpu_info; - -#endif // _CPUDETECT_H_ diff --git a/src/common/src/debug_interface.h b/src/common/src/debug_interface.h deleted file mode 100644 index 49cc54a8..00000000 --- a/src/common/src/debug_interface.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _DEBUGINTERFACE_H -#define _DEBUGINTERFACE_H - -#include -#include - -class DebugInterface -{ -protected: - virtual ~DebugInterface() {} - -public: - virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual int getInstructionSize(int /*instruction*/) {return 1;} - virtual bool isAlive() {return true;} - virtual bool isBreakpoint(unsigned int /*address*/) {return false;} - virtual void setBreakpoint(unsigned int /*address*/){} - virtual void clearBreakpoint(unsigned int /*address*/){} - virtual void clearAllBreakpoints() {} - virtual void toggleBreakpoint(unsigned int /*address*/){} - virtual bool isMemCheck(unsigned int /*address*/) {return false;} - virtual void toggleMemCheck(unsigned int /*address*/){} - virtual unsigned int readMemory(unsigned int /*address*/){return 0;} - virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} - virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} - virtual unsigned int readInstruction(unsigned int /*address*/){return 0;} - virtual unsigned int getPC() {return 0;} - virtual void setPC(unsigned int /*address*/) {} - virtual void step() {} - virtual void runToBreakpoint() {} - virtual void breakNow() {} - virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} - virtual void showJitResults(unsigned int /*address*/) {}; - virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} - virtual std::string getDescription(unsigned int /*address*/) = 0; -}; - -#endif diff --git a/src/common/src/emu_window.h b/src/common/src/emu_window.h deleted file mode 100644 index f4936705..00000000 --- a/src/common/src/emu_window.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file emu_window.h - * @author Neobrain - * @date 2012-06-01 - * @brief Interface for implementing an emulator window manager - * - * @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 CORE_EMUWINDOW_H_ -#define CORE_EMUWINDOW_H_ - -#include "common.h" - -//namespace input_common -//{ -//class KeyboardInput; -//} - -// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, -// QGLWidget, GLFW, etc...) -class EmuWindow -{ - -public: - /// Data structure to store an emuwindow configuration - struct Config{ - bool fullscreen; - int res_width; - int res_height; - }; - - /// Swap buffers to display the next frame - virtual void SwapBuffers() = 0; - - /// Polls window events - virtual void PollEvents() = 0; - - /// Makes the graphics context current for the caller thread - virtual void MakeCurrent() = 0; - - /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - virtual void DoneCurrent() = 0; - - /** - * @brief Called from KeyboardInput constructor to notify EmuWindow about its presence - * @param controller_interface Pointer to a running KeyboardInput interface - */ - //void set_controller_interface(input_common::KeyboardInput* controller_interface) { - // controller_interface_ = controller_interface; - //} - //input_common::KeyboardInput* controller_interface() { return controller_interface_; } - - Config config() { return config_; } - void set_config(Config val) { config_ = val; } - - int client_area_width() { return client_area_width_; } - void set_client_area_width(int val) { client_area_width_ = val; } - - int client_area_height() { return client_area_height_; } - void set_client_area_height(int val) { client_area_height_ = val; } - - std::string window_title() { return window_title_; } - void set_window_title(std::string val) { window_title_ = val; } - -protected: - EmuWindow() : client_area_width_(640), client_area_height_(480) { - char window_title[255]; - sprintf(window_title, "citra [%s|%s] - %s", - "null-cpu", - "null-renderer", - __DATE__); - window_title_ = window_title; - } - virtual ~EmuWindow() {} - - std::string window_title_; ///< Current window title, should be used by window impl. - - int client_area_width_; ///< Current client width, should be set by window impl. - int client_area_height_; ///< Current client height, should be set by window impl. - -private: - Config config_; ///< Internal configuration - -}; - -#endif // CORE_EMUWINDOW_H_ diff --git a/src/common/src/extended_trace.cpp b/src/common/src/extended_trace.cpp deleted file mode 100644 index 9f717dba..00000000 --- a/src/common/src/extended_trace.cpp +++ /dev/null @@ -1,433 +0,0 @@ -// -------------------------------------------------------------------------------------- -// -// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com -// For companies(Austin,TX): If you would like to get my resume, send an email. -// -// The source is free, but if you want to use it, mention my name and e-mail address -// -// History: -// 1.0 Initial version Zoltan Csizmadia -// 1.1 WhineCube version Masken -// 1.2 Dolphin version Masken -// -// -------------------------------------------------------------------------------------- - -#if defined(WIN32) - -#include -#include -#include "extended_trace.h" -#include "string_util.h" -using namespace std; - -#include -#include - -#define BUFFERSIZE 0x200 -#pragma warning(disable:4996) - -// Unicode safe char* -> TCHAR* conversion -void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) -{ -#if defined(UNICODE)||defined(_UNICODE) - ULONG index = 0; - PCSTR lpAct = lpszIn; - - for( ; ; lpAct++ ) - { - lpszOut[index++] = (TCHAR)(*lpAct); - if ( *lpAct == 0 ) - break; - } -#else - // This is trivial :) - strcpy( lpszOut, lpszIn ); -#endif -} - -// Let's figure out the path for the symbol files -// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath -// Note: There is no size check for lpszSymbolPath! -static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath ) -{ - CHAR lpszPath[BUFFERSIZE]; - - // Creating the default path - // ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" - strcpy( lpszSymbolPath, "." ); - - // environment variable _NT_SYMBOL_PATH - if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - } - - // environment variable _NT_ALTERNATE_SYMBOL_PATH - if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - } - - // environment variable SYSTEMROOT - if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszPath ); - strcat( lpszSymbolPath, ";" ); - - // SYSTEMROOT\System32 - strcat( lpszSymbolPath, lpszPath ); - strcat( lpszSymbolPath, "\\System32" ); - } - - // Add user defined path - if ( lpszIniPath != NULL ) - if ( lpszIniPath[0] != '\0' ) - { - strcat( lpszSymbolPath, ";" ); - strcat( lpszSymbolPath, lpszIniPath ); - } -} - -// Uninitialize the loaded symbol files -BOOL UninitSymInfo() { - return SymCleanup( GetCurrentProcess() ); -} - -// Initializes the symbol files -BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) -{ - CHAR lpszSymbolPath[BUFFERSIZE]; - DWORD symOptions = SymGetOptions(); - - symOptions |= SYMOPT_LOAD_LINES; - symOptions &= ~SYMOPT_UNDNAME; - SymSetOptions( symOptions ); - InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); - - return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE); -} - -// Get the module name from a given address -static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) -{ - BOOL ret = FALSE; - IMAGEHLP_MODULE moduleInfo; - - ::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); - moduleInfo.SizeOfStruct = sizeof(moduleInfo); - - if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) - { - // Got it! - PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule ); - ret = TRUE; - } - else - // Not found :( - _tcscpy( lpszModule, _T("?") ); - - return ret; -} - -// Get function prototype and parameter info from ip address and stack address -static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) -{ - BOOL ret = FALSE; - DWORD dwSymSize = 10000; - TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); - CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; - LPTSTR lpszParamSep = NULL; - LPTSTR lpszParsed = lpszUnDSymbol; - PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize ); - - ::ZeroMemory( pSym, dwSymSize ); - pSym->SizeOfStruct = dwSymSize; - pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL); - - // Set the default to unknown - _tcscpy( lpszSymbol, _T("?") ); - - // Get symbol info for IP -#ifndef _M_X64 - DWORD dwDisp = 0; - if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) -#else - //makes it compile but hell im not sure if this works... - DWORD64 dwDisp = 0; - if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) -#endif - { - // Make the symbol readable for humans - UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, - UNDNAME_COMPLETE | - UNDNAME_NO_THISTYPE | - UNDNAME_NO_SPECIAL_SYMS | - UNDNAME_NO_MEMBER_TYPE | - UNDNAME_NO_MS_KEYWORDS | - UNDNAME_NO_ACCESS_SPECIFIERS ); - - // Symbol information is ANSI string - PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol ); - - // I am just smarter than the symbol file :) - if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("mainCRTStartup()")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)")); - else - if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 ) - _tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()")); - - lpszSymbol[0] = _T('\0'); - - // Let's go through the stack, and modify the function prototype, and insert the actual - // parameter values from the stack - if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL) - { - ULONG index = 0; - for( ; ; index++ ) - { - lpszParamSep = _tcschr( lpszParsed, _T(',') ); - if ( lpszParamSep == NULL ) - break; - - *lpszParamSep = _T('\0'); - - _tcscat( lpszSymbol, lpszParsed ); - _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) ); - - lpszParsed = lpszParamSep + 1; - } - - lpszParamSep = _tcschr( lpszParsed, _T(')') ); - if ( lpszParamSep != NULL ) - { - *lpszParamSep = _T('\0'); - - _tcscat( lpszSymbol, lpszParsed ); - _stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) ); - - lpszParsed = lpszParamSep + 1; - } - } - - _tcscat( lpszSymbol, lpszParsed ); - - ret = TRUE; - } - GlobalFree( pSym ); - - return ret; -} - -// Get source file name and line number from IP address -// The output format is: "sourcefile(linenumber)" or -// "modulename!address" or -// "address" -static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ) -{ - BOOL ret = FALSE; - IMAGEHLP_LINE lineInfo; - DWORD dwDisp; - TCHAR lpszFileName[BUFFERSIZE] = _T(""); - TCHAR lpModuleInfo[BUFFERSIZE] = _T(""); - - _tcscpy( lpszSourceInfo, _T("?(?)") ); - - ::ZeroMemory( &lineInfo, sizeof( lineInfo ) ); - lineInfo.SizeOfStruct = sizeof( lineInfo ); - - if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) ) - { - // Got it. Let's use "sourcefile(linenumber)" format - PCSTR2LPTSTR( lineInfo.FileName, lpszFileName ); - TCHAR fname[_MAX_FNAME]; - TCHAR ext[_MAX_EXT]; - _tsplitpath(lpszFileName, NULL, NULL, fname, ext); - _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber ); - ret = TRUE; - } - else - { - // There is no source file information. :( - // Let's use the "modulename!address" format - GetModuleNameFromAddress( address, lpModuleInfo ); - - if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0')) - // There is no modulename information. :(( - // Let's use the "address" format - _stprintf( lpszSourceInfo, _T("0x%08X"), address ); - else - _stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address ); - - ret = FALSE; - } - - return ret; -} - -void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) -{ - TCHAR symInfo[BUFFERSIZE] = _T("?"); - TCHAR srcInfo[BUFFERSIZE] = _T("?"); - - GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); - GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); - etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); -} - -void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) -{ - STACKFRAME callStack; - BOOL bResult; - CONTEXT context; - HANDLE hProcess = GetCurrentProcess(); - - // If it's not this thread, let's suspend it, and resume it at the end - if ( hThread != GetCurrentThread() ) - if ( SuspendThread( hThread ) == -1 ) - { - // whaaat ?! - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &context, sizeof(context) ); - context.ContextFlags = CONTEXT_FULL; - - if ( !GetThreadContext( hThread, &context ) ) - { - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &callStack, sizeof(callStack) ); -#ifndef _M_X64 - callStack.AddrPC.Offset = context.Eip; - callStack.AddrStack.Offset = context.Esp; - callStack.AddrFrame.Offset = context.Ebp; -#else - callStack.AddrPC.Offset = context.Rip; - callStack.AddrStack.Offset = context.Rsp; - callStack.AddrFrame.Offset = context.Rbp; -#endif - callStack.AddrPC.Mode = AddrModeFlat; - callStack.AddrStack.Mode = AddrModeFlat; - callStack.AddrFrame.Mode = AddrModeFlat; - - etfprint(file, "Call stack info: \n"); - etfprint(file, lpszMessage); - - PrintFunctionAndSourceInfo(file, callStack); - - for( ULONG index = 0; ; index++ ) - { - bResult = StackWalk( - IMAGE_FILE_MACHINE_I386, - hProcess, - hThread, - &callStack, - NULL, - NULL, - SymFunctionTableAccess, - SymGetModuleBase, - NULL); - - if ( index == 0 ) - continue; - - if( !bResult || callStack.AddrFrame.Offset == 0 ) - break; - - PrintFunctionAndSourceInfo(file, callStack); - - } - - if ( hThread != GetCurrentThread() ) - ResumeThread( hThread ); -} - -void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) -{ - STACKFRAME callStack; - BOOL bResult; - TCHAR symInfo[BUFFERSIZE] = _T("?"); - TCHAR srcInfo[BUFFERSIZE] = _T("?"); - HANDLE hProcess = GetCurrentProcess(); - - // If it's not this thread, let's suspend it, and resume it at the end - if ( hThread != GetCurrentThread() ) - if ( SuspendThread( hThread ) == -1 ) - { - // whaaat ?! - etfprint(file, "Call stack info failed\n"); - return; - } - - ::ZeroMemory( &callStack, sizeof(callStack) ); - callStack.AddrPC.Offset = eip; - callStack.AddrStack.Offset = esp; - callStack.AddrFrame.Offset = ebp; - callStack.AddrPC.Mode = AddrModeFlat; - callStack.AddrStack.Mode = AddrModeFlat; - callStack.AddrFrame.Mode = AddrModeFlat; - - etfprint(file, "Call stack info: \n"); - etfprint(file, lpszMessage); - - PrintFunctionAndSourceInfo(file, callStack); - - for( ULONG index = 0; ; index++ ) - { - bResult = StackWalk( - IMAGE_FILE_MACHINE_I386, - hProcess, - hThread, - &callStack, - NULL, - NULL, - SymFunctionTableAccess, - SymGetModuleBase, - NULL); - - if ( index == 0 ) - continue; - - if( !bResult || callStack.AddrFrame.Offset == 0 ) - break; - - PrintFunctionAndSourceInfo(file, callStack); - } - - if ( hThread != GetCurrentThread() ) - ResumeThread( hThread ); -} - -char g_uefbuf[2048]; - -void etfprintf(FILE *file, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int len = vsprintf(g_uefbuf, format, ap); - fwrite(g_uefbuf, 1, len, file); - va_end(ap); -} - -void etfprint(FILE *file, const std::string &text) -{ - size_t len = text.length(); - fwrite(text.data(), 1, len, file); -} - -#endif //WIN32 diff --git a/src/common/src/extended_trace.h b/src/common/src/extended_trace.h deleted file mode 100644 index 1552e901..00000000 --- a/src/common/src/extended_trace.h +++ /dev/null @@ -1,53 +0,0 @@ -// ----------------------------------------------------------------------------------------- -// -// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com -// For companies(Austin,TX): If you would like to get my resume, send an email. -// -// The source is free, but if you want to use it, mention my name and e-mail address -// -// History: -// 1.0 Initial version Zoltan Csizmadia -// 1.1 WhineCube version Masken -// 1.2 Dolphin version Masken -// -// ---------------------------------------------------------------------------------------- - -#ifndef _EXTENDEDTRACE_H_INCLUDED_ -#define _EXTENDEDTRACE_H_INCLUDED_ - -#if defined(WIN32) - -#include -#include - -#include - -#pragma comment( lib, "imagehlp.lib" ) - -#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath ) -#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() -#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file) -#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp) -// class File; - -BOOL InitSymInfo( PCSTR ); -BOOL UninitSymInfo(); -void StackTrace(HANDLE, char const* msg, FILE *file); -void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp); - -// functions by Masken -void etfprintf(FILE *file, const char *format, ...); -void etfprint(FILE *file, const std::string &text); -#define UEFBUFSIZE 2048 -extern char g_uefbuf[UEFBUFSIZE]; - -#else // not WIN32 - -#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) -#define EXTENDEDTRACEUNINITIALIZE() ((void)0) -#define STACKTRACE(file) ((void)0) -#define STACKTRACE2(file, eip, esp, ebp) ((void)0) - -#endif // WIN32 - -#endif // _EXTENDEDTRACE_H_INCLUDED_ diff --git a/src/common/src/fifo_queue.h b/src/common/src/fifo_queue.h deleted file mode 100644 index 57efcd83..00000000 --- a/src/common/src/fifo_queue.h +++ /dev/null @@ -1,115 +0,0 @@ - -#ifndef _FIFO_QUEUE_H_ -#define _FIFO_QUEUE_H_ - -// a simple lockless thread-safe, -// single reader, single writer queue - -#include "atomic.h" - -namespace Common -{ - -template -class FifoQueue -{ -public: - FifoQueue() : m_size(0) - { - m_write_ptr = m_read_ptr = new ElementPtr(); - } - - ~FifoQueue() - { - // this will empty out the whole queue - delete m_read_ptr; - } - - u32 Size() const - { - return m_size; - } - - bool Empty() const - { - //return (m_read_ptr == m_write_ptr); - return (0 == m_size); - } - - T& Front() const - { - return *m_read_ptr->current; - } - - template - void Push(Arg&& t) - { - // create the element, add it to the queue - m_write_ptr->current = new T(std::forward(t)); - // set the next pointer to a new element ptr - // then advance the write pointer - m_write_ptr = m_write_ptr->next = new ElementPtr(); - Common::AtomicIncrement(m_size); - } - - void Pop() - { - Common::AtomicDecrement(m_size); - ElementPtr *const tmpptr = m_read_ptr; - // advance the read pointer - m_read_ptr = m_read_ptr->next; - // set the next element to NULL to stop the recursive deletion - tmpptr->next = NULL; - delete tmpptr; // this also deletes the element - } - - bool Pop(T& t) - { - if (Empty()) - return false; - - t = std::move(Front()); - Pop(); - - return true; - } - - // not thread-safe - void Clear() - { - m_size = 0; - delete m_read_ptr; - m_write_ptr = m_read_ptr = new ElementPtr(); - } - -private: - // stores a pointer to element - // and a pointer to the next ElementPtr - class ElementPtr - { - public: - ElementPtr() : current(NULL), next(NULL) {} - - ~ElementPtr() - { - if (current) - { - delete current; - // recusion ftw - if (next) - delete next; - } - } - - T *volatile current; - ElementPtr *volatile next; - }; - - ElementPtr *volatile m_write_ptr; - ElementPtr *volatile m_read_ptr; - volatile u32 m_size; -}; - -} - -#endif diff --git a/src/common/src/file_search.cpp b/src/common/src/file_search.cpp deleted file mode 100644 index 59f64010..00000000 --- a/src/common/src/file_search.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "common_paths.h" -#ifndef _WIN32 -#include -#include -#else -#include -#endif - -#include -#include - -#include "file_search.h" - -#include "string_util.h" - - -CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories) -{ - // Reverse the loop order for speed? - for (size_t j = 0; j < _rSearchStrings.size(); j++) - { - for (size_t i = 0; i < _rDirectories.size(); i++) - { - FindFiles(_rSearchStrings[j], _rDirectories[i]); - } - } -} - - -void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) -{ - std::string GCMSearchPath; - BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); -#ifdef _WIN32 - WIN32_FIND_DATA findData; - HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); - - if (FindFirst != INVALID_HANDLE_VALUE) - { - bool bkeepLooping = true; - - while (bkeepLooping) - { - if (findData.cFileName[0] != '.') - { - std::string strFilename; - BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); - m_FileNames.push_back(strFilename); - } - - bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false; - } - } - FindClose(FindFirst); - - -#else - // TODO: super lame/broken - - auto end_match(_searchString); - - // assuming we have a "*.blah"-like pattern - if (!end_match.empty() && end_match[0] == '*') - end_match.erase(0, 1); - - // ugly - if (end_match == ".*") - end_match.clear(); - - DIR* dir = opendir(_strPath.c_str()); - - if (!dir) - return; - - while (auto const dp = readdir(dir)) - { - std::string found(dp->d_name); - - if ((found != ".") && (found != "..") - && (found.size() >= end_match.size()) - && std::equal(end_match.rbegin(), end_match.rend(), found.rbegin())) - { - std::string full_name; - if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR) - full_name = _strPath + found; - else - full_name = _strPath + DIR_SEP + found; - - m_FileNames.push_back(full_name); - } - } - - closedir(dir); -#endif -} - -const CFileSearch::XStringVector& CFileSearch::GetFileNames() const -{ - return m_FileNames; -} diff --git a/src/common/src/file_search.h b/src/common/src/file_search.h deleted file mode 100644 index 2a9ff801..00000000 --- a/src/common/src/file_search.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FILESEARCH_H_ -#define _FILESEARCH_H_ - -#include -#include - -class CFileSearch -{ -public: - typedef std::vectorXStringVector; - - CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories); - const XStringVector& GetFileNames() const; - -private: - - void FindFiles(const std::string& _searchString, const std::string& _strPath); - - XStringVector m_FileNames; -}; - -#endif // _FILESEARCH_H_ - diff --git a/src/common/src/file_util.cpp b/src/common/src/file_util.cpp deleted file mode 100644 index 8b47cb3e..00000000 --- a/src/common/src/file_util.cpp +++ /dev/null @@ -1,910 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "common_paths.h" -#include "file_util.h" -#include "string_util.h" - -#ifdef _WIN32 -#include -#include // for SHGetFolderPath -#include -#include // for GetSaveFileName -#include -#include // getcwd -#else -#include -#include -#include -#include -#include -#endif - -#if defined(__APPLE__) -#include -#include -#include -#endif - -#include -#include - -#include "string_util.h" - -#ifndef S_ISDIR -#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) -#endif - -#ifdef BSD4_4 -#define stat64 stat -#define fstat64 fstat -#endif - -// This namespace has various generic functions related to files and paths. -// The code still needs a ton of cleanup. -// REMEMBER: strdup considered harmful! -namespace File -{ - -// 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] == DIR_SEP_CHR) - fname[i--] = '\0'; - } - return; -} - -// Returns true if file filename exists -bool Exists(const std::string &filename) -{ - struct stat64 file_info; - - std::string copy(filename); - StripTailDirSlashes(copy); - -#ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); -#else - int result = stat64(copy.c_str(), &file_info); -#endif - - return (result == 0); -} - -// Returns true if filename is a directory -bool IsDirectory(const std::string &filename) -{ - struct stat64 file_info; - - std::string copy(filename); - StripTailDirSlashes(copy); - -#ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); -#else - int result = stat64(copy.c_str(), &file_info); -#endif - - if (result < 0) { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } - - return S_ISDIR(file_info.st_mode); -} - -// Deletes a given filename, return true on success -// Doesn't supports deleting a directory -bool Delete(const std::string &filename) -{ - INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); - - // Return true because we care about the file no - // being there, not the actual delete. - if (!Exists(filename)) - { - WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); - return true; - } - - // We can't delete a directory - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); - return false; - } - -#ifdef _WIN32 - if (!DeleteFile(UTF8ToTStr(filename).c_str())) - { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } -#else - if (unlink(filename.c_str()) == -1) { - WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } -#endif - - return true; -} - -// Returns true if successful, or path already exists. -bool CreateDir(const std::string &path) -{ - INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); -#ifdef _WIN32 - if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) - return true; - DWORD error = GetLastError(); - if (error == ERROR_ALREADY_EXISTS) - { - WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); - return true; - } - ERROR_LOG(COMMON, "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) - { - WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); - return true; - } - - ERROR_LOG(COMMON, "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; - INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - - if (File::Exists(fullPath)) - { - INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); - return true; - } - - size_t position = 0; - while (true) - { - // Find next sub path - position = fullPath.find(DIR_SEP_CHR, position); - - // we're done, yay! - if (position == fullPath.npos) - return true; - - // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") - std::string const subPath(fullPath.substr(0, position + 1)); - if (!File::IsDirectory(subPath)) - File::CreateDir(subPath); - - // A safety check - panicCounter--; - if (panicCounter <= 0) - { - ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); - return false; - } - position++; - } -} - - -// Deletes a directory filename, returns true on success -bool DeleteDir(const std::string &filename) -{ - INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); - - // check if a directory - if (!File::IsDirectory(filename)) - { - ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); - return false; - } - -#ifdef _WIN32 - if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) - return true; -#else - if (rmdir(filename.c_str()) == 0) - return true; -#endif - ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); - - return false; -} - -// renames file srcFilename to destFilename, returns true on success -bool Rename(const std::string &srcFilename, const std::string &destFilename) -{ - INFO_LOG(COMMON, "Rename: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); - if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) - return true; - ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; -} - -// copies file srcFilename to destFilename, returns true on success -bool Copy(const std::string &srcFilename, const std::string &destFilename) -{ - INFO_LOG(COMMON, "Copy: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); -#ifdef _WIN32 - if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) - return true; - - ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; -#else - - // buffer size -#define BSIZE 1024 - - char buffer[BSIZE]; - - // Open input file - FILE *input = fopen(srcFilename.c_str(), "rb"); - if (!input) - { - ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; - } - - // open output file - FILE *output = fopen(destFilename.c_str(), "wb"); - if (!output) - { - fclose(input); - ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; - } - - // copy loop - while (!feof(input)) - { - // read input - int rnum = fread(buffer, sizeof(char), BSIZE, input); - if (rnum != BSIZE) - { - if (ferror(input) != 0) - { - ERROR_LOG(COMMON, - "Copy: failed reading from source, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - goto bail; - } - } - - // write output - int wnum = fwrite(buffer, sizeof(char), rnum, output); - if (wnum != rnum) - { - ERROR_LOG(COMMON, - "Copy: failed writing to output, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - goto bail; - } - } - // close files - 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 GetSize(const std::string &filename) -{ - if (!Exists(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); - return 0; - } - - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); - return 0; - } - - struct stat64 buf; -#ifdef _WIN32 - if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) -#else - if (stat64(filename.c_str(), &buf) == 0) -#endif - { - DEBUG_LOG(COMMON, "GetSize: %s: %lld", - filename.c_str(), (long long)buf.st_size); - return buf.st_size; - } - - ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", - filename.c_str(), GetLastErrorMsg()); - return 0; -} - -// Overloaded GetSize, accepts file descriptor -u64 GetSize(const int fd) -{ - struct stat64 buf; - if (fstat64(fd, &buf) != 0) { - ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", - fd, GetLastErrorMsg()); - return 0; - } - return buf.st_size; -} - -// Overloaded GetSize, accepts FILE* -u64 GetSize(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) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); - return 0; - } - u64 size = ftello(f); - if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg()); - return 0; - } - return size; -} - -// creates an empty file filename, returns true on success -bool CreateEmptyFile(const std::string &filename) -{ - INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - - if (!File::IOFile(filename, "wb")) - { - ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", - filename.c_str(), GetLastErrorMsg()); - return false; - } - - return true; -} - - -// Scans the directory tree gets, starting from _Directory and adds the -// results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) -{ - INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); - // How many files + directories we found - u32 foundEntries = 0; -#ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; - - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return foundEntries; - } - // windows loop - do - { - FSTEntry entry; - const std::string virtualName(TStrToUTF8(ffd.cFileName)); -#else - struct dirent dirent, *result = NULL; - - DIR *dirp = opendir(directory.c_str()); - if (!dirp) - return 0; - - // non windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - FSTEntry entry; - 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; - entry.virtualName = virtualName; - entry.physicalName = directory; - entry.physicalName += DIR_SEP + entry.virtualName; - - if (IsDirectory(entry.physicalName.c_str())) - { - entry.isDirectory = true; - // is a directory, lets go inside - entry.size = ScanDirectoryTree(entry.physicalName, entry); - foundEntries += (u32)entry.size; - } - else - { // is a file - entry.isDirectory = false; - entry.size = GetSize(entry.physicalName.c_str()); - } - ++foundEntries; - // Push into the tree - parentEntry.children.push_back(entry); -#ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); -#else - } - closedir(dirp); -#endif - // Return number of entries found. - return foundEntries; -} - - -// Deletes the given directory and anything under it. Returns true on success. -bool DeleteDirRecursively(const std::string &directory) -{ - INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); -#ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return false; - } - - // windows loop - do - { - const std::string virtualName(TStrToUTF8(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 + DIR_SEP_CHR + virtualName; - if (IsDirectory(newPath)) - { - if (!DeleteDirRecursively(newPath)) - { - #ifndef _WIN32 - closedir(dirp); - #endif - - return false; - } - } - else - { - if (!File::Delete(newPath)) - { - #ifndef _WIN32 - closedir(dirp); - #endif - - return false; - } - } - -#ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); -#else - } - closedir(dirp); -#endif - File::DeleteDir(directory); - - return true; -} - -// Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string &source_path, const std::string &dest_path) -{ -#ifndef _WIN32 - if (source_path == dest_path) return; - if (!File::Exists(source_path)) return; - if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); - - struct dirent dirent, *result = NULL; - DIR *dirp = opendir(source_path.c_str()); - if (!dirp) return; - - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtualName(result->d_name); - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; - - std::string source, dest; - source = source_path + virtualName; - dest = dest_path + virtualName; - if (IsDirectory(source)) - { - source += '/'; - dest += '/'; - if (!File::Exists(dest)) File::CreateFullPath(dest); - CopyDir(source, dest); - } - else if (!File::Exists(dest)) File::Copy(source, dest); - } - closedir(dirp); -#endif -} - -// Returns the current directory -std::string GetCurrentDir() -{ - char *dir; - // Get the current working directory (getcwd uses malloc) - if (!(dir = __getcwd(NULL, 0))) { - - ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", - GetLastErrorMsg()); - 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; -} - -#if defined(__APPLE__) -std::string GetBundleDirectory() -{ - CFURLRef BundleRef; - char AppBundlePath[MAXPATHLEN]; - // Get the main bundle for the app - BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); - CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); - CFRelease(BundleRef); - CFRelease(BundlePath); - - return AppBundlePath; -} -#endif - -#ifdef _WIN32 -std::string& GetExeDirectory() -{ - static std::string DolphinPath; - if (DolphinPath.empty()) - { - TCHAR Dolphin_exe_Path[2048]; - GetModuleFileName(NULL, Dolphin_exe_Path, 2048); - DolphinPath = TStrToUTF8(Dolphin_exe_Path); - DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); - } - return DolphinPath; -} -#endif - -std::string GetSysDirectory() -{ - std::string sysDir; - -#if defined (__APPLE__) - sysDir = GetBundleDirectory(); - sysDir += DIR_SEP; - sysDir += SYSDATA_DIR; -#else - sysDir = SYSDATA_DIR; -#endif - sysDir += DIR_SEP; - - INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); - return sysDir; -} - -// Returns a string with a Dolphin data dir or file in the user's home -// directory. To be used in "multi-user" mode (that is, installed). -const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) -{ - static std::string paths[NUM_PATH_INDICES]; - - // Set up all paths and files on the first run - if (paths[D_USER_IDX].empty()) - { -#ifdef _WIN32 - paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; -#else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) - paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; - else - paths[D_USER_IDX] = std::string(getenv("HOME") ? - getenv("HOME") : getenv("PWD") ? - getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; -#endif - - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; - paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; - paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; - paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - } - - if (!newPath.empty()) - { - if (!File::IsDirectory(newPath)) - { - WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); - return paths[DirIDX]; - } - else - { - paths[DirIDX] = newPath; - } - - switch (DirIDX) - { - case D_ROOT_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; - paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; - break; - - case D_USER_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; - paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; - paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; - paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - break; - - case D_CONFIG_IDX: - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; - break; - - case D_DUMP_IDX: - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - break; - - case D_LOGS_IDX: - paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; - } - } - - return paths[DirIDX]; -} - -//std::string GetThemeDir(const std::string& theme_name) -//{ -// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; -// -//#if !defined(_WIN32) -// // If theme does not exist in user's dir load from shared directory -// if (!File::Exists(dir)) -// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; -//#endif -// -// return dir; -//} - -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) -{ - return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); -} - -bool ReadFileToString(bool text_file, const char *filename, std::string &str) -{ - File::IOFile file(filename, text_file ? "r" : "rb"); - auto const f = file.GetHandle(); - - if (!f) - return false; - - str.resize(static_cast(GetSize(f))); - return file.ReadArray(&str[0], str.size()); -} - -IOFile::IOFile() - : m_file(NULL), m_good(true) -{} - -IOFile::IOFile(std::FILE* file) - : m_file(file), m_good(true) -{} - -IOFile::IOFile(const std::string& filename, const char openmode[]) - : m_file(NULL), m_good(true) -{ - Open(filename, openmode); -} - -IOFile::~IOFile() -{ - Close(); -} - -IOFile::IOFile(IOFile&& other) - : m_file(NULL), m_good(true) -{ - Swap(other); -} - -IOFile& IOFile::operator=(IOFile&& other) -{ - Swap(other); - return *this; -} - -void IOFile::Swap(IOFile& other) -{ - std::swap(m_file, other.m_file); - std::swap(m_good, other.m_good); -} - -bool IOFile::Open(const std::string& filename, const char openmode[]) -{ - Close(); -#ifdef _WIN32 - _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); -#else - m_file = fopen(filename.c_str(), openmode); -#endif - - m_good = IsOpen(); - return m_good; -} - -bool IOFile::Close() -{ - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; - - m_file = NULL; - return m_good; -} - -std::FILE* IOFile::ReleaseHandle() -{ - std::FILE* const ret = m_file; - m_file = NULL; - return ret; -} - -void IOFile::SetHandle(std::FILE* file) -{ - Close(); - Clear(); - m_file = file; -} - -u64 IOFile::GetSize() -{ - if (IsOpen()) - return File::GetSize(m_file); - else - return 0; -} - -bool IOFile::Seek(s64 off, int origin) -{ - if (!IsOpen() || 0 != fseeko(m_file, off, origin)) - m_good = false; - - return m_good; -} - -u64 IOFile::Tell() -{ - if (IsOpen()) - return ftello(m_file); - else - return -1; -} - -bool IOFile::Flush() -{ - if (!IsOpen() || 0 != std::fflush(m_file)) - m_good = false; - - return m_good; -} - -bool IOFile::Resize(u64 size) -{ - if (!IsOpen() || 0 != -#ifdef _WIN32 - // ector: _chsize sucks, not 64-bit safe - // F|RES: changed to _chsize_s. i think it is 64-bit safe - _chsize_s(_fileno(m_file), size) -#else - // TODO: handle 64bit and growing - ftruncate(fileno(m_file), size) -#endif - ) - m_good = false; - - return m_good; -} - -} // namespace diff --git a/src/common/src/file_util.h b/src/common/src/file_util.h deleted file mode 100644 index f4ef949d..00000000 --- a/src/common/src/file_util.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FILEUTIL_H_ -#define _FILEUTIL_H_ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "string_util.h" - -// User directory indices for GetUserPath -enum { - D_USER_IDX, - D_ROOT_IDX, - D_CONFIG_IDX, - D_GAMECONFIG_IDX, - D_MAPS_IDX, - D_CACHE_IDX, - D_SHADERCACHE_IDX, - D_SHADERS_IDX, - D_STATESAVES_IDX, - D_SCREENSHOTS_IDX, - D_HIRESTEXTURES_IDX, - D_DUMP_IDX, - D_DUMPFRAMES_IDX, - D_DUMPAUDIO_IDX, - D_DUMPTEXTURES_IDX, - D_DUMPDSP_IDX, - D_LOGS_IDX, - D_SYSCONF_IDX, - F_EMUCONFIG_IDX, - F_DEBUGGERCONFIG_IDX, - F_LOGGERCONFIG_IDX, - F_MAINLOG_IDX, - F_RAMDUMP_IDX, - F_ARAMDUMP_IDX, - F_SYSCONF_IDX, - NUM_PATH_INDICES -}; - -namespace File -{ - -// FileSystem tree node/ -struct FSTEntry -{ - bool isDirectory; - u64 size; // file length or number of entries from children - std::string physicalName; // name on disk - std::string virtualName; // name in FST names table - std::vector children; -}; - -// Returns true if file filename exists -bool Exists(const std::string &filename); - -// Returns true if filename is a directory -bool IsDirectory(const std::string &filename); - -// Returns the size of filename (64bit) -u64 GetSize(const std::string &filename); - -// Overloaded GetSize, accepts file descriptor -u64 GetSize(const int fd); - -// Overloaded GetSize, accepts FILE* -u64 GetSize(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 Delete(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 Rename(const std::string &srcFilename, const std::string &destFilename); - -// copies file srcFilename to destFilename, returns true on success -bool Copy(const std::string &srcFilename, const std::string &destFilename); - -// creates an empty file filename, returns true on success -bool CreateEmptyFile(const std::string &filename); - -// Scans the directory tree gets, starting from _Directory and adds the -// results into parentEntry. Returns the number of files+directories found -u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry); - -// 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(); - -// Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string &source_path, const std::string &dest_path); - -// Set the current directory to given directory -bool SetCurrentDir(const std::string &directory); - -// Returns a pointer to a string with a Dolphin data dir in the user's home -// directory. To be used in "multi-user" mode (that is, installed). -const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); - -// probably doesn't belong here -//std::string GetThemeDir(const std::string& theme_name); - -// Returns the path to where the sys file are -std::string GetSysDirectory(); - -#ifdef __APPLE__ -std::string GetBundleDirectory(); -#endif - -#ifdef _WIN32 -std::string &GetExeDirectory(); -#endif - -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); -bool ReadFileToString(bool text_file, const char *filename, std::string &str); - -// simple wrapper for cstdlib file functions to -// hopefully will make error checking easier -// and make forgetting an fclose() harder -class IOFile : public NonCopyable -{ -public: - IOFile(); - IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); - - ~IOFile(); - - IOFile(IOFile&& other); - IOFile& operator=(IOFile&& other); - - void Swap(IOFile& other); - - bool Open(const std::string& filename, const char openmode[]); - bool Close(); - - template - bool ReadArray(T* data, size_t length) - { - if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) - m_good = false; - - return m_good; - } - - template - bool WriteArray(const T* data, size_t length) - { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) - m_good = false; - - return m_good; - } - - bool ReadBytes(void* data, size_t length) - { - return ReadArray(reinterpret_cast(data), length); - } - - bool WriteBytes(const void* data, size_t length) - { - return WriteArray(reinterpret_cast(data), length); - } - - bool IsOpen() { return NULL != m_file; } - - // m_good is set to false when a read, write or other function fails - bool IsGood() { return m_good; } - operator void*() { return m_good ? m_file : NULL; } - - std::FILE* ReleaseHandle(); - - std::FILE* GetHandle() { return m_file; } - - void SetHandle(std::FILE* file); - - bool Seek(s64 off, int origin); - u64 Tell(); - u64 GetSize(); - bool Resize(u64 size); - bool Flush(); - - // clear error state - void Clear() { m_good = true; std::clearerr(m_file); } - - std::FILE* m_file; - bool m_good; -private: - IOFile(IOFile&); - IOFile& operator=(IOFile& other); -}; - -} // namespace - -// To deal with Windows being dumb at unicode: -template -void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) -{ -#ifdef _WIN32 - fstream.open(UTF8ToTStr(filename).c_str(), openmode); -#else - fstream.open(filename.c_str(), openmode); -#endif -} - -#endif diff --git a/src/common/src/fixed_size_queue.h b/src/common/src/fixed_size_queue.h deleted file mode 100644 index 1f507f4a..00000000 --- a/src/common/src/fixed_size_queue.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _FIXED_SIZE_QUEUE_H_ -#define _FIXED_SIZE_QUEUE_H_ - -// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the -// real STL classes. - -// Not fully featured, no safety checking yet. Add features as needed. - -// TODO: "inline" storage? - -template -class fixed_size_queue.h -{ - T *storage; - int head; - int tail; - int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. - - // Make copy constructor private for now. - fixed_size_queue.h(fixed_size_queue.h &other) { } - -public: - fixed_size_queue.h() - { - storage = new T[N]; - clear(); - } - - ~fixed_size_queue.h() - { - delete [] storage; - } - - void clear() { - head = 0; - tail = 0; - count = 0; - } - - void push(T t) { - storage[tail] = t; - tail++; - if (tail == N) - tail = 0; - count++; - } - - void pop() { - head++; - if (head == N) - head = 0; - count--; - } - - T pop_front() { - const T &temp = storage[head]; - pop(); - return temp; - } - - T &front() { return storage[head]; } - const T &front() const { return storage[head]; } - - size_t size() const { - return count; - } -}; - -#endif // _FIXED_SIZE_QUEUE_H_ - diff --git a/src/common/src/hash.cpp b/src/common/src/hash.cpp deleted file mode 100644 index 5303f07b..00000000 --- a/src/common/src/hash.cpp +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "hash.h" -#if _M_SSE >= 0x402 -#include "cpu_detect.h" -#include -#endif - -static u64 (*ptrHashFunction)(const u8 *src, int len, u32 samples) = &GetMurmurHash3; - -// uint32_t -// WARNING - may read one more byte! -// Implementation from Wikipedia. -u32 HashFletcher(const u8* data_u8, size_t length) -{ - const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */ - size_t len = (length + 1) / 2; /* Length in 16-bit words */ - u32 sum1 = 0xffff, sum2 = 0xffff; - - while (len) - { - size_t tlen = len > 360 ? 360 : len; - len -= tlen; - - do { - sum1 += *data++; - sum2 += sum1; - } - while (--tlen); - - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - } - - // Second reduction step to reduce sums to 16 bits - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - return(sum2 << 16 | sum1); -} - - -// Implementation from Wikipedia -// Slightly slower than Fletcher above, but slightly more reliable. -#define MOD_ADLER 65521 -// data: Pointer to the data to be summed; len is in bytes -u32 HashAdler32(const u8* data, size_t len) -{ - u32 a = 1, b = 0; - - while (len) - { - size_t tlen = len > 5550 ? 5550 : len; - len -= tlen; - - do - { - a += *data++; - b += a; - } - while (--tlen); - - a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); - b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); - } - - // It can be shown that a <= 0x1013a here, so a single subtract will do. - if (a >= MOD_ADLER) - { - a -= MOD_ADLER; - } - - // It can be shown that b can reach 0xfff87 here. - b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); - - if (b >= MOD_ADLER) - { - b -= MOD_ADLER; - } - - return((b << 16) | a); -} - -// Stupid hash - but can't go back now :) -// Don't use for new things. At least it's reasonably fast. -u32 HashEctor(const u8* ptr, int length) -{ - u32 crc = 0; - - for (int i = 0; i < length; i++) - { - crc ^= ptr[i]; - crc = (crc << 3) | (crc >> 29); - } - - return(crc); -} - - -#ifdef _M_X64 - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -inline u64 getblock(const u64 * p, int i) -{ - return p[i]; -} - -//---------- -// 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; -} - -u64 GetMurmurHash3(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 = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - - u64 h1 = 0x9368e53c2f6af274; - u64 h2 = 0x586dcd208f7cd3fd; - - u64 c1 = 0x87c37b91114253d5; - u64 c2 = 0x4cf5ad432745937f; - - - //---------- - // body - - const u64 * blocks = (const u64 *)(data); - - for(int i = 0; i < nblocks; i+=Step) - { - u64 k1 = getblock(blocks,i*2+0); - u64 k2 = getblock(blocks,i*2+1); - - bmix64(h1,h2,k1,k2,c1,c2); - } - - //---------- - // tail - - 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); - }; - - //---------- - // finalization - - h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = fmix64(h1); - h2 = fmix64(h2); - - h1 += h2; - - return h1; -} - - -// CRC32 hash using the SSE4.2 instruction -u64 GetCRC32(const u8 *src, int len, u32 samples) -{ -#if _M_SSE >= 0x402 - u64 h = len; - u32 Step = (len / 8); - const u64 *data = (const u64 *)src; - const u64 *end = data + Step; - if(samples == 0) samples = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - while(data < end) - { - h = _mm_crc32_u64(h, data[0]); - data += Step; - } - - const u8 *data2 = (const u8*)end; - return _mm_crc32_u64(h, u64(data2[0])); -#else - return 0; -#endif -} - - -/* - * NOTE: This hash function is used for custom texture loading/dumping, so - * it should not be changed, which would require all custom textures to be - * recalculated for their new hash values. If the hashing function is - * changed, make sure this one is still used when the legacy parameter is - * true. - */ -u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) -{ - const u64 m = 0xc6a4a7935bd1e995; - u64 h = len * m; - const int r = 47; - u32 Step = (len / 8); - const u64 *data = (const u64 *)src; - const u64 *end = data + Step; - if(samples == 0) samples = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - while(data < end) - { - u64 k = data[0]; - data+=Step; - k *= m; - k ^= k >> r; - k *= m; - h ^= k; - h *= m; - } - - const u8 * data2 = (const u8*)end; - - switch(len & 7) - { - case 7: h ^= u64(data2[6]) << 48; - case 6: h ^= u64(data2[5]) << 40; - case 5: h ^= u64(data2[4]) << 32; - case 4: h ^= u64(data2[3]) << 24; - case 3: h ^= u64(data2[2]) << 16; - case 2: h ^= u64(data2[1]) << 8; - case 1: h ^= u64(data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; -} -#else -// CRC32 hash using the SSE4.2 instruction -u64 GetCRC32(const u8 *src, int len, u32 samples) -{ -#if _M_SSE >= 0x402 - u32 h = len; - u32 Step = (len/4); - const u32 *data = (const u32 *)src; - const u32 *end = data + Step; - if(samples == 0) samples = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - while(data < end) - { - h = _mm_crc32_u32(h, data[0]); - data += Step; - } - - const u8 *data2 = (const u8*)end; - return (u64)_mm_crc32_u32(h, u32(data2[0])); -#else - return 0; -#endif -} - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -inline u32 getblock(const u32 * p, int i) -{ - return p[i]; -} - -//---------- -// Finalization mix - force all bits of a hash block to avalanche - -// avalanches all bits to within 0.25% bias - -inline u32 fmix32(u32 h) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2) -{ - k1 *= c1; - k1 = _rotl(k1,11); - k1 *= c2; - h1 ^= k1; - h1 += h2; - - h2 = _rotl(h2,17); - - k2 *= c2; - k2 = _rotl(k2,11); - k2 *= c1; - h2 ^= k2; - h2 += h1; - - h1 = h1*3+0x52dce729; - h2 = h2*3+0x38495ab5; - - c1 = c1*5+0x7b7d159c; - c2 = c2*5+0x6bce6396; -} - -//---------- - -u64 GetMurmurHash3(const u8* src, int len, u32 samples) -{ - const u8 * data = (const u8*)src; - u32 out[2]; - const int nblocks = len / 8; - u32 Step = (len / 4); - if(samples == 0) samples = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - - u32 h1 = 0x8de1c3ac; - u32 h2 = 0xbab98226; - - u32 c1 = 0x95543787; - u32 c2 = 0x2ad7eb25; - - //---------- - // body - - const u32 * blocks = (const u32 *)(data + nblocks*8); - - for(int i = -nblocks; i < 0; i+=Step) - { - u32 k1 = getblock(blocks,i*2+0); - u32 k2 = getblock(blocks,i*2+1); - - bmix32(h1,h2,k1,k2,c1,c2); - } - - //---------- - // tail - - const u8 * tail = (const u8*)(data + nblocks*8); - - u32 k1 = 0; - u32 k2 = 0; - - switch(len & 7) - { - case 7: k2 ^= tail[6] << 16; - case 6: k2 ^= tail[5] << 8; - case 5: k2 ^= tail[4] << 0; - case 4: k1 ^= tail[3] << 24; - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0] << 0; - bmix32(h1,h2,k1,k2,c1,c2); - }; - - //---------- - // finalization - - h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = fmix32(h1); - h2 = fmix32(h2); - - h1 += h2; - h2 += h1; - - out[0] = h1; - out[1] = h2; - - return *((u64 *)&out); -} - -/* - * FIXME: The old 32-bit version of this hash made different hashes than the - * 64-bit version. Until someone can make a new version of the 32-bit one that - * makes identical hashes, this is just a c/p of the 64-bit one. - */ -u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) -{ - const u64 m = 0xc6a4a7935bd1e995ULL; - u64 h = len * m; - const int r = 47; - u32 Step = (len / 8); - const u64 *data = (const u64 *)src; - const u64 *end = data + Step; - if(samples == 0) samples = max(Step, 1u); - Step = Step / samples; - if(Step < 1) Step = 1; - while(data < end) - { - u64 k = data[0]; - data+=Step; - k *= m; - k ^= k >> r; - k *= m; - h ^= k; - h *= m; - } - - const u8 * data2 = (const u8*)end; - - switch(len & 7) - { - case 7: h ^= u64(data2[6]) << 48; - case 6: h ^= u64(data2[5]) << 40; - case 5: h ^= u64(data2[4]) << 32; - case 4: h ^= u64(data2[3]) << 24; - case 3: h ^= u64(data2[2]) << 16; - case 2: h ^= u64(data2[1]) << 8; - case 1: h ^= u64(data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; -} -#endif - -u64 GetHash64(const u8 *src, int len, u32 samples) -{ - return ptrHashFunction(src, len, samples); -} - -// sets the hash function used for the texture cache -void SetHash64Function(bool useHiresTextures) -{ - if (useHiresTextures) - { - ptrHashFunction = &GetHashHiresTexture; - } -#if _M_SSE >= 0x402 - else if (cpu_info.bSSE4_2 && !useHiresTextures) // sse crc32 version - { - ptrHashFunction = &GetCRC32; - } -#endif - else - { - ptrHashFunction = &GetMurmurHash3; - } -} - - - diff --git a/src/common/src/hash.h b/src/common/src/hash.h deleted file mode 100644 index addfa4b5..00000000 --- a/src/common/src/hash.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _HASH_H_ -#define _HASH_H_ - -#include "common.h" - -u32 HashFletcher(const u8* data_u8, size_t length); // FAST. Length & 1 == 0. -u32 HashAdler32(const u8* data, size_t len); // Fairly accurate, slightly slower -u32 HashFNV(const u8* ptr, int length); // Another fast and decent hash -u32 HashEctor(const u8* ptr, int length); // JUNK. DO NOT USE FOR NEW THINGS -u64 GetCRC32(const u8 *src, int len, u32 samples); // SSE4.2 version of CRC32 -u64 GetHashHiresTexture(const u8 *src, int len, u32 samples); -u64 GetMurmurHash3(const u8 *src, int len, u32 samples); -u64 GetHash64(const u8 *src, int len, u32 samples); -void SetHash64Function(bool useHiresTextures); -#endif // _HASH_H_ diff --git a/src/common/src/linear_disk_cache.h b/src/common/src/linear_disk_cache.h deleted file mode 100644 index da5d6b9b..00000000 --- a/src/common/src/linear_disk_cache.h +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _LINEAR_DISKCACHE -#define _LINEAR_DISKCACHE - -#include "common.h" -#include - -// defined in Version.cpp -extern const char *scm_rev_git_str; - -// On disk format: -//header{ -// u32 'DCAC'; -// u32 version; // svn_rev -// u16 sizeof(key_type); -// u16 sizeof(value_type); -//} - -//key_value_pair{ -// u32 value_size; -// key_type key; -// value_type[value_size] value; -//} - -template -class LinearDiskCacheReader -{ -public: - virtual void Read(const K &key, const V *value, u32 value_size) = 0; -}; - -// Dead simple unsorted key-value store with append functionality. -// No random read functionality, all reading is done in OpenAndRead. -// Keys and values can contain any characters, including \0. -// -// Suitable for caching generated shader bytecode between executions. -// Not tuned for extreme performance but should be reasonably fast. -// Does not support keys or values larger than 2GB, which should be reasonable. -// Keys must have non-zero length; values can have zero length. - -// K and V are some POD type -// K : the key type -// V : value array type -template -class LinearDiskCache -{ -public: - // return number of read entries - u32 OpenAndRead(const char *filename, LinearDiskCacheReader &reader) - { - using std::ios_base; - - // close any currently opened file - Close(); - m_num_entries = 0; - - // try opening for reading/writing - OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); - - m_file.seekg(0, std::ios::end); - std::fstream::pos_type end_pos = m_file.tellg(); - m_file.seekg(0, std::ios::beg); - std::fstream::pos_type start_pos = m_file.tellg(); - std::streamoff file_size = end_pos - start_pos; - - if (m_file.is_open() && ValidateHeader()) - { - // good header, read some key/value pairs - K key; - - V *value = NULL; - u32 value_size; - u32 entry_number; - - std::fstream::pos_type last_pos = m_file.tellg(); - - while (Read(&value_size)) - { - std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; - if (next_extent > file_size) - break; - - delete[] value; - value = new V[value_size]; - - // read key/value and pass to reader - if (Read(&key) && - Read(value, value_size) && - Read(&entry_number) && - entry_number == m_num_entries+1) - { - reader.Read(key, value, value_size); - } - else - { - break; - } - - m_num_entries++; - last_pos = m_file.tellg(); - } - m_file.seekp(last_pos); - m_file.clear(); - - delete[] value; - return m_num_entries; - } - - // failed to open file for reading or bad header - // close and recreate file - Close(); - m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); - WriteHeader(); - return 0; - } - - void Sync() - { - m_file.flush(); - } - - void Close() - { - if (m_file.is_open()) - m_file.close(); - // clear any error flags - m_file.clear(); - } - - // Appends a key-value pair to the store. - void Append(const K &key, const V *value, u32 value_size) - { - // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) - Write(&value_size); - Write(&key); - Write(value, value_size); - m_num_entries++; - Write(&m_num_entries); - } - -private: - void WriteHeader() - { - Write(&m_header); - } - - bool ValidateHeader() - { - char file_header[sizeof(Header)]; - - return (Read(file_header, sizeof(Header)) - && !memcmp((const char*)&m_header, file_header, sizeof(Header))); - } - - template - bool Write(const D *data, u32 count = 1) - { - return m_file.write((const char*)data, count * sizeof(D)).good(); - } - - template - bool Read(const D *data, u32 count = 1) - { - return m_file.read((char*)data, count * sizeof(D)).good(); - } - - struct Header - { - Header() - : id(*(u32*)"DCAC") - , key_t_size(sizeof(K)) - , value_t_size(sizeof(V)) - { - memcpy(ver, scm_rev_git_str, 40); - } - - const u32 id; - const u16 key_t_size, value_t_size; - char ver[40]; - - } m_header; - - std::fstream m_file; - u32 m_num_entries; -}; - -#endif // _LINEAR_DISKCACHE diff --git a/src/common/src/log.h b/src/common/src/log.h deleted file mode 100644 index 432a307f..00000000 --- a/src/common/src/log.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _LOG_H_ -#define _LOG_H_ - -#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. -#define ERROR_LEVEL 2 // Critical errors -#define WARNING_LEVEL 3 // Something is suspicious. -#define INFO_LEVEL 4 // General information. -#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. - -namespace LogTypes -{ - -enum LOG_TYPE { - ACTIONREPLAY, - AUDIO, - AUDIO_INTERFACE, - BOOT, - COMMANDPROCESSOR, - COMMON, - CONSOLE, - DISCIO, - FILEMON, - DSPHLE, - DSPLLE, - DSP_MAIL, - DSPINTERFACE, - DVDINTERFACE, - DYNA_REC, - EXPANSIONINTERFACE, - GDB_STUB, - ARM11, - GPFIFO, - OSHLE, - MASTER_LOG, - MEMMAP, - MEMCARD_MANAGER, - OSREPORT, - PAD, - PROCESSORINTERFACE, - PIXELENGINE, - SERIALINTERFACE, - SP1, - STREAMINGINTERFACE, - VIDEO, - VIDEOINTERFACE, - LOADER, - FILESYS, - WII_IPC_DVD, - WII_IPC_ES, - WII_IPC_FILEIO, - WII_IPC_HID, - WII_IPC_HLE, - WII_IPC_NET, - WII_IPC_WC24, - WII_IPC_SSL, - RENDER, - LCD, - HW, - TIME, - NETPLAY, - - NUMBER_OF_LOGS // Must be last -}; - -// FIXME: should this be removed? -enum LOG_LEVELS { - LNOTICE = NOTICE_LEVEL, - LERROR = ERROR_LEVEL, - LWARNING = WARNING_LEVEL, - LINFO = INFO_LEVEL, - LDEBUG = DEBUG_LEVEL, -}; - -#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS -#define LOGTYPES_TYPE LogTypes::LOG_TYPE - -} // namespace - -void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, - const char *file, int line, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 5, 6))) -#endif - ; - -#if defined LOGGING || defined _DEBUG || defined DEBUGFAST -#define MAX_LOGLEVEL DEBUG_LEVEL -#else -#ifndef MAX_LOGLEVEL -#define MAX_LOGLEVEL WARNING_LEVEL -#endif // loglevel -#endif // logging - -#ifdef GEKKO -#define GENERIC_LOG(t, v, ...) -#else -// Let the compiler optimize this out -#define GENERIC_LOG(t, v, ...) { \ - if (v <= MAX_LOGLEVEL) \ - GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ - } -#endif - -#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) -#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) -#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) -#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0) -#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0) - -#if MAX_LOGLEVEL >= DEBUG_LEVEL -#define _dbg_assert_(_t_, _a_) \ - if (!(_a_)) {\ - ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \ - __LINE__, __FILE__, __TIME__); \ - if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \ - } -#define _dbg_assert_msg_(_t_, _a_, ...)\ - if (!(_a_)) {\ - ERROR_LOG(_t_, __VA_ARGS__); \ - if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ - } -#define _dbg_update_() Host_UpdateLogDisplay(); - -#else // not debug -#define _dbg_update_() ; - -#ifndef _dbg_assert_ -#define _dbg_assert_(_t_, _a_) {} -#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} -#endif // dbg_assert -#endif // MAX_LOGLEVEL DEBUG - -#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_) - -#ifndef GEKKO -#ifdef _WIN32 -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ - } -#else // not win32 -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ - } -#endif // WIN32 -#else // GEKKO -#define _assert_msg_(_t_, _a_, _fmt_, ...) -#endif - -#endif // _LOG_H_ diff --git a/src/common/src/log_manager.cpp b/src/common/src/log_manager.cpp deleted file mode 100644 index b5b03484..00000000 --- a/src/common/src/log_manager.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#ifdef ANDROID -#include "Host.h" -#endif -#include "log_manager.h" -#include "console_listener.h" -#include "timer.h" -#include "thread.h" -#include "file_util.h" - -void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - if (LogManager::GetInstance()) - LogManager::GetInstance()->Log(level, type, - file, line, fmt, args); - va_end(args); -} - -LogManager *LogManager::m_logManager = NULL; - -LogManager::LogManager() -{ - // create log files - m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); - m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); - m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); - m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); - m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); - m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); - m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); - m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); - m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt"); - m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt"); - m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); - m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); - m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); - m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); - m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); - m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); - m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); - m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); - m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); - m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); - m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11"); - m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); - m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); - m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); - m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); - m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); - m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); - m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT"); - m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); - m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); - m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing"); - m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader"); - m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); - m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); - m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); - m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); - m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); - m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); - m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); - m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); - m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); - m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); - m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); - m_Log[LogTypes::HW] = new LogContainer("HARDWARE", "HARDWARE"); - m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); - m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); - m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); - - m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); - m_consoleLog = new ConsoleListener(); - m_debuggerLog = new DebuggerLogListener(); - - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_Log[i]->SetEnable(true); - m_Log[i]->AddListener(m_fileLog); - m_Log[i]->AddListener(m_consoleLog); -#ifdef _MSC_VER - if (IsDebuggerPresent()) - m_Log[i]->AddListener(m_debuggerLog); -#endif - } -} - -LogManager::~LogManager() -{ - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog); - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog); - m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog); - } - - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - delete m_Log[i]; - - delete m_fileLog; - delete m_consoleLog; - delete m_debuggerLog; -} - -void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char *format, va_list args) -{ - char temp[MAX_MSGLEN]; - char msg[MAX_MSGLEN * 2]; - LogContainer *log = m_Log[type]; - - if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) - return; - - CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); - - static const char level_to_char[7] = "-NEWID"; - sprintf(msg, "%s %s:%u %c[%s]: %s\n", - Common::Timer::GetTimeFormatted().c_str(), - file, line, level_to_char[(int)level], - log->GetShortName(), temp); -#ifdef ANDROID - Host_SysMessage(msg); -#endif - printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this - log->Trigger(level, msg); -} - -void LogManager::Init() -{ - m_logManager = new LogManager(); -} - -void LogManager::Shutdown() -{ - delete m_logManager; - m_logManager = NULL; -} - -LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable) - : m_enable(enable) -{ - strncpy(m_fullName, fullName, 128); - strncpy(m_shortName, shortName, 32); - m_level = LogTypes::LWARNING; -} - -// LogContainer -void LogContainer::AddListener(LogListener *listener) -{ - std::lock_guard lk(m_listeners_lock); - m_listeners.insert(listener); -} - -void LogContainer::RemoveListener(LogListener *listener) -{ - std::lock_guard lk(m_listeners_lock); - m_listeners.erase(listener); -} - -void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) -{ - std::lock_guard lk(m_listeners_lock); - - std::set::const_iterator i; - for (i = m_listeners.begin(); i != m_listeners.end(); ++i) - { - (*i)->Log(level, msg); - } -} - -FileLogListener::FileLogListener(const char *filename) -{ - OpenFStream(m_logfile, filename, std::ios::app); - SetEnable(true); -} - -void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) -{ - if (!IsEnabled() || !IsValid()) - return; - - std::lock_guard lk(m_log_lock); - m_logfile << msg << std::flush; -} - -void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) -{ -#if _MSC_VER - ::OutputDebugStringA(msg); -#endif -} diff --git a/src/common/src/log_manager.h b/src/common/src/log_manager.h deleted file mode 100644 index 579198ff..00000000 --- a/src/common/src/log_manager.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _LOGMANAGER_H_ -#define _LOGMANAGER_H_ - -#include "log.h" -#include "string_util.h" -#include "thread.h" -#include "file_util.h" - -#include -#include - -#define MAX_MESSAGES 8000 -#define MAX_MSGLEN 1024 - - -// pure virtual interface -class LogListener -{ -public: - virtual ~LogListener() {} - - virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0; -}; - -class FileLogListener : public LogListener -{ -public: - FileLogListener(const char *filename); - - void Log(LogTypes::LOG_LEVELS, const char *msg); - - bool IsValid() { return !m_logfile.fail(); } - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - const char* GetName() const { return "file"; } - -private: - std::mutex m_log_lock; - std::ofstream m_logfile; - bool m_enable; -}; - -class DebuggerLogListener : public LogListener -{ -public: - void Log(LogTypes::LOG_LEVELS, const char *msg); -}; - -class LogContainer -{ -public: - LogContainer(const char* shortName, const char* fullName, bool enable = false); - - const char* GetShortName() const { return m_shortName; } - const char* GetFullName() const { return m_fullName; } - - void AddListener(LogListener* listener); - void RemoveListener(LogListener* listener); - - void Trigger(LogTypes::LOG_LEVELS, const char *msg); - - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - LogTypes::LOG_LEVELS GetLevel() const { return m_level; } - - void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } - - bool HasListeners() const { return !m_listeners.empty(); } - -private: - char m_fullName[128]; - char m_shortName[32]; - bool m_enable; - LogTypes::LOG_LEVELS m_level; - std::mutex m_listeners_lock; - std::set m_listeners; -}; - -class ConsoleListener; - -class LogManager : NonCopyable -{ -private: - LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; - FileLogListener *m_fileLog; - ConsoleListener *m_consoleLog; - DebuggerLogListener *m_debuggerLog; - static LogManager *m_logManager; // Singleton. Ugh. - - LogManager(); - ~LogManager(); -public: - - static u32 GetMaxLevel() { return MAX_LOGLEVEL; } - - void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char *file, int line, const char *fmt, va_list args); - - void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) - { - m_Log[type]->SetLevel(level); - } - - void SetEnable(LogTypes::LOG_TYPE type, bool enable) - { - m_Log[type]->SetEnable(enable); - } - - bool IsEnabled(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->IsEnabled(); - } - - const char* GetShortName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetShortName(); - } - - const char* GetFullName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetFullName(); - } - - void AddListener(LogTypes::LOG_TYPE type, LogListener *listener) - { - m_Log[type]->AddListener(listener); - } - - void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener) - { - m_Log[type]->RemoveListener(listener); - } - - FileLogListener *GetFileListener() const - { - return m_fileLog; - } - - ConsoleListener *GetConsoleListener() const - { - return m_consoleLog; - } - - DebuggerLogListener *GetDebuggerListener() const - { - return m_debuggerLog; - } - - static LogManager* GetInstance() - { - return m_logManager; - } - - static void SetInstance(LogManager *logManager) - { - m_logManager = logManager; - } - - static void Init(); - static void Shutdown(); -}; - -#endif // _LOGMANAGER_H_ diff --git a/src/common/src/math_util.cpp b/src/common/src/math_util.cpp deleted file mode 100644 index da90f8d7..00000000 --- a/src/common/src/math_util.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "math_util.h" - -#include -#include - -namespace MathUtil -{ - -u32 ClassifyDouble(double dvalue) -{ - // TODO: Optimize the below to be as fast as possible. - IntDouble value; - value.d = dvalue; - u64 sign = value.i & DOUBLE_SIGN; - u64 exp = value.i & DOUBLE_EXP; - if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u64 mantissa = value.i & DOUBLE_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - //Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } -} - -u32 ClassifyFloat(float fvalue) -{ - // TODO: Optimize the below to be as fast as possible. - IntFloat value; - value.f = fvalue; - u32 sign = value.i & FLOAT_SIGN; - u32 exp = value.i & FLOAT_EXP; - if (exp > FLOAT_ZERO && exp < FLOAT_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u32 mantissa = value.i & FLOAT_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; // Quiet NAN - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - // Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } -} - - -} // namespace - -inline void MatrixMul(int n, const float *a, const float *b, float *result) -{ - for (int i = 0; i < n; ++i) - { - for (int j = 0; j < n; ++j) - { - float temp = 0; - for (int k = 0; k < n; ++k) - { - temp += a[i * n + k] * b[k * n + j]; - } - result[i * n + j] = temp; - } - } -} - -// Calculate sum of a float list -float MathFloatVectorSum(const std::vector& Vec) -{ - return std::accumulate(Vec.begin(), Vec.end(), 0.0f); -} - -void Matrix33::LoadIdentity(Matrix33 &mtx) -{ - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[4] = 1.0f; - mtx.data[8] = 1.0f; -} - -void Matrix33::RotateX(Matrix33 &mtx, float rad) -{ - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1; - mtx.data[4] = c; - mtx.data[5] = -s; - mtx.data[7] = s; - mtx.data[8] = c; -} -void Matrix33::RotateY(Matrix33 &mtx, float rad) -{ - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = c; - mtx.data[2] = s; - mtx.data[4] = 1; - mtx.data[6] = -s; - mtx.data[8] = c; -} - -void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result) -{ - MatrixMul(3, a.data, b.data, result.data); -} - -void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3]) -{ - for (int i = 0; i < 3; ++i) { - result[i] = 0; - for (int k = 0; k < 3; ++k) { - result[i] += a.data[i * 3 + k] * vec[k]; - } - } -} - -void Matrix44::LoadIdentity(Matrix44 &mtx) -{ - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[5] = 1.0f; - mtx.data[10] = 1.0f; - mtx.data[15] = 1.0f; -} - -void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33) -{ - for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - mtx.data[i * 4 + j] = m33.data[i * 3 + j]; - } - } - - for (int i = 0; i < 3; ++i) - { - mtx.data[i * 4 + 3] = 0; - mtx.data[i + 12] = 0; - } - mtx.data[15] = 1.0f; -} - -void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16]) -{ - for(int i = 0; i < 16; ++i) { - mtx.data[i] = mtxArray[i]; - } -} - -void Matrix44::Translate(Matrix44 &mtx, const float vec[3]) -{ - LoadIdentity(mtx); - mtx.data[3] = vec[0]; - mtx.data[7] = vec[1]; - mtx.data[11] = vec[2]; -} - -void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) -{ - MatrixMul(4, a.data, b.data, result.data); -} - diff --git a/src/common/src/math_util.h b/src/common/src/math_util.h deleted file mode 100644 index 4410c5e0..00000000 --- a/src/common/src/math_util.h +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _MATH_UTIL_H_ -#define _MATH_UTIL_H_ - -#include "common.h" - -#include - -namespace MathUtil -{ - -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL, - DOUBLE_EXP = 0x7FF0000000000000ULL, - DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL, - DOUBLE_ZERO = 0x0000000000000000ULL; - -static const u32 FLOAT_SIGN = 0x80000000, - FLOAT_EXP = 0x7F800000, - FLOAT_FRAC = 0x007FFFFF, - FLOAT_ZERO = 0x00000000; - -union IntDouble { - double d; - u64 i; -}; -union IntFloat { - float f; - u32 i; -}; - -inline bool IsNAN(double d) -{ - IntDouble x; x.d = d; - return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) ); -} - -inline bool IsQNAN(double d) -{ - IntDouble x; x.d = d; - return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) && - ((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) ); -} - -inline bool IsSNAN(double d) -{ - IntDouble x; x.d = d; - return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) && - ((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) ); -} - -inline float FlushToZero(float f) -{ - IntFloat x; x.f = f; - if ((x.i & FLOAT_EXP) == 0) - x.i &= FLOAT_SIGN; // turn into signed zero - return x.f; -} - -inline double FlushToZeroAsFloat(double d) -{ - IntDouble x; x.d = d; - if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL) - x.i &= DOUBLE_SIGN; // turn into signed zero - return x.d; -} - -enum PPCFpClass -{ - PPC_FPCLASS_QNAN = 0x11, - PPC_FPCLASS_NINF = 0x9, - PPC_FPCLASS_NN = 0x8, - PPC_FPCLASS_ND = 0x18, - PPC_FPCLASS_NZ = 0x12, - PPC_FPCLASS_PZ = 0x2, - PPC_FPCLASS_PD = 0x14, - PPC_FPCLASS_PN = 0x4, - PPC_FPCLASS_PINF = 0x5, -}; - -// Uses PowerPC conventions for the return value, so it can be easily -// used directly in CPU emulation. -u32 ClassifyDouble(double dvalue); -// More efficient float version. -u32 ClassifyFloat(float fvalue); - -template -struct Rectangle -{ - T left; - T top; - T right; - T bottom; - - Rectangle() - { } - - Rectangle(T theLeft, T theTop, T theRight, T theBottom) - : left(theLeft), top(theTop), right(theRight), bottom(theBottom) - { } - - bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } - - T GetWidth() const { return abs(right - left); } - T GetHeight() const { return abs(bottom - top); } - - // If the rectangle is in a coordinate system with a lower-left origin, use - // this Clamp. - void ClampLL(T x1, T y1, T x2, T y2) - { - if (left < x1) left = x1; - if (right > x2) right = x2; - if (top > y1) top = y1; - if (bottom < y2) bottom = y2; - } - - // If the rectangle is in a coordinate system with an upper-left origin, - // use this Clamp. - void ClampUL(T x1, T y1, T x2, T y2) - { - if (left < x1) left = x1; - if (right > x2) right = x2; - if (top < y1) top = y1; - if (bottom > y2) bottom = y2; - } -}; - -} // namespace MathUtil - -inline float pow2f(float x) {return x * x;} -inline double pow2(double x) {return x * x;} - -float MathFloatVectorSum(const std::vector&); - -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) - -// Rounds down. 0 -> undefined -inline u64 Log2(u64 val) -{ -#if defined(__GNUC__) - return 63 - __builtin_clzll(val); - -#elif defined(_MSC_VER) && defined(_M_X64) - unsigned long result = -1; - _BitScanReverse64(&result, val); - return result; - -#else - u64 result = -1; - while (val != 0) - { - val >>= 1; - ++result; - } - return result; -#endif -} - -// Tiny matrix/vector library. -// Used for things like Free-Look in the gfx backend. - -class Matrix33 -{ -public: - static void LoadIdentity(Matrix33 &mtx); - - // set mtx to be a rotation matrix around the x axis - static void RotateX(Matrix33 &mtx, float rad); - // set mtx to be a rotation matrix around the y axis - static void RotateY(Matrix33 &mtx, float rad); - - // set result = a x b - static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); - static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); - - float data[9]; -}; - -class Matrix44 -{ -public: - static void LoadIdentity(Matrix44 &mtx); - static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); - static void Set(Matrix44 &mtx, const float mtxArray[16]); - - static void Translate(Matrix44 &mtx, const float vec[3]); - - static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); - - float data[16]; -}; - -#endif // _MATH_UTIL_H_ diff --git a/src/common/src/mem_arena.cpp b/src/common/src/mem_arena.cpp deleted file mode 100644 index 1a6fcf44..00000000 --- a/src/common/src/mem_arena.cpp +++ /dev/null @@ -1,477 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "memory_util.h" -#include "mem_arena.h" - -#ifdef _WIN32 -//#include "CommonWindows.h" -#else -#include -#include -#include -#include -#include -#ifdef ANDROID -#include -#include -#endif -#endif - -#ifdef IOS -void* globalbase = NULL; -#endif - -#ifdef ANDROID - -// Hopefully this ABI will never change... - - -#define ASHMEM_DEVICE "/dev/ashmem" - -/* -* ashmem_create_region - creates a new ashmem region and returns the file -* descriptor, or <0 on error -* -* `name' is an optional label to give the region (visible in /proc/pid/maps) -* `size' is the size of the region, in page-aligned bytes -*/ -int ashmem_create_region(const char *name, size_t size) -{ - int fd, ret; - - fd = open(ASHMEM_DEVICE, O_RDWR); - if (fd < 0) - return fd; - - if (name) { - char buf[ASHMEM_NAME_LEN]; - - strncpy(buf, name, sizeof(buf)); - ret = ioctl(fd, ASHMEM_SET_NAME, buf); - if (ret < 0) - goto error; - } - - ret = ioctl(fd, ASHMEM_SET_SIZE, size); - if (ret < 0) - goto error; - - return fd; - -error: - ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret); - close(fd); - return ret; -} - -int ashmem_set_prot_region(int fd, int prot) -{ - return ioctl(fd, ASHMEM_SET_PROT_MASK, prot); -} - -int ashmem_pin_region(int fd, size_t offset, size_t len) -{ - struct ashmem_pin pin = { offset, len }; - return ioctl(fd, ASHMEM_PIN, &pin); -} - -int ashmem_unpin_region(int fd, size_t offset, size_t len) -{ - struct ashmem_pin pin = { offset, len }; - return ioctl(fd, ASHMEM_UNPIN, &pin); -} -#endif // Android - - - -#ifndef _WIN32 -// do not make this "static" -#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) -std::string ram_temp_file = "/home/user/gc_mem.tmp"; -#else -std::string ram_temp_file = "/tmp/gc_mem.tmp"; -#endif -#elif !defined(_XBOX) -SYSTEM_INFO sysInfo; -#endif - - -// Windows mappings need to be on 64K boundaries, due to Alpha legacy. -#ifdef _WIN32 -size_t roundup(size_t x) { -#ifndef _XBOX - int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; -#else - int gran = 0x10000; // 64k in 360 -#endif - return (x + gran - 1) & ~(gran - 1); -} -#else -size_t roundup(size_t x) { - return x; -} -#endif - - -void MemArena::GrabLowMemSpace(size_t size) -{ -#ifdef _WIN32 -#ifndef _XBOX - hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); - GetSystemInfo(&sysInfo); -#endif -#elif defined(ANDROID) - // Use ashmem so we don't have to allocate a file on disk! - fd = ashmem_create_region("PPSSPP_RAM", size); - // Note that it appears that ashmem is pinned by default, so no need to pin. - if (fd < 0) - { - ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); - return; - } -#else - mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); - if (fd < 0) - { - ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno)); - return; - } - // delete immediately, we keep the fd so it still lives - unlink(ram_temp_file.c_str()); - if (ftruncate(fd, size) != 0) - { - ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size); - } - return; -#endif -} - - -void MemArena::ReleaseSpace() -{ -#ifdef _WIN32 - CloseHandle(hMemoryMapping); - hMemoryMapping = 0; -#elif defined(__SYMBIAN32__) - memmap->Close(); - delete memmap; -#else - close(fd); -#endif -} - - -void *MemArena::CreateView(s64 offset, size_t size, void *base) -{ -#ifdef _WIN32 -#ifdef _XBOX - size = roundup(size); - // use 64kb pages - void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); - return ptr; -#else - size = roundup(size); - void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); - return ptr; -#endif -#else - void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | - // Do not sync memory to underlying file. Linux has this by default. -#ifdef BLACKBERRY - MAP_NOSYNCFILE | -#elif defined(__FreeBSD__) - MAP_NOSYNC | -#endif - ((base == 0) ? 0 : MAP_FIXED), fd, offset); - - if (retval == MAP_FAILED) - { - NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd); - return 0; - } - return retval; -#endif -} - - -void MemArena::ReleaseView(void* view, size_t size) -{ -#ifdef _WIN32 -#ifndef _XBOX - UnmapViewOfFile(view); -#endif -#elif defined(__SYMBIAN32__) - memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); -#else - munmap(view, size); -#endif -} - -#ifndef __SYMBIAN32__ -u8* MemArena::Find4GBBase() -{ -#ifdef _M_X64 -#ifdef _WIN32 - // 64 bit - u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE); - VirtualFree(base, 0, MEM_RELEASE); - return base; -#else - // Very precarious - mmap cannot return an error when trying to map already used pages. - // This makes the Windows approach above unusable on Linux, so we will simply pray... - return reinterpret_cast(0x2300000000ULL); -#endif - -#else // 32 bit - -#ifdef _WIN32 - u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE); - if (base) { - VirtualFree(base, 0, MEM_RELEASE); - } - return base; -#else -#ifdef IOS - void* base = NULL; - if (globalbase == NULL){ - base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno)); - return 0; - } - munmap(base, 0x08000000); - globalbase = base; - } - else{ base = globalbase; } -#else - void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (base == MAP_FAILED) { - PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); - return 0; - } - munmap(base, 0x10000000); -#endif - return static_cast(base); -#endif -#endif -} -#endif - - -// yeah, this could also be done in like two bitwise ops... -#define SKIP(a_flags, b_flags) -// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) -// continue; -// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) -// continue; - -static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { - // OK, we know where to find free space. Now grab it! - // We just mimic the popular BAT setup. - size_t position = 0; - size_t last_position = 0; - -#if defined(_XBOX) - void *ptr; -#endif - - // Zero all the pointers to be sure. - for (int i = 0; i < num_views; i++) - { - if (views[i].out_ptr_low) - *views[i].out_ptr_low = 0; - if (views[i].out_ptr) - *views[i].out_ptr = 0; - } - - int i; - for (i = 0; i < num_views; i++) - { - const MemoryView &view = views[i]; - if (view.size == 0) - continue; - SKIP(flags, view.flags); - if (view.flags & MV_MIRROR_PREVIOUS) { - position = last_position; - } - else { -#ifdef __SYMBIAN32__ - *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); - arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - } - *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); -#elif defined(_XBOX) - *(view.out_ptr_low) = (u8*)(base + view.virtual_address); - //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); - } - *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); -#else - *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size); - if (!*view.out_ptr_low) - goto bail; - } -#ifdef _M_X64 - *view.out_ptr = (u8*)arena->CreateView( - position, view.size, base + view.virtual_address); -#else - if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical. - // No need to create multiple identical views. - *view.out_ptr = *views[i - 1].out_ptr; - } - else { - *view.out_ptr = (u8*)arena->CreateView( - position, view.size, base + (view.virtual_address & 0x3FFFFFFF)); - if (!*view.out_ptr) - goto bail; - } -#endif - -#endif - last_position = position; - position += roundup(view.size); - } - - return true; - -bail: - // Argh! ERROR! Free what we grabbed so far so we can try again. - for (int j = 0; j <= i; j++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if (views[j].out_ptr_low && *views[j].out_ptr_low) - { - arena->ReleaseView(*views[j].out_ptr_low, views[j].size); - *views[j].out_ptr_low = NULL; - } - if (*views[j].out_ptr) - { -#ifdef _M_X64 - arena->ReleaseView(*views[j].out_ptr, views[j].size); -#else - if (!(views[j].flags & MV_MIRROR_PREVIOUS)) - { - arena->ReleaseView(*views[j].out_ptr, views[j].size); - } -#endif - *views[j].out_ptr = NULL; - } - } - return false; -} - -u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) -{ - size_t total_mem = 0; - int base_attempts = 0; - - for (int i = 0; i < num_views; i++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) - total_mem += roundup(views[i].size); - } - // Grab some pagefile backed memory out of the void ... -#ifndef __SYMBIAN32__ - arena->GrabLowMemSpace(total_mem); -#endif - - // Now, create views in high memory where there's plenty of space. -#ifdef _M_X64 - u8 *base = MemArena::Find4GBBase(); - // This really shouldn't fail - in 64-bit, there will always be enough - // address space. - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#elif defined(_XBOX) - // Reserve 256MB - u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - exit(0); - return 0; - } -#elif defined(_WIN32) - // Try a whole range of possible bases. Return once we got a valid one. - u32 max_base_addr = 0x7FFF0000 - 0x10000000; - u8 *base = NULL; - - for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) - { - base_attempts++; - base = (u8 *)base_addr; - if (Memory_TryBase(base, views, num_views, flags, arena)) - { - INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); - base_attempts = 0; - break; - } - } -#elif defined(__SYMBIAN32__) - arena->memmap = new RChunk(); - arena->memmap->CreateDisconnectedLocal(0, 0, 0x10000000); - if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } - u8* base = arena->memmap->Base(); -#else - // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. - u8 *base = MemArena::Find4GBBase(); - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#endif - if (base_attempts) - PanicAlert("No possible memory base pointer found!"); - return base; -} - -void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) -{ - for (int i = 0; i < num_views; i++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if (views[i].out_ptr_low && *views[i].out_ptr_low) - arena->ReleaseView(*views[i].out_ptr_low, views[i].size); - if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) - arena->ReleaseView(*views[i].out_ptr, views[i].size); - *views[i].out_ptr = NULL; - if (views[i].out_ptr_low) - *views[i].out_ptr_low = NULL; - } -} diff --git a/src/common/src/mem_arena.h b/src/common/src/mem_arena.h deleted file mode 100644 index 8bdf9f18..00000000 --- a/src/common/src/mem_arena.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _MEMARENA_H_ -#define _MEMARENA_H_ - -#ifdef _WIN32 -#include -#endif - -#ifdef __SYMBIAN32__ -#include -#endif - -#include "common.h" - -// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. -// Multiple views can mirror the same section of the block, which makes it very convient for emulating -// memory mirrors. - -class MemArena -{ -public: - void GrabLowMemSpace(size_t size); - void ReleaseSpace(); - void *CreateView(s64 offset, size_t size, void *base = 0); - void ReleaseView(void *view, size_t size); - -#ifdef __SYMBIAN32__ - RChunk* memmap; -#else - // This only finds 1 GB in 32-bit - static u8 *Find4GBBase(); -#endif -private: - -#ifdef _WIN32 - HANDLE hMemoryMapping; -#else - int fd; -#endif -}; - -enum { - MV_MIRROR_PREVIOUS = 1, - // MV_FAKE_VMEM = 2, - // MV_WII_ONLY = 4, - MV_IS_PRIMARY_RAM = 0x100, - MV_IS_EXTRA1_RAM = 0x200, - MV_IS_EXTRA2_RAM = 0x400, -}; - -struct MemoryView -{ - u8 **out_ptr_low; - u8 **out_ptr; - u32 virtual_address; - u32 size; - u32 flags; -}; - -// Uses a memory arena to set up an emulator-friendly memory map according to -// a passed-in list of MemoryView structures. -u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena); -void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena); - -#endif // _MEMARENA_H_ diff --git a/src/common/src/memory_util.cpp b/src/common/src/memory_util.cpp deleted file mode 100644 index cc6e77b3..00000000 --- a/src/common/src/memory_util.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#include "common.h" -#include "memory_util.h" -#include "string_util.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#endif - -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) -#include -#define PAGE_MASK (getpagesize() - 1) -#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) -#endif - -// This is purposely not a full wrapper for virtualalloc/mmap, but it -// provides exactly the primitive operations that Dolphin needs. - -void* AllocateExecutableMemory(size_t size, bool low) -{ -#if defined(_WIN32) - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - static char *map_hint = 0; -#if defined(__x86_64__) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ -#endif - void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE -#if defined(__x86_64__) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) -#endif - , -1, 0); -#endif /* defined(_WIN32) */ - - // printf("Mapped executable memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - -#if defined(__FreeBSD__) - if (ptr == MAP_FAILED) - { - ptr = NULL; -#else - if (ptr == NULL) - { -#endif - PanicAlert("Failed to allocate executable memory"); - } -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) - else - { - if (low) - { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - // printf("Next map will (hopefully) be at %p\n", map_hint); - } - } -#endif - -#if defined(_M_X64) - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); -#endif - - return ptr; -} - -void* AllocateMemoryPages(size_t size) -{ -#ifdef _WIN32 - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); -#else - void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate raw memory"); - - return ptr; -} - -void* AllocateAlignedMemory(size_t size,size_t alignment) -{ -#ifdef _WIN32 - void* ptr = _aligned_malloc(size,alignment); -#else - void* ptr = NULL; -#ifdef ANDROID - ptr = memalign(alignment, size); -#else - if (posix_memalign(&ptr, alignment, size) != 0) - ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); -#endif -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate aligned memory"); - - return ptr; -} - -void FreeMemoryPages(void* ptr, size_t size) -{ - if (ptr) - { -#ifdef _WIN32 - - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); - ptr = NULL; // Is this our responsibility? - -#else - munmap(ptr, size); -#endif - } -} - -void FreeAlignedMemory(void* ptr) -{ - if (ptr) - { -#ifdef _WIN32 - _aligned_free(ptr); -#else - free(ptr); -#endif - } -} - -void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); -#endif -} - -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) - PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); -#endif -} - -std::string MemUsage() -{ -#ifdef _WIN32 -#pragma comment(lib, "psapi") - DWORD processID = GetCurrentProcessId(); - HANDLE hProcess; - PROCESS_MEMORY_COUNTERS pmc; - std::string Ret; - - // Print information about the memory usage of the process. - - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (NULL == hProcess) return "MemUsage Error"; - - if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); - - CloseHandle(hProcess); - return Ret; -#else - return ""; -#endif -} diff --git a/src/common/src/memory_util.h b/src/common/src/memory_util.h deleted file mode 100644 index 49b2589d..00000000 --- a/src/common/src/memory_util.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - - -#ifndef _MEMORYUTIL_H -#define _MEMORYUTIL_H - -#ifndef _WIN32 -#include -#endif -#include - -void* AllocateExecutableMemory(size_t size, bool low = true); -void* AllocateMemoryPages(size_t size); -void FreeMemoryPages(void* ptr, size_t size); -void* AllocateAlignedMemory(size_t size,size_t alignment); -void FreeAlignedMemory(void* ptr); -void WriteProtectMemory(void* ptr, size_t size, bool executable = false); -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); -std::string MemUsage(); - -inline int GetPageSize() { return 4096; } - -#endif diff --git a/src/common/src/misc.cpp b/src/common/src/misc.cpp deleted file mode 100644 index 93580547..00000000 --- a/src/common/src/misc.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" - -#ifdef _WIN32 -#include -#endif - -// Neither Android nor OS X support TLS -#if defined(__APPLE__) || (ANDROID && __clang__) -#define __thread -#endif - -// Generic function to get last error message. -// Call directly after the command or use the error num. -// This function might change the error code. -const char* GetLastErrorMsg() -{ - static const size_t buff_size = 255; - -#ifdef _WIN32 - static __declspec(thread) char err_str[buff_size] = {}; - - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - err_str, buff_size, NULL); -#else - static __thread char err_str[buff_size] = {}; - - // Thread safe (XSI-compliant) - strerror_r(errno, err_str, buff_size); -#endif - - return err_str; -} diff --git a/src/common/src/msg_handler.cpp b/src/common/src/msg_handler.cpp deleted file mode 100644 index 8e9fe218..00000000 --- a/src/common/src/msg_handler.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include // System - -#include "common.h" // Local -#include "string_util.h" - -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); -static MsgAlertHandler msg_handler = DefaultMsgHandler; -static bool AlertEnabled = true; - -std::string DefaultStringTranslator(const char* text); -static StringTranslator str_translator = DefaultStringTranslator; - -// Select which of these functions that are used for message boxes. If -// wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp -void RegisterMsgAlertHandler(MsgAlertHandler handler) -{ - msg_handler = handler; -} - -// Select translation function. For wxWidgets use wxStringTranslator in Main.cpp -void RegisterStringTranslator(StringTranslator translator) -{ - str_translator = translator; -} - -// enable/disable the alert handler -void SetEnableAlert(bool enable) -{ - AlertEnabled = enable; -} - -// This is the first stop for gui alerts where the log is updated and the -// correct window is shown -bool MsgAlert(bool yes_no, int Style, const char* format, ...) -{ - // Read message and write it to the log - std::string caption; - char buffer[2048]; - - static std::string info_caption; - static std::string warn_caption; - static std::string ques_caption; - static std::string crit_caption; - - if (!info_caption.length()) - { - info_caption = str_translator(_trans("Information")); - ques_caption = str_translator(_trans("Question")); - warn_caption = str_translator(_trans("Warning")); - crit_caption = str_translator(_trans("Critical")); - } - - switch(Style) - { - case INFORMATION: - caption = info_caption; - break; - case QUESTION: - caption = ques_caption; - break; - case WARNING: - caption = warn_caption; - break; - case CRITICAL: - caption = crit_caption; - break; - } - - va_list args; - va_start(args, format); - CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); - va_end(args); - - ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); - - // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored - if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) - return msg_handler(caption.c_str(), buffer, yes_no, Style); - - return true; -} - -// Default non library dependent panic alert -bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) -{ -//#ifdef _WIN32 -// int STYLE = MB_ICONINFORMATION; -// if (Style == QUESTION) STYLE = MB_ICONQUESTION; -// if (Style == WARNING) STYLE = MB_ICONWARNING; -// -// return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); -//#else - printf("%s\n", text); - return true; -//#endif -} - -// Default (non) translator -std::string DefaultStringTranslator(const char* text) -{ - return text; -} - diff --git a/src/common/src/msg_handler.h b/src/common/src/msg_handler.h deleted file mode 100644 index bde2808f..00000000 --- a/src/common/src/msg_handler.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _MSGHANDLER_H_ -#define _MSGHANDLER_H_ - -#include - -// Message alerts -enum MSG_TYPE -{ - INFORMATION, - QUESTION, - WARNING, - CRITICAL -}; - -typedef bool (*MsgAlertHandler)(const char* caption, const char* text, - bool yes_no, int Style); -typedef std::string (*StringTranslator)(const char* text); - -void RegisterMsgAlertHandler(MsgAlertHandler handler); -void RegisterStringTranslator(StringTranslator translator); - -extern bool MsgAlert(bool yes_no, int Style, const char* format, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) -#endif - ; -void SetEnableAlert(bool enable); - -#ifndef GEKKO -#ifdef _WIN32 - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) -#else - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) -#endif -#else -// GEKKO - #define SuccessAlert(format, ...) ; - #define PanicAlert(format, ...) ; - #define PanicYesNo(format, ...) ; - #define AskYesNo(format, ...) ; - #define CriticalAlert(format, ...) ; - #define SuccessAlertT(format, ...) ; - #define PanicAlertT(format, ...) ; - #define PanicYesNoT(format, ...) ; - #define AskYesNoT(format, ...) ; - #define CriticalAlertT(format, ...) ; -#endif - -#endif // _MSGHANDLER_H_ diff --git a/src/common/src/platform.h b/src/common/src/platform.h deleted file mode 100644 index 84c6b636..00000000 --- a/src/common/src/platform.h +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (C) 2005-2012 Gekko Emulator - * - * @file platform.h - * @author ShizZy - * @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 "common_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 - -#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 - -#include - -#define NOMINMAX -#define EMU_FASTCALL __fastcall - -inline struct tm* localtime_r(const time_t *clock, struct tm *result) { - if (localtime_s(result, clock) == 0) - return result; - return NULL; -} - -#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 -#define MAX_PATH PATH_MAX - -#include -#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/scm_rev.h b/src/common/src/scm_rev.h deleted file mode 100644 index 69962c58..00000000 --- a/src/common/src/scm_rev.h +++ /dev/null @@ -1,4 +0,0 @@ -#define SCM_REV_STR "a7b06698ff012aa7b1094414e796ffae1ca1eb4d" -#define SCM_DESC_STR "a7b0669" -#define SCM_BRANCH_STR "master" -#define SCM_IS_MASTER 1 diff --git a/src/common/src/std_condition_variable.h b/src/common/src/std_condition_variable.h deleted file mode 100644 index cee7a9dc..00000000 --- a/src/common/src/std_condition_variable.h +++ /dev/null @@ -1,170 +0,0 @@ - -#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__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ - -// GCC 4.4 provides -#include - -#elif __has_include() && !ANDROID - -// clang and libc++ provide on OSX. However, the version -// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable. -// -// We work around this issue by undefining and redefining _. - -#undef _ -#include -#define _(s) wxGetTranslation((s)) - -#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& 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 - void wait(unique_lock& lock, Predicate pred) - { - while (!pred()) - wait(lock); - } - - //template - //cv_status wait_until(unique_lock& lock, - // const chrono::time_point& abs_time); - - //template - // bool wait_until(unique_lock& lock, - // const chrono::time_point& abs_time, - // Predicate pred); - - //template - //cv_status wait_for(unique_lock& lock, - // const chrono::duration& rel_time); - - //template - // bool wait_for(unique_lock& lock, - // const chrono::duration& 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 deleted file mode 100644 index 26eb58b6..00000000 --- a/src/common/src/std_mutex.h +++ /dev/null @@ -1,365 +0,0 @@ - -#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__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ -// GCC 4.4 provides -#include -#elif __has_include() && !ANDROID -// Clang + libc++ -#include -#else - -// partial implementation for win32/pthread - -#include - -#if defined(_WIN32) -// WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -#else -// POSIX -#include - -#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 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 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 - //unique_lock(mutex_type& m, const chrono::time_point& abs_time); - - //template - //unique_lock(mutex_type& m, const chrono::duration& 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(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(u); -#endif - swap(other); - } - - void lock() - { - mutex()->lock(); - owns = true; - } - - bool try_lock() - { - owns = mutex()->try_lock(); - return owns; - } - - //template - //bool try_lock_for(const chrono::duration& rel_time); - //template - //bool try_lock_until(const chrono::time_point& 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() - { - auto const ret = mutex(); - - pm = NULL; - owns = false; - - return ret; - } - - 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 -void swap(unique_lock& x, unique_lock& y) -{ - x.swap(y); -} - -} - -#endif -#endif diff --git a/src/common/src/std_thread.h b/src/common/src/std_thread.h deleted file mode 100644 index 9ed0072c..00000000 --- a/src/common/src/std_thread.h +++ /dev/null @@ -1,317 +0,0 @@ - -#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__) - -#ifndef __has_include -#define __has_include(s) 0 -#endif - -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ -// GCC 4.4 provides -#ifndef _GLIBCXX_USE_SCHED_YIELD -#define _GLIBCXX_USE_SCHED_YIELD -#endif -#include -#elif __has_include() && !ANDROID -// Clang + libc++ -#include -#else - -// partial std::thread implementation for win32/pthread - -#include - -#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) -#define USE_RVALUE_REFERENCES -#endif - -#ifdef __APPLE__ -#import -#endif - -#if defined(_WIN32) -// WIN32 - -#define WIN32_LEAN_AND_MEAN -#include - -#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 -#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 - -#ifndef _POSIX_THREADS -#error unsupported platform (no pthreads?) -#endif - -#include - -#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 - //thread(C&& func, A&&... args); - - template - thread(C func) - { - StartThread(new Func(func)); - } - - template - thread(C func, A arg) - { - StartThread(new FuncArg(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(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(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(sysinfo.dwNumberOfProcessors); -#else - return 0; -#endif - } - -private: - id m_id; - -#ifdef _WIN32 - native_handle_type m_handle; -#endif - - template - void StartThread(F* param) - { -#ifdef USE_BEGINTHREADEX - m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); -#elif defined(_WIN32) - m_handle = CreateThread(NULL, 0, &RunAndDelete, 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, param)) - m_id = id(); -#endif - } - - template - class Func - { - public: - Func(C _func) : func(_func) {} - - void Run() { func(); } - - private: - C const func; - }; - - template - class FuncArg - { - public: - FuncArg(C _func, A _arg) : func(_func), arg(_arg) {} - - void Run() { func(arg); } - - private: - C const func; - A arg; - }; - - template - static THREAD_RETURN RunAndDelete(void* param) - { -#ifdef __APPLE__ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -#endif - static_cast(param)->Run(); - delete static_cast(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/string_util.cpp b/src/common/src/string_util.cpp deleted file mode 100644 index 415dcbbc..00000000 --- a/src/common/src/string_util.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include -#include - -#include "common.h" -#include "common_paths.h" -#include "string_util.h" - -#ifdef _WIN32 - #include -#else - #include - #include -#endif - -// faster than sscanf -bool AsciiToHex(const char* _szValue, u32& result) -{ - char *endptr = NULL; - const u32 value = strtoul(_szValue, &endptr, 16); - - if (!endptr || *endptr) - return false; - - result = value; - return true; -} - -bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) -{ - int writtenCount; - -#ifdef _WIN32 - // You would think *printf are simple, right? Iterate on each character, - // if it's a format specifier handle it properly, etc. - // - // Nooooo. Not according to the C standard. - // - // According to the C99 standard (7.19.6.1 "The fprintf function") - // The format shall be a multibyte character sequence - // - // Because some character encodings might have '%' signs in the middle of - // a multibyte sequence (SJIS for example only specifies that the first - // byte of a 2 byte sequence is "high", the second byte can be anything), - // printf functions have to decode the multibyte sequences and try their - // best to not screw up. - // - // Unfortunately, on Windows, the locale for most languages is not UTF-8 - // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the - // locale, and completely fails when trying to decode UTF-8 as EUC-CN. - // - // On the other hand, the fix is simple: because we use UTF-8, no such - // multibyte handling is required as we can simply assume that no '%' char - // will be present in the middle of a multibyte sequence. - // - // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. - static locale_t c_locale = NULL; - if (!c_locale) - c_locale = _create_locale(LC_ALL, ".1252"); - writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); -#else - writtenCount = vsnprintf(out, outsize, format, args); -#endif - - if (writtenCount > 0 && writtenCount < outsize) - { - out[writtenCount] = '\0'; - return true; - } - else - { - out[outsize - 1] = '\0'; - return false; - } -} - -std::string StringFromFormat(const char* format, ...) -{ - va_list args; - char *buf = NULL; -#ifdef _WIN32 - int required = 0; - - va_start(args, format); - required = _vscprintf(format, args); - buf = new char[required + 1]; - CharArrayFromFormatV(buf, required + 1, format, args); - va_end(args); - - std::string temp = buf; - delete[] buf; -#else - va_start(args, format); - if (vasprintf(&buf, format, args) < 0) - ERROR_LOG(COMMON, "Unable to allocate memory for string"); - va_end(args); - - std::string temp = buf; - free(buf); -#endif - return temp; -} - -// For Debugging. Read out an u8 array. -std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) -{ - std::ostringstream oss; - oss << std::setfill('0') << std::hex; - - for (int line = 0; size; ++data, --size) - { - oss << std::setw(2) << (int)*data; - - if (line_len == ++line) - { - oss << '\n'; - line = 0; - } - else if (spaces) - oss << ' '; - } - - return oss.str(); -} - -// Turns " hej " into "hej". Also handles tabs. -std::string StripSpaces(const std::string &str) -{ - const size_t s = str.find_first_not_of(" \t\r\n"); - - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; -} - -// "\"hello\"" is turned to "hello" -// This one assumes that the string has already been space stripped in both -// ends, as done by StripSpaces above, for example. -std::string StripQuotes(const std::string& s) -{ - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; -} - -bool TryParse(const std::string &str, u32 *const output) -{ - char *endptr = NULL; - - // Reset errno to a value other than ERANGE - errno = 0; - - unsigned long value = strtoul(str.c_str(), &endptr, 0); - - if (!endptr || *endptr) - return false; - - if (errno == ERANGE) - return false; - -#if ULONG_MAX > UINT_MAX - if (value >= 0x100000000ull - && value <= 0xFFFFFFFF00000000ull) - return false; -#endif - - *output = static_cast(value); - return true; -} - -bool TryParse(const std::string &str, bool *const output) -{ - if ("1" == str || !strcasecmp("true", str.c_str())) - *output = true; - else if ("0" == str || !strcasecmp("false", str.c_str())) - *output = false; - else - return false; - - return true; -} - -std::string StringFromInt(int value) -{ - char temp[16]; - sprintf(temp, "%i", value); - return temp; -} - -std::string StringFromBool(bool value) -{ - return value ? "True" : "False"; -} - -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) -{ - if (full_path.empty()) - return false; - - size_t dir_end = full_path.find_last_of("/" - // windows needs the : included for something like just "C:" to be considered a directory -#ifdef _WIN32 - ":" -#endif - ); - if (std::string::npos == dir_end) - dir_end = 0; - else - dir_end += 1; - - size_t fname_end = full_path.rfind('.'); - if (fname_end < dir_end || std::string::npos == fname_end) - fname_end = full_path.size(); - - if (_pPath) - *_pPath = full_path.substr(0, dir_end); - - if (_pFilename) - *_pFilename = full_path.substr(dir_end, fname_end - dir_end); - - if (_pExtension) - *_pExtension = full_path.substr(fname_end); - - return true; -} - -void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) -{ - _CompleteFilename = _Path; - - // check for seperator - if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) - _CompleteFilename += DIR_SEP_CHR; - - // add the filename - _CompleteFilename += _Filename; -} - -void SplitString(const std::string& str, const char delim, std::vector& output) -{ - std::istringstream iss(str); - output.resize(1); - - while (std::getline(iss, *output.rbegin(), delim)) - output.push_back(""); - - output.pop_back(); -} - -std::string TabsToSpaces(int tab_size, const std::string &in) -{ - const std::string spaces(tab_size, ' '); - std::string out(in); - - size_t i = 0; - while (out.npos != (i = out.find('\t'))) - out.replace(i, 1, spaces); - - return out; -} - -std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) -{ - while(1) - { - size_t pos = result.find(src); - if (pos == std::string::npos) break; - result.replace(pos, src.size(), dest); - } - return result; -} - -// UriDecode and UriEncode are from http://www.codeguru.com/cpp/cpp/string/conversions/print.php/c12759 -// by jinq0123 (November 2, 2006) - -// Uri encode and decode. -// RFC1630, RFC1738, RFC2396 - -//#include -//#include - -const char HEX2DEC[256] = -{ - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16, - - /* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, - /* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, - /* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - - /* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - - /* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, - /* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 -}; - -std::string UriDecode(const std::string & sSrc) -{ - // Note from RFC1630: "Sequences which start with a percent sign - // but are not followed by two hexadecimal characters (0-9, A-F) are reserved - // for future extension" - - const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); - const size_t SRC_LEN = sSrc.length(); - const unsigned char * const SRC_END = pSrc + SRC_LEN; - const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' - - char * const pStart = new char[SRC_LEN]; - char * pEnd = pStart; - - while (pSrc < SRC_LAST_DEC) - { - if (*pSrc == '%') - { - char dec1, dec2; - if (16 != (dec1 = HEX2DEC[*(pSrc + 1)]) - && 16 != (dec2 = HEX2DEC[*(pSrc + 2)])) - { - *pEnd++ = (dec1 << 4) + dec2; - pSrc += 3; - continue; - } - } - - *pEnd++ = *pSrc++; - } - - // the last 2- chars - while (pSrc < SRC_END) - *pEnd++ = *pSrc++; - - std::string sResult(pStart, pEnd); - delete [] pStart; - return sResult; -} - -// Only alphanum is safe. -const char SAFE[256] = -{ - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, - - /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, - /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, - /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, - /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, - - /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - - /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 -}; - -std::string UriEncode(const std::string & sSrc) -{ - const char DEC2HEX[16 + 1] = "0123456789ABCDEF"; - const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); - const size_t SRC_LEN = sSrc.length(); - unsigned char * const pStart = new unsigned char[SRC_LEN * 3]; - unsigned char * pEnd = pStart; - const unsigned char * const SRC_END = pSrc + SRC_LEN; - - for (; pSrc < SRC_END; ++pSrc) - { - if (SAFE[*pSrc]) - *pEnd++ = *pSrc; - else - { - // escape this char - *pEnd++ = '%'; - *pEnd++ = DEC2HEX[*pSrc >> 4]; - *pEnd++ = DEC2HEX[*pSrc & 0x0F]; - } - } - - std::string sResult((char *)pStart, (char *)pEnd); - delete [] pStart; - return sResult; -} - -#ifdef _WIN32 - -std::string UTF16ToUTF8(const std::wstring& input) -{ - auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); - - std::string output; - output.resize(size); - - if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) - output.clear(); - - return output; -} - -std::wstring CPToUTF16(u32 code_page, const std::string& input) -{ - auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); - - std::wstring output; - output.resize(size); - - if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size())) - output.clear(); - - return output; -} - -std::wstring UTF8ToUTF16(const std::string& input) -{ - return CPToUTF16(CP_UTF8, input); -} - -std::string SHIFTJISToUTF8(const std::string& input) -{ - return UTF16ToUTF8(CPToUTF16(932, input)); -} - -std::string CP1252ToUTF8(const std::string& input) -{ - return UTF16ToUTF8(CPToUTF16(1252, input)); -} - -#else - -template -std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) -{ - std::string result; - - iconv_t const conv_desc = iconv_open("UTF-8", fromcode); - if ((iconv_t)-1 == conv_desc) - { - ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); - } - else - { - size_t const in_bytes = sizeof(T) * input.size(); - size_t const out_buffer_size = 4 * in_bytes; - - std::string out_buffer; - out_buffer.resize(out_buffer_size); - - auto src_buffer = &input[0]; - size_t src_bytes = in_bytes; - auto dst_buffer = &out_buffer[0]; - size_t dst_bytes = out_buffer.size(); - - while (src_bytes != 0) - { - size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, - &dst_buffer, &dst_bytes); - - if ((size_t)-1 == iconv_result) - { - if (EILSEQ == errno || EINVAL == errno) - { - // Try to skip the bad character - if (src_bytes != 0) - { - --src_bytes; - ++src_buffer; - } - } - else - { - ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); - break; - } - } - } - - out_buffer.resize(out_buffer_size - dst_bytes); - out_buffer.swap(result); - - iconv_close(conv_desc); - } - - return result; -} - -std::string CP1252ToUTF8(const std::string& input) -{ - //return CodeToUTF8("CP1252//TRANSLIT", input); - //return CodeToUTF8("CP1252//IGNORE", input); - return CodeToUTF8("CP1252", input); -} - -std::string SHIFTJISToUTF8(const std::string& input) -{ - //return CodeToUTF8("CP932", input); - return CodeToUTF8("SJIS", input); -} - -std::string UTF16ToUTF8(const std::wstring& input) -{ - std::string result = - // CodeToUTF8("UCS-2", input); - // CodeToUTF8("UCS-2LE", input); - // CodeToUTF8("UTF-16", input); - CodeToUTF8("UTF-16LE", input); - - // TODO: why is this needed? - result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); - return result; -} - -#endif diff --git a/src/common/src/string_util.h b/src/common/src/string_util.h deleted file mode 100644 index fcbae471..00000000 --- a/src/common/src/string_util.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _STRINGUTIL_H_ -#define _STRINGUTIL_H_ - -#include - -#include -#include -#include -#include - -#include "common.h" - -std::string StringFromFormat(const char* format, ...); -// Cheap! -bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); - -template -inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) -{ - va_list args; - va_start(args, format); - CharArrayFromFormatV(out, Count, format, args); - va_end(args); -} - -// Good -std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); - -std::string StripSpaces(const std::string &s); -std::string StripQuotes(const std::string &s); - -// Thousand separator. Turns 12345678 into 12,345,678 -template -std::string ThousandSeparate(I value, int spaces = 0) -{ - std::ostringstream oss; - -// std::locale("") seems to be broken on many platforms -#if defined _WIN32 || (defined __linux__ && !defined __clang__) - oss.imbue(std::locale("")); -#endif - oss << std::setw(spaces) << value; - - return oss.str(); -} - -std::string StringFromInt(int value); -std::string StringFromBool(bool value); - -bool TryParse(const std::string &str, bool *output); -bool TryParse(const std::string &str, u32 *output); - -template -static bool TryParse(const std::string &str, N *const output) -{ - std::istringstream iss(str); - - N tmp = 0; - if (iss >> tmp) - { - *output = tmp; - return true; - } - else - return false; -} - -// TODO: kill this -bool AsciiToHex(const char* _szValue, u32& result); - -std::string TabsToSpaces(int tab_size, const std::string &in); - -void SplitString(const std::string& str, char delim, std::vector& output); - -// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); - -void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); -std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); -std::string UriDecode(const std::string & sSrc); -std::string UriEncode(const std::string & sSrc); - -std::string CP1252ToUTF8(const std::string& str); -std::string SHIFTJISToUTF8(const std::string& str); -std::string UTF16ToUTF8(const std::wstring& str); - -#ifdef _WIN32 - -std::wstring UTF8ToUTF16(const std::string& str); - -#ifdef _UNICODE -inline std::string TStrToUTF8(const std::wstring& str) -{ return UTF16ToUTF8(str); } - -inline std::wstring UTF8ToTStr(const std::string& str) -{ return UTF8ToUTF16(str); } -#else -inline std::string TStrToUTF8(const std::string& str) -{ return str; } - -inline std::string UTF8ToTStr(const std::string& str) -{ return str; } -#endif - -#endif - -#endif // _STRINGUTIL_H_ diff --git a/src/common/src/swap.h b/src/common/src/swap.h deleted file mode 100644 index d07d9fcc..00000000 --- a/src/common/src/swap.h +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project / Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -// Android -#if defined(ANDROID) -#include - -#if _BYTE_ORDER == _LITTLE_ENDIAN && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif _BYTE_ORDER == _BIG_ENDIAN && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// GCC 4.6+ -#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - -#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// LLVM/clang -#elif __clang__ - -#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// MSVC -#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) - -#ifdef _XBOX -#define COMMON_BIG_ENDIAN 1 -#else -#define COMMON_LITTLE_ENDIAN 1 -#endif - -#endif - -// Worst case, default to little endian. -#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN -#define COMMON_LITTLE_ENDIAN 1 -#endif - -template -struct swap_struct_t { - typedef swap_struct_t swapped_t; - -protected: - T value; - - static T swap(T v) { - return F::swap(v); - } -public: - T const swap() const { - return swap(value); - - } - swap_struct_t() : value((T)0) {} - swap_struct_t(const T &v): value(swap(v)) {} - - template - swapped_t& operator=(const S &source) { - value = swap((T)source); - return *this; - } - - operator long() const { return (long)swap(); } - operator s8() const { return (s8)swap(); } - operator u8() const { return (u8)swap(); } - operator s16() const { return (s16)swap(); } - operator u16() const { return (u16)swap(); } - operator s32() const { return (s32)swap(); } - operator u32() const { return (u32)swap(); } - operator s64() const { return (s64)swap(); } - operator u64() const { return (u64)swap(); } - operator float() const { return (float)swap(); } - operator double() const { return (double)swap(); } - - // +v - swapped_t operator +() const { - return +swap(); - } - // -v - swapped_t operator -() const { - return -swap(); - } - - // v / 5 - swapped_t operator/(const swapped_t &i) const { - return swap() / i.swap(); - } - template - swapped_t operator/(const S &i) const { - return swap() / i; - } - - // v * 5 - swapped_t operator*(const swapped_t &i) const { - return swap() * i.swap(); - } - template - swapped_t operator*(const S &i) const { - return swap() * i; - } - - // v + 5 - swapped_t operator+(const swapped_t &i) const { - return swap() + i.swap(); - } - template - swapped_t operator+(const S &i) const { - return swap() + (T)i; - } - // v - 5 - swapped_t operator-(const swapped_t &i) const { - return swap() - i.swap(); - } - template - swapped_t operator-(const S &i) const { - return swap() - (T)i; - } - - // v += 5 - swapped_t& operator+=(const swapped_t &i) { - value = swap(swap() + i.swap()); - return *this; - } - template - swapped_t& operator+=(const S &i) { - value = swap(swap() + (T)i); - return *this; - } - // v -= 5 - swapped_t& operator-=(const swapped_t &i) { - value = swap(swap() - i.swap()); - return *this; - } - template - swapped_t& operator-=(const S &i) { - value = swap(swap() - (T)i); - return *this; - } - - // ++v - swapped_t& operator++() { - value = swap(swap()+1); - return *this; - } - // --v - swapped_t& operator--() { - value = swap(swap()-1); - return *this; - } - - // v++ - swapped_t operator++(int) { - swapped_t old = *this; - value = swap(swap()+1); - return old; - } - // v-- - swapped_t operator--(int) { - swapped_t old = *this; - value = swap(swap()-1); - return old; - } - // Comparaison - // v == i - bool operator==(const swapped_t &i) const { - return swap() == i.swap(); - } - template - bool operator==(const S &i) const { - return swap() == i; - } - - // v != i - bool operator!=(const swapped_t &i) const { - return swap() != i.swap(); - } - template - bool operator!=(const S &i) const { - return swap() != i; - } - - // v > i - bool operator>(const swapped_t &i) const { - return swap() > i.swap(); - } - template - bool operator>(const S &i) const { - return swap() > i; - } - - // v < i - bool operator<(const swapped_t &i) const { - return swap() < i.swap(); - } - template - bool operator<(const S &i) const { - return swap() < i; - } - - // v >= i - bool operator>=(const swapped_t &i) const { - return swap() >= i.swap(); - } - template - bool operator>=(const S &i) const { - return swap() >= i; - } - - // v <= i - bool operator<=(const swapped_t &i) const { - return swap() <= i.swap(); - } - template - bool operator<=(const S &i) const { - return swap() <= i; - } - - // logical - swapped_t operator !() const { - return !swap(); - } - - // bitmath - swapped_t operator ~() const { - return ~swap(); - } - - swapped_t operator &(const swapped_t &b) const { - return swap() & b.swap(); - } - template - swapped_t operator &(const S &b) const { - return swap() & b; - } - swapped_t& operator &=(const swapped_t &b) { - value = swap(swap() & b.swap()); - return *this; - } - template - swapped_t& operator &=(const S b) { - value = swap(swap() & b); - return *this; - } - - swapped_t operator |(const swapped_t &b) const { - return swap() | b.swap(); - } - template - swapped_t operator |(const S &b) const { - return swap() | b; - } - swapped_t& operator |=(const swapped_t &b) { - value = swap(swap() | b.swap()); - return *this; - } - template - swapped_t& operator |=(const S &b) { - value = swap(swap() | b); - return *this; - } - - swapped_t operator ^(const swapped_t &b) const { - return swap() ^ b.swap(); - } - template - swapped_t operator ^(const S &b) const { - return swap() ^ b; - } - swapped_t& operator ^=(const swapped_t &b) { - value = swap(swap() ^ b.swap()); - return *this; - } - template - swapped_t& operator ^=(const S &b) { - value = swap(swap() ^ b); - return *this; - } - - template - swapped_t operator <<(const S &b) const { - return swap() << b; - } - template - swapped_t& operator <<=(const S &b) const { - value = swap(swap() << b); - return *this; - } - - template - swapped_t operator >>(const S &b) const { - return swap() >> b; - } - template - swapped_t& operator >>=(const S &b) const { - value = swap(swap() >> b); - return *this; - } - - // Member - /** todo **/ - - - // Arithmetics - template - friend S operator+(const S &p, const swapped_t v); - - template - friend S operator-(const S &p, const swapped_t v); - - template - friend S operator/(const S &p, const swapped_t v); - - template - friend S operator*(const S &p, const swapped_t v); - - template - friend S operator%(const S &p, const swapped_t v); - - // Arithmetics + assignements - template - friend S operator+=(const S &p, const swapped_t v); - - template - friend S operator-=(const S &p, const swapped_t v); - - // Bitmath - template - friend S operator&(const S &p, const swapped_t v); - - // Comparison - template - friend bool operator<(const S &p, const swapped_t v); - - template - friend bool operator>(const S &p, const swapped_t v); - - template - friend bool operator<=(const S &p, const swapped_t v); - - template - friend bool operator>=(const S &p, const swapped_t v); - - template - friend bool operator!=(const S &p, const swapped_t v); - - template - friend bool operator==(const S &p, const swapped_t v); -}; - - -// Arithmetics -template -S operator+(const S &i, const swap_struct_t v) { - return i + v.swap(); -} - -template -S operator-(const S &i, const swap_struct_t v) { - return i - v.swap(); -} - -template -S operator/(const S &i, const swap_struct_t v) { - return i / v.swap(); -} - -template -S operator*(const S &i, const swap_struct_t v) { - return i * v.swap(); -} - -template -S operator%(const S &i, const swap_struct_t v) { - return i % v.swap(); -} - -// Arithmetics + assignements -template -S &operator+=(S &i, const swap_struct_t v) { - i += v.swap(); - return i; -} - -template -S &operator-=(S &i, const swap_struct_t v) { - i -= v.swap(); - return i; -} - -// Logical -template -S operator&(const S &i, const swap_struct_t v) { - return i & v.swap(); -} - -template -S operator&(const swap_struct_t v, const S &i) { - return (S)(v.swap() & i); -} - - -// Comparaison -template -bool operator<(const S &p, const swap_struct_t v) { - return p < v.swap(); -} -template -bool operator>(const S &p, const swap_struct_t v) { - return p > v.swap(); -} -template -bool operator<=(const S &p, const swap_struct_t v) { - return p <= v.swap(); -} -template -bool operator>=(const S &p, const swap_struct_t v) { - return p >= v.swap(); -} -template -bool operator!=(const S &p, const swap_struct_t v) { - return p != v.swap(); -} -template -bool operator==(const S &p, const swap_struct_t v) { - return p == v.swap(); -} - -template -struct swap_64_t { - static T swap(T x) { - return (T)bswap64(*(u64 *)&x); - } -}; - -template -struct swap_32_t { - static T swap(T x) { - return (T)bswap32(*(u32 *)&x); - } -}; - -template -struct swap_16_t { - static T swap(T x) { - return (T)bswap16(*(u16 *)&x); - } -}; - -template -struct swap_float_t { - static T swap(T x) { - return (T)bswapf(*(float *)&x); - } -}; - -template -struct swap_double_t { - static T swap(T x) { - return (T)bswapd(*(double *)&x); - } -}; - -#if COMMON_LITTLE_ENDIAN -typedef u32 u32_le; -typedef u16 u16_le; -typedef u64 u64_le; - -typedef s32 s32_le; -typedef s16 s16_le; -typedef s64 s64_le; - -typedef float float_le; -typedef double double_le; - -typedef swap_struct_t> u64_be; -typedef swap_struct_t> s64_be; - -typedef swap_struct_t> u32_be; -typedef swap_struct_t> s32_be; - -typedef swap_struct_t> u16_be; -typedef swap_struct_t> s16_be; - -typedef swap_struct_t > float_be; -typedef swap_struct_t > double_be; -#else - -typedef swap_struct_t> u64_le; -typedef swap_struct_t> s64_le; - -typedef swap_struct_t> u32_le; -typedef swap_struct_t> s32_le; - -typedef swap_struct_t> u16_le; -typedef swap_struct_t> s16_le; - -typedef swap_struct_t > float_le; -typedef swap_struct_t > double_le; - -typedef u32 u32_be; -typedef u16 u16_be; -typedef u64 u64_be; - -typedef s32 s32_be; -typedef s16 s16_be; -typedef s64 s64_be; - -typedef float float_be; -typedef double double_be; -#endif \ No newline at end of file diff --git a/src/common/src/thread.cpp b/src/common/src/thread.cpp deleted file mode 100644 index 27dbf3f9..00000000 --- a/src/common/src/thread.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "thread.h" -#include "common.h" - -#ifdef __APPLE__ -#include -#elif defined BSD4_4 -#include -#endif - -#ifdef USE_BEGINTHREADEX -#include -#endif - -namespace Common -{ - -int CurrentThreadId() -{ -#ifdef _WIN32 - return GetCurrentThreadId(); -#elif defined __APPLE__ - return mach_thread_self(); -#else - return 0; -#endif -} - -#ifdef _WIN32 - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) -{ - SetThreadAffinityMask(thread, mask); -} - -void SetCurrentThreadAffinity(u32 mask) -{ - SetThreadAffinityMask(GetCurrentThread(), mask); -} - -// Supporting functions -void SleepCurrentThread(int ms) -{ - Sleep(ms); -} - -void SwitchCurrentThread() -{ - SwitchToThread(); -} - -// Sets the debugger-visible name of the current thread. -// Uses undocumented (actually, it is now documented) trick. -// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp - -// This is implemented much nicer in upcoming msvc++, see: -// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx -void SetCurrentThreadName(const char* szThreadName) -{ - static const DWORD MS_VC_EXCEPTION = 0x406D1388; - - #pragma pack(push,8) - struct THREADNAME_INFO - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } info; - #pragma pack(pop) - - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = -1; //dwThreadID; - info.dwFlags = 0; - - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - {} -} - -#else // !WIN32, so must be POSIX threads - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) -{ -#ifdef __APPLE__ - thread_policy_set(pthread_mach_thread_np(thread), - THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); -#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) - cpu_set_t cpu_set; - CPU_ZERO(&cpu_set); - - for (int i = 0; i != sizeof(mask) * 8; ++i) - if ((mask >> i) & 1) - CPU_SET(i, &cpu_set); - - pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); -#endif -} - -void SetCurrentThreadAffinity(u32 mask) -{ - SetThreadAffinity(pthread_self(), mask); -} - -void SleepCurrentThread(int ms) -{ - usleep(1000 * ms); -} - -void SwitchCurrentThread() -{ - usleep(1000 * 1); -} - -void SetCurrentThreadName(const char* szThreadName) -{ -#ifdef __APPLE__ - pthread_setname_np(szThreadName); -#else - pthread_setname_np(pthread_self(), szThreadName); -#endif -} - -#endif - -} // namespace Common diff --git a/src/common/src/thread.h b/src/common/src/thread.h deleted file mode 100644 index 6384a44a..00000000 --- a/src/common/src/thread.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _THREAD_H_ -#define _THREAD_H_ - -#include "std_condition_variable.h" -#include "std_mutex.h" -#include "std_thread.h" - -// Don't include common.h here as it will break LogManager -#include "common_types.h" -#include -#include - -// This may not be defined outside _WIN32 -#ifndef _WIN32 -#ifndef INFINITE -#define INFINITE 0xffffffff -#endif - -//for gettimeofday and struct time(spec|val) -#include -#include -#endif - -namespace Common -{ - -int CurrentThreadId(); - -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); -void SetCurrentThreadAffinity(u32 mask); - -class Event -{ -public: - Event() - : is_set(false) - {}; - - void Set() - { - std::lock_guard lk(m_mutex); - if (!is_set) - { - is_set = true; - m_condvar.notify_one(); - } - } - - void Wait() - { - std::unique_lock lk(m_mutex); - m_condvar.wait(lk, IsSet(this)); - is_set = false; - } - - void Reset() - { - std::unique_lock lk(m_mutex); - // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration - is_set = false; - } - -private: - class IsSet - { - public: - IsSet(const Event* ev) - : m_event(ev) - {} - - bool operator()() - { - return m_event->is_set; - } - - private: - const Event* const m_event; - }; - - volatile bool is_set; - std::condition_variable m_condvar; - std::mutex m_mutex; -}; - -// TODO: doesn't work on windows with (count > 2) -class Barrier -{ -public: - Barrier(size_t count) - : m_count(count), m_waiting(0) - {} - - // block until "count" threads call Sync() - bool Sync() - { - std::unique_lock lk(m_mutex); - - // TODO: broken when next round of Sync()s - // is entered before all waiting threads return from the notify_all - - if (m_count == ++m_waiting) - { - m_waiting = 0; - m_condvar.notify_all(); - return true; - } - else - { - m_condvar.wait(lk, IsDoneWating(this)); - return false; - } - } - -private: - class IsDoneWating - { - public: - IsDoneWating(const Barrier* bar) - : m_bar(bar) - {} - - bool operator()() - { - return (0 == m_bar->m_waiting); - } - - private: - const Barrier* const m_bar; - }; - - std::condition_variable m_condvar; - std::mutex m_mutex; - const size_t m_count; - volatile size_t m_waiting; -}; - -void SleepCurrentThread(int ms); -void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms - -// Use this function during a spin-wait to make the current thread -// relax while another thread is working. This may be more efficient -// than using events because event functions use kernel calls. -inline void YieldCPU() -{ - std::this_thread::yield(); -} - -void SetCurrentThreadName(const char *name); - -} // namespace Common - -#endif // _THREAD_H_ diff --git a/src/common/src/thunk.h b/src/common/src/thunk.h deleted file mode 100644 index c9e6fd39..00000000 --- a/src/common/src/thunk.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _THUNK_H_ -#define _THUNK_H_ - -#include - -#include "common.h" -#include "x64Emitter.h" - -// This simple class creates a wrapper around a C/C++ function that saves all fp state -// before entering it, and restores it upon exit. This is required to be able to selectively -// call functions from generated code, without inflicting the performance hit and increase -// of complexity that it means to protect the generated code from this problem. - -// This process is called thunking. - -// There will only ever be one level of thunking on the stack, plus, -// we don't want to pollute the stack, so we store away regs somewhere global. -// NOT THREAD SAFE. This may only be used from the CPU thread. -// Any other thread using this stuff will be FATAL. - -class ThunkManager : public Gen::XCodeBlock -{ - std::map thunks; - - const u8 *save_regs; - const u8 *load_regs; - -public: - ThunkManager() { - Init(); - } - ~ThunkManager() { - Shutdown(); - } - void *ProtectFunction(void *function, int num_params); -private: - void Init(); - void Shutdown(); - void Reset(); -}; - -#endif // _THUNK_H_ diff --git a/src/common/src/timer.cpp b/src/common/src/timer.cpp deleted file mode 100644 index 90604292..00000000 --- a/src/common/src/timer.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#endif - -#include "common.h" -#include "timer.h" -#include "string_util.h" - -namespace Common -{ - -u32 Timer::GetTimeMs() -{ -#ifdef _WIN32 - return timeGetTime(); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); -#endif -} - -// -------------------------------------------- -// Initiate, Start, Stop, and Update the time -// -------------------------------------------- - -// Set initial values for the class -Timer::Timer() - : m_LastTime(0), m_StartTime(0), m_Running(false) -{ - Update(); -} - -// Write the starting time -void Timer::Start() -{ - m_StartTime = GetTimeMs(); - m_Running = true; -} - -// Stop the timer -void Timer::Stop() -{ - // Write the final time - m_LastTime = GetTimeMs(); - m_Running = false; -} - -// Update the last time variable -void Timer::Update() -{ - m_LastTime = GetTimeMs(); - //TODO(ector) - QPF -} - -// ------------------------------------- -// Get time difference and elapsed time -// ------------------------------------- - -// Get the number of milliseconds since the last Update() -u64 Timer::GetTimeDifference() -{ - return GetTimeMs() - m_LastTime; -} - -// Add the time difference since the last Update() to the starting time. -// This is used to compensate for a paused game. -void Timer::AddTimeDifference() -{ - m_StartTime += GetTimeDifference(); -} - -// Get the time elapsed since the Start() -u64 Timer::GetTimeElapsed() -{ - // If we have not started yet, return 1 (because then I don't - // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) return 1; - - // Return the final timer time if the timer is stopped - if (!m_Running) return (m_LastTime - m_StartTime); - - return (GetTimeMs() - m_StartTime); -} - -// Get the formatted time elapsed since the Start() -std::string Timer::GetTimeElapsedFormatted() const -{ - // If we have not started yet, return zero - if (m_StartTime == 0) - return "00:00:00:000"; - - // The number of milliseconds since the start. - // Use a different value if the timer is stopped. - u64 Milliseconds; - if (m_Running) - Milliseconds = GetTimeMs() - m_StartTime; - else - Milliseconds = m_LastTime - m_StartTime; - // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); - // Minutes - u32 Minutes = Seconds / 60; - // Hours - u32 Hours = Minutes / 60; - - std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", - Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); - return TmpStr; -} - -// Get current time -void Timer::IncreaseResolution() -{ -#ifdef _WIN32 - timeBeginPeriod(1); -#endif -} - -void Timer::RestoreResolution() -{ -#ifdef _WIN32 - timeEndPeriod(1); -#endif -} - -// Get the number of seconds since January 1 1970 -u64 Timer::GetTimeSinceJan1970() -{ - time_t ltime; - time(<ime); - return((u64)ltime); -} - -u64 Timer::GetLocalTimeSinceJan1970() -{ - time_t sysTime, tzDiff, tzDST; - struct tm * gmTime; - - time(&sysTime); - - // Account for DST where needed - gmTime = localtime(&sysTime); - if(gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; - - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); - - return (u64)(sysTime + tzDiff + tzDST); -} - -// Return the current time formatted as Minutes:Seconds:Milliseconds -// in the form 00:00:000. -std::string Timer::GetTimeFormatted() -{ - time_t sysTime; - struct tm * gmTime; - char formattedTime[13]; - char tmp[13]; - - time(&sysTime); - gmTime = localtime(&sysTime); - - strftime(tmp, 6, "%M:%S", gmTime); - - // Now tack on the milliseconds -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); - sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); -#endif - - return std::string(formattedTime); -} - -// Returns a timestamp with decimals for precise time comparisons -// ---------------- -double Timer::GetDoubleTime() -{ -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); -#else - struct timeval t; - (void)gettimeofday(&t, NULL); -#endif - // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); - - // Remove a few years. We only really want enough seconds to make - // sure that we are detecting actual actions, perhaps 60 seconds is - // enough really, but I leave a year of seconds anyway, in case the - // user's clock is incorrect or something like that. - TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); - - // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; -#ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; -#else - double ms = t.tv_usec / 1000000.0; -#endif - double TmpTime = Seconds + ms; - - return TmpTime; -} - -} // Namespace Common diff --git a/src/common/src/timer.h b/src/common/src/timer.h deleted file mode 100644 index 20c86762..00000000 --- a/src/common/src/timer.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include "common.h" -#include - -namespace Common -{ -class Timer -{ -public: - Timer(); - - void Start(); - void Stop(); - void Update(); - - // The time difference is always returned in milliseconds, regardless of alternative internal representation - u64 GetTimeDifference(); - void AddTimeDifference(); - - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); - static double GetDoubleTime(); - - static std::string GetTimeFormatted(); - std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed(); - - static u32 GetTimeMs(); - -private: - u64 m_LastTime; - u64 m_StartTime; - bool m_Running; -}; - -} // Namespace Common - -#endif // _TIMER_H_ diff --git a/src/common/src/utf8.cpp b/src/common/src/utf8.cpp deleted file mode 100644 index 9aa8088e..00000000 --- a/src/common/src/utf8.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/* - Basic UTF-8 manipulation routines - by Jeff Bezanson - placed in the public domain Fall 2005 - - This code is designed to provide the utilities you need to manipulate - UTF-8 as an internal string encoding. These functions do not perform the - error checking normally needed when handling UTF-8 data, so if you happen - to be from the Unicode Consortium you will want to flay me alive. - I do this because error checking can be performed at the boundaries (I/O), - with these routines reserved for higher performance on data known to be - valid. -*/ - -#ifdef _WIN32 -#include -#undef min -#undef max -#endif - -#include -#include -#include -#include - -#include -#include - -#include "common_types.h" -#include "utf8.h" - -// is start of UTF sequence -inline bool isutf(char c) { - return (c & 0xC0) != 0x80; -} - -static const u32 offsetsFromUTF8[6] = { - 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL -}; - -static const u8 trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5, -}; - -/* returns length of next utf-8 sequence */ -int u8_seqlen(const char *s) -{ - return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1; -} - -/* conversions without error checking - only works for valid UTF-8, i.e. no 5- or 6-byte sequences - srcsz = source size in bytes, or -1 if 0-terminated - sz = dest size in # of wide characters - - returns # characters converted - dest will always be L'\0'-terminated, even if there isn't enough room - for all the characters. - if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. -*/ -int u8_toucs(u32 *dest, int sz, const char *src, int srcsz) -{ - u32 ch; - const char *src_end = src + srcsz; - int nb; - int i=0; - - while (i < sz-1) { - nb = trailingBytesForUTF8[(unsigned char)*src]; - if (srcsz == -1) { - if (*src == 0) - goto done_toucs; - } - else { - if (src + nb >= src_end) - goto done_toucs; - } - ch = 0; - switch (nb) { - /* these fall through deliberately */ - case 3: ch += (unsigned char)*src++; ch <<= 6; - case 2: ch += (unsigned char)*src++; ch <<= 6; - case 1: ch += (unsigned char)*src++; ch <<= 6; - case 0: ch += (unsigned char)*src++; - } - ch -= offsetsFromUTF8[nb]; - dest[i++] = ch; - } - done_toucs: - dest[i] = 0; - return i; -} - -/* srcsz = number of source characters, or -1 if 0-terminated - sz = size of dest buffer in bytes - - returns # characters converted - dest will only be '\0'-terminated if there is enough space. this is - for consistency; imagine there are 2 bytes of space left, but the next - character requires 3 bytes. in this case we could NUL-terminate, but in - general we can't when there's insufficient space. therefore this function - only NUL-terminates if all the characters fit, and there's space for - the NUL as well. - the destination string will never be bigger than the source string. -*/ -int u8_toutf8(char *dest, int sz, u32 *src, int srcsz) -{ - u32 ch; - int i = 0; - char *dest_end = dest + sz; - - while (srcsz<0 ? src[i]!=0 : i < srcsz) { - ch = src[i]; - if (ch < 0x80) { - if (dest >= dest_end) - return i; - *dest++ = (char)ch; - } - else if (ch < 0x800) { - if (dest >= dest_end-1) - return i; - *dest++ = (ch>>6) | 0xC0; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x10000) { - if (dest >= dest_end-2) - return i; - *dest++ = (ch>>12) | 0xE0; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - else if (ch < 0x110000) { - if (dest >= dest_end-3) - return i; - *dest++ = (ch>>18) | 0xF0; - *dest++ = ((ch>>12) & 0x3F) | 0x80; - *dest++ = ((ch>>6) & 0x3F) | 0x80; - *dest++ = (ch & 0x3F) | 0x80; - } - i++; - } - if (dest < dest_end) - *dest = '\0'; - return i; -} - -int u8_wc_toutf8(char *dest, u32 ch) -{ - if (ch < 0x80) { - dest[0] = (char)ch; - return 1; - } - if (ch < 0x800) { - dest[0] = (ch>>6) | 0xC0; - dest[1] = (ch & 0x3F) | 0x80; - return 2; - } - if (ch < 0x10000) { - dest[0] = (ch>>12) | 0xE0; - dest[1] = ((ch>>6) & 0x3F) | 0x80; - dest[2] = (ch & 0x3F) | 0x80; - return 3; - } - if (ch < 0x110000) { - dest[0] = (ch>>18) | 0xF0; - dest[1] = ((ch>>12) & 0x3F) | 0x80; - dest[2] = ((ch>>6) & 0x3F) | 0x80; - dest[3] = (ch & 0x3F) | 0x80; - return 4; - } - return 0; -} - -/* charnum => byte offset */ -int u8_offset(const char *str, int charnum) -{ - int offs=0; - - while (charnum > 0 && str[offs]) { - (void)(isutf(str[++offs]) || isutf(str[++offs]) || - isutf(str[++offs]) || ++offs); - charnum--; - } - return offs; -} - -/* byte offset => charnum */ -int u8_charnum(const char *s, int offset) -{ - int charnum = 0, offs=0; - - while (offs < offset && s[offs]) { - (void)(isutf(s[++offs]) || isutf(s[++offs]) || - isutf(s[++offs]) || ++offs); - charnum++; - } - return charnum; -} - -/* number of characters */ -int u8_strlen(const char *s) -{ - int count = 0; - int i = 0; - - while (u8_nextchar(s, &i) != 0) - count++; - - return count; -} - -/* reads the next utf-8 sequence out of a string, updating an index */ -u32 u8_nextchar(const char *s, int *i) -{ - u32 ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += (unsigned char)s[(*i)++]; - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; -} - -void u8_inc(const char *s, int *i) -{ - (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || - isutf(s[++(*i)]) || ++(*i)); -} - -void u8_dec(const char *s, int *i) -{ - (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || - isutf(s[--(*i)]) || --(*i)); -} - -int octal_digit(char c) -{ - return (c >= '0' && c <= '7'); -} - -int hex_digit(char c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f')); -} - -/* assumes that src points to the character after a backslash - returns number of input characters processed */ -int u8_read_escape_sequence(const char *str, u32 *dest) -{ - u32 ch; - char digs[9]="\0\0\0\0\0\0\0\0"; - int dno=0, i=1; - - ch = (u32)str[0]; /* take literal character */ - if (str[0] == 'n') - ch = L'\n'; - else if (str[0] == 't') - ch = L'\t'; - else if (str[0] == 'r') - ch = L'\r'; - else if (str[0] == 'b') - ch = L'\b'; - else if (str[0] == 'f') - ch = L'\f'; - else if (str[0] == 'v') - ch = L'\v'; - else if (str[0] == 'a') - ch = L'\a'; - else if (octal_digit(str[0])) { - i = 0; - do { - digs[dno++] = str[i++]; - } while (octal_digit(str[i]) && dno < 3); - ch = strtol(digs, NULL, 8); - } - else if (str[0] == 'x') { - while (hex_digit(str[i]) && dno < 2) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'u') { - while (hex_digit(str[i]) && dno < 4) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - else if (str[0] == 'U') { - while (hex_digit(str[i]) && dno < 8) { - digs[dno++] = str[i++]; - } - if (dno > 0) - ch = strtol(digs, NULL, 16); - } - *dest = ch; - - return i; -} - -/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 - example: u8_unescape(mybuf, 256, "hello\\u220e") - note the double backslash is needed if called on a C string literal */ -int u8_unescape(char *buf, int sz, char *src) -{ - int c=0, amt; - u32 ch; - char temp[4]; - - while (*src && c < sz) { - if (*src == '\\') { - src++; - amt = u8_read_escape_sequence(src, &ch); - } - else { - ch = (u32)*src; - amt = 1; - } - src += amt; - amt = u8_wc_toutf8(temp, ch); - if (amt > sz-c) - break; - memcpy(&buf[c], temp, amt); - c += amt; - } - if (c < sz) - buf[c] = '\0'; - return c; -} - -const char *u8_strchr(const char *s, u32 ch, int *charn) -{ - int i = 0, lasti=0; - u32 c; - - *charn = 0; - while (s[i]) { - c = u8_nextchar(s, &i); - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn) -{ - u32 i = 0, lasti=0; - u32 c; - int csz; - - *charn = 0; - while (i < sz) { - c = csz = 0; - do { - c <<= 6; - c += (unsigned char)s[i++]; - csz++; - } while (i < sz && !isutf(s[i])); - c -= offsetsFromUTF8[csz-1]; - - if (c == ch) { - return &s[lasti]; - } - lasti = i; - (*charn)++; - } - return NULL; -} - -int u8_is_locale_utf8(const char *locale) -{ - /* this code based on libutf8 */ - const char* cp = locale; - - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { - if (*cp == '.') { - const char* encoding = ++cp; - for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) - ; - if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) - || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) - return 1; /* it's UTF-8 */ - break; - } - } - return 0; -} - -int UTF8StringNonASCIICount(const char *utf8string) { - UTF8 utf(utf8string); - int count = 0; - while (!utf.end()) { - int c = utf.next(); - if (c > 127) - ++count; - } - return count; -} - -bool UTF8StringHasNonASCII(const char *utf8string) { - return UTF8StringNonASCIICount(utf8string) > 0; -} - -#ifdef _WIN32 - -std::string ConvertWStringToUTF8(const wchar_t *wstr) { - int len = (int)wcslen(wstr); - int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL); - std::string s; - s.resize(size); - if (size > 0) { - WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL); - } - return s; -} - -std::string ConvertWStringToUTF8(const std::wstring &wstr) { - int len = (int)wstr.size(); - int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL); - std::string s; - s.resize(size); - if (size > 0) { - WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL); - } - return s; -} - -void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) { - int len = (int)source.size(); - int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); - MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); -} - -std::wstring ConvertUTF8ToWString(const std::string &source) { - int len = (int)source.size(); - int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); - std::wstring str; - str.resize(size); - if (size > 0) { - MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, &str[0], size); - } - return str; -} - -#endif \ No newline at end of file diff --git a/src/common/src/utf8.h b/src/common/src/utf8.h deleted file mode 100644 index 36cf7571..00000000 --- a/src/common/src/utf8.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Basic UTF-8 manipulation routines - by Jeff Bezanson - placed in the public domain Fall 2005 - - This code is designed to provide the utilities you need to manipulate - UTF-8 as an internal string encoding. These functions do not perform the - error checking normally needed when handling UTF-8 data, so if you happen - to be from the Unicode Consortium you will want to flay me alive. - I do this because error checking can be performed at the boundaries (I/O), - with these routines reserved for higher performance on data known to be - valid. -*/ - -// Further modified, and C++ stuff added, by hrydgard@gmail.com. - -#pragma once - -#include "common_types.h" -#include - -u32 u8_nextchar(const char *s, int *i); -int u8_wc_toutf8(char *dest, u32 ch); -int u8_strlen(const char *s); - -class UTF8 { -public: - static const u32 INVALID = (u32)-1; - UTF8(const char *c) : c_(c), index_(0) {} - bool end() const { return c_[index_] == 0; } - u32 next() { - return u8_nextchar(c_, &index_); - } - u32 peek() { - int tempIndex = index_; - return u8_nextchar(c_, &tempIndex); - } - int length() const { - return u8_strlen(c_); - } - int byteIndex() const { - return index_; - } - static int encode(char *dest, u32 ch) { - return u8_wc_toutf8(dest, ch); - } - -private: - const char *c_; - int index_; -}; - -int UTF8StringNonASCIICount(const char *utf8string); - -bool UTF8StringHasNonASCII(const char *utf8string); - - -// UTF8 to Win32 UTF-16 -// Should be used when calling Win32 api calls -#ifdef _WIN32 - -std::string ConvertWStringToUTF8(const std::wstring &wstr); -std::string ConvertWStringToUTF8(const wchar_t *wstr); -void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source); -std::wstring ConvertUTF8ToWString(const std::string &source); - -#endif \ No newline at end of file diff --git a/src/common/src/version.cpp b/src/common/src/version.cpp deleted file mode 100644 index 01890dbb..00000000 --- a/src/common/src/version.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "scm_rev.h" - -#ifdef _DEBUG - #define BUILD_TYPE_STR "Debug " -#elif defined DEBUGFAST - #define BUILD_TYPE_STR "DebugFast " -#else - #define BUILD_TYPE_STR "" -#endif - -const char *scm_rev_str = "emu " -#if !SCM_IS_MASTER - "[" SCM_BRANCH_STR "] " -#endif - -#ifdef __INTEL_COMPILER - BUILD_TYPE_STR SCM_DESC_STR "-ICC"; -#else - BUILD_TYPE_STR SCM_DESC_STR; -#endif - -#ifdef _M_X64 -#define NP_ARCH "x64" -#else -#ifdef _M_ARM -#define NP_ARCH "ARM" -#else -#define NP_ARCH "x86" -#endif -#endif - -#ifdef _WIN32 -const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH; -#elif __APPLE__ -const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH; -#else -const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH; -#endif - -const char *scm_rev_git_str = SCM_REV_STR; diff --git a/src/common/std_condition_variable.h b/src/common/std_condition_variable.h new file mode 100644 index 00000000..cee7a9dc --- /dev/null +++ b/src/common/std_condition_variable.h @@ -0,0 +1,170 @@ + +#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__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ + +// GCC 4.4 provides +#include + +#elif __has_include() && !ANDROID + +// clang and libc++ provide on OSX. However, the version +// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable. +// +// We work around this issue by undefining and redefining _. + +#undef _ +#include +#define _(s) wxGetTranslation((s)) + +#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& 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 + void wait(unique_lock& lock, Predicate pred) + { + while (!pred()) + wait(lock); + } + + //template + //cv_status wait_until(unique_lock& lock, + // const chrono::time_point& abs_time); + + //template + // bool wait_until(unique_lock& lock, + // const chrono::time_point& abs_time, + // Predicate pred); + + //template + //cv_status wait_for(unique_lock& lock, + // const chrono::duration& rel_time); + + //template + // bool wait_for(unique_lock& lock, + // const chrono::duration& 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/std_mutex.h b/src/common/std_mutex.h new file mode 100644 index 00000000..26eb58b6 --- /dev/null +++ b/src/common/std_mutex.h @@ -0,0 +1,365 @@ + +#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__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +// GCC 4.4 provides +#include +#elif __has_include() && !ANDROID +// Clang + libc++ +#include +#else + +// partial implementation for win32/pthread + +#include + +#if defined(_WIN32) +// WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +#else +// POSIX +#include + +#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 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 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 + //unique_lock(mutex_type& m, const chrono::time_point& abs_time); + + //template + //unique_lock(mutex_type& m, const chrono::duration& 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(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(u); +#endif + swap(other); + } + + void lock() + { + mutex()->lock(); + owns = true; + } + + bool try_lock() + { + owns = mutex()->try_lock(); + return owns; + } + + //template + //bool try_lock_for(const chrono::duration& rel_time); + //template + //bool try_lock_until(const chrono::time_point& 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() + { + auto const ret = mutex(); + + pm = NULL; + owns = false; + + return ret; + } + + 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 +void swap(unique_lock& x, unique_lock& y) +{ + x.swap(y); +} + +} + +#endif +#endif diff --git a/src/common/std_thread.h b/src/common/std_thread.h new file mode 100644 index 00000000..9ed0072c --- /dev/null +++ b/src/common/std_thread.h @@ -0,0 +1,317 @@ + +#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__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +// GCC 4.4 provides +#ifndef _GLIBCXX_USE_SCHED_YIELD +#define _GLIBCXX_USE_SCHED_YIELD +#endif +#include +#elif __has_include() && !ANDROID +// Clang + libc++ +#include +#else + +// partial std::thread implementation for win32/pthread + +#include + +#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) +#define USE_RVALUE_REFERENCES +#endif + +#ifdef __APPLE__ +#import +#endif + +#if defined(_WIN32) +// WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#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 +#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 + +#ifndef _POSIX_THREADS +#error unsupported platform (no pthreads?) +#endif + +#include + +#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 + //thread(C&& func, A&&... args); + + template + thread(C func) + { + StartThread(new Func(func)); + } + + template + thread(C func, A arg) + { + StartThread(new FuncArg(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(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(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(sysinfo.dwNumberOfProcessors); +#else + return 0; +#endif + } + +private: + id m_id; + +#ifdef _WIN32 + native_handle_type m_handle; +#endif + + template + void StartThread(F* param) + { +#ifdef USE_BEGINTHREADEX + m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); +#elif defined(_WIN32) + m_handle = CreateThread(NULL, 0, &RunAndDelete, 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, param)) + m_id = id(); +#endif + } + + template + class Func + { + public: + Func(C _func) : func(_func) {} + + void Run() { func(); } + + private: + C const func; + }; + + template + class FuncArg + { + public: + FuncArg(C _func, A _arg) : func(_func), arg(_arg) {} + + void Run() { func(arg); } + + private: + C const func; + A arg; + }; + + template + static THREAD_RETURN RunAndDelete(void* param) + { +#ifdef __APPLE__ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +#endif + static_cast(param)->Run(); + delete static_cast(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/string_util.cpp b/src/common/string_util.cpp new file mode 100644 index 00000000..415dcbbc --- /dev/null +++ b/src/common/string_util.cpp @@ -0,0 +1,531 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include + +#include "common.h" +#include "common_paths.h" +#include "string_util.h" + +#ifdef _WIN32 + #include +#else + #include + #include +#endif + +// faster than sscanf +bool AsciiToHex(const char* _szValue, u32& result) +{ + char *endptr = NULL; + const u32 value = strtoul(_szValue, &endptr, 16); + + if (!endptr || *endptr) + return false; + + result = value; + return true; +} + +bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) +{ + int writtenCount; + +#ifdef _WIN32 + // You would think *printf are simple, right? Iterate on each character, + // if it's a format specifier handle it properly, etc. + // + // Nooooo. Not according to the C standard. + // + // According to the C99 standard (7.19.6.1 "The fprintf function") + // The format shall be a multibyte character sequence + // + // Because some character encodings might have '%' signs in the middle of + // a multibyte sequence (SJIS for example only specifies that the first + // byte of a 2 byte sequence is "high", the second byte can be anything), + // printf functions have to decode the multibyte sequences and try their + // best to not screw up. + // + // Unfortunately, on Windows, the locale for most languages is not UTF-8 + // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the + // locale, and completely fails when trying to decode UTF-8 as EUC-CN. + // + // On the other hand, the fix is simple: because we use UTF-8, no such + // multibyte handling is required as we can simply assume that no '%' char + // will be present in the middle of a multibyte sequence. + // + // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. + static locale_t c_locale = NULL; + if (!c_locale) + c_locale = _create_locale(LC_ALL, ".1252"); + writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); +#else + writtenCount = vsnprintf(out, outsize, format, args); +#endif + + if (writtenCount > 0 && writtenCount < outsize) + { + out[writtenCount] = '\0'; + return true; + } + else + { + out[outsize - 1] = '\0'; + return false; + } +} + +std::string StringFromFormat(const char* format, ...) +{ + va_list args; + char *buf = NULL; +#ifdef _WIN32 + int required = 0; + + va_start(args, format); + required = _vscprintf(format, args); + buf = new char[required + 1]; + CharArrayFromFormatV(buf, required + 1, format, args); + va_end(args); + + std::string temp = buf; + delete[] buf; +#else + va_start(args, format); + if (vasprintf(&buf, format, args) < 0) + ERROR_LOG(COMMON, "Unable to allocate memory for string"); + va_end(args); + + std::string temp = buf; + free(buf); +#endif + return temp; +} + +// For Debugging. Read out an u8 array. +std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) +{ + std::ostringstream oss; + oss << std::setfill('0') << std::hex; + + for (int line = 0; size; ++data, --size) + { + oss << std::setw(2) << (int)*data; + + if (line_len == ++line) + { + oss << '\n'; + line = 0; + } + else if (spaces) + oss << ' '; + } + + return oss.str(); +} + +// Turns " hej " into "hej". Also handles tabs. +std::string StripSpaces(const std::string &str) +{ + const size_t s = str.find_first_not_of(" \t\r\n"); + + if (str.npos != s) + return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); + else + return ""; +} + +// "\"hello\"" is turned to "hello" +// This one assumes that the string has already been space stripped in both +// ends, as done by StripSpaces above, for example. +std::string StripQuotes(const std::string& s) +{ + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return s.substr(1, s.size() - 2); + else + return s; +} + +bool TryParse(const std::string &str, u32 *const output) +{ + char *endptr = NULL; + + // Reset errno to a value other than ERANGE + errno = 0; + + unsigned long value = strtoul(str.c_str(), &endptr, 0); + + if (!endptr || *endptr) + return false; + + if (errno == ERANGE) + return false; + +#if ULONG_MAX > UINT_MAX + if (value >= 0x100000000ull + && value <= 0xFFFFFFFF00000000ull) + return false; +#endif + + *output = static_cast(value); + return true; +} + +bool TryParse(const std::string &str, bool *const output) +{ + if ("1" == str || !strcasecmp("true", str.c_str())) + *output = true; + else if ("0" == str || !strcasecmp("false", str.c_str())) + *output = false; + else + return false; + + return true; +} + +std::string StringFromInt(int value) +{ + char temp[16]; + sprintf(temp, "%i", value); + return temp; +} + +std::string StringFromBool(bool value) +{ + return value ? "True" : "False"; +} + +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) +{ + if (full_path.empty()) + return false; + + size_t dir_end = full_path.find_last_of("/" + // windows needs the : included for something like just "C:" to be considered a directory +#ifdef _WIN32 + ":" +#endif + ); + if (std::string::npos == dir_end) + dir_end = 0; + else + dir_end += 1; + + size_t fname_end = full_path.rfind('.'); + if (fname_end < dir_end || std::string::npos == fname_end) + fname_end = full_path.size(); + + if (_pPath) + *_pPath = full_path.substr(0, dir_end); + + if (_pFilename) + *_pFilename = full_path.substr(dir_end, fname_end - dir_end); + + if (_pExtension) + *_pExtension = full_path.substr(fname_end); + + return true; +} + +void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) +{ + _CompleteFilename = _Path; + + // check for seperator + if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) + _CompleteFilename += DIR_SEP_CHR; + + // add the filename + _CompleteFilename += _Filename; +} + +void SplitString(const std::string& str, const char delim, std::vector& output) +{ + std::istringstream iss(str); + output.resize(1); + + while (std::getline(iss, *output.rbegin(), delim)) + output.push_back(""); + + output.pop_back(); +} + +std::string TabsToSpaces(int tab_size, const std::string &in) +{ + const std::string spaces(tab_size, ' '); + std::string out(in); + + size_t i = 0; + while (out.npos != (i = out.find('\t'))) + out.replace(i, 1, spaces); + + return out; +} + +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) +{ + while(1) + { + size_t pos = result.find(src); + if (pos == std::string::npos) break; + result.replace(pos, src.size(), dest); + } + return result; +} + +// UriDecode and UriEncode are from http://www.codeguru.com/cpp/cpp/string/conversions/print.php/c12759 +// by jinq0123 (November 2, 2006) + +// Uri encode and decode. +// RFC1630, RFC1738, RFC2396 + +//#include +//#include + +const char HEX2DEC[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16, + + /* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, + /* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, + /* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + + /* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + + /* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 +}; + +std::string UriDecode(const std::string & sSrc) +{ + // Note from RFC1630: "Sequences which start with a percent sign + // but are not followed by two hexadecimal characters (0-9, A-F) are reserved + // for future extension" + + const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); + const size_t SRC_LEN = sSrc.length(); + const unsigned char * const SRC_END = pSrc + SRC_LEN; + const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' + + char * const pStart = new char[SRC_LEN]; + char * pEnd = pStart; + + while (pSrc < SRC_LAST_DEC) + { + if (*pSrc == '%') + { + char dec1, dec2; + if (16 != (dec1 = HEX2DEC[*(pSrc + 1)]) + && 16 != (dec2 = HEX2DEC[*(pSrc + 2)])) + { + *pEnd++ = (dec1 << 4) + dec2; + pSrc += 3; + continue; + } + } + + *pEnd++ = *pSrc++; + } + + // the last 2- chars + while (pSrc < SRC_END) + *pEnd++ = *pSrc++; + + std::string sResult(pStart, pEnd); + delete [] pStart; + return sResult; +} + +// Only alphanum is safe. +const char SAFE[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, + + /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, + /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, + /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, + /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, + + /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + + /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 +}; + +std::string UriEncode(const std::string & sSrc) +{ + const char DEC2HEX[16 + 1] = "0123456789ABCDEF"; + const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); + const size_t SRC_LEN = sSrc.length(); + unsigned char * const pStart = new unsigned char[SRC_LEN * 3]; + unsigned char * pEnd = pStart; + const unsigned char * const SRC_END = pSrc + SRC_LEN; + + for (; pSrc < SRC_END; ++pSrc) + { + if (SAFE[*pSrc]) + *pEnd++ = *pSrc; + else + { + // escape this char + *pEnd++ = '%'; + *pEnd++ = DEC2HEX[*pSrc >> 4]; + *pEnd++ = DEC2HEX[*pSrc & 0x0F]; + } + } + + std::string sResult((char *)pStart, (char *)pEnd); + delete [] pStart; + return sResult; +} + +#ifdef _WIN32 + +std::string UTF16ToUTF8(const std::wstring& input) +{ + auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); + + std::string output; + output.resize(size); + + if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) + output.clear(); + + return output; +} + +std::wstring CPToUTF16(u32 code_page, const std::string& input) +{ + auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); + + std::wstring output; + output.resize(size); + + if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size())) + output.clear(); + + return output; +} + +std::wstring UTF8ToUTF16(const std::string& input) +{ + return CPToUTF16(CP_UTF8, input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(932, input)); +} + +std::string CP1252ToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(1252, input)); +} + +#else + +template +std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) +{ + std::string result; + + iconv_t const conv_desc = iconv_open("UTF-8", fromcode); + if ((iconv_t)-1 == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + size_t const in_bytes = sizeof(T) * input.size(); + size_t const out_buffer_size = 4 * in_bytes; + + std::string out_buffer; + out_buffer.resize(out_buffer_size); + + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); + + while (src_bytes != 0) + { + size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, + &dst_buffer, &dst_bytes); + + if ((size_t)-1 == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) + { + // Try to skip the bad character + if (src_bytes != 0) + { + --src_bytes; + ++src_buffer; + } + } + else + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + break; + } + } + } + + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + iconv_close(conv_desc); + } + + return result; +} + +std::string CP1252ToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP1252//TRANSLIT", input); + //return CodeToUTF8("CP1252//IGNORE", input); + return CodeToUTF8("CP1252", input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP932", input); + return CodeToUTF8("SJIS", input); +} + +std::string UTF16ToUTF8(const std::wstring& input) +{ + std::string result = + // CodeToUTF8("UCS-2", input); + // CodeToUTF8("UCS-2LE", input); + // CodeToUTF8("UTF-16", input); + CodeToUTF8("UTF-16LE", input); + + // TODO: why is this needed? + result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); + return result; +} + +#endif diff --git a/src/common/string_util.h b/src/common/string_util.h new file mode 100644 index 00000000..fcbae471 --- /dev/null +++ b/src/common/string_util.h @@ -0,0 +1,111 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _STRINGUTIL_H_ +#define _STRINGUTIL_H_ + +#include + +#include +#include +#include +#include + +#include "common.h" + +std::string StringFromFormat(const char* format, ...); +// Cheap! +bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); + +template +inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) +{ + va_list args; + va_start(args, format); + CharArrayFromFormatV(out, Count, format, args); + va_end(args); +} + +// Good +std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); + +std::string StripSpaces(const std::string &s); +std::string StripQuotes(const std::string &s); + +// Thousand separator. Turns 12345678 into 12,345,678 +template +std::string ThousandSeparate(I value, int spaces = 0) +{ + std::ostringstream oss; + +// std::locale("") seems to be broken on many platforms +#if defined _WIN32 || (defined __linux__ && !defined __clang__) + oss.imbue(std::locale("")); +#endif + oss << std::setw(spaces) << value; + + return oss.str(); +} + +std::string StringFromInt(int value); +std::string StringFromBool(bool value); + +bool TryParse(const std::string &str, bool *output); +bool TryParse(const std::string &str, u32 *output); + +template +static bool TryParse(const std::string &str, N *const output) +{ + std::istringstream iss(str); + + N tmp = 0; + if (iss >> tmp) + { + *output = tmp; + return true; + } + else + return false; +} + +// TODO: kill this +bool AsciiToHex(const char* _szValue, u32& result); + +std::string TabsToSpaces(int tab_size, const std::string &in); + +void SplitString(const std::string& str, char delim, std::vector& output); + +// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); + +void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); +std::string UriDecode(const std::string & sSrc); +std::string UriEncode(const std::string & sSrc); + +std::string CP1252ToUTF8(const std::string& str); +std::string SHIFTJISToUTF8(const std::string& str); +std::string UTF16ToUTF8(const std::wstring& str); + +#ifdef _WIN32 + +std::wstring UTF8ToUTF16(const std::string& str); + +#ifdef _UNICODE +inline std::string TStrToUTF8(const std::wstring& str) +{ return UTF16ToUTF8(str); } + +inline std::wstring UTF8ToTStr(const std::string& str) +{ return UTF8ToUTF16(str); } +#else +inline std::string TStrToUTF8(const std::string& str) +{ return str; } + +inline std::string UTF8ToTStr(const std::string& str) +{ return str; } +#endif + +#endif + +#endif // _STRINGUTIL_H_ diff --git a/src/common/swap.h b/src/common/swap.h new file mode 100644 index 00000000..d07d9fcc --- /dev/null +++ b/src/common/swap.h @@ -0,0 +1,535 @@ +// Copyright (c) 2012- PPSSPP Project / Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +// Android +#if defined(ANDROID) +#include + +#if _BYTE_ORDER == _LITTLE_ENDIAN && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif _BYTE_ORDER == _BIG_ENDIAN && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// GCC 4.6+ +#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) + +#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// LLVM/clang +#elif __clang__ + +#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) +#define COMMON_LITTLE_ENDIAN 1 +#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) +#define COMMON_BIG_ENDIAN 1 +#endif + +// MSVC +#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) + +#ifdef _XBOX +#define COMMON_BIG_ENDIAN 1 +#else +#define COMMON_LITTLE_ENDIAN 1 +#endif + +#endif + +// Worst case, default to little endian. +#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN +#define COMMON_LITTLE_ENDIAN 1 +#endif + +template +struct swap_struct_t { + typedef swap_struct_t swapped_t; + +protected: + T value; + + static T swap(T v) { + return F::swap(v); + } +public: + T const swap() const { + return swap(value); + + } + swap_struct_t() : value((T)0) {} + swap_struct_t(const T &v): value(swap(v)) {} + + template + swapped_t& operator=(const S &source) { + value = swap((T)source); + return *this; + } + + operator long() const { return (long)swap(); } + operator s8() const { return (s8)swap(); } + operator u8() const { return (u8)swap(); } + operator s16() const { return (s16)swap(); } + operator u16() const { return (u16)swap(); } + operator s32() const { return (s32)swap(); } + operator u32() const { return (u32)swap(); } + operator s64() const { return (s64)swap(); } + operator u64() const { return (u64)swap(); } + operator float() const { return (float)swap(); } + operator double() const { return (double)swap(); } + + // +v + swapped_t operator +() const { + return +swap(); + } + // -v + swapped_t operator -() const { + return -swap(); + } + + // v / 5 + swapped_t operator/(const swapped_t &i) const { + return swap() / i.swap(); + } + template + swapped_t operator/(const S &i) const { + return swap() / i; + } + + // v * 5 + swapped_t operator*(const swapped_t &i) const { + return swap() * i.swap(); + } + template + swapped_t operator*(const S &i) const { + return swap() * i; + } + + // v + 5 + swapped_t operator+(const swapped_t &i) const { + return swap() + i.swap(); + } + template + swapped_t operator+(const S &i) const { + return swap() + (T)i; + } + // v - 5 + swapped_t operator-(const swapped_t &i) const { + return swap() - i.swap(); + } + template + swapped_t operator-(const S &i) const { + return swap() - (T)i; + } + + // v += 5 + swapped_t& operator+=(const swapped_t &i) { + value = swap(swap() + i.swap()); + return *this; + } + template + swapped_t& operator+=(const S &i) { + value = swap(swap() + (T)i); + return *this; + } + // v -= 5 + swapped_t& operator-=(const swapped_t &i) { + value = swap(swap() - i.swap()); + return *this; + } + template + swapped_t& operator-=(const S &i) { + value = swap(swap() - (T)i); + return *this; + } + + // ++v + swapped_t& operator++() { + value = swap(swap()+1); + return *this; + } + // --v + swapped_t& operator--() { + value = swap(swap()-1); + return *this; + } + + // v++ + swapped_t operator++(int) { + swapped_t old = *this; + value = swap(swap()+1); + return old; + } + // v-- + swapped_t operator--(int) { + swapped_t old = *this; + value = swap(swap()-1); + return old; + } + // Comparaison + // v == i + bool operator==(const swapped_t &i) const { + return swap() == i.swap(); + } + template + bool operator==(const S &i) const { + return swap() == i; + } + + // v != i + bool operator!=(const swapped_t &i) const { + return swap() != i.swap(); + } + template + bool operator!=(const S &i) const { + return swap() != i; + } + + // v > i + bool operator>(const swapped_t &i) const { + return swap() > i.swap(); + } + template + bool operator>(const S &i) const { + return swap() > i; + } + + // v < i + bool operator<(const swapped_t &i) const { + return swap() < i.swap(); + } + template + bool operator<(const S &i) const { + return swap() < i; + } + + // v >= i + bool operator>=(const swapped_t &i) const { + return swap() >= i.swap(); + } + template + bool operator>=(const S &i) const { + return swap() >= i; + } + + // v <= i + bool operator<=(const swapped_t &i) const { + return swap() <= i.swap(); + } + template + bool operator<=(const S &i) const { + return swap() <= i; + } + + // logical + swapped_t operator !() const { + return !swap(); + } + + // bitmath + swapped_t operator ~() const { + return ~swap(); + } + + swapped_t operator &(const swapped_t &b) const { + return swap() & b.swap(); + } + template + swapped_t operator &(const S &b) const { + return swap() & b; + } + swapped_t& operator &=(const swapped_t &b) { + value = swap(swap() & b.swap()); + return *this; + } + template + swapped_t& operator &=(const S b) { + value = swap(swap() & b); + return *this; + } + + swapped_t operator |(const swapped_t &b) const { + return swap() | b.swap(); + } + template + swapped_t operator |(const S &b) const { + return swap() | b; + } + swapped_t& operator |=(const swapped_t &b) { + value = swap(swap() | b.swap()); + return *this; + } + template + swapped_t& operator |=(const S &b) { + value = swap(swap() | b); + return *this; + } + + swapped_t operator ^(const swapped_t &b) const { + return swap() ^ b.swap(); + } + template + swapped_t operator ^(const S &b) const { + return swap() ^ b; + } + swapped_t& operator ^=(const swapped_t &b) { + value = swap(swap() ^ b.swap()); + return *this; + } + template + swapped_t& operator ^=(const S &b) { + value = swap(swap() ^ b); + return *this; + } + + template + swapped_t operator <<(const S &b) const { + return swap() << b; + } + template + swapped_t& operator <<=(const S &b) const { + value = swap(swap() << b); + return *this; + } + + template + swapped_t operator >>(const S &b) const { + return swap() >> b; + } + template + swapped_t& operator >>=(const S &b) const { + value = swap(swap() >> b); + return *this; + } + + // Member + /** todo **/ + + + // Arithmetics + template + friend S operator+(const S &p, const swapped_t v); + + template + friend S operator-(const S &p, const swapped_t v); + + template + friend S operator/(const S &p, const swapped_t v); + + template + friend S operator*(const S &p, const swapped_t v); + + template + friend S operator%(const S &p, const swapped_t v); + + // Arithmetics + assignements + template + friend S operator+=(const S &p, const swapped_t v); + + template + friend S operator-=(const S &p, const swapped_t v); + + // Bitmath + template + friend S operator&(const S &p, const swapped_t v); + + // Comparison + template + friend bool operator<(const S &p, const swapped_t v); + + template + friend bool operator>(const S &p, const swapped_t v); + + template + friend bool operator<=(const S &p, const swapped_t v); + + template + friend bool operator>=(const S &p, const swapped_t v); + + template + friend bool operator!=(const S &p, const swapped_t v); + + template + friend bool operator==(const S &p, const swapped_t v); +}; + + +// Arithmetics +template +S operator+(const S &i, const swap_struct_t v) { + return i + v.swap(); +} + +template +S operator-(const S &i, const swap_struct_t v) { + return i - v.swap(); +} + +template +S operator/(const S &i, const swap_struct_t v) { + return i / v.swap(); +} + +template +S operator*(const S &i, const swap_struct_t v) { + return i * v.swap(); +} + +template +S operator%(const S &i, const swap_struct_t v) { + return i % v.swap(); +} + +// Arithmetics + assignements +template +S &operator+=(S &i, const swap_struct_t v) { + i += v.swap(); + return i; +} + +template +S &operator-=(S &i, const swap_struct_t v) { + i -= v.swap(); + return i; +} + +// Logical +template +S operator&(const S &i, const swap_struct_t v) { + return i & v.swap(); +} + +template +S operator&(const swap_struct_t v, const S &i) { + return (S)(v.swap() & i); +} + + +// Comparaison +template +bool operator<(const S &p, const swap_struct_t v) { + return p < v.swap(); +} +template +bool operator>(const S &p, const swap_struct_t v) { + return p > v.swap(); +} +template +bool operator<=(const S &p, const swap_struct_t v) { + return p <= v.swap(); +} +template +bool operator>=(const S &p, const swap_struct_t v) { + return p >= v.swap(); +} +template +bool operator!=(const S &p, const swap_struct_t v) { + return p != v.swap(); +} +template +bool operator==(const S &p, const swap_struct_t v) { + return p == v.swap(); +} + +template +struct swap_64_t { + static T swap(T x) { + return (T)bswap64(*(u64 *)&x); + } +}; + +template +struct swap_32_t { + static T swap(T x) { + return (T)bswap32(*(u32 *)&x); + } +}; + +template +struct swap_16_t { + static T swap(T x) { + return (T)bswap16(*(u16 *)&x); + } +}; + +template +struct swap_float_t { + static T swap(T x) { + return (T)bswapf(*(float *)&x); + } +}; + +template +struct swap_double_t { + static T swap(T x) { + return (T)bswapd(*(double *)&x); + } +}; + +#if COMMON_LITTLE_ENDIAN +typedef u32 u32_le; +typedef u16 u16_le; +typedef u64 u64_le; + +typedef s32 s32_le; +typedef s16 s16_le; +typedef s64 s64_le; + +typedef float float_le; +typedef double double_le; + +typedef swap_struct_t> u64_be; +typedef swap_struct_t> s64_be; + +typedef swap_struct_t> u32_be; +typedef swap_struct_t> s32_be; + +typedef swap_struct_t> u16_be; +typedef swap_struct_t> s16_be; + +typedef swap_struct_t > float_be; +typedef swap_struct_t > double_be; +#else + +typedef swap_struct_t> u64_le; +typedef swap_struct_t> s64_le; + +typedef swap_struct_t> u32_le; +typedef swap_struct_t> s32_le; + +typedef swap_struct_t> u16_le; +typedef swap_struct_t> s16_le; + +typedef swap_struct_t > float_le; +typedef swap_struct_t > double_le; + +typedef u32 u32_be; +typedef u16 u16_be; +typedef u64 u64_be; + +typedef s32 s32_be; +typedef s16 s16_be; +typedef s64 s64_be; + +typedef float float_be; +typedef double double_be; +#endif \ No newline at end of file diff --git a/src/common/thread.cpp b/src/common/thread.cpp new file mode 100644 index 00000000..27dbf3f9 --- /dev/null +++ b/src/common/thread.cpp @@ -0,0 +1,133 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "thread.h" +#include "common.h" + +#ifdef __APPLE__ +#include +#elif defined BSD4_4 +#include +#endif + +#ifdef USE_BEGINTHREADEX +#include +#endif + +namespace Common +{ + +int CurrentThreadId() +{ +#ifdef _WIN32 + return GetCurrentThreadId(); +#elif defined __APPLE__ + return mach_thread_self(); +#else + return 0; +#endif +} + +#ifdef _WIN32 + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +{ + SetThreadAffinityMask(thread, mask); +} + +void SetCurrentThreadAffinity(u32 mask) +{ + SetThreadAffinityMask(GetCurrentThread(), mask); +} + +// Supporting functions +void SleepCurrentThread(int ms) +{ + Sleep(ms); +} + +void SwitchCurrentThread() +{ + SwitchToThread(); +} + +// Sets the debugger-visible name of the current thread. +// Uses undocumented (actually, it is now documented) trick. +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp + +// This is implemented much nicer in upcoming msvc++, see: +// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx +void SetCurrentThreadName(const char* szThreadName) +{ + static const DWORD MS_VC_EXCEPTION = 0x406D1388; + + #pragma pack(push,8) + struct THREADNAME_INFO + { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero + } info; + #pragma pack(pop) + + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = -1; //dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_CONTINUE_EXECUTION) + {} +} + +#else // !WIN32, so must be POSIX threads + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) +{ +#ifdef __APPLE__ + thread_policy_set(pthread_mach_thread_np(thread), + THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); +#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + + for (int i = 0; i != sizeof(mask) * 8; ++i) + if ((mask >> i) & 1) + CPU_SET(i, &cpu_set); + + pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); +#endif +} + +void SetCurrentThreadAffinity(u32 mask) +{ + SetThreadAffinity(pthread_self(), mask); +} + +void SleepCurrentThread(int ms) +{ + usleep(1000 * ms); +} + +void SwitchCurrentThread() +{ + usleep(1000 * 1); +} + +void SetCurrentThreadName(const char* szThreadName) +{ +#ifdef __APPLE__ + pthread_setname_np(szThreadName); +#else + pthread_setname_np(pthread_self(), szThreadName); +#endif +} + +#endif + +} // namespace Common diff --git a/src/common/thread.h b/src/common/thread.h new file mode 100644 index 00000000..6384a44a --- /dev/null +++ b/src/common/thread.h @@ -0,0 +1,156 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _THREAD_H_ +#define _THREAD_H_ + +#include "std_condition_variable.h" +#include "std_mutex.h" +#include "std_thread.h" + +// Don't include common.h here as it will break LogManager +#include "common_types.h" +#include +#include + +// This may not be defined outside _WIN32 +#ifndef _WIN32 +#ifndef INFINITE +#define INFINITE 0xffffffff +#endif + +//for gettimeofday and struct time(spec|val) +#include +#include +#endif + +namespace Common +{ + +int CurrentThreadId(); + +void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); +void SetCurrentThreadAffinity(u32 mask); + +class Event +{ +public: + Event() + : is_set(false) + {}; + + void Set() + { + std::lock_guard lk(m_mutex); + if (!is_set) + { + is_set = true; + m_condvar.notify_one(); + } + } + + void Wait() + { + std::unique_lock lk(m_mutex); + m_condvar.wait(lk, IsSet(this)); + is_set = false; + } + + void Reset() + { + std::unique_lock lk(m_mutex); + // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration + is_set = false; + } + +private: + class IsSet + { + public: + IsSet(const Event* ev) + : m_event(ev) + {} + + bool operator()() + { + return m_event->is_set; + } + + private: + const Event* const m_event; + }; + + volatile bool is_set; + std::condition_variable m_condvar; + std::mutex m_mutex; +}; + +// TODO: doesn't work on windows with (count > 2) +class Barrier +{ +public: + Barrier(size_t count) + : m_count(count), m_waiting(0) + {} + + // block until "count" threads call Sync() + bool Sync() + { + std::unique_lock lk(m_mutex); + + // TODO: broken when next round of Sync()s + // is entered before all waiting threads return from the notify_all + + if (m_count == ++m_waiting) + { + m_waiting = 0; + m_condvar.notify_all(); + return true; + } + else + { + m_condvar.wait(lk, IsDoneWating(this)); + return false; + } + } + +private: + class IsDoneWating + { + public: + IsDoneWating(const Barrier* bar) + : m_bar(bar) + {} + + bool operator()() + { + return (0 == m_bar->m_waiting); + } + + private: + const Barrier* const m_bar; + }; + + std::condition_variable m_condvar; + std::mutex m_mutex; + const size_t m_count; + volatile size_t m_waiting; +}; + +void SleepCurrentThread(int ms); +void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms + +// Use this function during a spin-wait to make the current thread +// relax while another thread is working. This may be more efficient +// than using events because event functions use kernel calls. +inline void YieldCPU() +{ + std::this_thread::yield(); +} + +void SetCurrentThreadName(const char *name); + +} // namespace Common + +#endif // _THREAD_H_ diff --git a/src/common/thunk.h b/src/common/thunk.h new file mode 100644 index 00000000..c9e6fd39 --- /dev/null +++ b/src/common/thunk.h @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _THUNK_H_ +#define _THUNK_H_ + +#include + +#include "common.h" +#include "x64Emitter.h" + +// This simple class creates a wrapper around a C/C++ function that saves all fp state +// before entering it, and restores it upon exit. This is required to be able to selectively +// call functions from generated code, without inflicting the performance hit and increase +// of complexity that it means to protect the generated code from this problem. + +// This process is called thunking. + +// There will only ever be one level of thunking on the stack, plus, +// we don't want to pollute the stack, so we store away regs somewhere global. +// NOT THREAD SAFE. This may only be used from the CPU thread. +// Any other thread using this stuff will be FATAL. + +class ThunkManager : public Gen::XCodeBlock +{ + std::map thunks; + + const u8 *save_regs; + const u8 *load_regs; + +public: + ThunkManager() { + Init(); + } + ~ThunkManager() { + Shutdown(); + } + void *ProtectFunction(void *function, int num_params); +private: + void Init(); + void Shutdown(); + void Reset(); +}; + +#endif // _THUNK_H_ diff --git a/src/common/timer.cpp b/src/common/timer.cpp new file mode 100644 index 00000000..90604292 --- /dev/null +++ b/src/common/timer.cpp @@ -0,0 +1,226 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +#include "common.h" +#include "timer.h" +#include "string_util.h" + +namespace Common +{ + +u32 Timer::GetTimeMs() +{ +#ifdef _WIN32 + return timeGetTime(); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); + return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); +#endif +} + +// -------------------------------------------- +// Initiate, Start, Stop, and Update the time +// -------------------------------------------- + +// Set initial values for the class +Timer::Timer() + : m_LastTime(0), m_StartTime(0), m_Running(false) +{ + Update(); +} + +// Write the starting time +void Timer::Start() +{ + m_StartTime = GetTimeMs(); + m_Running = true; +} + +// Stop the timer +void Timer::Stop() +{ + // Write the final time + m_LastTime = GetTimeMs(); + m_Running = false; +} + +// Update the last time variable +void Timer::Update() +{ + m_LastTime = GetTimeMs(); + //TODO(ector) - QPF +} + +// ------------------------------------- +// Get time difference and elapsed time +// ------------------------------------- + +// Get the number of milliseconds since the last Update() +u64 Timer::GetTimeDifference() +{ + return GetTimeMs() - m_LastTime; +} + +// Add the time difference since the last Update() to the starting time. +// This is used to compensate for a paused game. +void Timer::AddTimeDifference() +{ + m_StartTime += GetTimeDifference(); +} + +// Get the time elapsed since the Start() +u64 Timer::GetTimeElapsed() +{ + // If we have not started yet, return 1 (because then I don't + // have to change the FPS calculation in CoreRerecording.cpp . + if (m_StartTime == 0) return 1; + + // Return the final timer time if the timer is stopped + if (!m_Running) return (m_LastTime - m_StartTime); + + return (GetTimeMs() - m_StartTime); +} + +// Get the formatted time elapsed since the Start() +std::string Timer::GetTimeElapsedFormatted() const +{ + // If we have not started yet, return zero + if (m_StartTime == 0) + return "00:00:00:000"; + + // The number of milliseconds since the start. + // Use a different value if the timer is stopped. + u64 Milliseconds; + if (m_Running) + Milliseconds = GetTimeMs() - m_StartTime; + else + Milliseconds = m_LastTime - m_StartTime; + // Seconds + u32 Seconds = (u32)(Milliseconds / 1000); + // Minutes + u32 Minutes = Seconds / 60; + // Hours + u32 Hours = Minutes / 60; + + std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", + Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); + return TmpStr; +} + +// Get current time +void Timer::IncreaseResolution() +{ +#ifdef _WIN32 + timeBeginPeriod(1); +#endif +} + +void Timer::RestoreResolution() +{ +#ifdef _WIN32 + timeEndPeriod(1); +#endif +} + +// Get the number of seconds since January 1 1970 +u64 Timer::GetTimeSinceJan1970() +{ + time_t ltime; + time(<ime); + return((u64)ltime); +} + +u64 Timer::GetLocalTimeSinceJan1970() +{ + time_t sysTime, tzDiff, tzDST; + struct tm * gmTime; + + time(&sysTime); + + // Account for DST where needed + gmTime = localtime(&sysTime); + if(gmTime->tm_isdst == 1) + tzDST = 3600; + else + tzDST = 0; + + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + tzDiff = sysTime - mktime(gmTime); + + return (u64)(sysTime + tzDiff + tzDST); +} + +// Return the current time formatted as Minutes:Seconds:Milliseconds +// in the form 00:00:000. +std::string Timer::GetTimeFormatted() +{ + time_t sysTime; + struct tm * gmTime; + char formattedTime[13]; + char tmp[13]; + + time(&sysTime); + gmTime = localtime(&sysTime); + + strftime(tmp, 6, "%M:%S", gmTime); + + // Now tack on the milliseconds +#ifdef _WIN32 + struct timeb tp; + (void)::ftime(&tp); + sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); + sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); +#endif + + return std::string(formattedTime); +} + +// Returns a timestamp with decimals for precise time comparisons +// ---------------- +double Timer::GetDoubleTime() +{ +#ifdef _WIN32 + struct timeb tp; + (void)::ftime(&tp); +#else + struct timeval t; + (void)gettimeofday(&t, NULL); +#endif + // Get continuous timestamp + u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); + + // Remove a few years. We only really want enough seconds to make + // sure that we are detecting actual actions, perhaps 60 seconds is + // enough really, but I leave a year of seconds anyway, in case the + // user's clock is incorrect or something like that. + TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); + + // Make a smaller integer that fits in the double + u32 Seconds = (u32)TmpSeconds; +#ifdef _WIN32 + double ms = tp.millitm / 1000.0 / 1000.0; +#else + double ms = t.tv_usec / 1000000.0; +#endif + double TmpTime = Seconds + ms; + + return TmpTime; +} + +} // Namespace Common diff --git a/src/common/timer.h b/src/common/timer.h new file mode 100644 index 00000000..20c86762 --- /dev/null +++ b/src/common/timer.h @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "common.h" +#include + +namespace Common +{ +class Timer +{ +public: + Timer(); + + void Start(); + void Stop(); + void Update(); + + // The time difference is always returned in milliseconds, regardless of alternative internal representation + u64 GetTimeDifference(); + void AddTimeDifference(); + + static void IncreaseResolution(); + static void RestoreResolution(); + static u64 GetTimeSinceJan1970(); + static u64 GetLocalTimeSinceJan1970(); + static double GetDoubleTime(); + + static std::string GetTimeFormatted(); + std::string GetTimeElapsedFormatted() const; + u64 GetTimeElapsed(); + + static u32 GetTimeMs(); + +private: + u64 m_LastTime; + u64 m_StartTime; + bool m_Running; +}; + +} // Namespace Common + +#endif // _TIMER_H_ diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp new file mode 100644 index 00000000..9aa8088e --- /dev/null +++ b/src/common/utf8.cpp @@ -0,0 +1,463 @@ +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ + +#ifdef _WIN32 +#include +#undef min +#undef max +#endif + +#include +#include +#include +#include + +#include +#include + +#include "common_types.h" +#include "utf8.h" + +// is start of UTF sequence +inline bool isutf(char c) { + return (c & 0xC0) != 0x80; +} + +static const u32 offsetsFromUTF8[6] = { + 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL +}; + +static const u8 trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5, +}; + +/* returns length of next utf-8 sequence */ +int u8_seqlen(const char *s) +{ + return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1; +} + +/* conversions without error checking + only works for valid UTF-8, i.e. no 5- or 6-byte sequences + srcsz = source size in bytes, or -1 if 0-terminated + sz = dest size in # of wide characters + + returns # characters converted + dest will always be L'\0'-terminated, even if there isn't enough room + for all the characters. + if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. +*/ +int u8_toucs(u32 *dest, int sz, const char *src, int srcsz) +{ + u32 ch; + const char *src_end = src + srcsz; + int nb; + int i=0; + + while (i < sz-1) { + nb = trailingBytesForUTF8[(unsigned char)*src]; + if (srcsz == -1) { + if (*src == 0) + goto done_toucs; + } + else { + if (src + nb >= src_end) + goto done_toucs; + } + ch = 0; + switch (nb) { + /* these fall through deliberately */ + case 3: ch += (unsigned char)*src++; ch <<= 6; + case 2: ch += (unsigned char)*src++; ch <<= 6; + case 1: ch += (unsigned char)*src++; ch <<= 6; + case 0: ch += (unsigned char)*src++; + } + ch -= offsetsFromUTF8[nb]; + dest[i++] = ch; + } + done_toucs: + dest[i] = 0; + return i; +} + +/* srcsz = number of source characters, or -1 if 0-terminated + sz = size of dest buffer in bytes + + returns # characters converted + dest will only be '\0'-terminated if there is enough space. this is + for consistency; imagine there are 2 bytes of space left, but the next + character requires 3 bytes. in this case we could NUL-terminate, but in + general we can't when there's insufficient space. therefore this function + only NUL-terminates if all the characters fit, and there's space for + the NUL as well. + the destination string will never be bigger than the source string. +*/ +int u8_toutf8(char *dest, int sz, u32 *src, int srcsz) +{ + u32 ch; + int i = 0; + char *dest_end = dest + sz; + + while (srcsz<0 ? src[i]!=0 : i < srcsz) { + ch = src[i]; + if (ch < 0x80) { + if (dest >= dest_end) + return i; + *dest++ = (char)ch; + } + else if (ch < 0x800) { + if (dest >= dest_end-1) + return i; + *dest++ = (ch>>6) | 0xC0; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x10000) { + if (dest >= dest_end-2) + return i; + *dest++ = (ch>>12) | 0xE0; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + else if (ch < 0x110000) { + if (dest >= dest_end-3) + return i; + *dest++ = (ch>>18) | 0xF0; + *dest++ = ((ch>>12) & 0x3F) | 0x80; + *dest++ = ((ch>>6) & 0x3F) | 0x80; + *dest++ = (ch & 0x3F) | 0x80; + } + i++; + } + if (dest < dest_end) + *dest = '\0'; + return i; +} + +int u8_wc_toutf8(char *dest, u32 ch) +{ + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = (ch>>6) | 0xC0; + dest[1] = (ch & 0x3F) | 0x80; + return 2; + } + if (ch < 0x10000) { + dest[0] = (ch>>12) | 0xE0; + dest[1] = ((ch>>6) & 0x3F) | 0x80; + dest[2] = (ch & 0x3F) | 0x80; + return 3; + } + if (ch < 0x110000) { + dest[0] = (ch>>18) | 0xF0; + dest[1] = ((ch>>12) & 0x3F) | 0x80; + dest[2] = ((ch>>6) & 0x3F) | 0x80; + dest[3] = (ch & 0x3F) | 0x80; + return 4; + } + return 0; +} + +/* charnum => byte offset */ +int u8_offset(const char *str, int charnum) +{ + int offs=0; + + while (charnum > 0 && str[offs]) { + (void)(isutf(str[++offs]) || isutf(str[++offs]) || + isutf(str[++offs]) || ++offs); + charnum--; + } + return offs; +} + +/* byte offset => charnum */ +int u8_charnum(const char *s, int offset) +{ + int charnum = 0, offs=0; + + while (offs < offset && s[offs]) { + (void)(isutf(s[++offs]) || isutf(s[++offs]) || + isutf(s[++offs]) || ++offs); + charnum++; + } + return charnum; +} + +/* number of characters */ +int u8_strlen(const char *s) +{ + int count = 0; + int i = 0; + + while (u8_nextchar(s, &i) != 0) + count++; + + return count; +} + +/* reads the next utf-8 sequence out of a string, updating an index */ +u32 u8_nextchar(const char *s, int *i) +{ + u32 ch = 0; + int sz = 0; + + do { + ch <<= 6; + ch += (unsigned char)s[(*i)++]; + sz++; + } while (s[*i] && !isutf(s[*i])); + ch -= offsetsFromUTF8[sz-1]; + + return ch; +} + +void u8_inc(const char *s, int *i) +{ + (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || + isutf(s[++(*i)]) || ++(*i)); +} + +void u8_dec(const char *s, int *i) +{ + (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || + isutf(s[--(*i)]) || --(*i)); +} + +int octal_digit(char c) +{ + return (c >= '0' && c <= '7'); +} + +int hex_digit(char c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')); +} + +/* assumes that src points to the character after a backslash + returns number of input characters processed */ +int u8_read_escape_sequence(const char *str, u32 *dest) +{ + u32 ch; + char digs[9]="\0\0\0\0\0\0\0\0"; + int dno=0, i=1; + + ch = (u32)str[0]; /* take literal character */ + if (str[0] == 'n') + ch = L'\n'; + else if (str[0] == 't') + ch = L'\t'; + else if (str[0] == 'r') + ch = L'\r'; + else if (str[0] == 'b') + ch = L'\b'; + else if (str[0] == 'f') + ch = L'\f'; + else if (str[0] == 'v') + ch = L'\v'; + else if (str[0] == 'a') + ch = L'\a'; + else if (octal_digit(str[0])) { + i = 0; + do { + digs[dno++] = str[i++]; + } while (octal_digit(str[i]) && dno < 3); + ch = strtol(digs, NULL, 8); + } + else if (str[0] == 'x') { + while (hex_digit(str[i]) && dno < 2) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'u') { + while (hex_digit(str[i]) && dno < 4) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + else if (str[0] == 'U') { + while (hex_digit(str[i]) && dno < 8) { + digs[dno++] = str[i++]; + } + if (dno > 0) + ch = strtol(digs, NULL, 16); + } + *dest = ch; + + return i; +} + +/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 + example: u8_unescape(mybuf, 256, "hello\\u220e") + note the double backslash is needed if called on a C string literal */ +int u8_unescape(char *buf, int sz, char *src) +{ + int c=0, amt; + u32 ch; + char temp[4]; + + while (*src && c < sz) { + if (*src == '\\') { + src++; + amt = u8_read_escape_sequence(src, &ch); + } + else { + ch = (u32)*src; + amt = 1; + } + src += amt; + amt = u8_wc_toutf8(temp, ch); + if (amt > sz-c) + break; + memcpy(&buf[c], temp, amt); + c += amt; + } + if (c < sz) + buf[c] = '\0'; + return c; +} + +const char *u8_strchr(const char *s, u32 ch, int *charn) +{ + int i = 0, lasti=0; + u32 c; + + *charn = 0; + while (s[i]) { + c = u8_nextchar(s, &i); + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn) +{ + u32 i = 0, lasti=0; + u32 c; + int csz; + + *charn = 0; + while (i < sz) { + c = csz = 0; + do { + c <<= 6; + c += (unsigned char)s[i++]; + csz++; + } while (i < sz && !isutf(s[i])); + c -= offsetsFromUTF8[csz-1]; + + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return NULL; +} + +int u8_is_locale_utf8(const char *locale) +{ + /* this code based on libutf8 */ + const char* cp = locale; + + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { + if (*cp == '.') { + const char* encoding = ++cp; + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) + ; + if ((cp-encoding == 5 && !strncmp(encoding, "UTF-8", 5)) + || (cp-encoding == 4 && !strncmp(encoding, "utf8", 4))) + return 1; /* it's UTF-8 */ + break; + } + } + return 0; +} + +int UTF8StringNonASCIICount(const char *utf8string) { + UTF8 utf(utf8string); + int count = 0; + while (!utf.end()) { + int c = utf.next(); + if (c > 127) + ++count; + } + return count; +} + +bool UTF8StringHasNonASCII(const char *utf8string) { + return UTF8StringNonASCIICount(utf8string) > 0; +} + +#ifdef _WIN32 + +std::string ConvertWStringToUTF8(const wchar_t *wstr) { + int len = (int)wcslen(wstr); + int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL); + std::string s; + s.resize(size); + if (size > 0) { + WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL); + } + return s; +} + +std::string ConvertWStringToUTF8(const std::wstring &wstr) { + int len = (int)wstr.size(); + int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL); + std::string s; + s.resize(size); + if (size > 0) { + WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL); + } + return s; +} + +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) { + int len = (int)source.size(); + int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); + MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); +} + +std::wstring ConvertUTF8ToWString(const std::string &source) { + int len = (int)source.size(); + int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); + std::wstring str; + str.resize(size); + if (size > 0) { + MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, &str[0], size); + } + return str; +} + +#endif \ No newline at end of file diff --git a/src/common/utf8.h b/src/common/utf8.h new file mode 100644 index 00000000..36cf7571 --- /dev/null +++ b/src/common/utf8.h @@ -0,0 +1,67 @@ +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ + +// Further modified, and C++ stuff added, by hrydgard@gmail.com. + +#pragma once + +#include "common_types.h" +#include + +u32 u8_nextchar(const char *s, int *i); +int u8_wc_toutf8(char *dest, u32 ch); +int u8_strlen(const char *s); + +class UTF8 { +public: + static const u32 INVALID = (u32)-1; + UTF8(const char *c) : c_(c), index_(0) {} + bool end() const { return c_[index_] == 0; } + u32 next() { + return u8_nextchar(c_, &index_); + } + u32 peek() { + int tempIndex = index_; + return u8_nextchar(c_, &tempIndex); + } + int length() const { + return u8_strlen(c_); + } + int byteIndex() const { + return index_; + } + static int encode(char *dest, u32 ch) { + return u8_wc_toutf8(dest, ch); + } + +private: + const char *c_; + int index_; +}; + +int UTF8StringNonASCIICount(const char *utf8string); + +bool UTF8StringHasNonASCII(const char *utf8string); + + +// UTF8 to Win32 UTF-16 +// Should be used when calling Win32 api calls +#ifdef _WIN32 + +std::string ConvertWStringToUTF8(const std::wstring &wstr); +std::string ConvertWStringToUTF8(const wchar_t *wstr); +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source); +std::wstring ConvertUTF8ToWString(const std::string &source); + +#endif \ No newline at end of file diff --git a/src/common/version.cpp b/src/common/version.cpp new file mode 100644 index 00000000..01890dbb --- /dev/null +++ b/src/common/version.cpp @@ -0,0 +1,45 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "scm_rev.h" + +#ifdef _DEBUG + #define BUILD_TYPE_STR "Debug " +#elif defined DEBUGFAST + #define BUILD_TYPE_STR "DebugFast " +#else + #define BUILD_TYPE_STR "" +#endif + +const char *scm_rev_str = "emu " +#if !SCM_IS_MASTER + "[" SCM_BRANCH_STR "] " +#endif + +#ifdef __INTEL_COMPILER + BUILD_TYPE_STR SCM_DESC_STR "-ICC"; +#else + BUILD_TYPE_STR SCM_DESC_STR; +#endif + +#ifdef _M_X64 +#define NP_ARCH "x64" +#else +#ifdef _M_ARM +#define NP_ARCH "ARM" +#else +#define NP_ARCH "x86" +#endif +#endif + +#ifdef _WIN32 +const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH; +#elif __APPLE__ +const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH; +#else +const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH; +#endif + +const char *scm_rev_git_str = SCM_REV_STR; -- cgit v1.2.3