async-iso: Current state of the code. It was done on vs2012 so only the vs2012 project file is updated with the file changes.

git-svn-id: http://pcsx2.googlecode.com/svn/branches/async-iso@5466 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2012-12-01 19:42:24 +00:00
parent d7372ef0cd
commit 568e74f0e4
14 changed files with 1446 additions and 700 deletions

183
pcsx2/AsyncFileReader.h Normal file
View File

@ -0,0 +1,183 @@
#pragma once
/*
// --------------------------------------------------------------------------------------
// MultiPartIso
// --------------------------------------------------------------------------------------
// An encapsulating class for array boundschecking and easy ScopedPointer behavior.
//
class _IsoPart
{
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) );
}
};
*/
#ifdef WIN32
# include <Windows.h>
# undef Yield
#endif
class AsyncFileReader
{
protected:
AsyncFileReader(void) {}
wxString m_filename;
uint m_blocksize;
public:
virtual ~AsyncFileReader(void) {};
virtual bool Open(const wxString& fileName)=0;
virtual int ReadSync(void* pBuffer, uint sector, uint count)=0;
virtual void BeginRead(void* pBuffer, uint sector, uint count)=0;
virtual int FinishRead(void)=0;
virtual void CancelRead(void)=0;
virtual void Close(void)=0;
virtual int GetBlockCount(void) const=0;
virtual void SetBlockSize(uint bytes) {}
uint GetBlockSize() const { return m_blocksize; }
const wxString& GetFilename() const
{
return m_filename;
}
};
class FlatFileReader : public AsyncFileReader
{
#ifdef WIN32
HANDLE hOverlappedFile;
OVERLAPPED asyncOperationContext;
bool asyncInProgress;
HANDLE hEvent;
#else
# error Not implemented
#endif
public:
FlatFileReader(void);
virtual ~FlatFileReader(void);
virtual bool Open(const wxString& fileName);
virtual int ReadSync(void* pBuffer, uint sector, uint count);
virtual void BeginRead(void* pBuffer, uint sector, uint count);
virtual int FinishRead(void);
virtual void CancelRead(void);
virtual void Close(void);
virtual int GetBlockCount(void) const;
void SetBlockSize(uint bytes) { m_blocksize = bytes; }
};
class MultipartFileReader : public AsyncFileReader
{
DeclareNoncopyableObject( MultipartFileReader );
static const int MaxParts = 8;
struct Part {
uint start;
uint end; // exclusive
bool isReading;
AsyncFileReader* reader;
} m_parts[MaxParts];
uint m_numparts;
uint GetFirstPart(uint lsn);
void FindParts();
public:
MultipartFileReader(AsyncFileReader* firstPart);
virtual ~MultipartFileReader(void);
virtual bool Open(const wxString& fileName);
virtual int ReadSync(void* pBuffer, uint sector, uint count);
virtual void BeginRead(void* pBuffer, uint sector, uint count);
virtual int FinishRead(void);
virtual void CancelRead(void);
virtual void Close(void);
virtual int GetBlockCount(void) const;
void SetBlockSize(uint bytes);
static AsyncFileReader* DetectMultipart(AsyncFileReader* reader);
};
class BlockdumpFileReader : public AsyncFileReader
{
DeclareNoncopyableObject( BlockdumpFileReader );
wxFileInputStream* m_file;
// total number of blocks in the ISO image (including all parts)
u32 m_blocks;
s32 m_blockofs;
// dtable / dtablesize are used when reading blockdumps
ScopedArray<u32> m_dtable;
int m_dtablesize;
int m_lresult;
public:
BlockdumpFileReader(void);
virtual ~BlockdumpFileReader(void);
virtual bool Open(const wxString& fileName);
virtual int ReadSync(void* pBuffer, uint sector, uint count);
virtual void BeginRead(void* pBuffer, uint sector, uint count);
virtual int FinishRead(void);
virtual void CancelRead(void);
virtual void Close(void);
virtual int GetBlockCount(void) const;
static bool DetectBlockdump(AsyncFileReader* reader);
int GetBlockOffset() { return m_blockofs; }
};

View File

@ -0,0 +1,153 @@
#include "PrecompiledHeader.h"
#include "AsyncFileReader.h"
#include "IopCommon.h"
#include "IsoFileFormats.h"
#include <errno.h>
enum isoFlags
{
ISOFLAGS_BLOCKDUMP_V2 = 0x0004,
ISOFLAGS_BLOCKDUMP_V3 = 0x0020
};
static const uint BlockDumpHeaderSize = 16;
bool BlockdumpFileReader::DetectBlockdump(AsyncFileReader* reader)
{
uint oldbs = reader->GetBlockSize();
reader->SetBlockSize(1);
char buf[4];
reader->ReadSync(buf, 0, 4);
bool isbd = (strncmp(buf, "BDV2", 4) == 0);
if(!isbd)
reader->SetBlockSize(oldbs);
return isbd;
}
BlockdumpFileReader::BlockdumpFileReader(void)
{
}
BlockdumpFileReader::~BlockdumpFileReader(void)
{
Close();
}
bool BlockdumpFileReader::Open(const wxString& fileName)
{
char buf[32];
m_filename = fileName;
m_file = new wxFileInputStream( m_filename );
m_file->SeekI(0);
m_file->Read(buf, 4);
if (strncmp(buf, "BDV2", 4) != 0)
{
return false;
}
//m_flags = ISOFLAGS_BLOCKDUMP_V2;
m_file->Read(&m_blocksize, sizeof(m_blocksize));
m_file->Read(&m_blocks, sizeof(m_blocks));
m_file->Read(&m_blockofs, sizeof(m_blockofs));
wxFileOffset flen = m_file->GetLength();
static const wxFileOffset datalen = flen - BlockDumpHeaderSize;
pxAssert( (datalen % (m_blocksize + 4)) == 0);
m_dtablesize = datalen / (m_blocksize + 4);
m_dtable = new u32[m_dtablesize];
m_file->SeekI(BlockDumpHeaderSize);
for (int i=0; i < m_dtablesize; ++i)
{
m_file->Read(&(m_dtable[i]), sizeof(m_dtable[i]));
m_file->SeekI(m_blocksize, wxFromCurrent);
}
return true;
}
int BlockdumpFileReader::ReadSync(void* pBuffer, uint lsn, uint count)
{
u8* dst = (u8*)pBuffer;
// Console.WriteLn("_isoReadBlockD %u, blocksize=%u, blockofs=%u\n", lsn, iso->blocksize, iso->blockofs);
while(count > 0)
{
bool ok = false;
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;
m_file->SeekI( BlockDumpHeaderSize + (i * (m_blocksize + 4)) );
m_file->Read( &check_lsn, sizeof(check_lsn) );
pxAssert( check_lsn == lsn );
#else
m_file->Seek( BlockDumpHeaderSize + (i * (m_blocksize + 4)) + 4 );
#endif
m_file->Read( dst, m_blocksize );
ok = true;
break;
}
if(!ok)
{
Console.WriteLn("Block %u not found in dump", lsn);
return -1;
}
count--;
lsn++;
dst += m_blocksize;
}
return 0;
}
void BlockdumpFileReader::BeginRead(void* pBuffer, uint sector, uint count)
{
m_lresult = ReadSync(pBuffer, sector, count);
}
int BlockdumpFileReader::FinishRead(void)
{
return m_lresult;
}
void BlockdumpFileReader::CancelRead(void)
{
}
void BlockdumpFileReader::Close(void)
{
if(m_file)
{
delete m_file;
m_file = NULL;
}
}
int BlockdumpFileReader::GetBlockCount(void) const
{
return m_blocks;
}

View File

