// ACFile.cpp // Implementation of class cACFile #include "stdafx.h" #include "DatFile.h" #define AC_NUMFILELOC 0x03E #define AC_ROOTDIRPTRLOC 0x148 #define new DEBUG_NEW cDatFile::cFile::cFile( cDatFile *pSource, BYTE *pFirstSector, DWORD dwSize ) : m_pFirstSector( pFirstSector ), m_pCurrentSector( pFirstSector ), m_pCurrentByte( pFirstSector + sizeof( DWORD ) ), m_dwSize( dwSize ), m_dwOffset( 0 ), m_pSource( pSource ) { } void cDatFile::cFile::reset() { m_pCurrentSector = m_pFirstSector; m_pCurrentByte = m_pFirstSector + sizeof( DWORD ); m_dwOffset = 0; } DWORD cDatFile::cFile::read( BYTE *pbBuffer, DWORD dwSize ) { // Check if we can fit if( dwSize + m_dwOffset > m_dwSize ) dwSize = m_dwSize - m_dwOffset; DWORD dwRemaining = dwSize; while( dwRemaining > 0 ) { if( ( m_pCurrentByte + dwRemaining ) > m_pCurrentSector + m_pSource->m_dwSectorSize ) { // We are reading over a sector boundary, read what we've got and reset for the next sector DWORD dwSection = ( m_pCurrentSector + m_pSource->m_dwSectorSize ) - m_pCurrentByte; ::memcpy( pbBuffer, m_pCurrentByte, dwSection ); m_pCurrentSector = m_pSource->m_pData + *reinterpret_cast< DWORD * >( m_pCurrentSector ); m_pCurrentByte = m_pCurrentSector + sizeof( DWORD ); dwRemaining -= dwSection; pbBuffer += dwSection; } else { ::memcpy( pbBuffer, m_pCurrentByte, dwRemaining ); m_pCurrentByte += dwRemaining; dwRemaining = 0; } } m_dwOffset += dwSize; return dwSize; } DWORD cDatFile::cFile::skip( DWORD dwSize ) { // Check if we can fit if( dwSize + m_dwOffset > m_dwSize ) dwSize = m_dwSize - m_dwOffset; DWORD dwRemaining = dwSize; while( dwRemaining > 0 ) { if( ( m_pCurrentByte + dwRemaining ) > m_pCurrentSector + m_pSource->m_dwSectorSize ) { // We are reading over a sector boundary, read what we've got and reset for the next sector DWORD dwSection = ( m_pCurrentSector + m_pSource->m_dwSectorSize ) - m_pCurrentByte; m_pCurrentSector = m_pSource->m_pData + *reinterpret_cast< DWORD * >( m_pCurrentSector ); m_pCurrentByte = m_pCurrentSector + sizeof( DWORD ); dwRemaining -= dwSection; } else { m_pCurrentByte += dwRemaining; dwRemaining = 0; } } m_dwOffset += dwSize; return dwSize; } cDatFile::cDatFile( LPCTSTR szFilename, DWORD dwSectorSize ) : m_hFile( NULL ), m_hMapping( NULL ), m_pData( NULL ), m_dwSectorSize( dwSectorSize ) { m_hFile = ::CreateFile( szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL ); if( m_hFile == INVALID_HANDLE_VALUE ) throw std::exception(); // Proceed to create the file mapping m_hMapping = ::CreateFileMapping( m_hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); if( m_hMapping == NULL ) { ::CloseHandle( m_hFile ); throw std::exception(); } m_pData = reinterpret_cast< BYTE * >( ::MapViewOfFileEx( m_hMapping, FILE_MAP_READ, 0, 0, 0, NULL ) ); if( m_pData == NULL ) { ::CloseHandle( m_hMapping ); ::CloseHandle( m_hFile ); throw std::exception(); } } cDatFile::~cDatFile() { ::UnmapViewOfFile( m_pData ); ::CloseHandle( m_hMapping ); ::CloseHandle( m_hFile ); } cDatFile::cFile cDatFile::getFile( DWORD dwFileNumber ) { cDirectory dir; // Search for our golden file for ( DWORD dwDirStart = *reinterpret_cast< DWORD * >( m_pData + AC_ROOTDIRPTRLOC ); dwDirStart != 0; ) { cFile dir_entry( this, m_pData + dwDirStart, sizeof( cDirectory ) ); dir_entry.read( reinterpret_cast< BYTE * >( &dir ), sizeof( cDirectory ) ); // Now, the files are located like triplets, so copy the triplets cFileEntry *pEntry = dir.m_files, *pEndEntry = pEntry + dir.m_dwFiles; for( cFileEntry *pIter = pEntry; pIter != pEndEntry && pIter->m_dwID < dwFileNumber; ++ pIter ); // We either got an exact match - or we attempt to further narrow down the file if( pIter != pEndEntry ) { // We found some sort of match if( pIter->m_dwID == dwFileNumber ) // This is an exact match hooray return cFile( this, m_pData + pIter->m_dwOffset, pIter->m_dwSize ); } // We have an inexact match, but now we attempt to recurse if( dir.m_subdirs[ 0 ] == 0 ) // If the first entry in the directory is 0, there are no // helpers - we lose, it's not here break; dwDirStart = dir.m_subdirs[ pIter - pEntry ]; } // If we get here, the file wasn't found - sniff throw std::exception(); }