2023-11-11 00:39:08 +02:00
/*
* CLoadFile . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# include "StdInc.h"
# include "CLoadFile.h"
VCMI_LIB_NAMESPACE_BEGIN
2024-01-20 20:34:51 +02:00
CLoadFile : : CLoadFile ( const boost : : filesystem : : path & fname , ESerializationVersion minimalVersion )
2023-11-11 00:39:08 +02:00
: serializer ( this )
{
openNextFile ( fname , minimalVersion ) ;
}
//must be instantiated in .cpp file for access to complete types of all member fields
CLoadFile : : ~ CLoadFile ( ) = default ;
2024-02-02 02:36:57 +02:00
int CLoadFile : : read ( std : : byte * data , unsigned size )
2023-11-11 00:39:08 +02:00
{
sfile - > read ( reinterpret_cast < char * > ( data ) , size ) ;
return size ;
}
2024-01-20 20:34:51 +02:00
void CLoadFile : : openNextFile ( const boost : : filesystem : : path & fname , ESerializationVersion minimalVersion )
2023-11-11 00:39:08 +02:00
{
2024-07-27 18:51:23 +02:00
serializer . loadingGamestate = true ;
2024-03-28 04:03:44 +02:00
assert ( ! serializer . reverseEndianness ) ;
2024-01-20 20:34:51 +02:00
assert ( minimalVersion < = ESerializationVersion : : CURRENT ) ;
2023-11-11 00:39:08 +02:00
try
{
fName = fname . string ( ) ;
sfile = std : : make_unique < std : : fstream > ( fname . c_str ( ) , std : : ios : : in | std : : ios : : binary ) ;
sfile - > exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ; //we throw a lot anyway
if ( ! ( * sfile ) )
THROW_FORMAT ( " Error: cannot open to read %s! " , fName ) ;
//we can read
char buffer [ 4 ] ;
sfile - > read ( buffer , 4 ) ;
if ( std : : memcmp ( buffer , " VCMI " , 4 ) ! = 0 )
THROW_FORMAT ( " Error: not a VCMI file(%s)! " , fName ) ;
2024-01-20 20:34:51 +02:00
serializer & serializer . version ;
if ( serializer . version < minimalVersion )
2023-11-11 00:39:08 +02:00
THROW_FORMAT ( " Error: too old file format (%s)! " , fName ) ;
2024-01-20 20:34:51 +02:00
if ( serializer . version > ESerializationVersion : : CURRENT )
2023-11-11 00:39:08 +02:00
{
2024-01-20 20:34:51 +02:00
logGlobal - > warn ( " Warning format version mismatch: found %d when current is %d! (file %s) \n " , vstd : : to_underlying ( serializer . version ) , vstd : : to_underlying ( ESerializationVersion : : CURRENT ) , fName ) ;
2023-11-11 00:39:08 +02:00
2024-01-20 20:34:51 +02:00
auto * versionptr = reinterpret_cast < char * > ( & serializer . version ) ;
2023-11-11 00:39:08 +02:00
std : : reverse ( versionptr , versionptr + 4 ) ;
2024-01-20 20:34:51 +02:00
logGlobal - > warn ( " Version number reversed is %x, checking... " , vstd : : to_underlying ( serializer . version ) ) ;
2023-11-11 00:39:08 +02:00
2024-01-20 20:34:51 +02:00
if ( serializer . version = = ESerializationVersion : : CURRENT )
2023-11-11 00:39:08 +02:00
{
logGlobal - > warn ( " %s seems to have different endianness! Entering reversing mode. " , fname . string ( ) ) ;
2024-03-28 04:03:44 +02:00
serializer . reverseEndianness = true ;
2023-11-11 00:39:08 +02:00
}
else
THROW_FORMAT ( " Error: too new file format (%s)! " , fName ) ;
}
}
catch ( . . . )
{
clear ( ) ; //if anything went wrong, we delete file and rethrow
throw ;
}
}
void CLoadFile : : reportState ( vstd : : CLoggerBase * out )
{
out - > debug ( " CLoadFile " ) ;
if ( ! ! sfile & & * sfile )
out - > debug ( " \t Opened %s Position: %d " , fName , sfile - > tellg ( ) ) ;
}
void CLoadFile : : clear ( )
{
sfile = nullptr ;
fName . clear ( ) ;
2024-01-20 20:34:51 +02:00
serializer . version = ESerializationVersion : : NONE ;
2023-11-11 00:39:08 +02:00
}
void CLoadFile : : checkMagicBytes ( const std : : string & text )
{
std : : string loaded = text ;
2024-02-02 02:36:57 +02:00
read ( reinterpret_cast < std : : byte * > ( loaded . data ( ) ) , text . length ( ) ) ;
2023-11-11 00:39:08 +02:00
if ( loaded ! = text )
throw std : : runtime_error ( " Magic bytes doesn't match! " ) ;
}
VCMI_LIB_NAMESPACE_END