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
This commit is contained in:
Jake.Stine 2010-10-18 01:40:49 +00:00
parent 4ee1781ce2
commit 2b4d7cc384
40 changed files with 1569 additions and 952 deletions

View File

@ -160,7 +160,8 @@
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
<Unit filename="../../include/Utilities/RwMutex.h" />
<Unit filename="../../include/Utilities/SafeArray.h" />
<Unit filename="../../include/Utilities/ScopedPtr.h" />
<Unit filename="../../include/Utilities/ScopedAlloc.h" />
<Unit filename="../../include/Utilities/ScopedPtr.h" />
<Unit filename="../../include/Utilities/ScopedPtrMT.h" />
<Unit filename="../../include/Utilities/StringHelpers.h" />
<Unit filename="../../include/Utilities/Threading.h" />
@ -172,7 +173,8 @@
<Unit filename="../../include/Utilities/pxEvents.h" />
<Unit filename="../../include/Utilities/pxRadioPanel.h" />
<Unit filename="../../include/Utilities/pxStaticText.h" />
<Unit filename="../../include/Utilities/win_memzero.h" />
<Unit filename="../../include/Utilities/pxStreams.h" />
<Unit filename="../../include/Utilities/win_memzero.h" />
<Unit filename="../../include/Utilities/wxAppWithHelpers.h" />
<Unit filename="../../include/Utilities/wxBaseTools.h" />
<Unit filename="../../include/Utilities/wxGuiTools.h" />
@ -201,7 +203,7 @@
<Unit filename="../../src/Utilities/pxCheckBox.cpp" />
<Unit filename="../../src/Utilities/pxRadioPanel.cpp" />
<Unit filename="../../src/Utilities/pxStaticText.cpp" />
<Unit filename="../../src/Utilities/pxTextStream.cpp" />
<Unit filename="../../src/Utilities/pxStreams.cpp" />
<Unit filename="../../src/Utilities/pxTranslate.cpp" />
<Unit filename="../../src/Utilities/pxWindowTextWriter.cpp" />
<Unit filename="../../src/Utilities/vssprintf.cpp" />

View File

@ -276,7 +276,7 @@
>
</File>
<File
RelativePath="..\..\src\Utilities\pxTextStream.cpp"
RelativePath="..\..\src\Utilities\pxStreams.cpp"
>
</File>
<File
@ -441,6 +441,10 @@
RelativePath="..\..\include\Utilities\pxStaticText.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\pxStreams.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\RedtapeWindows.h"
>
@ -453,6 +457,10 @@
RelativePath="..\..\include\Utilities\SafeArray.inl"
>
</File>
<File
RelativePath="..\..\include\Utilities\ScopedAlloc.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\ScopedPtr.h"
>

View File

@ -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 );

View File

@ -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"

View File

@ -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<BaseException> ScopedExcept;
// --------------------------------------------------------------------------------------
// Ps2Generic Exception
// --------------------------------------------------------------------------------------
@ -337,3 +340,4 @@ public: \
}
using Exception::BaseException;
using Exception::ScopedExcept;

View File

@ -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();

View File

@ -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();

View File

@ -90,6 +90,13 @@ void SafeArray<T>::Dispose()
safe_free( m_ptr );
}
template< typename T >
T* SafeArray<T>::_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<T>::SafeList( int initialSize, const wxChar* name )
}
template< typename T >
T* SafeList<T>::_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 >

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<T>
{
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<T>
{
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");
}
};

View File

@ -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;
}

View File

@ -17,6 +17,7 @@
#include "Dependencies.h"
#include "SafeArray.h"
#include "ScopedMalloc.h"
#include <wx/tokenzr.h>
@ -128,7 +129,6 @@ struct ParsedAssignmentString
// accepts Ascii/UTF8 only.
//
// --------------------------------------------------------------------------------------
// FastFormatAscii
// --------------------------------------------------------------------------------------
@ -136,8 +136,9 @@ struct ParsedAssignmentString
class FastFormatAscii
{
protected:
SafeArray<char>* m_dest;
ScopedAlignedAlloc<char,16>* 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<char>* m_dest;
ScopedAlignedAlloc<char,16>* 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)

