From 2b4d7cc38469298f165629989b2b20c37a8389da Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Mon, 18 Oct 2010 01:40:49 +0000 Subject: [PATCH] wxIsoFile branch: (needs linux testing) * Convert IsoFileFormats.cpp into a class. * Use wxFile and wxFileInputStream instead of windows/posix specific file functions. * Added new ScopedAlloc classes, which are very simple dependency-free templates for exception-safe allocations. * FastFormatString: Improved performance ad fixed an obscure bug. * Drag&Drop (UI) - Improved the friendliness and responsiveness, so that PCSX2 doesn't end up tying up an explorer window while it prompts the user or issues error messages. git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxIsoFile@3934 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/build/Utilities/Utilities.cbp | 8 +- common/build/Utilities/utilities.vcproj | 10 +- common/include/Utilities/Assertions.h | 8 +- common/include/Utilities/Dependencies.h | 13 + common/include/Utilities/Exceptions.h | 4 + common/include/Utilities/General.h | 3 + common/include/Utilities/SafeArray.h | 42 +- common/include/Utilities/SafeArray.inl | 14 + common/include/Utilities/ScopedAlloc.h | 218 ++++++ common/include/Utilities/ScopedPtr.h | 3 + common/include/Utilities/StringHelpers.h | 54 +- common/include/Utilities/pxEvents.h | 2 +- common/include/Utilities/pxStreams.h | 80 +++ common/src/Utilities/CMakeLists.txt | 4 +- common/src/Utilities/Exceptions.cpp | 52 +- common/src/Utilities/FastFormatString.cpp | 98 ++- common/src/Utilities/ThreadTools.cpp | 26 +- common/src/Utilities/pxStreams.cpp | 204 ++++++ common/src/Utilities/pxTextStream.cpp | 102 --- common/src/Utilities/wxAppWithHelpers.cpp | 8 +- pcsx2/CDVD/CDVD.h | 2 +- pcsx2/CDVD/CDVDaccess.cpp | 90 +-- pcsx2/CDVD/CDVDisoReader.cpp | 117 ++-- pcsx2/CDVD/IsoFS/IsoFS.cpp | 2 +- pcsx2/CDVD/IsoFileFormats.cpp | 733 ++++++++++++--------- pcsx2/CDVD/IsoFileFormats.h | 155 ++++- pcsx2/CDVD/IsoFileTools.cpp | 141 ---- pcsx2/CDVD/IsoFileTools.h | 44 -- pcsx2/CMakeLists.txt | 2 - pcsx2/COP0.cpp | 2 +- pcsx2/Linux/pcsx2.cbp | 2 - pcsx2/System.cpp | 6 +- pcsx2/System.h | 4 +- pcsx2/gui/AppMain.cpp | 6 +- pcsx2/gui/Dialogs/ConfirmationDialogs.cpp | 2 +- pcsx2/gui/IsoDropTarget.cpp | 181 +++-- pcsx2/gui/MainMenuClicks.cpp | 19 +- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 8 - pcsx2/windows/WinCompressNTFS.cpp | 50 -- pcsx2/x86/ix86-32/iR5900-32.cpp | 2 +- 40 files changed, 1569 insertions(+), 952 deletions(-) create mode 100644 common/include/Utilities/ScopedAlloc.h create mode 100644 common/include/Utilities/pxStreams.h create mode 100644 common/src/Utilities/pxStreams.cpp delete mode 100644 common/src/Utilities/pxTextStream.cpp delete mode 100644 pcsx2/CDVD/IsoFileTools.cpp delete mode 100644 pcsx2/CDVD/IsoFileTools.h diff --git a/common/build/Utilities/Utilities.cbp b/common/build/Utilities/Utilities.cbp index 4ee3d0b232..585bc4c499 100644 --- a/common/build/Utilities/Utilities.cbp +++ b/common/build/Utilities/Utilities.cbp @@ -160,7 +160,8 @@ - + + @@ -172,7 +173,8 @@ - + + @@ -201,7 +203,7 @@ - + diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index 993fef8fac..6d7bf5ee1f 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -276,7 +276,7 @@ > + + @@ -453,6 +457,10 @@ RelativePath="..\..\include\Utilities\SafeArray.inl" > + + diff --git a/common/include/Utilities/Assertions.h b/common/include/Utilities/Assertions.h index b70bf2bcb1..d08fc8510c 100644 --- a/common/include/Utilities/Assertions.h +++ b/common/include/Utilities/Assertions.h @@ -157,16 +157,16 @@ extern pxDoAssertFnType* pxDoAssert; // IndexBoundsCheckDev. #define IndexBoundsCheck( objname, idx, sze ) pxAssertMsg( (uint)(idx) < (uint)(sze), \ - wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) + pxsFmt( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) #define IndexBoundsCheckDev( objname, idx, sze ) pxAssertDev( (uint)(idx) < (uint)(sze), \ - wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) + pxsFmt( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) #define IndexBoundsAssume( objname, idx, sze ) pxAssumeMsg( (uint)(idx) < (uint)(sze), \ - wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) + pxsFmt( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) #define IndexBoundsAssumeDev( objname, idx, sze ) pxAssumeDev( (uint)(idx) < (uint)(sze), \ - wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) + pxsFmt( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) ) extern void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg=NULL ); diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 82345dc354..68f0be1b70 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -23,7 +23,13 @@ // -------------------------------------------------------------------------------------- class wxOutputStream; +class wxFileOutputStream; +class wxFFileOutputStream; + class wxInputStream; +class wxFileInputStream; +class wxFFileInputStream; + class wxPoint; class wxRect; class wxSize; @@ -38,6 +44,11 @@ namespace Threading class pxThread; } +namespace Exception +{ + class BaseException; +} + // This should prove useful.... #define wxsFormat wxString::Format @@ -219,4 +230,6 @@ extern bool pxIsEnglish( int id ); #define pxE(key, english) pxExpandMsg( wxT(key), english ) +#include "Utilities/ScopedPtr.h" +#include "Utilities/ScopedMalloc.h" #include "Utilities/Assertions.h" diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index 6d103504c1..c58b15a4fa 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -43,6 +43,7 @@ namespace Exception { int MakeNewType(); + BaseException* FromErrno( const wxString& streamname, errno_t errcode ); // -------------------------------------------------------------------------------------- // BaseException @@ -92,6 +93,8 @@ namespace Exception virtual BaseException* Clone() const=0; }; + typedef ScopedPtr ScopedExcept; + // -------------------------------------------------------------------------------------- // Ps2Generic Exception // -------------------------------------------------------------------------------------- @@ -337,3 +340,4 @@ public: \ } using Exception::BaseException; +using Exception::ScopedExcept; diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index 7b78ec9382..cd997fc7fd 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -167,6 +167,9 @@ namespace HostSys } } +// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it. +#define SafeSysMunmap( ptr, size ) \ + ((void) ( HostSys::Munmap( (uptr)(ptr), size ), (ptr) = NULL )) extern void InitCPUTicks(); extern u64 GetTickFrequency(); diff --git a/common/include/Utilities/SafeArray.h b/common/include/Utilities/SafeArray.h index 2c90d955b8..6e6d940b97 100644 --- a/common/include/Utilities/SafeArray.h +++ b/common/include/Utilities/SafeArray.h @@ -15,34 +15,12 @@ #pragma once +// pxUSE_SECURE_MALLOC - enables bounds checking on scoped malloc allocations. -////////////////////////////////////////////////////////////////////////////////////////// -// Safe deallocation macros -- checks pointer validity (non-null) when needed, and sets -// pointer to null after deallocation. +#ifndef pxUSE_SECURE_MALLOC +#define pxUSE_SECURE_MALLOC 0 +#endif -#define safe_delete( ptr ) \ - ((void) (delete (ptr)), (ptr) = NULL) - -#define safe_delete_array( ptr ) \ - ((void) (delete[] (ptr)), (ptr) = NULL) - -// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on -// just about every compiler and libc implementation of any recentness. -#define safe_free( ptr ) \ - ( (void) (free( ptr ), !!0), (ptr) = NULL ) - //((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL)) - -#define safe_fclose( ptr ) \ - ((void) (( ( (ptr) != NULL ) && (fclose( ptr ), !!0) ), (ptr) = NULL)) - -// Implementation note: all known implementations of _aligned_free check the pointer for -// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to -// do it here. -#define safe_aligned_free( ptr ) \ - ((void) ( _aligned_free( ptr ), (ptr) = NULL )) - -#define SafeSysMunmap( ptr, size ) \ - ((void) ( HostSys::Munmap( (uptr)(ptr), size ), (ptr) = NULL )) // Microsoft Windows only macro, useful for freeing out COM objects: #define safe_release( ptr ) \ @@ -76,11 +54,7 @@ protected: // A safe array index fetcher. Asserts if the index is out of bounds (dev and debug // builds only -- no bounds checking is done in release builds). - T* _getPtr( uint i ) const - { - IndexBoundsAssumeDev( Name.c_str(), i, m_size ); - return &m_ptr[i]; - } + T* _getPtr( uint i ) const; public: virtual ~SafeArray() throw(); @@ -154,11 +128,7 @@ protected: virtual T* _virtual_realloc( int newsize ); void _MakeRoomFor_threshold( int newsize ); - T* _getPtr( uint i ) const - { - IndexBoundsAssumeDev( Name.c_str(), i, m_length ); - return &m_ptr[i]; - } + T* _getPtr( uint i ) const; public: virtual ~SafeList() throw(); diff --git a/common/include/Utilities/SafeArray.inl b/common/include/Utilities/SafeArray.inl index d0ea200d06..259651176f 100644 --- a/common/include/Utilities/SafeArray.inl +++ b/common/include/Utilities/SafeArray.inl @@ -90,6 +90,13 @@ void SafeArray::Dispose() safe_free( m_ptr ); } +template< typename T > +T* SafeArray::_getPtr( uint i ) const +{ + IndexBoundsAssumeDev( Name.c_str(), i, m_size ); + return &m_ptr[i]; +} + // reallocates the array to the explicit size. Can be used to shrink or grow an // array, and bypasses the internal threshold growth indicators. template< typename T > @@ -203,6 +210,13 @@ SafeList::SafeList( int initialSize, const wxChar* name ) } +template< typename T > +T* SafeList::_getPtr( uint i ) const +{ + IndexBoundsAssumeDev( Name.c_str(), i, m_length ); + return &m_ptr[i]; +} + // Ensures that the allocation is large enough to fit data of the // amount requested. The memory allocation is not resized smaller. template< typename T > diff --git a/common/include/Utilities/ScopedAlloc.h b/common/include/Utilities/ScopedAlloc.h new file mode 100644 index 0000000000..a5817953f7 --- /dev/null +++ b/common/include/Utilities/ScopedAlloc.h @@ -0,0 +1,218 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +// pxUSE_SECURE_MALLOC - enables bounds checking on scoped malloc allocations. + +#ifndef pxUSE_SECURE_MALLOC +#define pxUSE_SECURE_MALLOC 0 +#endif + +////////////////////////////////////////////////////////////////////////////////////////// +// Safe deallocation macros -- checks pointer validity (non-null) when needed, and sets +// pointer to null after deallocation. + +#define safe_delete( ptr ) \ + ((void) (delete (ptr)), (ptr) = NULL) + +#define safe_delete_array( ptr ) \ + ((void) (delete[] (ptr)), (ptr) = NULL) + +// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on +// just about every compiler and libc implementation of any recentness. +#define safe_free( ptr ) \ + ( (void) (free( ptr ), !!0), (ptr) = NULL ) +//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL)) + +#define safe_fclose( ptr ) \ + ((void) (( ( (ptr) != NULL ) && (fclose( ptr ), !!0) ), (ptr) = NULL)) + +// Implementation note: all known implementations of _aligned_free check the pointer for +// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to +// do it here. +#define safe_aligned_free( ptr ) \ + ((void) ( _aligned_free( ptr ), (ptr) = NULL )) + +// -------------------------------------------------------------------------------------- +// BaseScopedAlloc +// -------------------------------------------------------------------------------------- +// Base class that allows various ScopedMalloc types to be passed to functions that act +// on them. +// +// Rationale: This class and the derived varieties are provided as a simple autonomous self- +// destructing container for malloc. The entire class is almost completely dependency free, +// and thus can be included everywhere and anywhere without dependency hassles. +// +template< typename T > +class BaseScopedAlloc +{ +protected: + T* m_buffer; + uint m_size; + +public: + BaseScopedAlloc() + { + m_buffer = NULL; + m_size = 0; + } + + virtual ~BaseScopedAlloc() throw() + { + //pxAssume(m_buffer==NULL); + } + +public: + size_t GetSize() const { return m_size; } + size_t GetLength() const { return m_size; } + + // Allocates the object to the specified size. If an existing allocation is in + // place, it is freed and replaced with the new allocation, and all data is lost. + // Parameter: + // newSize - size of the new allocation, in elements (not bytes!). If the specified + // size is 0, the the allocation is freed, same as calling Free(). + virtual void Alloc( size_t newsize )=0; + + // Re-sizes the allocation to the requested size, without any data loss. + // Parameter: + // newSize - size of the new allocation, in elements (not bytes!). If the specified + // size is 0, the the allocation is freed, same as calling Free(). + virtual void Resize( size_t newsize )=0; + + void Free() + { + Alloc( 0 ); + } + + // Makes enough room for the requested size. Existing data in the array is retained. + void MakeRoomFor( uint size ) + { + if (size <= m_size) return; + Resize( size ); + } + + T* GetPtr( uint idx=0 ) const + { + #if pxUSE_SECURE_MALLOC + IndexBoundsAssumeDev( "ScopedAlloc", idx, m_size ); + #endif + return &m_buffer[idx]; + } + + T& operator[]( uint idx ) + { + #if pxUSE_SECURE_MALLOC + IndexBoundsAssumeDev( "ScopedAlloc", idx, m_size ); + #endif + return m_buffer[idx]; + } + + const T& operator[]( uint idx ) const + { + #if pxUSE_SECURE_MALLOC + IndexBoundsAssumeDev( "ScopedAlloc", idx, m_size ); + #endif + return m_buffer[idx]; + } +}; + +// -------------------------------------------------------------------------------------- +// ScopedAlloc +// -------------------------------------------------------------------------------------- +// A simple container class for a standard malloc allocation. By default, no bounds checking +// is performed, and there is no option for enabling bounds checking. If bounds checking and +// other features are needed, use the more robust SafeArray<> instead. +// +// See docs for BaseScopedAlloc for details and rationale. +// +template< typename T > +class ScopedAlloc : public BaseScopedAlloc +{ +public: + ScopedAlloc( size_t size=0 ) : BaseScopedAlloc() + { + Alloc(size); + } + + virtual ~ScopedAlloc() throw() + { + Alloc(0); + } + + virtual void Alloc( size_t newsize ) + { + safe_free(m_buffer); + m_size = newsize; + if (!m_size) return; + + m_buffer = (T*)malloc( m_size * sizeof(T) ); + if (!m_buffer) + throw Exception::OutOfMemory("ScopedAlloc"); + } + + virtual void Resize( size_t newsize ) + { + m_size = newsize; + m_buffer = (T*)realloc(m_buffer * sizeof(T), newsize); + + if (!m_buffer) + throw Exception::OutOfMemory("ScopedAlloc::Resize"); + } +}; + +// -------------------------------------------------------------------------------------- +// ScopedAlignedAlloc +// -------------------------------------------------------------------------------------- +// A simple container class for an aligned allocation. By default, no bounds checking is +// performed, and there is no option for enabling bounds checking. If bounds checking and +// other features are needed, use the more robust SafeArray<> instead. +// +// See docs for BaseScopedAlloc for details and rationale. +// +template< typename T, uint align > +class ScopedAlignedAlloc : public BaseScopedAlloc +{ +public: + ScopedAlignedAlloc( size_t size=0 ) : BaseScopedAlloc() + { + Alloc(size); + } + + virtual ~ScopedAlignedAlloc() throw() + { + Alloc(0); + } + + virtual void Alloc( size_t newsize ) + { + safe_aligned_free(m_buffer); + m_size = newsize; + if (!m_size) return; + + m_buffer = (T*)_aligned_malloc( m_size * sizeof(T), align ); + if (!m_buffer) + throw Exception::OutOfMemory(L"ScopedAlignedAlloc"); + } + + virtual void Resize( size_t newsize ) + { + m_size = newsize; + m_buffer = (T*)_aligned_realloc(m_buffer, newsize * sizeof(T), align); + + if (!m_buffer) + throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize"); + } +}; diff --git a/common/include/Utilities/ScopedPtr.h b/common/include/Utilities/ScopedPtr.h index f2dd48dc1e..76a0b510db 100644 --- a/common/include/Utilities/ScopedPtr.h +++ b/common/include/Utilities/ScopedPtr.h @@ -15,6 +15,8 @@ #pragma once +#include "Assertions.h" + // -------------------------------------------------------------------------------------- // ScopedPtr // -------------------------------------------------------------------------------------- @@ -170,6 +172,7 @@ public: { Delete(); m_array = ptr; + m_valid_range = 0xffffffff; } return *this; } diff --git a/common/include/Utilities/StringHelpers.h b/common/include/Utilities/StringHelpers.h index 9a1d148059..e7b565e764 100644 --- a/common/include/Utilities/StringHelpers.h +++ b/common/include/Utilities/StringHelpers.h @@ -17,6 +17,7 @@ #include "Dependencies.h" #include "SafeArray.h" +#include "ScopedMalloc.h" #include @@ -128,7 +129,6 @@ struct ParsedAssignmentString // accepts Ascii/UTF8 only. // - // -------------------------------------------------------------------------------------- // FastFormatAscii // -------------------------------------------------------------------------------------- @@ -136,8 +136,9 @@ struct ParsedAssignmentString class FastFormatAscii { protected: - SafeArray* m_dest; + ScopedAlignedAlloc* m_dest; bool m_deleteDest; + uint m_Length; public: FastFormatAscii(); @@ -147,12 +148,31 @@ public: void Clear(); bool IsEmpty() const; + uint Length() const { return m_Length; } const char* c_str() const { return m_dest->GetPtr(); } operator const char*() const { return m_dest->GetPtr(); } const wxString GetString() const; //operator wxString() const; + + FastFormatAscii& operator+=(const wxString& s) + { + Write( "%ls", s.c_str() ); + return *this; + } + + FastFormatAscii& operator+=(const wxChar* psz ) + { + Write( "%ls", psz ); + return *this; + } + + FastFormatAscii& operator+=(const char* psz ) + { + Write( "%s", psz ); + return *this; + } }; // -------------------------------------------------------------------------------------- @@ -161,8 +181,9 @@ public: class FastFormatUnicode { protected: - SafeArray* m_dest; + ScopedAlignedAlloc* m_dest; bool m_deleteDest; + uint m_Length; public: FastFormatUnicode(); @@ -175,16 +196,39 @@ public: void Clear(); bool IsEmpty() const; + uint Length() const { return m_Length; } + + FastFormatUnicode& ToUpper(); + FastFormatUnicode& ToLower(); const wxChar* c_str() const { return (const wxChar*)m_dest->GetPtr(); } operator const wxChar*() const { return (const wxChar*)m_dest->GetPtr(); } operator wxString() const { return (const wxChar*)m_dest->GetPtr(); } + + FastFormatUnicode& operator+=(const wxString& s) + { + Write( L"%s", s.c_str() ); + return *this; + } + + FastFormatUnicode& operator+=(const wxChar* psz ) + { + Write( L"%s", psz ); + return *this; + } + + FastFormatUnicode& operator+=(const char* psz ); }; extern bool pxParseAssignmentString( const wxString& src, wxString& ldest, wxString& rdest ); -#define pxsFmt FastFormatUnicode().Write -#define pxsFmtV FastFormatUnicode().WriteV +#define pxsFmt FastFormatUnicode().Write +#define pxsFmtV FastFormatUnicode().WriteV + +extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2); +extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2); +extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2); + ////////////////////////////////////////////////////////////////////////////////////////// // Custom internal sprintf functions, which are ASCII only (even in UNICODE builds) diff --git a/common/include/Utilities/pxEvents.h b/common/include/Utilities/pxEvents.h index 04dc516564..c4c1c2f9fd 100644 --- a/common/include/Utilities/pxEvents.h +++ b/common/include/Utilities/pxEvents.h @@ -35,7 +35,7 @@ class SynchronousActionState protected: bool m_posted; Threading::Semaphore m_sema; - ScopedPtr m_exception; + ScopedExcept m_exception; public: sptr return_value; diff --git a/common/include/Utilities/pxStreams.h b/common/include/Utilities/pxStreams.h new file mode 100644 index 0000000000..1eb07714d1 --- /dev/null +++ b/common/include/Utilities/pxStreams.h @@ -0,0 +1,80 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +// -------------------------------------------------------------------------------------- +// pxStreamWriter +// -------------------------------------------------------------------------------------- +class pxStreamWriter +{ + DeclareNoncopyableObject(pxStreamWriter); + +protected: + wxString m_filename; + ScopedPtr m_outstream; + +public: + pxStreamWriter(const wxString& filename, ScopedPtr& output); + pxStreamWriter(const wxString& filename, wxOutputStream* output); + + virtual ~pxStreamWriter() throw() {} + virtual void Write( const void* data, size_t size ); + + void Close() { m_outstream.Delete(); } + wxOutputStream* GetBaseStream() const { return m_outstream; } + + void SetStream( const wxString& filename, ScopedPtr& stream ); + void SetStream( const wxString& filename, wxOutputStream* stream ); + + wxString GetStreamName() const { return m_filename; } + + template< typename T > + void Write( const T& data ) + { + Write( &data, sizeof(data) ); + } +}; + +// -------------------------------------------------------------------------------------- +// pxStreamReader +// -------------------------------------------------------------------------------------- +class pxStreamReader +{ + DeclareNoncopyableObject(pxStreamReader); + +protected: + wxString m_filename; + ScopedPtr m_stream; + +public: + pxStreamReader(const wxString& filename, ScopedPtr& input); + pxStreamReader(const wxString& filename, wxInputStream* input); + + virtual ~pxStreamReader() throw() {} + virtual void Read( void* dest, size_t size ); + + void SetStream( const wxString& filename, ScopedPtr& stream ); + void SetStream( const wxString& filename, wxInputStream* stream ); + + wxInputStream* GetBaseStream() const { return m_stream; } + void Close() { m_stream.Delete(); } + + wxString GetStreamName() const { return m_filename; } + + template< typename T > + void Read( T& dest ) + { + Read( &dest, sizeof(dest) ); + } +}; diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index a219b45a56..72c51a5a53 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -113,7 +113,7 @@ set(UtilitiesSources pxCheckBox.cpp pxRadioPanel.cpp pxStaticText.cpp - pxTextStream.cpp + pxStreams.cpp pxTranslate.cpp pxWindowTextWriter.cpp Semaphore.cpp @@ -149,8 +149,10 @@ set(UtilitiesHeaders ../../include/Utilities/pxCheckBox.h ../../include/Utilities/pxRadioPanel.h ../../include/Utilities/pxStaticText.h + ../../include/Utilities/pxStreams.h ../../include/Utilities/RedtapeWindows.h ../../include/Utilities/SafeArray.h + ../../include/Utilities/ScopedAlloc.h ../../include/Utilities/ScopedPtr.h ../../include/Utilities/ScopedPtrMT.h ../../include/Utilities/StringHelpers.h diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index 11b4ee1783..e9030e35d4 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -169,8 +169,8 @@ Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxStr { IsSilent = false; - const wxString msg( wxsFormat( L"STL Runtime Error%s: %s", - (prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()), + const wxString msg( pxsFmt( L"STL Runtime Error%s: %s", + (prefix.IsEmpty() ? prefix.c_str() : pxsFmt(L" (%s)", prefix.c_str()).c_str()), fromUTF8( ex.what() ).c_str() ) ); @@ -181,8 +181,8 @@ Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& { IsSilent = false; - const wxString msg( wxsFormat( L"STL Exception%s: %s", - (prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()), + const wxString msg( pxsFmt( L"STL Exception%s: %s", + (prefix.IsEmpty() ? prefix.c_str() : pxsFmt(L" (%s)", prefix.c_str()).c_str()), fromUTF8( ex.what() ).c_str() ) ); @@ -207,7 +207,7 @@ wxString Exception::OutOfMemory::FormatDiagnosticMessage() const wxString Exception::OutOfMemory::FormatDisplayMessage() const { if (m_message_user.IsEmpty()) return FormatDisplayMessage(); - return m_message_user + wxsFormat( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str()); + return m_message_user + pxsFmt( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str()); } @@ -224,7 +224,7 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const wxString Exception::Stream::FormatDiagnosticMessage() const { - return wxsFormat( + return pxsFmt( L"%s\n\tFile/Object: %s", m_message_diag.c_str(), StreamName.c_str() ); @@ -234,8 +234,46 @@ wxString Exception::Stream::FormatDisplayMessage() const { wxString retval( m_message_user ); if (!StreamName.IsEmpty()) - retval += L"\n\n" + wxsFormat( _("Path: %s"), StreamName.c_str() ); + retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() ); return retval; } +// -------------------------------------------------------------------------------------- +// Exceptions from Errno (POSIX) +// -------------------------------------------------------------------------------------- + +// Translates an Errno code into an exception. +// Throws an exception based on the given error code (usually taken from ANSI C's errno) +BaseException* Exception::FromErrno( const wxString& streamname, errno_t errcode ) +{ + pxAssumeDev( errcode != 0, "Invalid NULL error code? (errno)" ); + + switch( errcode ) + { + case EINVAL: + pxFailDev( L"Invalid argument" ); + return &(new Exception::Stream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" ); + + case EACCES: // Access denied! + return new Exception::AccessDenied( streamname ); + + case EMFILE: // Too many open files! + return &(new Exception::CannotCreateStream( streamname ))->SetDiagMsg(L"Too many open files"); // File handle allocation failure + + case EEXIST: + return &(new Exception::CannotCreateStream( streamname ))->SetDiagMsg(L"File already exists"); + + case ENOENT: // File not found! + return new Exception::FileNotFound( streamname ); + + case EPIPE: + return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Broken pipe"); + + case EBADF: + return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number"); + + default: + return &(new Exception::Stream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode )); + } +} diff --git a/common/src/Utilities/FastFormatString.cpp b/common/src/Utilities/FastFormatString.cpp index 24085fbc44..175a8ae27c 100644 --- a/common/src/Utilities/FastFormatString.cpp +++ b/common/src/Utilities/FastFormatString.cpp @@ -15,6 +15,7 @@ #include "PrecompiledHeader.h" #include "Threading.h" + #include "TlsVariable.inl" #include "SafeArray.inl" @@ -36,6 +37,8 @@ template class SafeAlignedArray; // system deadlock. static const int MaxFormattedStringLength = 0x80000; +typedef ScopedAlignedAlloc CharBufferType; + // -------------------------------------------------------------------------------------- // FastFormatBuffers // -------------------------------------------------------------------------------------- @@ -50,7 +53,7 @@ class FastFormatBuffers protected: typedef char CharType; - typedef SafeAlignedArray BufferType; + typedef CharBufferType BufferType; static const uint BufferCount = 4; @@ -66,10 +69,7 @@ public: for (uint i=0; i > m_buffer_tls(buffer_is_avail); -static __ri void format_that_ascii_mess( SafeArray& buffer, uint writepos, const char* fmt, va_list argptr ) +//static __ri void format_that_ascii_mess( SafeArray& buffer, uint writepos, const char* fmt, va_list argptr ) +static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr ) { while( true ) { @@ -173,26 +174,27 @@ static __ri void format_that_ascii_mess( SafeArray& buffer, uint writepos, len += writepos; if (len < size) break; - buffer.ExactAlloc( len + 31 ); + buffer.Alloc( len + 128 ); }; // performing an assertion or log of a truncated string is unsafe, so let's not; even // though it'd be kinda nice if we did. } -static __ri void format_that_unicode_mess( SafeArray& buffer, uint writepos, const wxChar* fmt, va_list argptr) +// returns the length of the formatted string, in characters (wxChars). +static __ri uint format_that_unicode_mess( CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr) { while( true ) { int size = buffer.GetLength() / sizeof(wxChar); - int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos*2), size-writepos, fmt, argptr); + int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos*sizeof(wxChar)), size-writepos, fmt, argptr); // some implementations of vsnprintf() don't NUL terminate // the string if there is not enough space for it so // always do it manually ((wxChar*)buffer.GetPtr())[size-1] = L'\0'; - if( size >= MaxFormattedStringLength ) break; + if( size >= MaxFormattedStringLength ) return size-1; // vsnprintf() may return either -1 (traditional Unix behavior) or the // total number of characters which would have been written if the @@ -202,15 +204,18 @@ static __ri void format_that_unicode_mess( SafeArray& buffer, uint writepo len = size + (size/4); len += writepos; - if (len < size) break; - buffer.ExactAlloc( (len + 31) * sizeof(wxChar) ); + if (len < size) return len; + buffer.Alloc( (len + 128) * sizeof(wxChar) ); }; // performing an assertion or log of a truncated string is unsafe, so let's not; even // though it'd be kinda nice if we did. + + pxAssume( false ); + return 0; // unreachable. } -SafeArray* GetFormatBuffer( bool& deleteDest ) +CharBufferType* GetFormatBuffer( bool& deleteDest ) { deleteDest = false; if (buffer_is_avail) @@ -220,7 +225,8 @@ SafeArray* GetFormatBuffer( bool& deleteDest ) } deleteDest = true; - return new SafeArray(2048, L"Temporary string formatting buffer"); + + return new CharBufferType(2048); } // -------------------------------------------------------------------------------------- @@ -248,6 +254,7 @@ FastFormatUnicode::~FastFormatUnicode() throw() void FastFormatUnicode::Clear() { + m_Length = 0; ((wxChar*)m_dest->GetPtr())[0] = 0; } @@ -255,16 +262,18 @@ FastFormatUnicode& FastFormatUnicode::WriteV( const char* fmt, va_list argptr ) { wxString converted( fromUTF8(FastFormatAscii().WriteV( fmt, argptr )) ); - uint inspos = wxStrlen((wxChar*)m_dest->GetPtr()); - m_dest->MakeRoomFor((inspos + converted.Length() + 31)*sizeof(wxChar)); - wxStrcpy( &((wxChar*)m_dest->GetPtr())[inspos], converted ); - + const uint inspos = m_Length; + const uint convLen = converted.Length(); + m_dest->MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar)); + memcpy_fast( &((wxChar*)m_dest->GetPtr())[inspos], converted, (convLen+1)*sizeof(wxChar) ); + m_Length += convLen; + return *this; } FastFormatUnicode& FastFormatUnicode::WriteV( const wxChar* fmt, va_list argptr ) { - format_that_unicode_mess( *m_dest, wxStrlen((wxChar*)m_dest->GetPtr()), fmt, argptr ); + m_Length = format_that_unicode_mess( *m_dest, m_Length, fmt, argptr ); return *this; } @@ -291,6 +300,53 @@ bool FastFormatUnicode::IsEmpty() const return ((wxChar&)(*m_dest)[0]) == 0; } +FastFormatUnicode& FastFormatUnicode::ToUpper() +{ + wxChar* ch = (wxChar*)m_dest->GetPtr(); + for ( uint i=0; iGetPtr(); + for ( uint i=0; i ptr( const_cast(this)->m_except.DetachPtr() ); + ScopedExcept ptr( const_cast(this)->m_except.DetachPtr() ); if( ptr ) ptr->Rethrow(); - - //m_except->Rethrow(); } static bool m_BlockDeletions = false; @@ -429,13 +427,13 @@ void Threading::pxThread::_selfRunningTest( const wxChar* name ) const { if( HasPendingException() ) { - pxThreadLog.Error( GetName(), wxsFormat(L"An exception was thrown while waiting on a %s.", name) ); + pxThreadLog.Error( GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name) ); RethrowException(); } if( !m_running ) { - throw Exception::CancelEvent( wxsFormat( + throw Exception::CancelEvent( pxsFmt( L"Blocking thread %s was terminated while another thread was waiting on a %s.", GetName().c_str(), name ) ); @@ -558,7 +556,7 @@ void Threading::pxThread::_try_virtual_invoke( void (pxThread::*method)() ) catch( Exception::RuntimeError& ex ) { BaseException* woot = ex.Clone(); - woot->DiagMsg() += wxsFormat( L"(thread:%s)", GetName().c_str() ); + woot->DiagMsg() += pxsFmt( L"(thread:%s)", GetName().c_str() ); m_except = woot; } #ifndef PCSX2_DEVBUILD @@ -568,13 +566,13 @@ void Threading::pxThread::_try_virtual_invoke( void (pxThread::*method)() ) // the MSVC debugger (or by silent random annoying fail on debug-less linux). /*catch( std::logic_error& ex ) { - throw BaseException( wxsFormat( L"STL Logic Error (thread:%s): %s", + throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s", GetName().c_str(), fromUTF8( ex.what() ).c_str() ) ); } catch( std::exception& ex ) { - throw BaseException( wxsFormat( L"STL exception (thread:%s): %s", + throw BaseException( pxsFmt( L"STL exception (thread:%s): %s", GetName().c_str(), fromUTF8( ex.what() ).c_str() ) ); }*/ @@ -584,7 +582,7 @@ void Threading::pxThread::_try_virtual_invoke( void (pxThread::*method)() ) catch( BaseException& ex ) { BaseException* woot = ex.Clone(); - woot->DiagMsg() += wxsFormat( L"(thread:%s)", GetName().c_str() ); + woot->DiagMsg() += pxsFmt( L"(thread:%s)", GetName().c_str() ); m_except = woot; } #endif @@ -862,12 +860,12 @@ __fi void* Threading::_AtomicCompareExchangePointer( volatile uptr& target, uptr wxString Exception::BaseThreadError::FormatDiagnosticMessage() const { - return wxsFormat( m_message_diag, (m_thread==NULL) ? L"Null Thread Object" : m_thread->GetName().c_str()); + return pxsFmt( m_message_diag, (m_thread==NULL) ? L"Null Thread Object" : m_thread->GetName().c_str()); } wxString Exception::BaseThreadError::FormatDisplayMessage() const { - return wxsFormat( m_message_user, (m_thread==NULL) ? L"Null Thread Object" : m_thread->GetName().c_str()); + return pxsFmt( m_message_user, (m_thread==NULL) ? L"Null Thread Object" : m_thread->GetName().c_str()); } pxThread& Exception::BaseThreadError::Thread() diff --git a/common/src/Utilities/pxStreams.cpp b/common/src/Utilities/pxStreams.cpp new file mode 100644 index 0000000000..9966f2360f --- /dev/null +++ b/common/src/Utilities/pxStreams.cpp @@ -0,0 +1,204 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "wxBaseTools.h" +#include "pxStreams.h" + +#include + + +// -------------------------------------------------------------------------------------- +// pxStreamReader (implementations) +// -------------------------------------------------------------------------------------- +// Interface for reading data from a gzip stream. +// + +pxStreamReader::pxStreamReader(const wxString& filename, ScopedPtr& input) + : m_filename( filename ) + , m_stream( input.DetachPtr() ) +{ +} + +pxStreamReader::pxStreamReader(const wxString& filename, wxInputStream* input) + : m_filename( filename ) + , m_stream( input ) +{ +} + +void pxStreamReader::SetStream( const wxString& filename, ScopedPtr& stream ) +{ + m_filename = filename; + m_stream = stream.DetachPtr(); +} + +void pxStreamReader::SetStream( const wxString& filename, wxInputStream* stream ) +{ + m_filename = filename; + m_stream = stream; +} + +void pxStreamReader::Read( void* dest, size_t size ) +{ + m_stream->Read(dest, size); + if (m_stream->GetLastError() == wxSTREAM_READ_ERROR) + { + int err = errno; + if (!err) + throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)"); + + ScopedExcept ex(Exception::FromErrno(m_filename, err)); + ex->SetDiagMsg( L"cannot read from file: " + ex->DiagMsg() ); + ex->Rethrow(); + } + + // IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we + // must always use the explicit check against the number of bytes read to determine + // end-of-stream conditions. + + if ((size_t)m_stream->LastRead() < size) + throw Exception::EndOfStream( m_filename ); +} + +// -------------------------------------------------------------------------------------- +// pxStreamWriter +// -------------------------------------------------------------------------------------- +pxStreamWriter::pxStreamWriter(const wxString& filename, ScopedPtr& output) + : m_filename( filename ) + , m_outstream( output.DetachPtr() ) +{ + +} + +pxStreamWriter::pxStreamWriter(const wxString& filename, wxOutputStream* output) + : m_filename( filename ) + , m_outstream( output ) +{ +} + +void pxStreamWriter::SetStream( const wxString& filename, ScopedPtr& stream ) +{ + m_filename = filename; + m_outstream = stream.DetachPtr(); +} + +void pxStreamWriter::SetStream( const wxString& filename, wxOutputStream* stream ) +{ + m_filename = filename; + m_outstream = stream; +} + + +void pxStreamWriter::Write( const void* src, size_t size ) +{ + m_outstream->Write(src, size); + if(m_outstream->GetLastError() == wxSTREAM_WRITE_ERROR) + { + int err = errno; + if (!err) + throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream."); + + ScopedExcept ex(Exception::FromErrno(m_filename, err)); + ex->SetDiagMsg( L"Cannot write to file: " + ex->DiagMsg() ); + ex->Rethrow(); + } +} + +// -------------------------------------------------------------------------------------- +// pxTextStream +// -------------------------------------------------------------------------------------- + +// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap. +bool pxReadLine( wxInputStream& input, std::string& dest ) +{ + dest.clear(); + bool isUTF8 = false; + while ( true ) + { + char c; + input.Read(&c, sizeof(c)); + if( c == 0 ) break; + if( input.Eof() ) break; + if( c == '\n' ) break; // eat on UNIX + if( c == '\r' ) + { + input.Read(&c, sizeof(c)); + if( c == 0 ) break; + if( input.Eof() ) break; + if( c == '\n' ) break; + + input.Ungetch(c); + break; + } + dest += c; + if( c & 0x80 ) isUTF8 = true; + } + + return isUTF8; +} + +void pxReadLine( wxInputStream& input, wxString& dest, std::string& intermed ) +{ + dest.clear(); + if( pxReadLine( input, intermed ) ) + dest = fromUTF8(intermed.c_str()); + else + { + // Optimized ToAscii conversion. + // wx3.0 : NOT COMPATIBLE!! (on linux anyway) + const char* ascii = intermed.c_str(); + while( *ascii != 0 ) dest += (wchar_t)(unsigned char)*ascii++; + } +} + +void pxReadLine( wxInputStream& input, wxString& dest ) +{ + std::string line; + pxReadLine( input, dest, line ); +} + +wxString pxReadLine( wxInputStream& input ) +{ + wxString result; + pxReadLine( input, result ); + return result; +} + +void pxWriteLine( wxOutputStream& output ) +{ + output.Write( "\n", 1 ); +} + +void pxWriteLine( wxOutputStream& output, const wxString& text ) +{ + if( !text.IsEmpty() ) + { + pxToUTF8 utf8(text); + output.Write(utf8, utf8.Length()); + } + pxWriteLine( output ); +} + +void pxWriteMultiline( wxOutputStream& output, const wxString& src ) +{ + if( src.IsEmpty() ) return; + + wxString result( src ); + result.Replace( L"\r\n", L"\n" ); + result.Replace( L"\r", L"\n" ); + + pxToUTF8 utf8(result); + output.Write(utf8, utf8.Length()); +} diff --git a/common/src/Utilities/pxTextStream.cpp b/common/src/Utilities/pxTextStream.cpp deleted file mode 100644 index a380e06155..0000000000 --- a/common/src/Utilities/pxTextStream.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "wxBaseTools.h" -#include - - -// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap. -bool pxReadLine( wxInputStream& input, std::string& dest ) -{ - dest.clear(); - bool isUTF8 = false; - while ( true ) - { - char c; - input.Read(&c, sizeof(c)); - if( c == 0 ) break; - if( input.Eof() ) break; - if( c == '\n' ) break; // eat on UNIX - if( c == '\r' ) - { - input.Read(&c, sizeof(c)); - if( c == 0 ) break; - if( input.Eof() ) break; - if( c == '\n' ) break; - - input.Ungetch(c); - break; - } - dest += c; - if( c & 0x80 ) isUTF8 = true; - } - - return isUTF8; -} - -void pxReadLine( wxInputStream& input, wxString& dest, std::string& intermed ) -{ - dest.clear(); - if( pxReadLine( input, intermed ) ) - dest = fromUTF8(intermed.c_str()); - else - { - // Optimized ToAscii conversion. - // wx3.0 : NOT COMPATIBLE!! (on linux anyway) - const char* ascii = intermed.c_str(); - while( *ascii != 0 ) dest += (wchar_t)(unsigned char)*ascii++; - } -} - -void pxReadLine( wxInputStream& input, wxString& dest ) -{ - std::string line; - pxReadLine( input, dest, line ); -} - -wxString pxReadLine( wxInputStream& input ) -{ - wxString result; - pxReadLine( input, result ); - return result; -} - -void pxWriteLine( wxOutputStream& output ) -{ - output.Write( "\n", 1 ); -} - -void pxWriteLine( wxOutputStream& output, const wxString& text ) -{ - if( !text.IsEmpty() ) - { - pxToUTF8 utf8(text); - output.Write(utf8, utf8.Length()); - } - pxWriteLine( output ); -} - -void pxWriteMultiline( wxOutputStream& output, const wxString& src ) -{ - if( src.IsEmpty() ) return; - - wxString result( src ); - result.Replace( L"\r\n", L"\n" ); - result.Replace( L"\r", L"\n" ); - - pxToUTF8 utf8(result); - output.Write(utf8, utf8.Length()); -} diff --git a/common/src/Utilities/wxAppWithHelpers.cpp b/common/src/Utilities/wxAppWithHelpers.cpp index aee33ccd3c..8a1b28f9ac 100644 --- a/common/src/Utilities/wxAppWithHelpers.cpp +++ b/common/src/Utilities/wxAppWithHelpers.cpp @@ -145,12 +145,12 @@ void pxActionEvent::SetException( const BaseException& ex ) void pxActionEvent::SetException( BaseException* ex ) { - const wxString& prefix( wxsFormat(L"(%s) ", GetClassInfo()->GetClassName()) ); + const wxString& prefix( pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()) ); ex->DiagMsg() = prefix + ex->DiagMsg(); if( !m_state ) { - ScopedPtr exptr( ex ); // auto-delete it after handling. + ScopedExcept exptr( ex ); // auto-delete it after handling. ex->Rethrow(); } @@ -209,7 +209,7 @@ void pxSynchronousCommandEvent::SetException( BaseException* ex ) { if( !m_sync ) { - ScopedPtr exptr( ex ); // auto-delete it after handling. + ScopedExcept exptr( ex ); // auto-delete it after handling. ex->Rethrow(); } @@ -278,7 +278,7 @@ pxExceptionEvent::pxExceptionEvent( const BaseException& ex ) void pxExceptionEvent::InvokeEvent() { - ScopedPtr deleteMe( m_except ); + ScopedExcept deleteMe( m_except ); if( deleteMe ) deleteMe->Rethrow(); } diff --git a/pcsx2/CDVD/CDVD.h b/pcsx2/CDVD/CDVD.h index 7ff20ab458..ca5ee28108 100644 --- a/pcsx2/CDVD/CDVD.h +++ b/pcsx2/CDVD/CDVD.h @@ -42,7 +42,7 @@ static __fi s32 msf_to_lba(u8 m, u8 s, u8 f) return lsn; } -static __fi void lsn_to_msf(u8 *Time, s32 lsn) +static __fi void lsn_to_msf(u8* Time, s32 lsn) { u8 m, s, f; diff --git a/pcsx2/CDVD/CDVDaccess.cpp b/pcsx2/CDVD/CDVDaccess.cpp index 5ffa4dce96..ca39f2f876 100644 --- a/pcsx2/CDVD/CDVDaccess.cpp +++ b/pcsx2/CDVD/CDVDaccess.cpp @@ -57,7 +57,7 @@ int lastLSN; // needed for block dumping // Records last read block length for block dumping //static int plsn = 0; -static isoFile *blockDumpFile = NULL; +static isoFile blockDumpFile; // Assertion check for CDVD != NULL (in devel and debug builds), because its handier than // relying on DEP exceptions -- and a little more reliable too. @@ -341,56 +341,57 @@ bool DoCDVDopen() int cdtype = DoCDVDdetectDiskType(); - if (EmuConfig.CdvdDumpBlocks && (cdtype != CDVD_TYPE_NODISC)) + if (!EmuConfig.CdvdDumpBlocks || (cdtype == CDVD_TYPE_NODISC)) { - // TODO: Add a blockdumps configurable folder, and use that instead of CWD(). + blockDumpFile.Close(); + return true; + } - // TODO: "Untitled" should use pnach/slus name resolution, slus if no patch, - // and finally an "Untitled-[ElfCRC]" if no slus. + // TODO: Add a blockdumps configurable folder, and use that instead of CWD(). - wxString somepick( Path::GetFilenameWithoutExt( m_SourceFilename[m_CurrentSourceType] ) ); - if( somepick.IsEmpty() ) - somepick = L"Untitled"; + // TODO: "Untitled" should use pnach/slus name resolution, slus if no patch, + // and finally an "Untitled-[ElfCRC]" if no slus. - wxString temp( Path::Combine( wxGetCwd(), somepick ) ); + wxString somepick( Path::GetFilenameWithoutExt( m_SourceFilename[m_CurrentSourceType] ) ); + if( somepick.IsEmpty() ) + somepick = L"Untitled"; + + wxString temp( Path::Combine( wxGetCwd(), somepick ) ); #ifdef ENABLE_TIMESTAMPS - wxDateTime curtime( wxDateTime::GetTimeNow() ); + wxDateTime curtime( wxDateTime::GetTimeNow() ); - temp += wxsFormat( L" (%04d-%02d-%02d %02d-%02d-%02d)", - curtime.GetYear(), curtime.GetMonth(), curtime.GetDay(), - curtime.GetHour(), curtime.GetMinute(), curtime.GetSecond() - ); + temp += pxsFmt( L" (%04d-%02d-%02d %02d-%02d-%02d)", + curtime.GetYear(), curtime.GetMonth(), curtime.GetDay(), + curtime.GetHour(), curtime.GetMinute(), curtime.GetSecond() + ); #endif - temp += L".dump"; + temp += L".dump"; - cdvdTD td; - CDVD->getTD(0, &td); + cdvdTD td; + CDVD->getTD(0, &td); - blockDumpFile = isoCreate(temp.ToUTF8(), ISOFLAGS_BLOCKDUMP_V3); + blockDumpFile.Create(temp, ISOFLAGS_BLOCKDUMP_V3); - if( blockDumpFile != NULL ) - { - int blockofs = 0, blocksize = CD_FRAMESIZE_RAW, blocks = td.lsn; - - // hack: Because of limitations of the current cdvd design, we can't query the blocksize - // of the underlying media. So lets make a best guess: - - switch(cdtype) - { - case CDVD_TYPE_PS2DVD: - case CDVD_TYPE_DVDV: - case CDVD_TYPE_DETCTDVDS: - case CDVD_TYPE_DETCTDVDD: - blocksize = 2048; - break; - } - isoSetFormat(blockDumpFile, blockofs, blocksize, blocks); - } - } - else + if( blockDumpFile.IsOpened() ) { - blockDumpFile = NULL; + int blockofs = 0; + uint blocksize = CD_FRAMESIZE_RAW; + uint blocks = td.lsn; + + // hack: Because of limitations of the current cdvd design, we can't query the blocksize + // of the underlying media. So lets make a best guess: + + switch(cdtype) + { + case CDVD_TYPE_PS2DVD: + case CDVD_TYPE_DVDV: + case CDVD_TYPE_DETCTDVDS: + case CDVD_TYPE_DETCTDVDD: + blocksize = 2048; + break; + } + blockDumpFile.WriteFormat(blockofs, blocksize, blocks); } return true; @@ -399,7 +400,8 @@ bool DoCDVDopen() void DoCDVDclose() { CheckNullCDVD(); - if(blockDumpFile) isoClose(blockDumpFile); + blockDumpFile.Close(); + if( CDVD->close != NULL ) CDVD->close(); @@ -411,9 +413,9 @@ s32 DoCDVDreadSector(u8* buffer, u32 lsn, int mode) CheckNullCDVD(); int ret = CDVD->readSector(buffer,lsn,mode); - if(ret == 0 && blockDumpFile != NULL ) + if (ret == 0 && blockDumpFile.IsOpened()) { - isoWriteBlock(blockDumpFile, buffer, lsn); + blockDumpFile.WriteBlock(buffer, lsn); } return ret; @@ -450,9 +452,9 @@ s32 DoCDVDgetBuffer(u8* buffer) CheckNullCDVD(); int ret = CDVD->getBuffer2(buffer); - if (ret == 0 && blockDumpFile != NULL) + if (ret == 0 && blockDumpFile.IsOpened()) { - isoWriteBlock(blockDumpFile, buffer, lastLSN); + blockDumpFile.WriteBlock(buffer, lastLSN); } return ret; diff --git a/pcsx2/CDVD/CDVDisoReader.cpp b/pcsx2/CDVD/CDVDisoReader.cpp index 1dd544e896..d9a22afcba 100644 --- a/pcsx2/CDVD/CDVDisoReader.cpp +++ b/pcsx2/CDVD/CDVDisoReader.cpp @@ -30,7 +30,7 @@ static u8 *pbuffer; static u8 cdbuffer[2352] = {0}; -static isoFile *iso = NULL; +static isoFile iso; static int psize, cdtype; @@ -38,8 +38,7 @@ static s32 layer1start = -1; void CALLBACK ISOclose() { - isoClose(iso); - iso = NULL; + iso.Close(); } s32 CALLBACK ISOopen(const char* pTitle) @@ -52,14 +51,19 @@ s32 CALLBACK ISOopen(const char* pTitle) return -1; } - iso = isoOpen(pTitle); - if (iso == NULL) + // The current plugin API doesn't expect exceptions to propagate out of the API + // calls, so we need to catch them, log them, and return -1. + + try { + iso.Open(fromUTF8(pTitle)); + } + catch( BaseException& ex ) { - Console.Error( "CDVDiso Error: Failed loading %s", pTitle ); + Console.Error( ex.FormatDiagnosticMessage() ); return -1; } - switch (iso->type) + switch (iso.GetType()) { case ISOTYPE_DVD: cdtype = CDVD_TYPE_PS2DVD; @@ -113,7 +117,7 @@ s32 CALLBACK ISOgetTD(u8 Track, cdvdTD *Buffer) { if (Track == 0) { - Buffer->lsn = iso->blocks; + Buffer->lsn = iso.GetBlockCount(); } else { @@ -129,7 +133,7 @@ s32 CALLBACK ISOgetTD(u8 Track, cdvdTD *Buffer) static bool testForPartitionInfo( const u8 (&tempbuffer)[CD_FRAMESIZE_RAW] ) { - const int off = iso->blockofs; + const int off = iso.GetBlockOffset(); // test for: CD001 return ( @@ -143,9 +147,9 @@ static bool testForPartitionInfo( const u8 (&tempbuffer)[CD_FRAMESIZE_RAW] ) static bool FindLayer1Start() { - if( (layer1start != -1) || (iso->blocks < 0x230540) ) return true; + if( (layer1start != -1) || (iso.GetBlockCount() < 0x230540) ) return true; - Console.WriteLn("CDVDiso: searching for layer1..."); + Console.WriteLn("isoFile: searching for layer1..."); int blockresult = -1; @@ -156,28 +160,28 @@ static bool FindLayer1Start() wxString layerCacheFile( Path::Combine(GetSettingsFolder().ToString(), L"LayerBreakCache.ini") ); wxFileConfig layerCacheIni( wxEmptyString, wxEmptyString, layerCacheFile, wxEmptyString, wxCONFIG_USE_RELATIVE_PATH ); - wxString cacheKey; - cacheKey.Printf( L"%X", HashTools::Hash( iso->filename, strlen( iso->filename ) ) ); + FastFormatUnicode cacheKey; + cacheKey.Write( L"%X", HashTools::Hash( (s8*)iso.GetFilename().c_str(), iso.GetFilename().Length() * sizeof(wxChar) ) ); blockresult = layerCacheIni.Read( cacheKey, -1 ); if( blockresult != -1 ) { u8 tempbuffer[CD_FRAMESIZE_RAW]; - isoReadBlock(iso, tempbuffer, blockresult); + iso.ReadBlock(tempbuffer, blockresult); if( testForPartitionInfo( tempbuffer ) ) { - Console.WriteLn( "CDVDiso: loaded second layer from settings cache, sector=0x%8.8x", blockresult ); + Console.WriteLn( "isoFile: loaded second layer from settings cache, sector=0x%08x", blockresult ); layer1start = blockresult; } else { - Console.Warning( "CDVDiso: second layer info in the settings cache appears to be obsolete or invalid." ); + Console.Warning( "isoFile: second layer info in the settings cache appears to be obsolete or invalid. Ignoring..." ); } } else { - DevCon.WriteLn( "CDVDiso: no cached info for second layer found." ); + DevCon.WriteLn( "isoFile: no cached info for second layer found." ); } if( layer1start == -1 ) @@ -197,28 +201,29 @@ static bool FindLayer1Start() // to create the window and pass progress increments back to it. - uint midsector = (iso->blocks / 2) & ~0xf; + uint midsector = (iso.GetBlockCount() / 2) & ~0xf; uint deviation = 0; while( (layer1start == -1) && (deviation < midsector-16) ) { u8 tempbuffer[CD_FRAMESIZE_RAW]; - isoReadBlock(iso, tempbuffer, midsector-deviation); + iso.ReadBlock(tempbuffer, midsector-deviation); if(testForPartitionInfo( tempbuffer )) layer1start = midsector-deviation; else { - isoReadBlock(iso, tempbuffer, midsector+deviation); + iso.ReadBlock(tempbuffer, midsector+deviation); if( testForPartitionInfo( tempbuffer ) ) layer1start = midsector+deviation; } if( layer1start != -1 ) { - if( !pxAssertDev( tempbuffer[iso->blockofs] == 0x01, "Layer1-Detect: CD001 tag found, but the partition type is invalid." ) ) + const int blockofs = iso.GetBlockOffset(); + if( !pxAssertDev( tempbuffer[blockofs] == 0x01, "Layer1-Detect: CD001 tag found, but the partition type is invalid." ) ) { - Console.Error( "CDVDiso: Invalid partition type on layer 1!? (type=0x%x)", tempbuffer[iso->blockofs] ); + Console.Error( "isoFile: Invalid partition type on layer 1!? (type=0x%x)", tempbuffer[blockofs] ); } } deviation += 16; @@ -226,12 +231,12 @@ static bool FindLayer1Start() if( layer1start == -1 ) { - Console.Warning("CDVDiso: Couldn't find second layer... ignoring"); + Console.Error("isoFile: Couldn't find layer1... iso image is probably corrupt or incomplete."); return false; } else { - Console.WriteLn("CDVDiso: second layer found at sector 0x%8.8x", layer1start); + Console.WriteLn( Color_Blue, "isoFile: second layer found at sector 0x%08x", layer1start); // Save layer information to configuration: @@ -249,7 +254,7 @@ s32 CALLBACK ISOgetDualInfo(s32* dualType, u32* _layer1start) if(layer1start<0) { *dualType = 0; - *_layer1start = iso->blocks; + *_layer1start = iso.GetBlockCount(); } else { @@ -374,44 +379,43 @@ s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode) { int _lsn = lsn; - if (_lsn < 0) lsn = iso->blocks + _lsn; - if (lsn > iso->blocks) return -1; + if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn; + if (lsn > iso.GetBlockCount()) return -1; if(mode == CDVD_MODE_2352) { - isoReadBlock(iso, tempbuffer, lsn); + iso.ReadBlock(tempbuffer, lsn); return 0; } - isoReadBlock(iso, cdbuffer, lsn); + iso.ReadBlock(cdbuffer, lsn); pbuffer = cdbuffer; switch (mode) { - case CDVD_MODE_2352: - psize = 2352; - break; - case CDVD_MODE_2340: - pbuffer += 12; - psize = 2340; - break; - case CDVD_MODE_2328: - pbuffer += 24; - psize = 2328; - break; - case CDVD_MODE_2048: - pbuffer += 24; - psize = 2048; - break; + case CDVD_MODE_2352: + // Unreachable due to shortcut above. + pxAssume(false); + break; + + case CDVD_MODE_2340: + pbuffer += 12; + psize = 2340; + break; + case CDVD_MODE_2328: + pbuffer += 24; + psize = 2328; + break; + case CDVD_MODE_2048: + pbuffer += 24; + psize = 2048; + break; + + jNO_DEFAULT } - // version 3 blockdumps have no pbuffer header, so lets reset back to the - // original pointer. :) - if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) - pbuffer = cdbuffer; - - memcpy_fast(tempbuffer,pbuffer,psize); + memcpy_fast(tempbuffer, pbuffer, psize); return 0; } @@ -420,10 +424,10 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode) { int _lsn = lsn; - if (_lsn < 0) lsn = iso->blocks + _lsn; - if (lsn > iso->blocks) return -1; + if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn; + if (lsn > iso.GetBlockCount()) return -1; - isoReadBlock(iso, cdbuffer, lsn); + iso.ReadBlock(cdbuffer, lsn); pbuffer = cdbuffer; switch (mode) @@ -445,17 +449,12 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode) break; } - // version 3 blockdumps have no pbuffer header, so lets reset back to the - // original pointer. :) - if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) - pbuffer = cdbuffer; - return 0; } s32 CALLBACK ISOgetBuffer2(u8* buffer) { - memcpy_fast(buffer,pbuffer,psize); + memcpy_fast(buffer, pbuffer, psize); return 0; } diff --git a/pcsx2/CDVD/IsoFS/IsoFS.cpp b/pcsx2/CDVD/IsoFS/IsoFS.cpp index 8abe5f6716..48c98de1c3 100644 --- a/pcsx2/CDVD/IsoFS/IsoFS.cpp +++ b/pcsx2/CDVD/IsoFS/IsoFS.cpp @@ -94,7 +94,7 @@ IsoDirectory::IsoDirectory(SectorSource& r) } if( !isValid ) - throw Exception::FileNotFound(L"IsoFS") // FIXME: Should report the name of the ISO here... + throw Exception::FileNotFound(L"IsoFileSystem") // FIXME: Should report the name of the ISO here... .SetDiagMsg(L"IsoFS could not find the root directory on the ISO image."); DevCon.WriteLn( L"(IsoFS) Filesystem is " + FStype_ToString() ); diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index 81daf56ad0..fa9c53937e 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -16,400 +16,527 @@ #include "PrecompiledHeader.h" #include "IopCommon.h" - -#include -#include -#include - #include "IsoFileFormats.h" -static bool detect(isoFile *iso) +#include + +static const uint BlockDumpHeaderSize = 16; + +bool isoFile::detect() { u8 buf[2456]; u8* pbuf; - if (!isoReadBlock(iso, buf, 16)) return false; // Not readable + ReadBlock(buf, 16); - pbuf = (( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) ? buf : (buf + 24)); + pbuf = buf + 24; if (strncmp((char*)(pbuf+1), "CD001", 5)) return false; // Not ISO 9660 compliant if (*(u16*)(pbuf+166) == 2048) - iso->type = ISOTYPE_CD; + m_type = ISOTYPE_CD; else - iso->type = ISOTYPE_DVD; + m_type = ISOTYPE_DVD; return true; // We can deal with this. } -static bool _isoReadDtable(isoFile *iso) +void isoFile::_ReadDtable() { - uint ret; + _IsoPart& headpart( m_parts[0] ); - _seekfile(iso->handle, 0, SEEK_END); - iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize + 4); - iso->dtable = (u32*)malloc(iso->dtablesize * 4); + wxFileOffset flen = headpart.handle->GetLength(); + m_dtablesize = (flen - BlockDumpHeaderSize) / (m_blocksize + 4); + m_dtable = new u32[m_dtablesize]; - for (int i = 0; i < iso->dtablesize; i++) + headpart.Seek(BlockDumpHeaderSize); + + for (int i=0; i < m_dtablesize; ++i) { - _seekfile(iso->handle, 16 + (iso->blocksize + 4) * i, SEEK_SET); - ret = _readfile(iso->handle, &iso->dtable[i], 4); - if (ret < 4) return false; + headpart.Read(m_dtable[i]); + headpart.Seek(m_blocksize, wxFromCurrent); } - - return true; } -static bool tryIsoType(isoFile *iso, u32 size, s32 offset, s32 blockofs) +bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs) { - iso->blocksize = size; - iso->offset = offset; - iso->blockofs = blockofs; + m_blocksize = _size; + m_offset = _offset; + m_blockofs = _blockofs; - return detect(iso); + return detect(); } // based on florin's CDVDbin detection code :) -// Returns true if the image is valid/known/supported, or false if not (iso->type == ISOTYPE_ILLEGAL). -bool isoDetect(isoFile *iso) +// Parameter: +// +// +// Returns true if the image is valid/known/supported, or false if not (type == ISOTYPE_ILLEGAL). +bool isoFile::Detect( bool readType ) { char buf[32]; - int len; + int len = m_filename.Length(); - iso->type = ISOTYPE_ILLEGAL; + m_type = ISOTYPE_ILLEGAL; - len = strlen(iso->filename); + _IsoPart& headpart( m_parts[0] ); - _seekfile(iso->handle, 0, SEEK_SET); - _readfile(iso->handle, buf, 4); + headpart.Seek( 0 ); + headpart.Read( buf, 4 ); if (strncmp(buf, "BDV2", 4) == 0) { - iso->flags = ISOFLAGS_BLOCKDUMP_V2; - _readfile(iso->handle, &iso->blocksize, 4); - _readfile(iso->handle, &iso->blocks, 4); - _readfile(iso->handle, &iso->blockofs, 4); - _isoReadDtable(iso); - return (detect(iso)); - } - else if (strncmp(buf, "BDV3", 4) == 0) - { - iso->flags = ISOFLAGS_BLOCKDUMP_V3; - _readfile(iso->handle, &iso->blocksize, 4); - _readfile(iso->handle, &iso->blocks, 4); - _readfile(iso->handle, &iso->blockofs, 4); - _isoReadDtable(iso); - return (detect(iso)); - } - else - { - iso->blocks = 16; + m_flags = ISOFLAGS_BLOCKDUMP_V2; + headpart.Read(m_blocksize); + headpart.Read(m_blocks); + headpart.Read(m_blockofs); + + if (readType) + { + _ReadDtable(); + return detect(); + } + return true; } - if (tryIsoType(iso, 2048, 0, 24)) return true; // ISO 2048 - if (tryIsoType(iso, 2336, 0, 16)) return true; // RAW 2336 - if (tryIsoType(iso, 2352, 0, 0)) return true; // RAW 2352 - if (tryIsoType(iso, 2448, 0, 0)) return true; // RAWQ 2448 - if (tryIsoType(iso, 2048, 150 * 2048, 24)) return true; // NERO ISO 2048 - if (tryIsoType(iso, 2352, 150 * 2048, 0)) return true; // NERO RAW 2352 - if (tryIsoType(iso, 2448, 150 * 2048, 0)) return true; // NERO RAWQ 2448 - if (tryIsoType(iso, 2048, -8, 24)) return true; // ISO 2048 - if (tryIsoType(iso, 2352, -8, 0)) return true; // RAW 2352 - if (tryIsoType(iso, 2448, -8, 0)) return true; // RAWQ 2448 + // First sanity check: no sane CD image has less than 16 sectors, since that's what + // we need simply to contain a TOC. So if the file size is not large enough to + // accommodate that, it is NOT a CD image ---> + + wxFileOffset size = headpart.handle->GetLength(); + + if (size < (2048 * 16)) return false; + + m_blocks = 16; + + if (tryIsoType(2048, 0, 24)) return true; // ISO 2048 + if (tryIsoType(2336, 0, 16)) return true; // RAW 2336 + if (tryIsoType(2352, 0, 0)) return true; // RAW 2352 + if (tryIsoType(2448, 0, 0)) return true; // RAWQ 2448 + + if (tryIsoType(2048, 150 * 2048, 24)) return true; // NERO ISO 2048 + if (tryIsoType(2352, 150 * 2048, 0)) return true; // NERO RAW 2352 + if (tryIsoType(2448, 150 * 2048, 0)) return true; // NERO RAWQ 2448 + + if (tryIsoType(2048, -8, 24)) return true; // ISO 2048 + if (tryIsoType(2352, -8, 0)) return true; // RAW 2352 + if (tryIsoType(2448, -8, 0)) return true; // RAWQ 2448 + + m_offset = 0; + m_blocksize = CD_FRAMESIZE_RAW; + m_blockofs = 0; + m_type = ISOTYPE_AUDIO; - iso->offset = 0; - iso->blocksize = CD_FRAMESIZE_RAW; - iso->blockofs = 0; - iso->type = ISOTYPE_AUDIO; return true; } -isoFile *isoOpen(const char *filename) +// Generates format header information for blockdumps. +void isoFile::WriteFormat(int _blockofs, uint _blocksize, uint _blocks) { - isoFile *iso; + m_blocksize = _blocksize; + m_blocks = _blocks; + m_blockofs = _blockofs; - iso = (isoFile*)malloc(sizeof(isoFile)); - if (iso == NULL) return NULL; + Console.WriteLn("blockoffset = %d", m_blockofs); + Console.WriteLn("blocksize = %u", m_blocksize); + Console.WriteLn("blocks = %u", m_blocks); - memzero( *iso ); - strcpy(iso->filename, filename); - - iso->handle = _openfile( iso->filename, O_RDONLY); - if (iso->handle == NULL) + if (m_flags & ISOFLAGS_BLOCKDUMP_V2) { - Console.Error("ISO loader: Cannot access %s", iso->filename); - Console.Error(">> Make sure the iso file is not mounted in any disk emulation software! <<"); - return NULL; + outWrite("BDV2", 4); + outWrite(m_blocksize); + outWrite(m_blocks); + outWrite(m_blockofs); + } +} + +void isoFile::_ReadBlockD(u8* dst, uint lsn) +{ + _IsoPart& headpart( m_parts[0] ); + +// Console.WriteLn("_isoReadBlockD %u, blocksize=%u, blockofs=%u\n", lsn, iso->blocksize, iso->blockofs); + + memset(dst, 0, m_blockofs); + for (int i = 0; i < m_dtablesize; ++i) + { + if (m_dtable[i] != lsn) continue; + + // We store the LSN (u32) along with each block inside of blockdumps, so the + // seek position ends up being based on (m_blocksize + 4) instead of just m_blocksize. + +#ifdef PCSX2_DEBUG + u32 check_lsn; + headpart.Seek( BlockDumpHeaderSize + (i * (m_blocksize + 4)) ); + m_parts[0].Read( check_lsn ); + pxAssert( check_lsn == lsn ); +#else + headpart.Seek( BlockDumpHeaderSize + (i * (m_blocksize + 4)) + 4 ); +#endif + + m_parts[0].Read( dst + m_blockofs, m_blocksize ); } - if (!isoDetect(iso)) return NULL; + Console.WriteLn("Block %u not found in dump", lsn); +} - Console.WriteLn("detected blocksize = %u", iso->blocksize); +void isoFile::_ReadBlock(u8* dst, uint lsn) +{ + pxAssumeMsg(lsn <= m_blocks, "Invalid lsn passed into isoFile::_ReadBlock."); + pxAssumeMsg(m_numparts, "Invalid isoFile object state; an iso file needs at least one part!"); - if ((strlen(iso->filename) > 3) && strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0) + uint i; + for (i = 0; i < m_numparts-1; ++i) { - int i; - - _closefile(iso->handle); - iso->flags |= ISOFLAGS_MULTI; - iso->blocks = 0; - - for (i = 0; i < 8; i++) - { - iso->filename[strlen(iso->filename) - 1] = '0' + i; - iso->multih[i].handle = _openfile(iso->filename, O_RDONLY); - - if (iso->multih[i].handle == NULL) - { - break; - } - - iso->multih[i].slsn = iso->blocks; - _seekfile(iso->multih[i].handle, 0, SEEK_END); - iso->blocks += (u32)((_tellfile(iso->multih[i].handle) - iso->offset) / (iso->blocksize)); - iso->multih[i].elsn = iso->blocks - 1; - } - - if (i == 0) - { - return NULL; - } + // lsn indexes should always go in order; use an assertion just to be sure: + pxAssume(lsn >= m_parts[i].slsn); + if (lsn <= m_parts[i].elsn) break; } - if (iso->flags == 0) + wxFileOffset ofs = (wxFileOffset)(lsn - m_parts[i].slsn) * m_blocksize + m_offset; + +// Console.WriteLn("_isoReadBlock %u, blocksize=%u, blockofs=%u\n", lsn, iso->blocksize, iso->blockofs); + + memset(dst, 0, m_blockofs); + m_parts[i].Seek(ofs); + m_parts[i].Read(dst + m_blockofs, m_blocksize); +} + +void isoFile::ReadBlock(u8* dst, uint lsn) +{ + if (lsn > m_blocks) { - _seekfile(iso->handle, 0, SEEK_END); - iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / (iso->blocksize)); + FastFormatUnicode msg; + msg.Write("isoFile error: Block index is past the end of file! (%u > %u).", lsn, m_blocks); + + pxAssertDev(false, msg); + Console.Error(msg); + + // [TODO] : Throw exception? + // Typically an error like this is bad; indicating an invalid dump or corrupted + // iso file. + + return; + } + + if (m_flags == ISOFLAGS_BLOCKDUMP_V2) + _ReadBlockD(dst, lsn); + else + _ReadBlock(dst, lsn); + + if (m_type == ISOTYPE_CD) + { + lsn_to_msf(dst + 12, lsn); + dst[15] = 2; + } +} + +void isoFile::_WriteBlock(const u8* src, uint lsn) +{ + wxFileOffset ofs = (wxFileOffset)lsn * m_blocksize + m_offset; + + m_outstream->SeekO( ofs ); + outWrite( src + m_blockofs, m_blocksize ); +} + +void isoFile::_WriteBlockD(const u8* src, uint lsn) +{ + outWrite( lsn ); + outWrite( src + m_blockofs, m_blocksize ); +} + +void isoFile::WriteBlock(const u8* src, uint lsn) +{ + if (m_flags == ISOFLAGS_BLOCKDUMP_V2) + _WriteBlockD(src, lsn); + else + _WriteBlock(src, lsn); +} + +// -------------------------------------------------------------------------------------- +// IsoFile (implementations) : Init / Open / Create +// -------------------------------------------------------------------------------------- + +isoFile::isoFile() +{ + _init(); +} + +isoFile::~isoFile() throw() +{ + Close(); +} + +void isoFile::_init() +{ + m_type = ISOTYPE_ILLEGAL; + m_flags = 0; + + m_offset = 0; + m_blockofs = 0; + m_blocksize = 0; + m_blocks = 0; + + m_dtable = 0; + m_dtablesize = 0; +} + +// Tests for a filename extension in both upper and lower case, if the filesystem happens +// to be case-sensitive. +bool pxFileExists_WithExt( const wxFileName& filename, const wxString& ext ) +{ + wxFileName part1 = filename; + part1.SetExt( ext.Lower() ); + + if (part1.FileExists()) return true; + if (!wxFileName::IsCaseSensitive()) return false; + + part1.SetExt( ext.Upper() ); + return part1.FileExists(); +} + +void pxStream_OpenCheck( const wxStreamBase& stream, const wxString& fname, const wxString& mode ) +{ + if (stream.IsOk()) return; + + ScopedExcept ex(Exception::FromErrno(fname, errno)); + ex->SetDiagMsg( pxsFmt(L"Unable to open the file for %s: %s", mode.c_str(), ex->DiagMsg().c_str()) ); + ex->Rethrow(); +} + +// multi-part ISO support is provided for FAT32 compatibility; so that large 4GB+ isos +// can be split into multiple smaller files. +// +// Returns TRUE if multiple parts for the ISO are found. Returns FALSE if only one +// part is found. +void isoFile::FindParts() +{ + wxFileName nameparts( m_filename ); + wxString curext( nameparts.GetExt() ); + wxChar prefixch = wxTolower(curext[0]); + + // Multi-part rules! + // * The first part can either be the proper extension (ISO, MDF, etc) or the numerical + // extension (I00, I01, M00, M01, etc). + // * Numerical extensions MUST begin at 00 (I00 etc), regardless of if the first part + // is proper or numerical. + + uint i = 0; + + if ((curext.Length() == 3) && (curext[1] == L'0') && (curext[2] == L'0')) + { + // First file is an OO, so skip 0 in the loop below: + i = 1; + } + + FastFormatUnicode extbuf; + + extbuf.Write( L"%c%02u", prefixch, i ); + nameparts.SetExt( extbuf ); + if (!pxFileExists_WithExt(nameparts, extbuf)) return; + + DevCon.WriteLn( Color_Blue, "isoFile: multi-part %s detected...", curext.Upper().c_str() ); + ConsoleIndentScope indent; + + for (; i < MaxSplits; ++i) + { + extbuf.Clear(); + extbuf.Write( L"%c%02u", prefixch, i ); + if (!pxFileExists_WithExt(nameparts, extbuf)) break; + + _IsoPart& thispart( m_parts[m_numparts] ); + + thispart.handle = new wxFileInputStream( nameparts.GetFullPath() ); + pxStream_OpenCheck( *thispart.handle, nameparts.GetFullPath(), L"reading" ); + + m_blocks += thispart.CalculateBlocks( m_blocks, m_blocksize ); + + DevCon.WriteLn( Color_Blue, L"\tblocks %u - %u in: %s", + thispart.slsn, thispart.elsn, + nameparts.GetFullPath().c_str() + ); + ++m_numparts; + } + + //Console.WriteLn( Color_Blue, "isoFile: multi-part ISO loaded (%u parts found)", m_numparts ); +} + +// Tests the specified filename to see if it is a supported ISO type. This function typically +// executes faster than isoFile::Open since it does not do the following: +// * check for multi-part ISOs. I tests for header info in the main/root ISO only. +// * load blockdump indexes. +// +// Note that this is a member method, and that it will clobber any existing ISO state. +// (assertions are generated in debug mode if the object state is not already closed). +bool isoFile::Test( const wxString& srcfile ) +{ + pxAssertMsg( !m_parts[0].handle, "Warning! isoFile::Test is about to clobber whatever existing iso bound to this isoFile object!" ); + + Close(); + m_filename = srcfile; + + m_parts[0].handle = new wxFileInputStream( m_filename ); + pxStream_OpenCheck( *m_parts[0].handle, m_filename, L"reading" ); + + m_numparts = 1; + m_parts[0].slsn = 0; + + // elsn is unknown at this time, but is also unused when m_numparts == 1. + // (and if numparts is incremented, elsn will get assigned accordingly) + + return Detect( false ); +} + +void isoFile::Open( const wxString& srcfile ) +{ + Close(); + m_filename = srcfile; + + m_parts[0].handle = new wxFileInputStream( m_filename ); + pxStream_OpenCheck( *m_parts[0].handle, m_filename, L"reading" ); + + m_numparts = 1; + m_parts[0].slsn = 0; + + // elsn is unknown at this time, but is also unused when m_numparts == 1. + // (and if numparts is incremented, elsn will get assigned accordingly) + + if (!Detect()) + throw Exception::BadStream().SetUserMsg(wxLt("Unrecognized ISO file format.")); + + m_blocks = m_parts[0].CalculateBlocks( 0, m_blocksize ); + + FindParts(); + if (m_numparts > 1) + { + Console.WriteLn( Color_Blue, "isoFile: multi-part ISO detected. %u parts found." ); } const char* isotypename = NULL; - switch(iso->type) + switch(m_type) { case ISOTYPE_CD: isotypename = "CD"; break; case ISOTYPE_DVD: isotypename = "DVD"; break; case ISOTYPE_AUDIO: isotypename = "Audio CD"; break; - case ISOTYPE_DVDDL: isotypename = "DVDDL"; break; + + case ISOTYPE_DVDDL: + isotypename = "DVD9 (dual-layer)"; + break; case ISOTYPE_ILLEGAL: default: isotypename = "illegal media"; break; } - Console.WriteLn("isoOpen(%s): %s ok.", isotypename, iso->filename); - Console.WriteLn("The iso has %u blocks (size %u).", iso->blocks, iso->blocksize); - Console.WriteLn("The iso offset is %d, and the block offset is %d.", iso->offset, iso->blockofs); - return iso; + Console.WriteLn(Color_StrongBlue, L"isoFile open ok: %s", m_filename.c_str()); + + ConsoleIndentScope indent; + Console.WriteLn("Image type = %s", isotypename); + Console.WriteLn("Fileparts = %u", m_numparts); + DevCon.WriteLn ("blocks = %u", m_blocks); + DevCon.WriteLn ("offset = %d", m_offset); + DevCon.WriteLn ("blocksize = %u", m_blocksize); + DevCon.WriteLn ("blockoffset = %d", m_blockofs); } -isoFile *isoCreate(const char *filename, int flags) +void isoFile::Create(const wxString& filename, int flags) { - char Zfile[256]; + Close(); + m_filename = filename; - isoFile* iso = (isoFile*)malloc(sizeof(isoFile)); - if (iso == NULL) return NULL; + m_flags = flags; + m_offset = 0; + m_blockofs = 24; + m_blocksize = 2048; - memzero(*iso); - strcpy(iso->filename, filename); + m_outstream = new wxFileOutputStream( m_filename ); + pxStream_OpenCheck( *m_outstream, m_filename, L"writing" ); - iso->flags = flags; - iso->offset = 0; - iso->blockofs = 24; - iso->blocksize = 2048; + Console.WriteLn("isoFile create ok: %s ", m_filename.c_str()); +} - if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2)) +void isoFile::Close() +{ + for (uint i=0; iIsOk(); +} + +void isoFile::outWrite( const void* src, size_t size ) +{ + m_outstream->Write(src, size); + if(m_outstream->GetLastError() == wxSTREAM_WRITE_ERROR) { - sprintf(Zfile, "%s.table", iso->filename); - iso->htable = _openfile(Zfile, O_WRONLY); + int err = errno; + if (!err) + throw Exception::BadStream(m_filename).SetDiagMsg(pxsFmt(L"An error occurred while writing %u bytes to file", size)); - if (iso->htable == NULL) return NULL; + ScopedExcept ex(Exception::FromErrno(m_filename, err)); + ex->SetDiagMsg( pxsFmt(L"An error occurred while writing %u bytes to file: %s", size, ex->DiagMsg().c_str()) ); + ex->Rethrow(); + } +} + +// -------------------------------------------------------------------------------------- +// _IsoPart +// -------------------------------------------------------------------------------------- + +_IsoPart::~_IsoPart() throw() +{ +} + +void _IsoPart::Read( void* dest, size_t size ) +{ + handle->Read(dest, size); + if (handle->GetLastError() == wxSTREAM_READ_ERROR) + { + int err = errno; + if (!err) + throw Exception::BadStream(filename).SetDiagMsg(L"Cannot read from file (bad file handle?)"); + + ScopedExcept ex(Exception::FromErrno(filename, err)); + ex->SetDiagMsg( L"cannot read from file: " + ex->DiagMsg() ); + ex->Rethrow(); } - iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT); + // IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we + // must always use the explicit check against the number of bytes read to determine + // end-of-stream conditions. - if (iso->handle == NULL) - { - Console.Error("Error loading %s", iso->filename); - return NULL; - } - - Console.WriteLn("isoCreate: %s ok", iso->filename); - Console.WriteLn("offset = %d", iso->offset); - - return iso; + if ((size_t)handle->LastRead() < size) + throw Exception::EndOfStream( filename ); } -bool isoSetFormat(isoFile *iso, int blockofs, uint blocksize, uint blocks) +void _IsoPart::Seek(wxFileOffset pos, wxSeekMode mode) { - iso->blocksize = blocksize; - iso->blocks = blocks; - iso->blockofs = blockofs; - - Console.WriteLn("blockofs = %d", iso->blockofs); - Console.WriteLn("blocksize = %u", iso->blocksize); - Console.WriteLn("blocks = %u", iso->blocks); - - if (iso->flags & ISOFLAGS_BLOCKDUMP_V2) - { - if (_writefile(iso->handle, "BDV2", 4) < 4) return false; - if (_writefile(iso->handle, &blocksize, 4) < 4) return false; - if (_writefile(iso->handle, &blocks, 4) < 4) return false; - if (_writefile(iso->handle, &blockofs, 4) < 4) return false; - } - else if (iso->flags & ISOFLAGS_BLOCKDUMP_V3) - { - if (_writefile(iso->handle, "BDV3", 4) < 4) return false; - if (_writefile(iso->handle, &blocksize, 4) < 4) return false; - if (_writefile(iso->handle, &blocks, 4) < 4) return false; - } - - return true; + handle->SeekI(pos, mode); } -bool _isoReadBlock(isoFile *iso, u8 *dst, int lsn) +void _IsoPart::SeekEnd(wxFileOffset pos) { - u64 ofs = (u64)lsn * iso->blocksize + iso->offset; - - memset(dst, 0, iso->blockofs); - _seekfile(iso->handle, ofs, SEEK_SET); - - uint ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); - - if (ret < iso->blocksize) - { - Console.Error("read error in _isoReadBlock." ); - return false; - } - - return true; + handle->SeekI(pos, wxFromEnd); } -bool _isoReadBlockD(isoFile *iso, u8 *dst, uint lsn) +wxFileOffset _IsoPart::Tell() const { - uint ret; - -// Console.WriteLn("_isoReadBlockD %u, blocksize=%u, blockofs=%u\n", lsn, iso->blocksize, iso->blockofs); - - memset(dst, 0, iso->blockofs); - for (int i = 0; i < iso->dtablesize; i++) - { - if (iso->dtable[i] != lsn) continue; - - _seekfile(iso->handle, 16 + i * (iso->blocksize + 4) + 4, SEEK_SET); - ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); - - if (ret < iso->blocksize) return false; - - return true; - } - Console.WriteLn("Block %u not found in dump", lsn); - - return false; + return handle->TellI(); } -bool _isoReadBlockM(isoFile *iso, u8 *dst, uint lsn) +// returns the number of blocks contained in this part of the iso image. +uint _IsoPart::CalculateBlocks( uint startBlock, uint blocksize ) { - u64 ofs; - uint ret, i; + wxFileOffset partsize = handle->GetLength(); - for (i = 0; i < 8; i++) - { - if ((lsn >= iso->multih[i].slsn) && (lsn <= iso->multih[i].elsn)) - { - break; - } - } - - if (i == 8) return false; - - ofs = (u64)(lsn - iso->multih[i].slsn) * iso->blocksize + iso->offset; - -// Console.WriteLn("_isoReadBlock %u, blocksize=%u, blockofs=%u\n", lsn, iso->blocksize, iso->blockofs); - - memset(dst, 0, iso->blockofs); - _seekfile(iso->multih[i].handle, ofs, SEEK_SET); - ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); - - if (ret < iso->blocksize) - { - Console.Error("read error in _isoReadBlockM"); - return false; - } - - return true; + slsn = startBlock; + uint numBlocks = partsize / blocksize; + elsn = startBlock + numBlocks - 1; + return numBlocks; } - -bool isoReadBlock(isoFile *iso, u8 *dst, uint lsn) -{ - bool ret; - - if (lsn > iso->blocks) - { - Console.WriteLn("isoReadBlock: %u > %u", lsn, iso->blocks); - return false; - } - - if (iso->flags & ISOFLAGS_BLOCKDUMP_V2) - ret = _isoReadBlockD(iso, dst, lsn); - else if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) - ret = _isoReadBlockD(iso, dst, lsn); - else if (iso->flags & ISOFLAGS_MULTI) - ret = _isoReadBlockM(iso, dst, lsn); - else - ret = _isoReadBlock(iso, dst, lsn); - - if (!ret) return false; - - if (iso->type == ISOTYPE_CD) - { - lsn_to_msf(dst + 12, lsn); - dst[15] = 2; - } - - return true; -} - - -bool _isoWriteBlock(isoFile *iso, u8 *src, uint lsn) -{ - uint ret; - u64 ofs = (u64)lsn * iso->blocksize + iso->offset; - - _seekfile(iso->handle, ofs, SEEK_SET); - ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); - if (ret < iso->blocksize) return false; - - return true; -} - -bool _isoWriteBlockD(isoFile *iso, u8 *src, uint lsn) -{ - uint ret; - - ret = _writefile(iso->handle, &lsn, 4); - if (ret < 4) return false; - ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); - - if (ret < iso->blocksize) return false; - - return true; -} - -bool isoWriteBlock(isoFile *iso, u8 *src, uint lsn) -{ - if (iso->flags & ISOFLAGS_BLOCKDUMP_V3) - return _isoWriteBlockD(iso, src, lsn); - else - return _isoWriteBlock(iso, src, lsn); -} - -void isoClose(isoFile *iso) -{ - if (iso == NULL ) return; - if (iso->handle) _closefile(iso->handle); - if (iso->htable) _closefile(iso->htable); - safe_free( iso->buffer ); - safe_free( iso->dtable ); - safe_free( iso ); -} - diff --git a/pcsx2/CDVD/IsoFileFormats.h b/pcsx2/CDVD/IsoFileFormats.h index e0a5b134d9..9263d30a26 100644 --- a/pcsx2/CDVD/IsoFileFormats.h +++ b/pcsx2/CDVD/IsoFileFormats.h @@ -13,11 +13,11 @@ * If not, see . */ -#ifndef __LIBISO_H__ -#define __LIBISO_H__ +#pragma once #include "CDVD.h" -#include "IsoFileTools.h" +#include "wx/wfstream.h" + enum isoType { @@ -30,49 +30,134 @@ enum isoType enum isoFlags { - ISOFLAGS_Z = 0x0001, - ISOFLAGS_Z2 = 0x0002, ISOFLAGS_BLOCKDUMP_V2 = 0x0004, - ISOFLAGS_MULTI = 0x0008, - ISOFLAGS_BZ2 = 0x0010, ISOFLAGS_BLOCKDUMP_V3 = 0x0020 }; static const int CD_FRAMESIZE_RAW = 2448; -struct _multih +// -------------------------------------------------------------------------------------- +// MultiPartIso +// -------------------------------------------------------------------------------------- +// An encapsulating class for array boundschecking and easy ScopedPointer behavior. +// +class _IsoPart { - u32 slsn; - u32 elsn; - void *handle; + DeclareNoncopyableObject( _IsoPart ); + +public: + // starting block index of this part of the iso. + u32 slsn; + // ending bock index of this part of the iso. + u32 elsn; + + wxString filename; + ScopedPtr handle; + +public: + _IsoPart() {} + ~_IsoPart() throw(); + + void Read( void* dest, size_t size ); + + void Seek(wxFileOffset pos, wxSeekMode mode = wxFromStart); + void SeekEnd(wxFileOffset pos=0); + wxFileOffset Tell() const; + uint CalculateBlocks( uint startBlock, uint blocksize ); + + template< typename T > + void Read( T& dest ) + { + Read( &dest, sizeof(dest) ); + } }; -struct isoFile +// -------------------------------------------------------------------------------------- +// isoFile +// -------------------------------------------------------------------------------------- +class isoFile { - char filename[256]; - isoType type; - u32 flags; - s32 offset; - s32 blockofs; - u32 blocksize; - u32 blocks; - void *handle; - void *htable; - char *Ztable; - u32 *dtable; - int dtablesize; - _multih multih[8]; - int buflsn; - u8 *buffer; + DeclareNoncopyableObject( isoFile ); + +protected: + static const uint MaxSplits = 8; + +protected: + wxString m_filename; + uint m_numparts; + _IsoPart m_parts[MaxSplits]; + + isoType m_type; + u32 m_flags; + + s32 m_offset; + s32 m_blockofs; + u32 m_blocksize; + + // total number of blocks in the ISO image (including all parts) + u32 m_blocks; + + // dtable / dtablesize are used when reading blockdumps + ScopedArray m_dtable; + int m_dtablesize; + + ScopedPtr m_outstream; + + // Currently unused internal buffer (it was used for compressed + // iso support, before it was removed). + //ScopedArray m_buffer; + //int m_buflsn; + +public: + isoFile(); + virtual ~isoFile() throw(); + + bool IsOpened() const; + + isoType GetType() const { return m_type; } + + // Returns the number of blocks in the ISO image. + uint GetBlockCount() const { return m_blocks; } + + int GetBlockOffset() const { return m_blockofs; } + + const wxString& GetFilename() const + { + return m_filename; + } + + bool Test( const wxString& srcfile ); + void Open( const wxString& srcfile ); + void Create(const wxString& filename, int mode); + void Close(); + bool Detect( bool readType=true ); + + void WriteFormat(int blockofs, uint blocksize, uint blocks); + + void ReadBlock(u8* dst, uint lsn); + void WriteBlock(const u8* src, uint lsn); + +protected: + bool detect(); + void _init(); + void _ReadDtable(); + void _ReadBlock(u8* dst, uint lsn); + void _ReadBlockD(u8* dst, uint lsn); + + void _WriteBlock(const u8* src, uint lsn); + void _WriteBlockD(const u8* src, uint lsn); + + bool tryIsoType(u32 _size, s32 _offset, s32 _blockofs); + void FindParts(); + + void outWrite( const void* src, size_t size ); + + template< typename T > + void outWrite( const T& data ) + { + outWrite( &data, sizeof(data) ); + } }; -extern isoFile *isoOpen(const char *filename); -extern isoFile *isoCreate(const char *filename, int mode); -extern bool isoSetFormat(isoFile *iso, int blockofs, uint blocksize, uint blocks); -extern bool isoDetect(isoFile *iso); -extern bool isoReadBlock(isoFile *iso, u8 *dst, uint lsn); -extern bool isoWriteBlock(isoFile *iso, u8 *src, uint lsn); -extern void isoClose(isoFile *iso); -#endif /* __LIBISO_H__ */ diff --git a/pcsx2/CDVD/IsoFileTools.cpp b/pcsx2/CDVD/IsoFileTools.cpp deleted file mode 100644 index 3c0be3bdd8..0000000000 --- a/pcsx2/CDVD/IsoFileTools.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "IsoFileTools.h" - -#ifdef _WIN32 -# include - - -void *_openfile(const char *filename, int flags) -{ - HANDLE handle; - -// Console.WriteLn("_openfile %s, %d", filename, flags & O_RDONLY); - if (flags & O_WRONLY) - { - int _flags = CREATE_NEW; - if (flags & O_CREAT) _flags = CREATE_ALWAYS; - handle = CreateFile(fromUTF8(filename), GENERIC_WRITE, 0, NULL, _flags, 0, NULL); - } - else - { - handle = CreateFile(fromUTF8(filename), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); - } - - return (handle == INVALID_HANDLE_VALUE) ? NULL : handle; -} - -u64 _tellfile(void *handle) -{ - u64 ofs; - PLONG _ofs = (LONG*) & ofs; - _ofs[1] = 0; - _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); - return ofs; -} - -int _seekfile(void *handle, u64 offset, int whence) -{ - u64 ofs = (u64)offset; - PLONG _ofs = (LONG*) & ofs; - -// Console.WriteLn("_seekfile %p, %d_%d", handle, _ofs[1], _ofs[0]); - - SetFilePointer(handle, _ofs[0], &_ofs[1], (whence == SEEK_SET) ? FILE_BEGIN : FILE_END); - - return 0; -} - -u32 _readfile(void *handle, void *dst, int size) -{ - DWORD ret; - - ReadFile(handle, dst, size, &ret, NULL); -// Console.WriteLn("_readfile(%p, %d) = %d; %d", handle, size, ret, GetLastError()); - return ret; -} - -u32 _writefile(void *handle, const void *src, int size) -{ - DWORD ret; - -// _seekfile(handle, _tellfile(handle)); - WriteFile(handle, src, size, &ret, NULL); -// Console.WriteLn("_readfile(%p, %d) = %d", handle, size, ret); - return ret; -} - -void _closefile(void *handle) -{ - CloseHandle(handle); -} - -#else - -void *_openfile(const char *filename, int flags) -{ -// Console.WriteLn("_openfile %s %x", filename, flags); - - if (flags & O_WRONLY) - return fopen64(filename, "wb"); - else - return fopen64(filename, "rb"); -} - -u64 _tellfile(void *handle) -{ - FILE* fp = (FILE*)handle; - s64 cursize = ftell(fp); - - if (cursize == -1) - { - // try 64bit - cursize = ftello64(fp); - if (cursize < -1) - { - // zero top 32 bits - cursize &= 0xffffffff; - } - } - return cursize; -} - -int _seekfile(void *handle, u64 offset, int whence) -{ - int seekerr = fseeko64((FILE*)handle, offset, whence); - - if (seekerr == -1) Console.Error("Failed to seek."); - - return seekerr; -} - -u32 _readfile(void *handle, void *dst, int size) -{ - return fread(dst, 1, size, (FILE*)handle); -} - -u32 _writefile(void *handle, const void *src, int size) -{ - return fwrite(src, 1, size, (FILE*)handle); -} - -void _closefile(void *handle) -{ - fclose((FILE*)handle); -} - -#endif diff --git a/pcsx2/CDVD/IsoFileTools.h b/pcsx2/CDVD/IsoFileTools.h deleted file mode 100644 index 5c4469469c..0000000000 --- a/pcsx2/CDVD/IsoFileTools.h +++ /dev/null @@ -1,44 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE -#endif - -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif - -#ifndef __USE_FILE_OFFSET64 -#define __USE_FILE_OFFSET64 -#endif - -#define _FILE_OFFSET_BITS 64 - -#include "IopCommon.h" - -#include -#include -#include - -extern void *_openfile(const char *filename, int flags); -extern u64 _tellfile(void *handle); -extern int _seekfile(void *handle, u64 offset, int whence); -extern u32 _readfile(void *handle, void *dst, int size); -extern u32 _writefile(void *handle, const void *src, int size); -extern void _closefile(void *handle); - diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index d3f9f9d370..efa1d1cb37 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -238,7 +238,6 @@ set(pcsx2CDVDSources CDVD/CDVD.cpp CDVD/CDVDisoReader.cpp CDVD/IsoFileFormats.cpp - CDVD/IsoFileTools.cpp CDVD/IsoFS/IsoFile.cpp CDVD/IsoFS/IsoFSCDVD.cpp CDVD/IsoFS/IsoFS.cpp) @@ -251,7 +250,6 @@ set(pcsx2CDVDHeaders CDVD/CDVD_internal.h CDVD/CDVDisoReader.h CDVD/IsoFileFormats.h - CDVD/IsoFileTools.h CDVD/IsoFS/IsoDirectory.h CDVD/IsoFS/IsoFileDescriptor.h CDVD/IsoFS/IsoFile.h diff --git a/pcsx2/COP0.cpp b/pcsx2/COP0.cpp index ed8b5620e3..455a8054e6 100644 --- a/pcsx2/COP0.cpp +++ b/pcsx2/COP0.cpp @@ -37,7 +37,7 @@ __ri void cpuUpdateOperationMode() { void __fastcall WriteCP0Status(u32 value) { - DMA_LOG("COP0 Status write = 0x%08x", value); + //DMA_LOG("COP0 Status write = 0x%08x", value); cpuRegs.CP0.n.Status.val = value; cpuUpdateOperationMode(); diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index a0a92cd286..56d067c1d6 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -249,8 +249,6 @@ - - diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index faaee3531f..93779a3d99 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -163,7 +163,7 @@ class CpuInitializer { public: ScopedPtr MyCpu; - ScopedPtr ExThrown; + ScopedExcept ExThrown; CpuInitializer(); virtual ~CpuInitializer() throw(); @@ -213,6 +213,9 @@ CpuInitializer< CpuType >::~CpuInitializer() throw() MyCpu->Shutdown(); } +// -------------------------------------------------------------------------------------- +// CpuInitializerSet +// -------------------------------------------------------------------------------------- class CpuInitializerSet { public: @@ -233,7 +236,6 @@ public: }; - // returns the translated error message for the Virtual Machine failing to allocate! static wxString GetMemoryErrorVM() { diff --git a/pcsx2/System.h b/pcsx2/System.h index b8d9e17e41..1df237c4ba 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -43,8 +43,8 @@ protected: class SysCpuProviderPack { protected: - ScopedPtr m_RecExceptionEE; - ScopedPtr m_RecExceptionIOP; + ScopedExcept m_RecExceptionEE; + ScopedExcept m_RecExceptionIOP; public: ScopedPtr CpuProviders; diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 579ef3a1d1..a19e23f824 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -75,7 +75,7 @@ int AppOpenModalDialog( wxWindow* parent=NULL ) return DialogType( parent ).ShowModal(); } -static bool HandlePluginError( Exception::BaseException& ex ) +static bool HandlePluginError( BaseException& ex ) { if( !pxDialogExists( L"CoreSettings" ) ) { @@ -127,7 +127,7 @@ void PluginErrorEvent::InvokeEvent() { if( !m_except ) return; - ScopedPtr deleteMe( m_except ); + ScopedExcept deleteMe( m_except ); m_except = NULL; if( !HandlePluginError( *deleteMe ) ) @@ -141,7 +141,7 @@ void PluginInitErrorEvent::InvokeEvent() { if( !m_except ) return; - ScopedPtr deleteMe( m_except ); + ScopedExcept deleteMe( m_except ); m_except = NULL; if( !HandlePluginError( *deleteMe ) ) diff --git a/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp b/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp index 9a664d4043..fb95c87aaf 100644 --- a/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp +++ b/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp @@ -166,7 +166,7 @@ wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButton cfg->SetRecordDefaults( recdef ); cfg->SetPath( L"/" ); - result.LowerCase(); + result.MakeLower(); wxArrayString split; SplitString( split, result, L"," ); diff --git a/pcsx2/gui/IsoDropTarget.cpp b/pcsx2/gui/IsoDropTarget.cpp index 1b320da4a6..dcc740cdc3 100644 --- a/pcsx2/gui/IsoDropTarget.cpp +++ b/pcsx2/gui/IsoDropTarget.cpp @@ -31,47 +31,66 @@ wxString GetMsg_ConfirmSysReset() ); } -bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) +// -------------------------------------------------------------------------------------- +// DroppedTooManyFiles +// -------------------------------------------------------------------------------------- +class DroppedTooManyFiles : public pxActionEvent { - ScopedCoreThreadPopup stopped_core; +protected: + wxWindowID m_ownerid; - if( filenames.GetCount() > 1 ) +public: + DroppedTooManyFiles( const wxWindow* window ) + : pxActionEvent() { - wxDialogWithHelpers dialog( m_WindowBound, _("Drag and Drop Error") ); - dialog += dialog.Heading(AddAppName(_("It is an error to drop multiple files onto a %s window. One at a time please, thank you."))); - pxIssueConfirmation( dialog, MsgButtons().Cancel() ); - return false; + m_ownerid = window->GetId(); } - Console.WriteLn( L"(Drag&Drop) Received filename: " + filenames[0] ); + virtual ~DroppedTooManyFiles() throw() { } + virtual DroppedTooManyFiles *Clone() const { return new DroppedTooManyFiles(*this); } - // --------------- - // ELF CHECK - // --------------- +protected: + virtual void InvokeEvent() { - wxFileInputStream filechk( filenames[0] ); + ScopedCoreThreadPopup stopped_core; - if( !filechk.IsOk() ) - throw Exception::CannotCreateStream( filenames[0] ); + wxDialogWithHelpers dialog( wxWindow::FindWindowById(m_ownerid), _("Drag and Drop Error") ); + dialog += dialog.Heading(AddAppName(_("It is an error to drop multiple files onto a %s window. One at a time please, thank you."))); + pxIssueConfirmation( dialog, MsgButtons().Cancel() ); + } +}; - u8 ident[16]; - filechk.Read( ident, 16 ); - static const u8 elfIdent[4] = { 0x7f, 'E', 'L', 'F' }; +// -------------------------------------------------------------------------------------- +// DroppedElf +// -------------------------------------------------------------------------------------- +class DroppedElf : public pxActionEvent +{ +protected: + wxWindowID m_ownerid; - if( ((u32&)ident) == ((u32&)elfIdent) ) +public: + DroppedElf( const wxWindow* window ) + : pxActionEvent() { - Console.WriteLn( L"(Drag&Drop) Found ELF file type!" ); + m_ownerid = window->GetId(); + } - g_Conf->CurrentELF = filenames[0]; + virtual ~DroppedElf() throw() { } + virtual DroppedElf *Clone() const { return new DroppedElf(*this); } + +protected: + virtual void InvokeEvent() + { + ScopedCoreThreadPopup stopped_core; bool confirmed = true; if( SysHasValidState() ) { - wxDialogWithHelpers dialog( m_WindowBound, _("Confirm PS2 Reset") ); + wxDialogWithHelpers dialog( wxWindow::FindWindowById(m_ownerid), _("Confirm PS2 Reset") ); dialog += dialog.Heading(AddAppName(_("You have dropped the following ELF binary into %s:\n\n"))); dialog += dialog.GetCharHeight(); - dialog += dialog.Text( filenames[0] ); + dialog += dialog.Text( g_Conf->CurrentELF ); dialog += dialog.GetCharHeight(); dialog += dialog.Heading(GetMsg_ConfirmSysReset()); @@ -85,32 +104,106 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen } else stopped_core.AllowResume(); - - return true; - } } +}; - // --------------- - // ISO CHECK - // --------------- +// -------------------------------------------------------------------------------------- +// DroppedIso +// -------------------------------------------------------------------------------------- +class DroppedIso : public pxActionEvent +{ +protected: + wxWindowID m_ownerid; + wxString m_filename; - // FIXME : The whole IsoFileFormats api (meaning isoOpen / isoDetect / etc) needs to be - // converted to C++ and wxInputStream . Until then this is a nasty little exception unsafe - // hack ;) - - isoFile iso; - memzero(iso); - iso.handle = _openfile(filenames[0].ToUTF8(), O_RDONLY); - - if( iso.handle == NULL ) - throw Exception::CannotCreateStream( filenames[0] ); - - if (isoDetect(&iso)) +public: + DroppedIso( const wxWindow* window, const wxString& filename ) + : pxActionEvent() + , m_filename( filename ) { - Console.WriteLn( L"(Drag&Drop) Found valid ISO file type!" ); - SwapOrReset_Iso(m_WindowBound, stopped_core, filenames[0], AddAppName(_("You have dropped the following ISO image into %s:"))); + m_ownerid = window->GetId(); } - _closefile( iso.handle ); - return true; + virtual ~DroppedIso() throw() { } + virtual DroppedIso *Clone() const { return new DroppedIso(*this); } + +protected: + virtual void InvokeEvent() + { + ScopedCoreThreadPopup stopped_core; + SwapOrReset_Iso(wxWindow::FindWindowById(m_ownerid), stopped_core, m_filename, + AddAppName(_("You have dropped the following ISO image into %s:")) + ); + } +}; + +bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) +{ + // WARNING: Doing *anything* from the context of OnDropFiles will result in Windows + // Explorer getting tied up waiting for a response from the application's message pump. + // So whenever possible, issue messages from this function only, such that the + // messages are processed later on after the application has allowed Explorer to resume + // itself. + // + // This most likely *includes* throwing exceptions, hence all exceptions here-in being + // caught and re-packaged as messages posted back to the application, so that the drag& + // drop procedure is free to release the Windows Explorer from the tyranny of drag&drop + // interplay. + + try + { + if( filenames.GetCount() > 1 ) + { + wxGetApp().AddIdleEvent( DroppedTooManyFiles(m_WindowBound) ); + return false; + } + + Console.WriteLn( L"(Drag&Drop) Received filename: " + filenames[0] ); + + // --------------- + // ELF CHECK + // --------------- + { + wxFileInputStream filechk( filenames[0] ); + + if( !filechk.IsOk() ) + throw Exception::CannotCreateStream( filenames[0] ); + + u8 ident[16]; + filechk.Read( ident, 16 ); + static const u8 elfIdent[4] = { 0x7f, 'E', 'L', 'F' }; + + if( ((u32&)ident) == ((u32&)elfIdent) ) + { + Console.WriteLn( L"(Drag&Drop) Found ELF file type!" ); + + g_Conf->CurrentELF = filenames[0]; + + wxGetApp().PostEvent( DroppedElf(m_WindowBound) ); + return true; + } + } + + // --------------- + // ISO CHECK + // --------------- + + isoFile iso; + + if (iso.Test( filenames[0] )) + { + DevCon.WriteLn( L"(Drag&Drop) Found valid ISO file type!" ); + wxGetApp().PostEvent( DroppedIso(m_WindowBound, filenames[0]) ); + return true; + } + } + catch (BaseException& ex) + { + wxGetApp().AddIdleEvent( pxExceptionEvent(ex) ); + } + catch (std::runtime_error& ex) + { + wxGetApp().AddIdleEvent( pxExceptionEvent(Exception::RuntimeError(ex)) ); + } + return false; } diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 37890b7e4d..53458bb244 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -98,7 +98,7 @@ void MainEmuFrame::Menu_ResetAllSettings_Click(wxCommandEvent &event) { ScopedCoreThreadPopup suspender; - if( !Msgbox::OkCancel( wxsFormat( + if( !Msgbox::OkCancel( pxsFmt( pxE( ".Popup:DeleteSettings", L"This command clears %s settings and allows you to re-run the First-Time Wizard. You will need to " L"manually restart %s after this operation.\n\n" @@ -222,12 +222,13 @@ static wxString JoinFiletypes( const wxChar** src ) if( !dest.IsEmpty() ) dest += L";"; - dest += wxsFormat(L"*.%s", *src); + dest += pxsFmt(L"*.%s", *src); - #ifdef __LINUX__ - // omgosh! linux is CaSE SeNSiTiVE!! - dest += wxsFormat(L";*.%s", *src).MakeUpper(); - #endif + if (wxFileName::IsCaseSensitive()) + { + // omgosh! the filesystem is CaSE SeNSiTiVE!! + dest += pxsFmt(L";*.%s", *src).ToUpper(); + } ++src; } @@ -248,13 +249,13 @@ bool MainEmuFrame::_DoSelectIsoBrowser( wxString& result ) wxArrayString isoFilterTypes; - isoFilterTypes.Add(wxsFormat(_("All Supported (%s)"), (isoSupportedLabel + L" .dump").c_str())); + isoFilterTypes.Add(pxsFmt(_("All Supported (%s)"), (isoSupportedLabel + L" .dump").c_str())); isoFilterTypes.Add(isoSupportedList + L";*.dump"); - isoFilterTypes.Add(wxsFormat(_("Disc Images (%s)"), isoSupportedLabel.c_str() )); + isoFilterTypes.Add(pxsFmt(_("Disc Images (%s)"), isoSupportedLabel.c_str() )); isoFilterTypes.Add(isoSupportedList); - isoFilterTypes.Add(wxsFormat(_("Blockdumps (%s)"), L".dump" )); + isoFilterTypes.Add(pxsFmt(_("Blockdumps (%s)"), L".dump" )); isoFilterTypes.Add(L"*.dump"); isoFilterTypes.Add(_("All Files (*.*)")); diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 470d58976c..1affaf6adf 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1249,14 +1249,6 @@ RelativePath="..\..\CDVD\CDVDisoReader.h" > - - - - m_cpuException; - static ScopedPtr m_Exception; + static ScopedExcept m_Exception; #else # define SETJMP_CODE(x) #endif