@ -57,7 +57,8 @@ int lastLSN; // needed for block dumping
// Records last read block length for block dumping
//static int plsn = 0;
static isoFile blockDumpFile;
//static OutputIsoFile 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.
@ -336,12 +337,12 @@ bool DoCDVDopen()
if( ret == 1 ) throw Exception::CancelEvent(L"User canceled the CDVD plugin's open dialog.");
int cdtype = DoCDVDdetectDiskType();
/*
if (!EmuConfig.CdvdDumpBlocks || (cdtype == CDVD_TYPE_NODISC))
{
blockDumpFile.Close();
return true;
}
}*/
// TODO: Add a blockdumps configurable folder, and use that instead of CWD().
@ -366,7 +367,7 @@ bool DoCDVDopen()
cdvdTD td;
CDVD->getTD(0, &td);
/*
blockDumpFile.Create(temp, ISOFLAGS_BLOCKDUMP_V3);
if( blockDumpFile.IsOpened() )
@ -389,6 +390,7 @@ bool DoCDVDopen()
}
blockDumpFile.WriteFormat(blockofs, blocksize, blocks);
}
*/
return true;
}
@ -396,7 +398,7 @@ bool DoCDVDopen()
void DoCDVDclose()
{
CheckNullCDVD();
blockDumpFile.Close();
//blockDumpFile.Close();
if( CDVD->close != NULL )
CDVD->close();
@ -408,12 +410,12 @@ s32 DoCDVDreadSector(u8* buffer, u32 lsn, int mode)
{
CheckNullCDVD();
int ret = CDVD->readSector(buffer,lsn,mode);
/*
if (ret == 0 && blockDumpFile.IsOpened())
{
blockDumpFile.WriteBlock(buffer, lsn);
}
*/
return ret;
}
@ -447,12 +449,12 @@ s32 DoCDVDgetBuffer(u8* buffer)
{
CheckNullCDVD();
int ret = CDVD->getBuffer2(buffer);
/*
if (ret == 0 && blockDumpFile.IsOpened())
{
blockDumpFile.WriteBlock(buffer, lastLSN);
}
*/
return ret;
}

View File

@ -28,11 +28,11 @@
#include "CDVDisoReader.h"
static u8 *pbuffer;
static u8 cdbuffer[CD_FRAMESIZE_RAW] = {0};
static isoFile iso;
#include "AsyncFileReader.h"
static int psize, cdtype;
static InputIsoFile iso;
static int pmode, cdtype;
static s32 layer1start = -1;
static bool layer1searched = false;
@ -172,7 +172,7 @@ static void FindLayer1Start()
if( blockresult != -1 )
{
u8 tempbuffer[CD_FRAMESIZE_RAW];
iso.ReadBlock(tempbuffer, blockresult);
iso.ReadSync(tempbuffer, blockresult);
if( testForPartitionInfo( tempbuffer ) )
{
@ -212,13 +212,13 @@ static void FindLayer1Start()
while( (layer1start == -1) && (deviation < midsector-16) )
{
u8 tempbuffer[CD_FRAMESIZE_RAW];
iso.ReadBlock(tempbuffer, midsector-deviation);
iso.ReadSync(tempbuffer, midsector-deviation);
if(testForPartitionInfo( tempbuffer ))
layer1start = midsector-deviation;
else
{
iso.ReadBlock(tempbuffer, midsector+deviation);
iso.ReadSync(tempbuffer, midsector+deviation);
if( testForPartitionInfo( tempbuffer ) )
layer1start = midsector+deviation;
}
@ -380,6 +380,8 @@ s32 CALLBACK ISOgetTOC(void* toc)
s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode)
{
static u8 cdbuffer[CD_FRAMESIZE_RAW] = {0};
int _lsn = lsn;
if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn;
@ -387,13 +389,15 @@ s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode)
if(mode == CDVD_MODE_2352)
{
iso.ReadBlock(tempbuffer, lsn);
iso.ReadSync(tempbuffer, lsn);
return 0;
}
iso.ReadBlock(cdbuffer, lsn);
iso.ReadSync(cdbuffer, lsn);
pbuffer = cdbuffer;
u8 *pbuffer = cdbuffer;
int psize;
switch (mode)
{
@ -430,41 +434,23 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode)
if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn;
if (lsn > iso.GetBlockCount()) return -1;
iso.ReadBlock(cdbuffer, lsn);
pbuffer = cdbuffer;
iso.BeginRead2(lsn);
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;
}
pmode = mode;
return 0;
}
s32 CALLBACK ISOgetBuffer2(u8* buffer)
{
memcpy_fast(buffer, pbuffer, psize);
return 0;
return iso.FinishRead3(buffer, pmode);
}
u8* CALLBACK ISOgetBuffer()
{
return pbuffer;
}
//u8* CALLBACK ISOgetBuffer()
//{
// iso.FinishRead();
// return pbuffer;
//}
s32 CALLBACK ISOgetTrayStatus()
{
@ -495,7 +481,7 @@ CDVD_API CDVDapi_Iso =
ISOopen,
ISOreadTrack,
ISOgetBuffer, // emu shouldn't use this one.
NULL, //ISOgetBuffer, // emu shouldn't use this one.
ISOreadSubQ,
ISOgetTN,
ISOgetTD,

334
pcsx2/CDVD/InputIsoFile.cpp Normal file
View File

@ -0,0 +1,334 @@
/* 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 "IopCommon.h"
#include "IsoFileFormats.h"
#include <errno.h>
static const char* nameFromType(int type)
{
switch(type)
{
case ISOTYPE_CD: return "CD";
case ISOTYPE_DVD: return "DVD";
case ISOTYPE_AUDIO: return "Audio CD";
case ISOTYPE_DVDDL: return "DVD9 (dual-layer)";
case ISOTYPE_ILLEGAL: return "Illegal media";
default: return "Unknown or corrupt";
}
}
int InputIsoFile::ReadSync(u8* dst, uint lsn)
{
if (lsn > m_blocks)
{
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);
return -1;
}
m_reader->BeginRead(dst+m_blockofs, lsn, 1);
return m_reader->FinishRead();
}
void InputIsoFile::BeginRead2(uint lsn)
{
if (lsn > m_blocks)
{
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.
m_current_lsn = -1;
return;
}
m_current_lsn = lsn;
if(lsn >= m_read_lsn && lsn < (m_read_lsn+m_read_count))
{
// Already buffered
return;
}
m_read_lsn = lsn;
m_read_count = 1;
if(ReadUnit > 1)
{
//m_read_lsn = lsn - (lsn % ReadUnit);
m_read_count = min(ReadUnit, m_blocks - m_read_lsn);
}
m_reader->BeginRead(m_readbuffer, m_read_lsn, m_read_count);
m_read_inprogress = true;
}
int InputIsoFile::FinishRead3(u8* dst, uint mode)
{
int _offset, length;
int ret = 0;
if(m_current_lsn < 0)
return -1;
if(m_read_inprogress)
{
ret = m_reader->FinishRead();
m_read_inprogress = false;
if(ret < 0)
return ret;
}
switch (mode)
{
case CDVD_MODE_2352:
_offset = 0;
length = 2352;
break;
case CDVD_MODE_2340:
_offset = 12;
length = 2340;
break;
case CDVD_MODE_2328:
_offset = 24;
length = 2328;
break;
case CDVD_MODE_2048:
_offset = 24;
length = 2048;
break;
}
int end1 = m_blockofs + m_blocksize;
int end2 = _offset + length;
int end = min(end1, end2);
int diff = m_blockofs - _offset;
if(diff > 0)
{
memset(dst, 0, diff);
_offset = m_blockofs;
}
else
{
diff = 0;
}
length = end - _offset;
uint read_offset = (m_current_lsn - m_read_lsn) * m_blocksize;
memcpy_fast(dst + diff, m_readbuffer + read_offset, length);
if (m_type == ISOTYPE_CD && diff >= 12)
{
lsn_to_msf(dst + diff - 12, m_current_lsn);
dst[diff - 9] = 2;
}
return 0;
}
InputIsoFile::InputIsoFile()
{
_init();
}
InputIsoFile::~InputIsoFile() throw()
{
Close();
}
void InputIsoFile::_init()
{
m_type = ISOTYPE_ILLEGAL;
m_flags = 0;
m_offset = 0;
m_blockofs = 0;
m_blocksize = 0;
m_blocks = 0;
m_read_inprogress = false;
m_read_count = 0;
m_read_lsn = -1;
}
// 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 InputIsoFile::Test( const wxString& srcfile )
{
Close();
m_filename = srcfile;
return Open(srcfile, true);
}
bool InputIsoFile::Open( const wxString& srcfile, bool testOnly )
{
Close();
m_filename = srcfile;
m_reader = new FlatFileReader();
m_reader->Open(m_filename);
if(BlockdumpFileReader::DetectBlockdump(m_reader))
{
delete m_reader;
BlockdumpFileReader *bdr = new BlockdumpFileReader();;
bdr->Open(m_filename);
m_blockofs = bdr->GetBlockOffset();
m_blocksize = bdr->GetBlockSize();
m_reader = bdr;
ReadUnit = 1;
}
else
{
ReadUnit = MaxReadUnit;
bool detected = Detect();
if(testOnly)
return detected;
if (!detected)
throw Exception::BadStream()
.SetUserMsg(_("Unrecognized ISO image file format"))
.SetDiagMsg(L"ISO mounting failed: PCSX2 is unable to identify the ISO image type.");
m_reader->SetBlockSize(m_blocksize);
// Returns the original reader if single-part or a Multipart reader otherwise
m_reader = MultipartFileReader::DetectMultipart(m_reader);
}
m_blocks = m_reader->GetBlockCount();
Console.WriteLn(Color_StrongBlue, L"isoFile open ok: %s", m_filename.c_str());
ConsoleIndentScope indent;
Console.WriteLn("Image type = %s", nameFromType(m_type));
//Console.WriteLn("Fileparts = %u", m_numparts); // Pointless print, it's 1 unless it says otherwise above
DevCon.WriteLn ("blocks = %u", m_blocks);
DevCon.WriteLn ("offset = %d", m_offset);
DevCon.WriteLn ("blocksize = %u", m_blocksize);
DevCon.WriteLn ("blockoffset = %d", m_blockofs);
return true;
}
void InputIsoFile::Close()
{
delete m_reader;
m_reader = NULL;
_init();
}
bool InputIsoFile::IsOpened() const
{
return m_reader != NULL;
}
bool InputIsoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs)
{
static u8 buf[2456];
m_blocksize = _size;
m_offset = _offset;
m_blockofs = _blockofs;
m_reader->SetBlockSize(_size);
if(ReadSync(buf, 16) < 0)
return false;
if (strncmp((char*)(buf+25), "CD001", 5)) // Not ISO 9660 compliant
return false;
m_type = (*(u16*)(buf+190) == 2048) ? ISOTYPE_CD : ISOTYPE_DVD;
return true; // We can deal with this.
}
// based on florin's CDVDbin detection code :)
// Parameter:
//
//
// Returns true if the image is valid/known/supported, or false if not (type == ISOTYPE_ILLEGAL).
bool InputIsoFile::Detect( bool readType )
{
m_type = ISOTYPE_ILLEGAL;
AsyncFileReader* headpart = m_reader;
// 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 --->
int sectors = headpart->GetBlockCount();
if (sectors < 17)
return false;
m_blocks = 17;
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;
m_reader->SetBlockSize(m_blocksize);
//BUG: This also detects a memory-card-file as a valid Audio-CD ISO... -avih
return true;
}

View File

@ -1,560 +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 "IopCommon.h"
#include "IsoFileFormats.h"
#include <errno.h>
static const uint BlockDumpHeaderSize = 16;
bool isoFile::detect()
{
u8 buf[2456];
u8* pbuf;
ReadBlock(buf, 16);
pbuf = buf + 24;
if (strncmp((char*)(pbuf+1), "CD001", 5)) return false; // Not ISO 9660 compliant
if (*(u16*)(pbuf+166) == 2048)
m_type = ISOTYPE_CD;
else
m_type = ISOTYPE_DVD;
return true; // We can deal with this.
}
void isoFile::_ReadDtable()
{
_IsoPart& headpart( m_parts[0] );
wxFileOffset flen = headpart.handle->GetLength();
static const wxFileOffset datalen = flen - BlockDumpHeaderSize;
pxAssert( (datalen % (m_blocksize + 4)) == 0);
m_dtablesize = datalen / (m_blocksize + 4);
m_dtable = new u32[m_dtablesize];
headpart.Seek(BlockDumpHeaderSize);
for (int i=0; i < m_dtablesize; ++i)
{
headpart.Read(m_dtable[i]);
headpart.Seek(m_blocksize, wxFromCurrent);
}
}
bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs)
{
m_blocksize = _size;
m_offset = _offset;
m_blockofs = _blockofs;
return detect();
}
// based on florin's CDVDbin detection code :)
// 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];
m_type = ISOTYPE_ILLEGAL;
_IsoPart& headpart( m_parts[0] );
headpart.Seek( 0 );
headpart.Read( buf, 4 );
if (strncmp(buf, "BDV2", 4) == 0)
{
m_flags = ISOFLAGS_BLOCKDUMP_V2;
headpart.Read(m_blocksize);
headpart.Read(m_blocks);
headpart.Read(m_blockofs);
if (readType)
{
_ReadDtable();
return detect();
}
return true;
}
// 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;
//BUG: This also detects a memory-card-file as a valid Audio-CD ISO... -avih
return true;
}
// Generates format header information for blockdumps.
void isoFile::WriteFormat(int _blockofs, uint _blocksize, uint _blocks)
{
m_blocksize = _blocksize;
m_blocks = _blocks;
m_blockofs = _blockofs;
Console.WriteLn("blockoffset = %d", m_blockofs);
Console.WriteLn("blocksize = %u", m_blocksize);
Console.WriteLn("blocks = %u", m_blocks);
if (m_flags & ISOFLAGS_BLOCKDUMP_V2)
{
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 );
return;
}
Console.WriteLn("Block %u not found in dump", lsn);
}
void isoFile::_ReadBlock(u8* dst, uint lsn)
{
pxAssertMsg(lsn <= m_blocks, "Invalid lsn passed into isoFile::_ReadBlock.");
pxAssertMsg(m_numparts, "Invalid isoFile object state; an iso file needs at least one part!");
uint i;
for (i = 0; i < m_numparts-1; ++i)
{
// lsn indexes should always go in order; use an assertion just to be sure:
pxAssert(lsn >= m_parts[i].slsn);
if (lsn <= m_parts[i].elsn) break;
}
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)
{
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)
{
// Find and ignore blocks that have already been dumped:
for (int i=0; i<m_dtablesize; ++i)
{
if (m_dtable[i] == lsn) return;
}
m_dtable[m_dtablesize++] = 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(_("Unrecognized ISO image file format"))
.SetDiagMsg(L"ISO mounting failed: PCSX2 is unable to identify the ISO image type.");
if (!(m_flags & ISOFLAGS_BLOCKDUMP_V2))
{
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(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 = "DVD9 (dual-layer)";
break;
case ISOTYPE_ILLEGAL:
default:
isotypename = "illegal media";
break;
}
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);
}
void isoFile::Create(const wxString& filename, int flags)
{
Close();
m_filename = filename;
m_flags = flags;
m_offset = 0;
m_blockofs = 24;
m_blocksize = 2048;
m_outstream = new wxFileOutputStream( m_filename );
pxStream_OpenCheck( *m_outstream, m_filename, L"writing" );
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
}
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)
{
int err = errno;
if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(pxsFmt(L"An error occurred while writing %u bytes to file", size));
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();
}
// 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.
// Throwing exceptions here ends emulation.
// We should let the game decide what to do with missing data though.
if ((size_t)handle->LastRead() < size)
Console.Warning( "ISO read problem (Bad game rip?)" );
//throw Exception::EndOfStream( filename );
}
void _IsoPart::Seek(wxFileOffset pos, wxSeekMode mode)
{
handle->SeekI(pos, mode);
}
void _IsoPart::SeekEnd(wxFileOffset pos)
{
handle->SeekI(pos, wxFromEnd);
}
wxFileOffset _IsoPart::Tell() const
{
return handle->TellI();
}
// returns the number of blocks contained in this part of the iso image.
uint _IsoPart::CalculateBlocks( uint startBlock, uint blocksize )
{
wxFileOffset partsize = handle->GetLength();
slsn = startBlock;
uint numBlocks = partsize / blocksize;
elsn = startBlock + numBlocks - 1;
return numBlocks;
}

View File

@ -17,7 +17,7 @@
#include "CDVD.h"
#include "wx/wfstream.h"
#include "AsyncFileReader.h"
enum isoType
{
@ -28,64 +28,26 @@ enum isoType
ISOTYPE_DVDDL
};
enum isoFlags
{
ISOFLAGS_BLOCKDUMP_V2 = 0x0004,
ISOFLAGS_BLOCKDUMP_V3 = 0x0020
};
static const int CD_FRAMESIZE_RAW = 2448;
// --------------------------------------------------------------------------------------
// MultiPartIso
// --------------------------------------------------------------------------------------
// An encapsulating class for array boundschecking and easy ScopedPointer behavior.
//
class _IsoPart
{
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) );
}
};
// --------------------------------------------------------------------------------------
// isoFile
// --------------------------------------------------------------------------------------
class isoFile
class InputIsoFile
{
DeclareNoncopyableObject( isoFile );
DeclareNoncopyableObject( InputIsoFile );
static const uint MaxReadUnit = 128;
protected:
static const uint MaxSplits = 8;
uint ReadUnit;
protected:
wxString m_filename;
uint m_numparts;
_IsoPart m_parts[MaxSplits];
AsyncFileReader* m_reader;
uint m_current_lsn;
uint m_current_count;
isoType m_type;
u32 m_flags;
@ -96,29 +58,20 @@ protected:
// 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;
bool m_read_inprogress;
uint m_read_lsn;
uint m_read_count;
u8 m_readbuffer[MaxReadUnit * CD_FRAMESIZE_RAW];
public:
isoFile();
virtual ~isoFile() throw();
InputIsoFile();
virtual ~InputIsoFile() 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; }
uint GetBlockCount() const { return m_blocks; }
int GetBlockOffset() const { return m_blockofs; }
const wxString& GetFilename() const
@ -127,37 +80,18 @@ public:
}
bool Test( const wxString& srcfile );
void Open( const wxString& srcfile );
void Create(const wxString& filename, int mode);
bool Open( const wxString& srcfile, bool testOnly = false );
void Close();
bool Detect( bool readType=true );
void WriteFormat(int blockofs, uint blocksize, uint blocks);
int ReadSync(u8* dst, uint lsn);
void ReadBlock(u8* dst, uint lsn);
void WriteBlock(const u8* src, uint lsn);
void BeginRead2(uint lsn);
int FinishRead3(u8* dest, uint mode);
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) );
}
};

View File

@ -0,0 +1,211 @@
/* 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 "IopCommon.h"
#include "IsoFileFormats.h"
#include <errno.h>
/*
class OutputIsoFile
{
DeclareNoncopyableObject( OutputIsoFile );
protected:
wxString m_filename;
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:
OutputIsoFile();
virtual ~OutputIsoFile() throw();
bool IsOpened() const;
const wxString& GetFilename() const
{
return m_filename;
}
void Create(const wxString& filename, int mode);
void Close();
void WriteFormat(int blockofs, uint blocksize, uint blocks);
void WriteBlock(const u8* src, uint lsn);
protected:
void _init();
void _WriteBlock(const u8* src, uint lsn);
void _WriteBlockD(const u8* src, uint lsn);
void outWrite( const void* src, size_t size );
template< typename T >
void outWrite( const T& data )
{
outWrite( &data, sizeof(data) );
}
};
*/
/*
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();
}
OutputIsoFile::OutputIsoFile()
{
_init();
}
OutputIsoFile::~OutputIsoFile() throw()
{
Close();
}
void OutputIsoFile::_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;
}
void OutputIsoFile::Create(const wxString& filename, int flags)
{
Close();
m_filename = filename;
m_flags = flags;
m_offset = 0;
m_blockofs = 24;
m_blocksize = 2048;
m_outstream = new wxFileOutputStream( m_filename );
pxStream_OpenCheck( *m_outstream, m_filename, L"writing" );
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
}
// Generates format header information for blockdumps.
void OutputIsoFile::WriteFormat(int _blockofs, uint _blocksize, uint _blocks)
{
m_blocksize = _blocksize;
m_blocks = _blocks;
m_blockofs = _blockofs;
Console.WriteLn("blockoffset = %d", m_blockofs);
Console.WriteLn("blocksize = %u", m_blocksize);
Console.WriteLn("blocks = %u", m_blocks);
if (m_flags & ISOFLAGS_BLOCKDUMP_V2)
{
outWrite("BDV2", 4);
outWrite(m_blocksize);
outWrite(m_blocks);
outWrite(m_blockofs);
}
}
void OutputIsoFile::_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 OutputIsoFile::_WriteBlockD(const u8* src, uint lsn)
{
// Find and ignore blocks that have already been dumped:
for (int i=0; i<m_dtablesize; ++i)
{
if (m_dtable[i] == lsn) return;
}
m_dtable[m_dtablesize++] = lsn;
outWrite<u32>( lsn );
outWrite( src + m_blockofs, m_blocksize );
}
void OutputIsoFile::WriteBlock(const u8* src, uint lsn)
{
if (m_flags == ISOFLAGS_BLOCKDUMP_V2)
_WriteBlockD(src, lsn);
else
_WriteBlock(src, lsn);
}
void OutputIsoFile::Close()
{
m_dtable.Delete();
_init();
}
void OutputIsoFile::outWrite( 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(pxsFmt(L"An error occurred while writing %u bytes to file", size));
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();
}
}
bool OutputIsoFile::IsOpened() const
{
return m_outstream && m_outstream->IsOk();
}
*/

View File

@ -0,0 +1,228 @@
#include "PrecompiledHeader.h"
#include "AsyncFileReader.h"
// 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();
}
AsyncFileReader* MultipartFileReader::DetectMultipart(AsyncFileReader* reader)
{
MultipartFileReader* multi = new MultipartFileReader(reader);
multi->FindParts();
if (multi->m_numparts > 1)
{
Console.WriteLn( Color_Blue, "isoFile: multi-part ISO detected. %u parts found.", multi->m_numparts);
return multi;
}
multi->m_parts[0].reader = NULL;
delete multi;
return reader;
}
MultipartFileReader::MultipartFileReader(AsyncFileReader* firstPart)
{
memset(m_parts,0,sizeof(m_parts));
m_filename = firstPart->GetFilename();
m_numparts = 1;
m_parts[0].reader = firstPart;
m_parts[0].end = firstPart->GetBlockCount();
}
MultipartFileReader::~MultipartFileReader(void)
{
Close();
}
void MultipartFileReader::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;
int bsize = m_parts[0].reader->GetBlockSize();
int blocks = m_parts[0].end;
m_numparts = 1;
for (; i < MaxParts; ++i)
{
extbuf.Clear();
extbuf.Write( L"%c%02u", prefixch, i );
nameparts.SetExt( extbuf );
if (!pxFileExists_WithExt(nameparts, extbuf))
break;
Part* thispart = m_parts + m_numparts;
AsyncFileReader* thisreader = thispart->reader = new FlatFileReader();
wxString name = nameparts.GetFullPath();
thisreader->Open(name);
thisreader->SetBlockSize(bsize);
thispart->start = blocks;
uint bcount = thisreader->GetBlockCount();
blocks += bcount;
thispart->end = blocks;
DevCon.WriteLn( Color_Blue, L"\tblocks %u - %u in: %s",
thispart->start, thispart->end,
nameparts.GetFullPath().c_str()
);
++m_numparts;
}
//Console.WriteLn( Color_Blue, "isoFile: multi-part ISO loaded (%u parts found)", m_numparts );
}
bool MultipartFileReader::Open(const wxString& fileName)
{
// Cannot open a MultipartFileReader directly,
// use DetectMultipart to convert a FlatFileReader
return -1;
}
uint MultipartFileReader::GetFirstPart(uint lsn)
{
pxAssertMsg(lsn < GetBlockCount(), "Invalid lsn passed into MultipartFileReader::GetFirstPart.");
pxAssertMsg(m_numparts, "Invalid object state; multi-part iso file needs at least one part!");
for (uint i = 0; i < m_numparts; ++i)
{
if (lsn < m_parts[i].end)
return i;
}
// should never get here
return 0xBAAAAAAD;
}
int MultipartFileReader::ReadSync(void* pBuffer, uint sector, uint count)
{
BeginRead(pBuffer,sector,count);
return FinishRead();
}
void MultipartFileReader::BeginRead(void* pBuffer, uint sector, uint count)
{
u8* lBuffer = (u8*)pBuffer;
for(int i = GetFirstPart(sector); i < m_numparts; i++)
{
uint num = min(count, m_parts[i].end - sector);
m_parts[i].reader->BeginRead(lBuffer, sector - m_parts[i].start, num);
m_parts[i].isReading = true;
lBuffer += num * m_blocksize;
sector += num;
count -= num;
if(count <= 0)
break;
}
}
int MultipartFileReader::FinishRead(void)
{
int ret = 0;
for(int i=0;i<m_numparts;i++)
{
if(m_parts[i].isReading)
{
ret = min(ret, m_parts[i].reader->FinishRead());
m_parts[i].isReading = false;
if(ret < 0)
ret = -1;
}
}
return ret;
}
void MultipartFileReader::CancelRead(void)
{
for(int i=0;i<m_numparts;i++)
{
if(m_parts[i].isReading)
{
m_parts[i].reader->CancelRead();
m_parts[i].isReading = false;
}
}
}
void MultipartFileReader::Close(void)
{
for(int i=0;i<m_numparts;i++)
{
if(m_parts[i].reader)
{
m_parts[i].reader->Close();
delete m_parts[i].reader;
}
}
}
int MultipartFileReader::GetBlockCount(void) const
{
return m_parts[m_numparts-1].end;
}
void MultipartFileReader::SetBlockSize(uint bytes)
{
uint last_end = 0;
for(int i=0;i<m_numparts;i++)
{
m_parts[i].reader->SetBlockSize(bytes);
uint count = m_parts[i].reader->GetBlockCount();
m_parts[i].start = last_end;
m_parts[i].end = last_end = m_parts[i].start + count;
}
}

148
pcsx2/OutputIsoFile.cpp Normal file
View File

@ -0,0 +1,148 @@
/* 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 "IopCommon.h"
#include "IsoFileFormats.h"
#include <errno.h>
/*
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();
}
OutputIsoFile::OutputIsoFile()
{
_init();
}
OutputIsoFile::~OutputIsoFile() throw()
{
Close();
}
void OutputIsoFile::_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;
}
void OutputIsoFile::Create(const wxString& filename, int flags)
{
Close();
m_filename = filename;
m_flags = flags;
m_offset = 0;
m_blockofs = 24;
m_blocksize = 2048;
m_outstream = new wxFileOutputStream( m_filename );
pxStream_OpenCheck( *m_outstream, m_filename, L"writing" );
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
}
// Generates format header information for blockdumps.
void OutputIsoFile::WriteFormat(int _blockofs, uint _blocksize, uint _blocks)
{
m_blocksize = _blocksize;
m_blocks = _blocks;
m_blockofs = _blockofs;
Console.WriteLn("blockoffset = %d", m_blockofs);
Console.WriteLn("blocksize = %u", m_blocksize);
Console.WriteLn("blocks = %u", m_blocks);
if (m_flags & ISOFLAGS_BLOCKDUMP_V2)
{
outWrite("BDV2", 4);
outWrite(m_blocksize);
outWrite(m_blocks);
outWrite(m_blockofs);
}
}
void OutputIsoFile::_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 OutputIsoFile::_WriteBlockD(const u8* src, uint lsn)
{
// Find and ignore blocks that have already been dumped:
for (int i=0; i<m_dtablesize; ++i)
{
if (m_dtable[i] == lsn) return;
}
m_dtable[m_dtablesize++] = lsn;
outWrite<u32>( lsn );
outWrite( src + m_blockofs, m_blocksize );
}
void OutputIsoFile::WriteBlock(const u8* src, uint lsn)
{
if (m_flags == ISOFLAGS_BLOCKDUMP_V2)
_WriteBlockD(src, lsn);
else
_WriteBlock(src, lsn);
}
void OutputIsoFile::Close()
{
m_dtable.Delete();
_init();
}
void OutputIsoFile::outWrite( 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(pxsFmt(L"An error occurred while writing %u bytes to file", size));
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();
}
}
bool OutputIsoFile::IsOpened() const
{
return m_outstream && m_outstream->IsOk();
}
*/