View File

@ -35,7 +35,7 @@ class SynchronousActionState
protected:
bool m_posted;
Threading::Semaphore m_sema;
ScopedPtr<BaseException> m_exception;
ScopedExcept m_exception;
public:
sptr return_value;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
// --------------------------------------------------------------------------------------
// pxStreamWriter
// --------------------------------------------------------------------------------------
class pxStreamWriter
{
DeclareNoncopyableObject(pxStreamWriter);
protected:
wxString m_filename;
ScopedPtr<wxOutputStream> m_outstream;
public:
pxStreamWriter(const wxString& filename, ScopedPtr<wxOutputStream>& 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<wxOutputStream>& 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<wxInputStream> m_stream;
public:
pxStreamReader(const wxString& filename, ScopedPtr<wxInputStream>& input);
pxStreamReader(const wxString& filename, wxInputStream* input);
virtual ~pxStreamReader() throw() {}
virtual void Read( void* dest, size_t size );
void SetStream( const wxString& filename, ScopedPtr<wxInputStream>& 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) );
}
};

View File

@ -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

View File

@ -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 ));
}
}

View File

@ -15,6 +15,7 @@
#include "PrecompiledHeader.h"
#include "Threading.h"
#include "TlsVariable.inl"
#include "SafeArray.inl"
@ -36,6 +37,8 @@ template class SafeAlignedArray<u8,16>;
// system deadlock.
static const int MaxFormattedStringLength = 0x80000;
typedef ScopedAlignedAlloc<char,16> CharBufferType;
// --------------------------------------------------------------------------------------
// FastFormatBuffers
// --------------------------------------------------------------------------------------
@ -50,7 +53,7 @@ class FastFormatBuffers
protected:
typedef char CharType;
typedef SafeAlignedArray<CharType,16> BufferType;
typedef CharBufferType BufferType;
static const uint BufferCount = 4;
@ -66,10 +69,7 @@ public:
for (uint i=0; i<BufferCount; ++i)
{
m_buffers[i].Name = wxsFormat(L"%s Formatting Buffer (slot%d)",
(sizeof(CharType)==1) ? L"UTF8/Ascii" : L"Wide-char", i);
m_buffers[i].MakeRoomFor(1024);
m_buffers[i].ChunkSize = 2048;
m_buffers[i].Alloc(1024);
}
m_curslot = 0;
@ -92,14 +92,14 @@ public:
BufferType& GrabBuffer()
{
++m_curslot;
pxAssume(m_curslot<BufferCount);
pxAssume(m_curslot < BufferCount);
return m_buffers[m_curslot];
}
void ReleaseBuffer()
{
--m_curslot;
pxAssume(m_curslot<BufferCount);
pxAssume(m_curslot < BufferCount);
}
BufferType& operator[](uint i)
@ -150,7 +150,8 @@ public:
static bool buffer_is_avail = false;
static GlobalBufferManager< BaseTlsVariable< FastFormatBuffers > > m_buffer_tls(buffer_is_avail);
static __ri void format_that_ascii_mess( SafeArray<char>& buffer, uint writepos, const char* fmt, va_list argptr )
//static __ri void format_that_ascii_mess( SafeArray<char>& 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<char>& 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<char>& 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<char>& 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<char>* GetFormatBuffer( bool& deleteDest )
CharBufferType* GetFormatBuffer( bool& deleteDest )
{
deleteDest = false;
if (buffer_is_avail)
@ -220,7 +225,8 @@ SafeArray<char>* GetFormatBuffer( bool& deleteDest )
}
deleteDest = true;
return new SafeArray<char>(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; i<m_Length; ++i, ++ch )
*ch = (wxChar)wxToupper(*ch);
return *this;
}
FastFormatUnicode& FastFormatUnicode::ToLower()
{
wxChar* ch = (wxChar*)m_dest->GetPtr();
for ( uint i=0; i<m_Length; ++i, ++ch )
*ch = (wxChar)wxTolower(*ch);
return *this;
}
FastFormatUnicode& FastFormatUnicode::operator+=(const char* psz )
{
Write( L"%s", fromUTF8(psz).c_str() );
return *this;
}
wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
{
str1.Append(str2.c_str(), str2.Length());
return str1;
}
wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
{
wxString s = str1;
s += str2;
return s;
}
wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
{
wxString s = str1;
s += str2;
return s;
}
// --------------------------------------------------------------------------------------
// FastFormatAscii (implementations)
// --------------------------------------------------------------------------------------

