Files
2026-06-01 12:46:52 +02:00

310 lines
7.1 KiB
C++

#include "../../include/kfile/XFileBasedFS.h"
#include "../../include/kfile/KEncodedFile.h"
#include "../../include/toolkit/khash.h"
#include <stdlib.h>
struct DataFile
{
bool Init( const char *szBaseFileName ) { return true; }
bool DeInit() { return true; }
size_t GetCurrentSize() { return 0; }
size_t Read( size_t offset, void *buf, size_t size ) { return size; }
size_t Write( size_t offset, void *buf, size_t size ) { return size; }
};
struct XFileInfo
{
XFileInfo( size_t base, size_t size ) : nBaseOffset( base ), nFileSize( size )
{
}
size_t nBaseOffset;
size_t nFileSize;
};
__declspec( thread ) FILE* g_pFP;
struct XFSInfo
{
XFSInfo()
: nDataFileSize( 0 )
{}
std::string strDataFile;
std::string strIndexFile;
KHash< XFileInfo, hashPr_string_nocase > hsFileIndex;
size_t nDataFileSize;
};
struct XFile : public KStream
{
XFile( XFileBasedFS* pParent, FILE *fp, const char *szFileName, size_t base, size_t size )
: m_pParent( pParent ), m_fp( fp ), strFileName( szFileName ), m_nBaseOffset( base ), m_nSize( size ), m_nCurrentOffset( 0 ), m_bModified( false )
{
// 2010.04.29 - prodongi
setClassId("XFileFile");
}
~XFile()
{
if ( m_pParent )
m_pParent->close( this );
}
const char* GetFileName() { return strFileName.c_str(); }
size_t GetBaseOffset() { return m_nBaseOffset; }
virtual size_t Read( void *pBuf, size_t read_size );
virtual size_t Write( const void *pBuf, size_t write_size );
virtual size_t Seek( long offset, enum_seek_origin origin );
virtual size_t GetLength() const { return m_nSize; }
virtual size_t Tell() const { return m_nCurrentOffset; }
virtual bool Eos() const { return m_nCurrentOffset >= m_nSize; }
virtual bool IsValid() const { return m_fp != NULL; }
size_t GetMaxSize() { return m_nBaseOffset + m_nSize; }
private:
XFileBasedFS* m_pParent;
FILE * m_fp;
std::string strFileName;
size_t m_nBaseOffset;
size_t m_nCurrentOffset;
size_t m_nSize;
bool m_bModified;
};
size_t XFile::Write( const void *pBuf, size_t write_size )
{
#ifdef FILE_PACKER
fseek( m_fp, 0, SEEK_END );
if ( fwrite( pBuf, write_size, 1, m_fp ) != 1 ) return 0;
m_nSize += write_size;
m_bModified = true;
return write_size;
#else
return 0;
#endif
};
size_t XFile::Read( void *pBuf, size_t read_size )
{
if ( m_nCurrentOffset + read_size > m_nSize )
read_size = m_nSize - m_nCurrentOffset;
if ( read_size == 0 ) return 0;
::_fseeki64( m_fp, m_nBaseOffset + m_nCurrentOffset, SEEK_SET );
if ( fread( pBuf, read_size, 1, m_fp ) == 1 )
{
m_nCurrentOffset += read_size;
return read_size;
}
return 0;
}
size_t XFile::Seek( long offset, enum_seek_origin origin )
{
if ( origin == seekCur ) m_nCurrentOffset += offset;
else if ( origin == seekEnd ) m_nCurrentOffset = m_nSize;
else if ( origin == seekSet ) m_nCurrentOffset = offset;
if ( m_nCurrentOffset < 0 ) m_nCurrentOffset = 0;
if ( m_nCurrentOffset > m_nSize ) m_nCurrentOffset = m_nSize;
return m_nCurrentOffset;
}
KStream* XFileBasedFS::open( const char* szFileName, ACCESS_MODE access_mode )
{
if ( !g_pFP )
{
char *szAccessMode = "rb";
if ( access_mode & XFileBasedFS::WRITE ) szAccessMode = "a+b";
g_pFP = NULL;
fopen_s( &g_pFP, m_pInfo->strDataFile.c_str(), szAccessMode );
if ( !g_pFP )
{
// assert( 0 );
return NULL;
}
// 데이터 파일 크기 세팅
fseek( g_pFP, 0, SEEK_END );
m_pInfo->nDataFileSize = (size_t)::_ftelli64( g_pFP );
fseek( g_pFP, 0, SEEK_SET );
}
XFileInfo tag( 0, 0 );
if ( !m_pInfo->hsFileIndex.lookup( szFileName, tag ) )
{
#ifdef FILE_PACKER
m_pInfo->hsFileIndex.add( szFileName, XFileInfo( m_pInfo->nDataFileSize, 0 ) );
return new XFile( this, g_pFP, szFileName, m_pInfo->nDataFileSize, 0 );
#else
return NULL;
#endif
}
else
{
if ( tag.nFileSize == 0 ) return NULL;
#ifdef FILE_PACKER
return new XFile( this, g_pFP, szFileName, tag.nBaseOffset, tag.nFileSize );
#else
return new KEncodedFile( new XFile( this, g_pFP, szFileName, tag.nBaseOffset, tag.nFileSize ) );
#endif
}
}
bool XFileBasedFS::close( XFile *pFile )
{
#ifdef FILE_PACKER
fflush( g_pFP );
if ( pFile->GetMaxSize() > m_pInfo->nDataFileSize )
{
m_pInfo->nDataFileSize = pFile->GetMaxSize();
}
m_pInfo->hsFileIndex.modify( pFile->GetFileName(), XFileInfo( pFile->GetBaseOffset(), pFile->Size() ) );
#endif
return true;
}
XFileBasedFS::XFileBasedFS() : m_pInfo( new XFSInfo )
{
}
XFileBasedFS::~XFileBasedFS()
{
delete m_pInfo;
}
bool XFileBasedFS::initIndexFile( const char *szIndexFileName )
{
m_pInfo->strIndexFile = szIndexFileName;
#ifdef FILE_PACKER
char *szAccessMode = "rb";
#else
char *szAccessMode = "rb";
#endif
FILE *fp = NULL;
fopen_s( &fp, szIndexFileName, szAccessMode );
if ( !fp ) return false;
size_t cnt = 0;
fseek( fp, 0, SEEK_SET );
while ( !feof(fp) )
{
unsigned char name_size;
char szFileName[1024];
size_t offset;
size_t size;
if ( fread( &name_size, 1, 1, fp ) != 1 )
{
break;
}
++cnt;
assert( name_size );
if ( fread( szFileName, name_size, 1, fp ) != 1 ) assert( 0 );
szFileName[name_size] = 0;
for ( unsigned i = 0; i < name_size; ++i ) szFileName[i] -= 80;
if ( fread( &offset, sizeof(offset), 1, fp ) != 1 ) assert( 0 );
if ( fread( &size, sizeof(size), 1, fp ) != 1 ) assert( 0 );
m_pInfo->hsFileIndex.add( szFileName, XFileInfo( offset, size ) );
}
fclose( fp );
return true;
}
bool XFileBasedFS::writeIndexFile()
{
#ifdef FILE_PACKER
FILE *fp = fopen( m_pInfo->strIndexFile.c_str(), "wb" );
if ( !fp ) return false;
FILE *tfp = fopen( "index.txt", "w" );
bool res;
KHash< XFileInfo, hashPr_string_nocase >::node* _node = NULL;
res = m_pInfo->hsFileIndex.get_first_node( _node );
while ( res )
{
size_t nBaseOffset = _node->value.nBaseOffset;
size_t nFileSize = _node->value.nFileSize;
// do something
fprintf( tfp, "%s\n", _node->key.m_pStr );
fprintf( tfp, "%u\n", nBaseOffset );
fprintf( tfp, "%u\n", nFileSize );
unsigned char flen = strlen(_node->key.m_pStr);
char buf[1024];
s_memcpy( buf, sizeof( buf ), _node->key.m_pStr, flen );
for ( int i = 0; i < flen; ++i ) buf[i] += 80;
assert( flen );
if ( fwrite( &flen, 1, 1, fp ) != 1 ) assert( 0 );
if ( fwrite( buf, flen, 1, fp ) != 1 ) assert( 0 );
if ( fwrite( &nBaseOffset, sizeof(nBaseOffset), 1, fp ) != 1 ) assert( 0 );
if ( fwrite( &nFileSize, sizeof(nFileSize), 1, fp ) != 1 ) assert( 0 );
res = m_pInfo->hsFileIndex.get_next_node( _node );
fflush( tfp );
}
fclose( tfp );
fclose( fp );
#endif
return true;
}
size_t XFileBasedFS::getFileSize( const char *szFileName ) const
{
XFileInfo temp( 0, 0 );
if ( !m_pInfo->hsFileIndex.lookup( szFileName, temp ) ) return 0;
return temp.nFileSize;
}
bool XFileBasedFS::Init( const char *szIndexFileName, const char *szDataFileName )
{
// 데이터 파일 오픈
m_pInfo->strDataFile = szDataFileName;
// 인덱스 파일 오픈
return initIndexFile( szIndexFileName );
}
bool XFileBasedFS::DeInit()
{
fclose( g_pFP );
writeIndexFile();
m_pInfo->hsFileIndex.clear();
m_pInfo->strIndexFile = "";
return true;
}