View File

@ -186,7 +186,7 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
// ISO CHECK
// ---------------
isoFile iso;
InputIsoFile iso;
if (iso.Test( filenames[0] ))
{

View File

@ -0,0 +1,107 @@
#include "PrecompiledHeader.h"
#include "AsyncFileReader.h"
FlatFileReader::FlatFileReader(void)
{
m_blocksize = 2048;
hOverlappedFile = INVALID_HANDLE_VALUE;
hEvent = INVALID_HANDLE_VALUE;
asyncInProgress = false;
}
FlatFileReader::~FlatFileReader(void)
{
Close();
}
bool FlatFileReader::Open(const wxString& fileName)
{
m_filename = fileName;
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hOverlappedFile = CreateFile(
fileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED,
NULL);
return hOverlappedFile != INVALID_HANDLE_VALUE;
}
int FlatFileReader::ReadSync(void* pBuffer, uint sector, uint count)
{
//LARGE_INTEGER offset;
//offset.QuadPart = sector * (__int64)m_blocksize;
//
//DWORD bytesToRead = count * m_blocksize;
//DWORD bytes;
//if(!ReadFile(hOverlappedFile, pBuffer, bytesToRead, &bytes, NULL))
// return -1;
//return bytes;
BeginRead(pBuffer, sector, count);
return FinishRead();
}
void FlatFileReader::BeginRead(void* pBuffer, uint sector, uint count)
{
LARGE_INTEGER offset;
offset.QuadPart = sector * (__int64)m_blocksize;
DWORD bytesToRead = count * m_blocksize;
ZeroMemory(&asyncOperationContext, sizeof(asyncOperationContext));
asyncOperationContext.hEvent = hEvent;
asyncOperationContext.Offset = offset.LowPart;
asyncOperationContext.OffsetHigh = offset.HighPart;
ReadFile(hOverlappedFile, pBuffer, bytesToRead, NULL, &asyncOperationContext);
asyncInProgress = true;
}
int FlatFileReader::FinishRead(void)
{
DWORD bytes;
if(!GetOverlappedResult(hOverlappedFile, &asyncOperationContext, &bytes, TRUE))
{
asyncInProgress = false;
return -1;
}
asyncInProgress = false;
return bytes;
}
void FlatFileReader::CancelRead(void)
{
CancelIo(hOverlappedFile);
}
void FlatFileReader::Close(void)
{
if(asyncInProgress)
CancelRead();
if(hOverlappedFile != INVALID_HANDLE_VALUE)
CloseHandle(hOverlappedFile);
if(hEvent != INVALID_HANDLE_VALUE)
CloseHandle(hEvent);
hOverlappedFile = INVALID_HANDLE_VALUE;
hEvent = INVALID_HANDLE_VALUE;
}
int FlatFileReader::GetBlockCount(void) const
{
LARGE_INTEGER fileSize;
fileSize.LowPart = GetFileSize(hOverlappedFile, (DWORD*)&(fileSize.HighPart));
return (int)(fileSize.QuadPart / m_blocksize);
}

View File

@ -411,6 +411,8 @@
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp" />
<ClCompile Include="..\..\CDVD\OutputIsoFile.cpp" />
<ClCompile Include="..\..\GameDatabase.cpp" />
<ClCompile Include="..\..\Gif_Logger.cpp" />
<ClCompile Include="..\..\Gif_Unit.cpp" />
@ -421,6 +423,7 @@
<ClCompile Include="..\..\gui\Panels\GameDatabasePanel.cpp" />
<ClCompile Include="..\..\gui\Panels\MemoryCardListView.cpp" />
<ClCompile Include="..\..\IPU\IPUdma.cpp" />
<ClCompile Include="..\..\MultipartFileReader.cpp" />
<ClCompile Include="..\..\Patch.cpp" />
<ClCompile Include="..\..\Patch_Memory.cpp" />
<ClCompile Include="..\..\PrecompiledHeader.cpp">
@ -435,6 +438,7 @@
<ClCompile Include="..\..\x86\iMisc.cpp" />
<ClCompile Include="..\..\Pcsx2Config.cpp" />
<ClCompile Include="..\..\PluginManager.cpp" />
<ClCompile Include="..\FlatFileReaderWindows.cpp" />
<ClCompile Include="..\SamplProf.cpp" />
<ClCompile Include="..\..\SaveState.cpp" />
<ClCompile Include="..\..\SourceLog.cpp" />
@ -443,7 +447,7 @@
<ClCompile Include="..\..\System.cpp" />
<ClCompile Include="..\..\System\SysThreadBase.cpp" />
<ClCompile Include="..\..\Elfheader.cpp" />
<ClCompile Include="..\..\CDVD\IsoFileFormats.cpp" />
<ClCompile Include="..\..\CDVD\InputIsoFile.cpp" />
<ClCompile Include="..\..\Linux\LnxHostSys.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">true</ExcludedFromBuild>
@ -685,6 +689,7 @@
<ClCompile Include="..\..\ZipTools\thread_lzma.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\AsyncFileReader.h" />
<ClInclude Include="..\..\GameDatabase.h" />
<ClInclude Include="..\..\Gif_Unit.h" />
<ClInclude Include="..\..\gui\AppGameDatabase.h" />

View File

@ -275,9 +275,6 @@
<ClCompile Include="..\..\Elfheader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\CDVD\IsoFileFormats.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\Linux\LnxHostSys.cpp">
<Filter>System\Linux</Filter>
</ClCompile>
@ -817,6 +814,21 @@
<ClCompile Include="..\..\Gif_Logger.cpp">
<Filter>System\Ps2\GS</Filter>
</ClCompile>
<ClCompile Include="..\FlatFileReaderWindows.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\CDVD\InputIsoFile.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\MultipartFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\CDVD\OutputIsoFile.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Patch.h">
@ -1204,6 +1216,9 @@
<ClInclude Include="..\..\x86\microVU_Profiler.h">
<Filter>System\Ps2\EmotionEngine\VU\Dynarec\microVU</Filter>
</ClInclude>
<ClInclude Include="..\..\AsyncFileReader.h">
<Filter>System\ISO</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\3rdparty\wxWidgets\include\wx\msw\wx.rc">