View File

@ -154,7 +154,7 @@ bool Threading::_WaitGui_RecursionGuard( const wxChar* name )
if( !guard.IsReentrant() ) return false;
pxThreadLog.Write( pxGetCurrentThreadName(),
wxsFormat(L"Yield recursion in %s; opening modal dialog.", name)
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name)
);
return true;
}
@ -210,7 +210,7 @@ bool Threading::pxThread::AffinityAssert_AllowFromSelf( const DiagnosticOrigin&
if( IsSelf() ) return true;
if( IsDevBuild )
pxOnAssert( origin, wxsFormat( L"Thread affinity violation: Call allowed from '%s' thread only.", GetName().c_str() ) );
pxOnAssert( origin, pxsFmt( L"Thread affinity violation: Call allowed from '%s' thread only.", GetName().c_str() ) );
return false;
}
@ -220,7 +220,7 @@ bool Threading::pxThread::AffinityAssert_DisallowFromSelf( const DiagnosticOrigi
if( !IsSelf() ) return true;
if( IsDevBuild )
pxOnAssert( origin, wxsFormat( L"Thread affinity violation: Call is *not* allowed from '%s' thread.", GetName().c_str() ) );
pxOnAssert( origin, pxsFmt( L"Thread affinity violation: Call is *not* allowed from '%s' thread.", GetName().c_str() ) );
return false;
}
@ -404,10 +404,8 @@ void Threading::pxThread::RethrowException() const
// pointer might still be invalid after detachment, so might as well just detach and check
// after.
ScopedPtr<BaseException> ptr( const_cast<pxThread*>(this)->m_except.DetachPtr() );
ScopedExcept ptr( const_cast<pxThread*>(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()

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "wxBaseTools.h"
#include "pxStreams.h"
#include <wx/stream.h>
// --------------------------------------------------------------------------------------
// pxStreamReader (implementations)
// --------------------------------------------------------------------------------------
// Interface for reading data from a gzip stream.
//
pxStreamReader::pxStreamReader(const wxString& filename, ScopedPtr<wxInputStream>& 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<wxInputStream>& 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<wxOutputStream>& 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<wxOutputStream>& 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());
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "wxBaseTools.h"
#include <wx/stream.h>
// 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());
}

View File

@ -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<BaseException> 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<BaseException> 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<BaseException> deleteMe( m_except );
ScopedExcept deleteMe( m_except );
if( deleteMe ) deleteMe->Rethrow();
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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() );

View File

@ -16,400 +16,527 @@
#include "PrecompiledHeader.h"
#include "IopCommon.h"
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include "IsoFileFormats.h"
static bool detect(isoFile *iso)
#include <errno.h>
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<u32>( 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; i<MaxSplits; ++i)
m_parts[i].handle.Delete();
m_dtable.Delete();
_init();
}
bool isoFile::IsOpened() const
{
return m_parts[0].handle && m_parts[0].handle->IsOk();
}
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 );
}

View File

