mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
d7372ef0cd
commit
568e74f0e4
|
@ -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; }
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
*/
|
|
@ -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] ))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue