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
2025-04-16 17:05:52 +03:00
template < typename From , typename To >
struct static_caster
{
To operator ()( From p ) { return static_cast < To > ( p );}
};
2025-05-14 15:50:13 +03:00
CLoadFile :: CLoadFile ( const boost :: filesystem :: path & fname , IGameInfoCallback * cb )
2023-11-11 00:39:08 +02:00
: serializer ( this )
2025-04-12 21:25:23 +03:00
, sfile ( fname . c_str (), std :: ios :: in | std :: ios :: binary )
2023-11-11 00:39:08 +02:00
{
2025-04-12 21:25:23 +03:00
serializer . cb = cb ;
2024-07-27 16:51:23 +00:00
serializer . loadingGamestate = true ;
2024-03-28 03:03:44 +01:00
assert ( ! serializer . reverseEndianness );
2023-11-11 00:39:08 +02:00
2025-04-12 21:25:23 +03:00
sfile . exceptions ( std :: ifstream :: failbit | std :: ifstream :: badbit ); //we throw a lot anyway
if ( ! sfile )
2025-04-21 18:41:01 +03:00
throw std :: runtime_error ( "Error: cannot open file '" + fname . string () + "' for reading!" );
2025-04-12 21:25:23 +03:00
2025-04-21 18:41:01 +03:00
static const std :: string MAGIC = "VCMI" ;
std :: string readMagic = MAGIC ;
sfile . read ( readMagic . data (), 4 );
if ( readMagic != MAGIC )
throw std :: runtime_error ( "Error: '" + fname . string () + "' is not a VCMI file!" );
2025-04-12 21:25:23 +03:00
2025-04-16 17:05:52 +03:00
sfile . read ( reinterpret_cast < char *> ( & serializer . version ), sizeof ( serializer . version ));
2025-04-12 21:25:23 +03:00
if ( serializer . version < ESerializationVersion :: MINIMAL )
2025-04-21 18:41:01 +03:00
throw std :: runtime_error ( "Error: too old file format detected in '" + fname . string () + "'!" );
2025-04-12 21:25:23 +03:00
if ( serializer . version > ESerializationVersion :: CURRENT )
2023-11-11 00:39:08 +02:00
{
2025-04-21 18:41:01 +03: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 . string ());
2023-11-11 00:39:08 +02:00
2025-04-12 21:25:23 +03:00
auto * versionptr = reinterpret_cast < char *> ( & serializer . version );
std :: reverse ( versionptr , versionptr + 4 );
logGlobal -> warn ( "Version number reversed is %x, checking..." , vstd :: to_underlying ( serializer . version ));
2023-11-11 00:39:08 +02:00
2025-04-12 21:25:23 +03:00
if ( serializer . version == ESerializationVersion :: CURRENT )
2023-11-11 00:39:08 +02:00
{
2025-04-12 21:25:23 +03:00
logGlobal -> warn ( "%s seems to have different endianness! Entering reversing mode." , fname . string ());
serializer . reverseEndianness = true ;
2023-11-11 00:39:08 +02:00
}
2025-04-12 21:25:23 +03:00
else
2025-04-21 18:41:01 +03:00
throw std :: runtime_error ( "Error: too new file format detected in '" + fname . string () + "'!" );
2023-11-11 00:39:08 +02:00
}
2025-04-12 21:25:23 +03:00
std :: string loaded = SAVEGAME_MAGIC ;
sfile . read ( loaded . data (), SAVEGAME_MAGIC . length ());
if ( loaded != SAVEGAME_MAGIC )
2023-11-11 00:39:08 +02:00
throw std :: runtime_error ( "Magic bytes doesn't match!" );
}
2025-04-12 21:25:23 +03:00
int CLoadFile :: read ( std :: byte * data , unsigned size )
{
sfile . read ( reinterpret_cast < char *> ( data ), size );
return size ;
}
2023-11-11 00:39:08 +02:00
VCMI_LIB_NAMESPACE_END