@ -13,11 +13,11 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#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<wxFileInputStream> 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<u32> m_dtable;
int m_dtablesize;
ScopedPtr<wxFileOutputStream> m_outstream;
// Currently unused internal buffer (it was used for compressed
// iso support, before it was removed).
//ScopedArray<u8> 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__ */

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "IsoFileTools.h"
#ifdef _WIN32
# include <wx/msw/wrapwin.h>
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <stdio.h>
#include <fcntl.h>
#include <errno.h>
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);

View File

@ -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

View File

@ -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();

View File

@ -249,8 +249,6 @@
<Unit filename="../CDVD/IsoFS/SectorSource.h" />
<Unit filename="../CDVD/IsoFileFormats.cpp" />
<Unit filename="../CDVD/IsoFileFormats.h" />
<Unit filename="../CDVD/IsoFileTools.cpp" />
<Unit filename="../CDVD/IsoFileTools.h" />
<Unit filename="../COP0.cpp" />
<Unit filename="../COP0.h" />
<Unit filename="../COP2.cpp" />

View File

@ -163,7 +163,7 @@ class CpuInitializer
{
public:
ScopedPtr<CpuType> MyCpu;
ScopedPtr<BaseException> 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()
{

View File

@ -43,8 +43,8 @@ protected:
class SysCpuProviderPack
{
protected:
ScopedPtr<BaseException> m_RecExceptionEE;
ScopedPtr<BaseException> m_RecExceptionIOP;
ScopedExcept m_RecExceptionEE;
ScopedExcept m_RecExceptionIOP;
public:
ScopedPtr<CpuInitializerSet> CpuProviders;

View File

@ -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<BaseException> 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<BaseException> deleteMe( m_except );
ScopedExcept deleteMe( m_except );
m_except = NULL;
if( !HandlePluginError( *deleteMe ) )

View File

@ -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"," );

View File

@ -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;
}

View File

@ -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 (*.*)"));

View File

@ -1249,14 +1249,6 @@
RelativePath="..\..\CDVD\CDVDisoReader.h"
>
</File>
<File
RelativePath="..\..\CDVD\IsoFileTools.cpp"
>
</File>
<File
RelativePath="..\..\CDVD\IsoFileTools.h"
>
</File>
</Filter>
</Filter>
<Filter

View File

@ -16,41 +16,6 @@
#include "PrecompiledHeader.h"
#include "Win32.h"
// Translates an Errno code into an exception.
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode )
{
if( errcode == 0 ) return;
switch( errcode )
{
case EINVAL:
pxFailDev( L"Invalid argument" );
throw Exception::Stream( streamname ).SetDiagMsg(L"Invalid argument" );
case EACCES: // Access denied!
throw Exception::AccessDenied( streamname );
case EMFILE: // Too many open files!
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EEXIST:
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"File already exists");
case ENOENT: // File not found!
throw Exception::FileNotFound( streamname );
case EPIPE:
throw Exception::BadStream( streamname ).SetDiagMsg(L"Broken pipe");
case EBADF:
throw Exception::BadStream( streamname ).SetDiagMsg(L"Bad file number");
default:
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General file/stream error [errno: %d]", errcode ));
}
}
// Throws an exception based on the value returned from GetLastError.
// Performs an option return value success/fail check on hresult.
void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
@ -86,21 +51,6 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
}
}
// returns TRUE if an error occurred.
bool StreamException_LogFromErrno( const wxString& streamname, const wxChar* action, errno_t result )
{
try
{
StreamException_ThrowFromErrno( streamname, result );
}
catch( Exception::Stream& ex )
{
Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() );
return true;
}
return false;
}
// returns TRUE if an error occurred.
bool StreamException_LogLastError( const wxString& streamname, const wxChar* action, HANDLE result )
{

View File

@ -716,7 +716,7 @@ void recStep( void )
# define SETJMP_CODE(x) x
static jmp_buf m_SetJmp_StateCheck;
static ScopedPtr<BaseR5900Exception> m_cpuException;
static ScopedPtr<BaseException> m_Exception;
static ScopedExcept m_Exception;
#else
# define SETJMP_CODE(x)
#endif