Files
Rocky5 921f9fe9f8 Clean Copy
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
2024-01-08 19:01:29 +00:00

1045 lines
31 KiB
C++

/*
* XBMC
* 2003 by The Joker / Avalaunch team
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "system.h"
/*
Redbook : CDDA
Yellowbook : CDROM
ISO9660
CD-ROM Mode 1 divides the 2352 byte data area into:
-12 bytes of synchronisation
-4 bytes of header information
-2048 bytes of user information
-288 bytes of error correction and detection codes.
CD-ROM Mode 2 redefines the use of the 2352 byte data area as follows:
-12 bytes of synchronisation
-4 bytes of header information
-2336 bytes of user data.
ISO9660 specs:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
*/
#include "iso9660.h"
#include "utils/CharsetConverter.h"
#include "storage/DetectDVDType.h" // for MODE2_DATA_SIZE etc.
//#define _DEBUG_OUTPUT 1
static CRITICAL_SECTION m_critSection;
class iso9660 m_isoReader;
#define BUFFER_SIZE MODE2_DATA_SIZE
#define RET_ERR -1
using namespace std;
//******************************************************************************************************************
const string iso9660::ParseName(struct iso9660_Directory& isodir)
{
string temp_text = (char*)isodir.FileName;
temp_text.resize(isodir.Len_Fi);
int iPos = isodir.Len_Fi;
if (isodir.FileName[iPos] == 0)
{
iPos++;
}
if (isodir.FileName[iPos] == 'R' && isodir.FileName[iPos + 1] == 'R')
{
// rockridge
iPos += 5;
do
{
if (isodir.FileName[iPos] == 'N' && isodir.FileName[iPos + 1] == 'M')
{
// altername name
// "N" "M" LEN_NM 1 FLAGS NAMECONTENT
// BP1 BP2 BP3 BP4 BP5 BP6-LEN_NM
int iNameLen = isodir.FileName[iPos + 2] - 5;
temp_text = (char*) & isodir.FileName[iPos + 5];
temp_text.resize(iNameLen);
iPos += (iNameLen + 5);
}
if ( isascii(isodir.FileName[iPos]) && isascii(isodir.FileName[iPos + 1]))
{
// ??
// "?" "?" LEN
// BP1 BP2 BP3
iPos += isodir.FileName[iPos + 2];
}
}
while (33 + iPos < isodir.ucRecordLength && isodir.FileName[iPos + 2] != 0);
// when this isodir.FileName[iPos+2] is equal to 0 it should break out
// as it has finished the loop
// this is the fix for rockridge support
}
return temp_text;
}
bool iso9660::IsRockRidge(struct iso9660_Directory& isodir)
{
int iPos = isodir.Len_Fi;
if (isodir.FileName[iPos] == 0)
{
iPos++;
}
// found rock ridge in system use field
if (isodir.FileName[iPos] == 'R' && isodir.FileName[iPos + 1] == 'R')
return true;
return false;
}
//******************************************************************************************************************
struct iso_dirtree *iso9660::ReadRecursiveDirFromSector( DWORD sector, const char *path )
{
struct iso_dirtree* pDir = NULL;
struct iso_dirtree* pFile_Pointer = NULL;
char* pCurr_dir_cache = NULL;
DWORD iso9660searchpointer;
struct iso9660_Directory isodir;
struct iso9660_Directory curr_dir;
struct iso_directories *point = m_lastpath;
if (point)
{
while ( point->next )
{
if (strcmp(path, point->path) == 0) return NULL;
point = point->next;
}
}
#ifdef _DEBUG_OUTPUT
CStdString strTmp;
strTmp.Format("****************** Adding dir : %s\r", path);
OutputDebugString( strTmp.c_str() );
#endif
pDir = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
if (!pDir)
{
OutputDebugString("out of memory");
return NULL;
}
pDir->next = NULL;
pDir->path = NULL;
pDir->name = NULL;
pDir->dirpointer = NULL;
pFile_Pointer = pDir;
m_vecDirsAndFiles.push_back(pDir);
::SetFilePointer( m_info.ISO_HANDLE, m_info.iso.wSectorSizeLE * sector, 0, FILE_BEGIN );
DWORD lpNumberOfBytesRead = 0;
pCurr_dir_cache = (char*)malloc( 16*m_info.iso.wSectorSizeLE );
if (!pCurr_dir_cache )
{
OutputDebugString("out of memory\n");
return NULL;
}
BOOL bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache, m_info.iso.wSectorSizeLE, &lpNumberOfBytesRead, NULL );
if (!bResult || lpNumberOfBytesRead != m_info.iso.wSectorSizeLE)
{
OutputDebugString("unable to read\n");
return NULL;
}
memcpy( &isodir, pCurr_dir_cache, sizeof(isodir) );
memcpy( &curr_dir, pCurr_dir_cache, sizeof(isodir) );
if ( curr_dir.dwFileLengthLE > m_info.iso.wSectorSizeLE )
{
free( pCurr_dir_cache );
pCurr_dir_cache = (char*)malloc( 16 * isodir.dwFileLengthLE );
if (!pCurr_dir_cache )
{
OutputDebugString("out of memory\n");
return NULL;
}
::SetFilePointer( m_info.ISO_HANDLE, m_info.iso.wSectorSizeLE * sector, 0, FILE_BEGIN );
bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache , curr_dir.dwFileLengthLE, &lpNumberOfBytesRead, NULL );
if (!bResult || lpNumberOfBytesRead != curr_dir.dwFileLengthLE)
{
OutputDebugString("unable to read\n");
return NULL;
}
}
iso9660searchpointer = 0;
if (!m_lastpath)
{
m_lastpath = m_paths;
if ( !m_lastpath )
{
m_paths = (struct iso_directories *)malloc(sizeof(struct iso_directories));
if (!m_paths )
{
OutputDebugString("out of memory\n");
return NULL;
}
m_paths->path = NULL;
m_paths->dir = NULL;
m_paths->next = NULL;
m_lastpath = m_paths;
}
else
{
while ( m_lastpath->next )
m_lastpath = m_lastpath->next;
}
}
m_lastpath->next = ( struct iso_directories *)malloc( sizeof( struct iso_directories ) );
if (!m_lastpath->next )
{
OutputDebugString("out of memory\n");
return NULL;
}
m_lastpath = m_lastpath->next;
m_lastpath->next = NULL;
m_lastpath->dir = pDir;
m_lastpath->path = (char *)malloc(strlen(path) + 1);
if (!m_lastpath->path )
{
OutputDebugString("out of memory\n");
return NULL;
}
strcpy( m_lastpath->path, path );
while ( 1 )
{
if ( isodir.ucRecordLength )
iso9660searchpointer += isodir.ucRecordLength;
else
{
iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % m_info.iso.wSectorSizeLE)) + m_info.iso.wSectorSizeLE;
}
if ( curr_dir.dwFileLengthLE <= iso9660searchpointer )
{
break;
}
int isize = min(sizeof(isodir), sizeof(m_info.isodir));
memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer, isize);
if (!isodir.ucRecordLength)
continue;
if ( !(isodir.byFlags & Flag_NotExist) )
{
if ( (!( isodir.byFlags & Flag_Directory )) && ( isodir.Len_Fi > 1) )
{
string temp_text ;
bool bContinue = false;
if ( m_info.joliet )
{
bContinue = true;
isodir.FileName[isodir.Len_Fi] = isodir.FileName[isodir.Len_Fi + 1] = 0; //put terminator by its length
temp_text = GetThinText((WCHAR*)(isodir.FileName), isodir.Len_Fi/2 );
// temp_text.resize(isodir.Len_Fi);
}
if (!m_info.joliet && isodir.FileName[0] >= 0x20 )
{
temp_text = ParseName(isodir);
bContinue = true;
}
if (bContinue)
{
int semipos = temp_text.find(";", 0);
if (semipos >= 0)
temp_text.erase(semipos, temp_text.length() - semipos);
pFile_Pointer->next = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
if (!pFile_Pointer->next)
{
OutputDebugString("out of memory\n");
break;
}
m_vecDirsAndFiles.push_back(pFile_Pointer->next);
pFile_Pointer = pFile_Pointer->next;
pFile_Pointer->next = 0;
pFile_Pointer->dirpointer = NULL;
pFile_Pointer->path = (char *)malloc(strlen(path) + 1);
if (!pFile_Pointer->path)
{
OutputDebugString("out of memory");
return NULL;
}
strcpy( pFile_Pointer->path, path );
pFile_Pointer->name = (char *)malloc( temp_text.length() + 1);
if (!pFile_Pointer->name)
{
OutputDebugString("out of memory");
return NULL;
}
strcpy( pFile_Pointer->name , temp_text.c_str());
#ifdef _DEBUG_OUTPUT
//CStdString strTmp;
//strTmp.Format("adding sector : %X, File : %s size = %u pos = %x\r",sector,temp_text.c_str(), isodir.dwFileLengthLE, isodir.dwFileLocationLE );
//OutputDebugString( strTmp.c_str());
#endif
pFile_Pointer->Location = isodir.dwFileLocationLE;
pFile_Pointer->dirpointer = NULL;
pFile_Pointer ->Length = isodir.dwFileLengthLE;
IsoDateTimeToFileTime(&isodir.DateTime, &pFile_Pointer->filetime);
pFile_Pointer->type = 1;
}
}
}
}
iso9660searchpointer = 0;
memcpy( &curr_dir, pCurr_dir_cache, sizeof(isodir) );
memcpy( &isodir, pCurr_dir_cache, sizeof(isodir) );
while ( 1 )
{
if ( isodir.ucRecordLength )
iso9660searchpointer += isodir.ucRecordLength;
else
{
iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % m_info.iso.wSectorSizeLE)) + m_info.iso.wSectorSizeLE;
}
if ( curr_dir.dwFileLengthLE <= iso9660searchpointer )
{
free( pCurr_dir_cache );
pCurr_dir_cache = NULL;
return pDir;
}
memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer, min(sizeof(isodir), sizeof(m_info.isodir)));
if (!isodir.ucRecordLength)
continue;
if ( !(isodir.byFlags & Flag_NotExist) )
{
if ( (( isodir.byFlags & Flag_Directory )) && ( isodir.Len_Fi > 1) )
{
string temp_text ;
bool bContinue = false;
if ( m_info.joliet )
{
bContinue = true;
isodir.FileName[isodir.Len_Fi] = isodir.FileName[isodir.Len_Fi + 1] = 0; //put terminator by its length
temp_text = GetThinText((WCHAR*)(isodir.FileName), isodir.Len_Fi/2 );
// temp_text.resize(isodir.Len_Fi);
}
if (!m_info.joliet && isodir.FileName[0] >= 0x20 )
{
temp_text = ParseName(isodir);
bContinue = true;
}
if (bContinue)
{
// int semipos = temp_text.find(";",0); //the directory is not seperate by ";",but by its length
// if (semipos >= 0)
// temp_text.erase(semipos,temp_text.length()-semipos);
pFile_Pointer->next = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
if (!pFile_Pointer->next)
{
OutputDebugString("out of memory");
return NULL;
}
m_vecDirsAndFiles.push_back(pFile_Pointer->next);
pFile_Pointer = pFile_Pointer->next;
pFile_Pointer->next = 0;
pFile_Pointer->dirpointer = NULL;
pFile_Pointer->path = (char *)malloc(strlen(path) + 1);
if (!pFile_Pointer->path)
{
OutputDebugString("out of memory");
return NULL;
}
strcpy( pFile_Pointer->path, path );
pFile_Pointer->name = (char *)malloc( temp_text.length() + 1);
if (!pFile_Pointer->name)
{
OutputDebugString("out of memory");
return NULL;
}
strcpy( pFile_Pointer->name , temp_text.c_str());
#ifdef _DEBUG_OUTPUT
CStdString strTmp;
strTmp.Format("adding directory sector : %X, File : %s size = %u pos = %x\r", sector, temp_text.c_str(), isodir.dwFileLengthLE, isodir.dwFileLocationLE );
OutputDebugString( strTmp.c_str());
#endif
pFile_Pointer->Location = isodir.dwFileLocationLE;
pFile_Pointer->dirpointer = NULL;
pFile_Pointer->Length = isodir.dwFileLengthLE;
IsoDateTimeToFileTime(&isodir.DateTime, &pFile_Pointer->filetime);
string strPath = path;
if ( strlen( path ) > 1 ) strPath += "\\";
strPath += temp_text;
pFile_Pointer->dirpointer = ReadRecursiveDirFromSector( isodir.dwFileLocationLE, strPath.c_str() );
pFile_Pointer->type = 2;
}
}
}
}
return NULL;
}
//******************************************************************************************************************
iso9660::iso9660( )
{
memset(m_isoFiles, 0, sizeof(m_isoFiles));
InitializeCriticalSection(&m_critSection);
m_hCDROM = NULL;
Reset();
}
void iso9660::Scan()
{
if (m_hCDROM != NULL)
return ;
m_hCDROM = CIoSupport::OpenCDROM();
CIoSupport::AllocReadBuffer();
m_paths = 0;
m_lastpath = 0;
memset(&m_info, 0, sizeof(m_info));
m_info.ISO_HANDLE = m_hCDROM ;
m_info.Curr_dir_cache = 0;
m_info.Curr_dir = (char*)malloc( 4096 );
strcpy( m_info.Curr_dir, "\\" );
EnterCriticalSection(&m_critSection);
DWORD lpNumberOfBytesRead = 0;
::SetFilePointer( m_info.ISO_HANDLE, 0x8000, 0, FILE_BEGIN );
::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
if (strncmp(m_info.iso.szSignature, "CD001", 5))
{
CIoSupport::CloseCDROM( m_info.ISO_HANDLE);
CIoSupport::FreeReadBuffer();
m_info.ISO_HANDLE = NULL;
m_hCDROM = NULL;
m_info.iso9660 = 0;
LeaveCriticalSection(&m_critSection);
return ;
}
else
{
m_info.iso9660 = 1;
m_info.joliet = 0;
m_info.HeaderPos = 0x8000;
int current = 0x8000;
// first check if first file in the current VD has a rock-ridge NM. if it has, disable joliet
::SetFilePointer( m_info.ISO_HANDLE, m_info.iso.wSectorSizeLE * ((iso9660_Directory*)(&m_info.iso.szRootDir))->dwFileLocationLE, 0, FILE_BEGIN );
DWORD lpNumberOfBytesRead;
char* pCurr_dir_cache = (char*)malloc( 16*m_info.iso.wSectorSizeLE );
iso9660_Directory isodir;
BOOL bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache, m_info.iso.wSectorSizeLE, &lpNumberOfBytesRead, NULL );
memcpy( &isodir, pCurr_dir_cache, sizeof(isodir));
int iso9660searchpointer=0;
if ( isodir.ucRecordLength )
iso9660searchpointer += isodir.ucRecordLength;
else
iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % m_info.iso.wSectorSizeLE)) + m_info.iso.wSectorSizeLE;
memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer,min(sizeof(isodir), sizeof(m_info.isodir)));
free(pCurr_dir_cache);
if (bResult && lpNumberOfBytesRead == m_info.iso.wSectorSizeLE)
bResult = IsRockRidge(isodir);
while ( m_info.iso.byOne != 255)
{
if ( ( m_info.iso.byZero3[0] == 0x25 ) && ( m_info.iso.byZero3[1] == 0x2f ) && !bResult )
{
switch ( m_info.iso.byZero3[2] )
{
case 0x45 :
case 0x40 :
case 0x43 : m_info.HeaderPos = current;
m_info.joliet = 1;
}
// 25 2f 45 or 25 2f 40 or 25 2f 43 = jouliet, and best fitted for reading
}
current += 0x800;
::SetFilePointer( m_info.ISO_HANDLE, current, 0, FILE_BEGIN );
::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
}
::SetFilePointer( m_info.ISO_HANDLE, m_info.HeaderPos, 0, FILE_BEGIN );
::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
memcpy( &m_info.isodir, m_info.iso.szRootDir, sizeof(m_info.isodir));
}
memcpy( &m_info.isodir, &m_info.iso.szRootDir, sizeof(m_info.isodir) );
m_dirtree = ReadRecursiveDirFromSector( m_info.isodir.dwFileLocationLE, "\\" );
LeaveCriticalSection(&m_critSection);
}
//******************************************************************************************************************
iso9660::~iso9660( )
{
DeleteCriticalSection(&m_critSection);
Reset();
}
void iso9660::Reset()
{
if (m_info.Curr_dir)
free(m_info.Curr_dir);
m_info.Curr_dir = NULL;
if (m_info.Curr_dir_cache)
free(m_info.Curr_dir_cache);
m_info.Curr_dir_cache = NULL;
struct iso_directories* nextpath;
while ( m_paths )
{
nextpath = m_paths->next;
if (m_paths->path) free(m_paths->path);
free (m_paths);
m_paths = nextpath;
}
for (int i = 0; i < (int)m_vecDirsAndFiles.size(); ++i)
{
struct iso_dirtree* pDir = m_vecDirsAndFiles[i];
if (pDir->path) free(pDir->path);
if (pDir->name) free(pDir->name);
free(pDir);
}
m_vecDirsAndFiles.erase(m_vecDirsAndFiles.begin(), m_vecDirsAndFiles.end());
for (int i = 0; i < MAX_ISO_FILES;++i)
{
FreeFileContext( (HANDLE)i);
}
if (m_hCDROM)
{
CIoSupport::CloseCDROM(m_hCDROM);
CIoSupport::FreeReadBuffer();
}
m_hCDROM = NULL;
}
//******************************************************************************************************************
struct iso_dirtree *iso9660::FindFolder( char *Folder )
{
char *work;
work = (char *)malloc(m_info.iso.wSectorSizeLE);
char *temp;
struct iso_directories *lastpath = NULL;;
if ( strpbrk(Folder, ":") )
strcpy(work, strpbrk(Folder, ":") + 1);
else
strcpy(work, Folder);
temp = work + 1;
while ( strlen( temp ) > 1 && strpbrk( temp + 1, "\\" ) )
temp = strpbrk( temp + 1, "\\" );
if ( strlen( work ) > 1 && work[ strlen(work) - 1 ] == '*' )
{
work[ strlen(work) - 1 ] = 0;
}
if ( strlen( work ) > 2 )
if ( work[ strlen(work) - 1 ] == '\\' )
work[ strlen(work) - 1 ] = 0;
if (m_paths)
lastpath = m_paths->next;
while ( lastpath )
{
if ( !stricmp( lastpath->path, work))
{
free ( work );
return lastpath->dir;
}
lastpath = lastpath->next;
}
free ( work );
return 0;
}
//******************************************************************************************************************
HANDLE iso9660::FindFirstFile( char *szLocalFolder, WIN32_FIND_DATA *wfdFile )
{
if (m_info.ISO_HANDLE == 0) return (HANDLE)0;
memset( wfdFile, 0, sizeof(WIN32_FIND_DATA));
m_searchpointer = FindFolder( szLocalFolder );
if ( m_searchpointer )
{
m_searchpointer = m_searchpointer->next;
if ( m_searchpointer )
{
strcpy(wfdFile->cFileName, m_searchpointer->name );
if ( m_searchpointer->type == 2 )
wfdFile->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
wfdFile->ftLastWriteTime = m_searchpointer->filetime;
wfdFile->ftLastAccessTime = m_searchpointer->filetime;
wfdFile->ftCreationTime = m_searchpointer->filetime;
wfdFile->nFileSizeLow = m_searchpointer->Length;
return (HANDLE)1;
}
}
return (HANDLE)0;
}
//******************************************************************************************************************
int iso9660::FindNextFile( HANDLE szLocalFolder, WIN32_FIND_DATA *wfdFile )
{
memset( wfdFile, 0, sizeof(WIN32_FIND_DATA));
if ( m_searchpointer )
m_searchpointer = m_searchpointer->next;
if ( m_searchpointer )
{
strcpy(wfdFile->cFileName, m_searchpointer->name );
if ( m_searchpointer->type == 2 )
wfdFile->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
wfdFile->ftLastWriteTime = m_searchpointer->filetime;
wfdFile->ftLastAccessTime = m_searchpointer->filetime;
wfdFile->ftCreationTime = m_searchpointer->filetime;
wfdFile->nFileSizeLow = m_searchpointer->Length;
return 1;
}
return 0;
}
//******************************************************************************************************************
bool iso9660::FindClose( HANDLE szLocalFolder )
{
m_searchpointer = 0;
if (m_info.Curr_dir_cache) free(m_info.Curr_dir_cache);
m_info.Curr_dir_cache = 0;
return true;
}
//******************************************************************************************************************
string iso9660::GetThinText(WCHAR* strTxt, int iLen )
{
// convert from "fat" text (UTF-16BE) to "thin" text (UTF-8)
CStdStringW strTxtUnicode(strTxt, iLen);
CStdString utf8String;
g_charsetConverter.utf16BEtoUTF8(strTxtUnicode, utf8String);
return utf8String;
}
//************************************************************************************
HANDLE iso9660::OpenFile(const char *filename)
{
if (m_info.ISO_HANDLE == NULL) return INVALID_HANDLE_VALUE;
HANDLE hContext = AllocFileContext();
if (hContext == INVALID_HANDLE_VALUE) return hContext;
iso9660::isofile* pContext = GetFileContext(hContext);
WIN32_FIND_DATA fileinfo;
char *pointer, *pointer2;
char work[512];
pContext->m_bUseMode2 = false;
m_info.curr_filepos = 0;
pointer = (char*)filename;
while ( strpbrk( pointer, "\\/" ) )
pointer = strpbrk( pointer, "\\/" ) + 1;
strcpy(work, filename );
pointer2 = work;
while ( strpbrk(pointer2 + 1, "\\" ) )
pointer2 = strpbrk(pointer2 + 1, "\\" );
*(pointer2 + 1) = 0;
int loop = (int)FindFirstFile( work, &fileinfo );
while ( loop > 0)
{
if ( !stricmp(fileinfo.cFileName, pointer ) )
loop = -1;
else
loop = FindNextFile( NULL, &fileinfo );
}
if ( loop == 0 )
{
FreeFileContext(hContext);
return INVALID_HANDLE_VALUE;
}
pContext->m_dwCurrentBlock = m_searchpointer->Location;
pContext->m_dwFileSize = m_info.curr_filesize = fileinfo.nFileSizeLow;
pContext->m_pBuffer = new byte[CIRC_BUFFER_SIZE * BUFFER_SIZE];
pContext->m_dwStartBlock = pContext->m_dwCurrentBlock;
pContext->m_dwFilePos = 0;
pContext->m_dwCircBuffBegin = 0;
pContext->m_dwCircBuffEnd = 0;
pContext->m_dwCircBuffSectorStart = 0;
pContext->m_bUseMode2 = false;
bool bError;
EnterCriticalSection(&m_critSection);
bError = (CIoSupport::ReadSector(m_info.ISO_HANDLE, pContext->m_dwStartBlock, (char*) & (pContext->m_pBuffer[0])) < 0);
if ( bError )
{
bError = (CIoSupport::ReadSectorMode2(m_info.ISO_HANDLE, pContext->m_dwStartBlock, (char*) & (pContext->m_pBuffer[0])) < 0);
if ( !bError )
pContext->m_bUseMode2 = true;
}
LeaveCriticalSection(&m_critSection);
if (pContext->m_bUseMode2)
pContext->m_dwFileSize = (pContext->m_dwFileSize / 2048) * MODE2_DATA_SIZE;
return hContext;
}
//************************************************************************************
void iso9660::CloseFile(HANDLE hFile)
{
iso9660::isofile* pContext = GetFileContext(hFile);
if (pContext)
{
if (pContext->m_pBuffer)
{
delete [] pContext->m_pBuffer;
pContext->m_pBuffer = NULL;
}
}
FreeFileContext(hFile);
}
//************************************************************************************
bool iso9660::ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, byte** ppBuffer)
{
DWORD StartSectorInCircBuff = pContext->m_dwCircBuffSectorStart;
DWORD SectorsInCircBuff;
if ( pContext->m_dwCircBuffEnd >= pContext->m_dwCircBuffBegin )
SectorsInCircBuff = pContext->m_dwCircBuffEnd - pContext->m_dwCircBuffBegin;
else
SectorsInCircBuff = CIRC_BUFFER_SIZE - (pContext->m_dwCircBuffBegin - pContext->m_dwCircBuffEnd);
// If our sector is already in the circular buffer
if ( sector >= StartSectorInCircBuff &&
sector < (StartSectorInCircBuff + SectorsInCircBuff) &&
SectorsInCircBuff > 0 )
{
// Just retrieve it
DWORD SectorInCircBuff = (sector - StartSectorInCircBuff) +
pContext->m_dwCircBuffBegin;
if ( SectorInCircBuff >= CIRC_BUFFER_SIZE )
SectorInCircBuff -= CIRC_BUFFER_SIZE;
*ppBuffer = &(pContext->m_pBuffer[SectorInCircBuff]);
}
else
{
// Sector is not cache. Read it in.
bool SectorIsAdjacentInBuffer =
(StartSectorInCircBuff + SectorsInCircBuff) == sector;
if ( SectorsInCircBuff == CIRC_BUFFER_SIZE - 1 ||
!SectorIsAdjacentInBuffer)
{
// The cache is full. (Or its not an adjacent request in which we'll
// also flush the cache)
// If its adjacent, just get rid of the first sector.
if ( SectorIsAdjacentInBuffer )
{
// Release the first sector in cache
pContext->m_dwCircBuffBegin++;
if ( pContext->m_dwCircBuffBegin >= CIRC_BUFFER_SIZE )
pContext->m_dwCircBuffBegin -= CIRC_BUFFER_SIZE;
pContext->m_dwCircBuffSectorStart++;
SectorsInCircBuff--;
}
else
{
pContext->m_dwCircBuffBegin = pContext->m_dwCircBuffEnd = 0;
pContext->m_dwCircBuffSectorStart = 0;
SectorsInCircBuff = 0;
SectorIsAdjacentInBuffer = 0;
}
}
// Ok, we're ready to read the sector into the cache
bool bError;
EnterCriticalSection(&m_critSection);
if ( pContext->m_bUseMode2 )
{
bError = (CIoSupport::ReadSectorMode2(m_info.ISO_HANDLE, sector, (char*) & (pContext->m_pBuffer[pContext->m_dwCircBuffEnd])) < 0);
}
else
{
bError = (CIoSupport::ReadSector(m_info.ISO_HANDLE, sector, (char*) & (pContext->m_pBuffer[pContext->m_dwCircBuffEnd])) < 0);
}
LeaveCriticalSection(&m_critSection);
if ( bError )
return false;
*ppBuffer = &(pContext->m_pBuffer[pContext->m_dwCircBuffEnd]);
if ( pContext->m_dwCircBuffEnd == pContext->m_dwCircBuffBegin )
pContext->m_dwCircBuffSectorStart = sector;
pContext->m_dwCircBuffEnd++;
if ( pContext->m_dwCircBuffEnd >= CIRC_BUFFER_SIZE )
pContext->m_dwCircBuffEnd -= CIRC_BUFFER_SIZE;
}
return true;
}
//************************************************************************************
void iso9660::ReleaseSectorFromCache(iso9660::isofile* pContext, DWORD sector)
{
DWORD StartSectorInCircBuff = pContext->m_dwCircBuffSectorStart;
DWORD SectorsInCircBuff;
if ( pContext->m_dwCircBuffEnd >= pContext->m_dwCircBuffBegin )
SectorsInCircBuff = pContext->m_dwCircBuffEnd - pContext->m_dwCircBuffBegin;
else
SectorsInCircBuff = CIRC_BUFFER_SIZE - (pContext->m_dwCircBuffBegin - pContext->m_dwCircBuffEnd);
// If our sector is in the circular buffer
if ( sector >= StartSectorInCircBuff &&
sector < (StartSectorInCircBuff + SectorsInCircBuff) &&
SectorsInCircBuff > 0 )
{
DWORD SectorsToFlush = sector - StartSectorInCircBuff + 1;
pContext->m_dwCircBuffBegin += SectorsToFlush;
pContext->m_dwCircBuffSectorStart += SectorsToFlush;
if ( pContext->m_dwCircBuffBegin >= CIRC_BUFFER_SIZE )
pContext->m_dwCircBuffBegin -= CIRC_BUFFER_SIZE;
}
}
//************************************************************************************
long iso9660::ReadFile(HANDLE hFile, byte *pBuffer, long lSize)
{
bool bError;
long iBytesRead = 0;
DWORD sectorSize = 2048;
iso9660::isofile* pContext = GetFileContext(hFile);
if (!pContext) return -1;
if ( pContext->m_bUseMode2 )
sectorSize = MODE2_DATA_SIZE;
while (lSize > 0 && pContext->m_dwFilePos <= pContext->m_dwFileSize)
{
pContext->m_dwCurrentBlock = (DWORD) (pContext->m_dwFilePos / sectorSize);
int64_t iOffsetInBuffer = pContext->m_dwFilePos - (sectorSize * pContext->m_dwCurrentBlock);
pContext->m_dwCurrentBlock += pContext->m_dwStartBlock;
//char szBuf[256];
//sprintf(szBuf,"pos:%i cblk:%i sblk:%i off:%i",(long)m_dwFilePos, (long)m_dwCurrentBlock,(long)m_dwStartBlock,(long)iOffsetInBuffer);
//DBG(szBuf);
byte* pSector;
bError = !ReadSectorFromCache(pContext, pContext->m_dwCurrentBlock, &pSector);
if (!bError)
{
DWORD iBytes2Copy = lSize;
if (iBytes2Copy > (sectorSize - iOffsetInBuffer) )
iBytes2Copy = (DWORD) (sectorSize - iOffsetInBuffer);
memcpy( &pBuffer[iBytesRead], &pSector[iOffsetInBuffer], iBytes2Copy);
iBytesRead += iBytes2Copy;
lSize -= iBytes2Copy;
pContext->m_dwFilePos += iBytes2Copy;
if ( iBytes2Copy + iOffsetInBuffer == sectorSize )
ReleaseSectorFromCache(pContext, pContext->m_dwCurrentBlock);
// Why is this done? It is recalculated at the beginning of the loop
pContext->m_dwCurrentBlock += BUFFER_SIZE / MODE2_DATA_SIZE;
}
else
{
printf("EOF");
break;
}
}
if (iBytesRead == 0) return -1;
return iBytesRead;
}
//************************************************************************************
int64_t iso9660::Seek(HANDLE hFile, int64_t lOffset, int whence)
{
iso9660::isofile* pContext = GetFileContext(hFile);
if (!pContext) return -1;
int64_t dwFilePos = pContext->m_dwFilePos;
switch (whence)
{
case SEEK_SET:
// cur = pos
pContext->m_dwFilePos = lOffset;
break;
case SEEK_CUR:
// cur += pos
pContext->m_dwFilePos += lOffset;
break;
case SEEK_END:
// end += pos
pContext->m_dwFilePos = pContext->m_dwFileSize + lOffset;
break;
default:
return -1;
}
if (pContext->m_dwFilePos > pContext->m_dwFileSize || pContext->m_dwFilePos < 0)
{
pContext->m_dwFilePos = dwFilePos;
return pContext->m_dwFilePos;
}
return pContext->m_dwFilePos;
}
//************************************************************************************
int64_t iso9660::GetFileSize(HANDLE hFile)
{
iso9660::isofile* pContext = GetFileContext(hFile);
if (!pContext) return -1;
return pContext->m_dwFileSize;
}
//************************************************************************************
int64_t iso9660::GetFilePosition(HANDLE hFile)
{
iso9660::isofile* pContext = GetFileContext(hFile);
if (!pContext) return -1;
return pContext->m_dwFilePos;
}
//************************************************************************************
void iso9660::FreeFileContext(HANDLE hFile)
{
int iFile = (int)hFile;
if (iFile >= 1 && iFile < MAX_ISO_FILES)
{
if (m_isoFiles[iFile ]) delete m_isoFiles[iFile ];
m_isoFiles[iFile ] = NULL;
}
}
//************************************************************************************
HANDLE iso9660::AllocFileContext()
{
for (int i = 1; i < MAX_ISO_FILES; ++i)
{
if (m_isoFiles[i] == NULL)
{
m_isoFiles[i] = new isofile;
return (HANDLE)i;
}
}
return INVALID_HANDLE_VALUE;
}
//************************************************************************************
iso9660::isofile* iso9660::GetFileContext(HANDLE hFile)
{
int iFile = (int)hFile;
if (iFile >= 1 && iFile < MAX_ISO_FILES)
{
return m_isoFiles[iFile];
}
return NULL;
}
//************************************************************************************
bool iso9660::IsScanned()
{
return (m_hCDROM != NULL);
}
//************************************************************************************
void iso9660::IsoDateTimeToFileTime(iso9660_Datetime* isoDateTime, FILETIME* filetime)
{
tm t;
ZeroMemory(&t, sizeof(tm));
t.tm_year=isoDateTime->year;
t.tm_mon=isoDateTime->month-1;
t.tm_mday=isoDateTime->day;
t.tm_hour=isoDateTime->hour;
t.tm_min=isoDateTime->minute;
t.tm_sec=isoDateTime->second + (isoDateTime->gmtoff * (15 * 60));
t.tm_isdst=-1;
mktime(&t);
SYSTEMTIME time;
time.wYear=t.tm_year+1900;
time.wMonth=t.tm_mon+1;
time.wDayOfWeek=t.tm_wday;
time.wDay=t.tm_mday;
time.wHour=t.tm_hour;
time.wMinute=t.tm_min;
time.wSecond=t.tm_sec;
time.wMilliseconds=0;
SystemTimeToFileTime(&time, filetime);
}