openDecal/Native/Inject/DatFile.cpp
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:27:56 +01:00

164 lines
4.7 KiB
C++

// 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();
}