Refactor SaveState and RestoreState to use streams
parent
97a8cfe6f9
commit
a66b3d0672
|
@ -36,7 +36,6 @@
|
|||
#include "CBot/CBotCStack.h"
|
||||
#include "CBot/CBotDefParam.h"
|
||||
#include "CBot/CBotUtils.h"
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -364,69 +363,70 @@ void CBotClass::RestoreMethode(long& nIdent,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotClass::SaveStaticState(FILE* pf)
|
||||
bool CBotClass::SaveStaticState(std::ostream &ostr)
|
||||
{
|
||||
if (!WriteWord( pf, CBOTVERSION*2)) return false;
|
||||
if (!WriteLong(ostr, CBOTVERSION*2)) return false;
|
||||
|
||||
// saves the state of static variables in classes
|
||||
for (CBotClass* p : m_publicClasses)
|
||||
{
|
||||
if (!WriteWord( pf, 1 )) return false;
|
||||
if (!WriteWord(ostr, 1)) return false;
|
||||
// save the name of the class
|
||||
if (!WriteString( pf, p->GetName() )) return false;
|
||||
if (!WriteString(ostr, p->GetName())) return false;
|
||||
|
||||
CBotVar* pv = p->GetVar();
|
||||
while( pv != nullptr )
|
||||
{
|
||||
if ( pv->IsStatic() )
|
||||
{
|
||||
if (!WriteWord( pf, 1 )) return false;
|
||||
if (!WriteString( pf, pv->GetName() )) return false;
|
||||
if (!WriteWord(ostr, 1)) return false;
|
||||
if (!WriteString(ostr, pv->GetName())) return false;
|
||||
|
||||
if ( !pv->Save0State(pf) ) return false; // common header
|
||||
if ( !pv->Save1State(pf) ) return false; // saves as the child class
|
||||
if ( !WriteWord( pf, 0 ) ) return false;
|
||||
if (!pv->Save0State(ostr)) return false; // common header
|
||||
if (!pv->Save1State(ostr)) return false; // saves as the child class
|
||||
if (!WriteWord(ostr, 0)) return false;
|
||||
}
|
||||
pv = pv->GetNext();
|
||||
}
|
||||
|
||||
if (!WriteWord( pf, 0 )) return false;
|
||||
if (!WriteWord(ostr, 0)) return false;
|
||||
}
|
||||
|
||||
if (!WriteWord( pf, 0 )) return false;
|
||||
if (!WriteWord(ostr, 0)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotClass::RestoreStaticState(FILE* pf)
|
||||
bool CBotClass::RestoreStaticState(std::istream &istr)
|
||||
{
|
||||
std::string ClassName, VarName;
|
||||
CBotClass* pClass;
|
||||
unsigned short w;
|
||||
|
||||
if (!ReadWord( pf, w )) return false;
|
||||
if ( w != CBOTVERSION*2 ) return false;
|
||||
long version;
|
||||
if (!ReadLong(istr, version)) return false;
|
||||
if (version != CBOTVERSION*2) return false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!ReadWord( pf, w )) return false;
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
if ( w == 0 ) return true;
|
||||
|
||||
if (!ReadString( pf, ClassName )) return false;
|
||||
if (!ReadString(istr, ClassName)) return false;
|
||||
pClass = Find(ClassName);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!ReadWord( pf, w )) return false;
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
if ( w == 0 ) break;
|
||||
|
||||
CBotVar* pVar = nullptr;
|
||||
CBotVar* pv = nullptr;
|
||||
|
||||
if (!ReadString( pf, VarName )) return false;
|
||||
if (!ReadString(istr, VarName)) return false;
|
||||
if ( pClass != nullptr ) pVar = pClass->GetItem(VarName);
|
||||
|
||||
if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable
|
||||
if (!CBotVar::RestoreState(istr, pv)) return false; // the temp variable
|
||||
|
||||
if ( pVar != nullptr ) pVar->Copy(pv);
|
||||
delete pv;
|
||||
|
|
|
@ -331,18 +331,18 @@ public:
|
|||
static void ClearPublic();
|
||||
|
||||
/*!
|
||||
* \brief SaveStaticState
|
||||
* \param pf
|
||||
* \return
|
||||
* \brief Save all static variables from each public class
|
||||
* \param ostr Output stream
|
||||
* \return true on success
|
||||
*/
|
||||
static bool SaveStaticState(FILE* pf);
|
||||
static bool SaveStaticState(std::ostream &ostr);
|
||||
|
||||
/*!
|
||||
* \brief RestoreStaticState
|
||||
* \param pf
|
||||
* \return
|
||||
* \brief Restore all static variables in each public class
|
||||
* \param istr Input stream
|
||||
* \return true on success
|
||||
*/
|
||||
static bool RestoreStaticState(FILE* pf);
|
||||
static bool RestoreStaticState(std::istream &istr);
|
||||
|
||||
/**
|
||||
* \brief Request a lock on this class (for "synchronized" keyword)
|
||||
|
|
|
@ -21,129 +21,251 @@
|
|||
|
||||
#include "CBot/CBotClass.h"
|
||||
#include "CBot/CBotEnums.h"
|
||||
#include "CBot/CBotUtils.h"
|
||||
|
||||
namespace CBot
|
||||
{
|
||||
|
||||
|
||||
// file management
|
||||
|
||||
// necessary because it is not possible to do the fopen in the main program
|
||||
// fwrite and fread in a dll or using the FILE * returned.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
FILE* fOpen(const char* name, const char* mode)
|
||||
template<typename T>
|
||||
static bool WriteBinary(std::ostream &ostr, T value, unsigned padTo = 0)
|
||||
{
|
||||
return fopen(name, mode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int fClose(FILE* filehandle)
|
||||
{
|
||||
return fclose(filehandle);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::size_t fWrite(const void *buffer,
|
||||
std::size_t elemsize,
|
||||
std::size_t length,
|
||||
FILE* filehandle)
|
||||
{
|
||||
return fwrite(buffer, elemsize, length, filehandle);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::size_t fRead(void *buffer,
|
||||
std::size_t elemsize,
|
||||
std::size_t length,
|
||||
FILE* filehandle)
|
||||
{
|
||||
return fread(buffer, elemsize, length, filehandle);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ReadWord(FILE* pf, unsigned short& w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fread(&w, sizeof( unsigned short ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ReadFloat(FILE* pf, float& w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fread(&w, sizeof( float ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool WriteLong(FILE* pf, long w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fwrite(&w, sizeof( long ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ReadLong(FILE* pf, long& w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fread(&w, sizeof( long ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ReadString(FILE* pf, std::string& s)
|
||||
{
|
||||
unsigned short w;
|
||||
char buf[1000];
|
||||
size_t lg1, lg2;
|
||||
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
lg1 = w;
|
||||
lg2 = fread(buf, 1, lg1, pf );
|
||||
buf[lg2] = 0;
|
||||
|
||||
s = buf;
|
||||
return (lg1 == lg2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool WriteType(FILE* pf, const CBotTypResult &type)
|
||||
{
|
||||
int typ = type.GetType();
|
||||
if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
|
||||
if ( !WriteWord(pf, typ) ) return false;
|
||||
if ( typ == CBotTypClass )
|
||||
unsigned char chr;
|
||||
unsigned count = 1;
|
||||
while (value > 127) // unsigned LEB128
|
||||
{
|
||||
CBotClass* p = type.GetClass();
|
||||
if ( !WriteString(pf, p->GetName()) ) return false;
|
||||
++count;
|
||||
chr = (value & 0x7F) | 0x80;
|
||||
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||
value >>= 7;
|
||||
}
|
||||
if ( type.Eq( CBotTypArrayBody ) ||
|
||||
type.Eq( CBotTypArrayPointer ) )
|
||||
chr = value & 0x7F;
|
||||
if (count < padTo) chr |= 0x80;
|
||||
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||
|
||||
if (count < padTo)
|
||||
{
|
||||
if ( !WriteWord(pf, type.GetLimite()) ) return false;
|
||||
if ( !WriteType(pf, type.GetTypElem()) ) return false;
|
||||
while (++count < padTo)
|
||||
if (!(ostr << '\x80')) return false;
|
||||
if (!(ostr << '\x00')) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ReadType(FILE* pf, CBotTypResult &type)
|
||||
template<typename T>
|
||||
static bool ReadBinary(std::istream &istr, T &value)
|
||||
{
|
||||
value = 0;
|
||||
unsigned char chr;
|
||||
unsigned shift = 0;
|
||||
while (true) // unsigned LEB128
|
||||
{
|
||||
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||
if (shift < sizeof(T) * 8 - 1)
|
||||
value |= static_cast<T>(chr & 0x7F) << shift;
|
||||
shift += 7;
|
||||
if ((chr & 0x80) == 0) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool WriteSignedBinary(std::ostream &ostr, T value, unsigned padTo = 0)
|
||||
{
|
||||
signed char sign = value >> (8 * sizeof(T) - 1);
|
||||
unsigned count = 0;
|
||||
while (true) // signed LEB128
|
||||
{
|
||||
++count;
|
||||
unsigned char chr = value & 0x7F;
|
||||
value >>= 7;
|
||||
if (!(value != sign || ((chr ^ sign) & 0x40) != 0))
|
||||
{
|
||||
if (count < padTo) chr |= 0x80;
|
||||
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||
break;
|
||||
}
|
||||
chr |= 0x80;
|
||||
if (!ostr.put(chr)) return false;
|
||||
}
|
||||
|
||||
if (count < padTo)
|
||||
{
|
||||
char chr = (sign < 0) ? 0x7F : 0x00;
|
||||
while (++count < padTo)
|
||||
if (!ostr.put(chr | 0x80)) return false;
|
||||
if (!ostr.put(chr)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool ReadSignedBinary(std::istream &istr, T &value)
|
||||
{
|
||||
value = 0;
|
||||
unsigned char chr;
|
||||
unsigned shift = 0;
|
||||
while (true) // signed LEB128
|
||||
{
|
||||
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||
if (shift < sizeof(T) * 8 - 1)
|
||||
value |= (static_cast<T>(chr & 0x7F) << shift);
|
||||
shift += 7;
|
||||
if ((chr & 0x80) == 0) break;
|
||||
}
|
||||
|
||||
if (shift >= 8 * sizeof(T) - 1) shift = 8 * sizeof(T) - 1;
|
||||
if ((chr & 0x40) != 0)
|
||||
value |= static_cast<T>(-1) << shift;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteWord(std::ostream &ostr, unsigned short w)
|
||||
{
|
||||
return WriteBinary<unsigned short>(ostr, w);
|
||||
}
|
||||
|
||||
bool ReadWord(std::istream &istr, unsigned short &w)
|
||||
{
|
||||
return ReadBinary<unsigned short>(istr, w);
|
||||
}
|
||||
|
||||
bool WriteByte(std::ostream &ostr, char c)
|
||||
{
|
||||
if (!ostr.put(c)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadByte(std::istream &istr, char& c)
|
||||
{
|
||||
if (!istr.get(c)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteShort(std::ostream &ostr, short s)
|
||||
{
|
||||
return WriteSignedBinary<short>(ostr, s);
|
||||
}
|
||||
|
||||
bool ReadShort(std::istream &istr, short &s)
|
||||
{
|
||||
return ReadSignedBinary<short>(istr, s);
|
||||
}
|
||||
|
||||
bool WriteInt(std::ostream &ostr, int i)
|
||||
{
|
||||
return WriteSignedBinary<int>(ostr, i);
|
||||
}
|
||||
|
||||
bool ReadInt(std::istream &istr, int &i)
|
||||
{
|
||||
return ReadSignedBinary<int>(istr, i);
|
||||
}
|
||||
|
||||
bool WriteLong(std::ostream &ostr, long l, unsigned padTo)
|
||||
{
|
||||
return WriteSignedBinary<long>(ostr, l, padTo);
|
||||
}
|
||||
|
||||
bool ReadLong(std::istream &istr, long &l)
|
||||
{
|
||||
return ReadSignedBinary<long>(istr, l);
|
||||
}
|
||||
|
||||
bool WriteFloat(std::ostream &ostr, float f)
|
||||
{
|
||||
union {float fValue; unsigned int iValue;} u;
|
||||
u.fValue = 0.0f;
|
||||
u.iValue = 0;
|
||||
|
||||
u.fValue = f;
|
||||
return WriteBinary<unsigned int>(ostr, u.iValue);
|
||||
}
|
||||
|
||||
bool ReadFloat(std::istream &istr, float &f)
|
||||
{
|
||||
union {float fValue; unsigned int iValue;} u;
|
||||
u.fValue = 0.0f;
|
||||
u.iValue = 0;
|
||||
|
||||
if (!ReadBinary<unsigned int>(istr, u.iValue)) return false;
|
||||
f = u.fValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDouble(std::ostream &ostr, double d)
|
||||
{
|
||||
union {double dValue; unsigned long iValue;} u;
|
||||
u.dValue = 0.0;
|
||||
u.iValue = 0;
|
||||
|
||||
u.dValue = d;
|
||||
return WriteBinary<unsigned long>(ostr, u.iValue);
|
||||
}
|
||||
|
||||
bool ReadDouble(std::istream &istr, double &d)
|
||||
{
|
||||
union {double dValue; unsigned long iValue;} u;
|
||||
u.dValue = 0.0;
|
||||
u.iValue = 0;
|
||||
|
||||
if (!ReadBinary<unsigned long>(istr, u.iValue)) return false;
|
||||
d = u.dValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteString(std::ostream &ostr, const std::string &s)
|
||||
{
|
||||
if (!WriteBinary<size_t>(ostr, s.size())) return false;
|
||||
if (!ostr.write(&(s[0]), s.size())) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadString(std::istream &istr, std::string &s)
|
||||
{
|
||||
size_t length = 0;
|
||||
if (!ReadBinary<size_t>(istr, length)) return false;
|
||||
|
||||
s.resize(length);
|
||||
if (length != 0)
|
||||
{
|
||||
if (!istr.read(&(s[0]), length)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteType(std::ostream &ostr, const CBotTypResult &type)
|
||||
{
|
||||
int typ = type.GetType();
|
||||
if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
|
||||
if ( !WriteWord(ostr, typ) ) return false;
|
||||
if ( typ == CBotTypClass )
|
||||
{
|
||||
CBotClass* p = type.GetClass();
|
||||
if (!WriteString(ostr, p->GetName())) return false;
|
||||
}
|
||||
if ( type.Eq( CBotTypArrayBody ) ||
|
||||
type.Eq( CBotTypArrayPointer ) )
|
||||
{
|
||||
if (!WriteWord(ostr, type.GetLimite())) return false;
|
||||
if (!WriteType(ostr, type.GetTypElem())) return false;
|
||||
}
|
||||
|
||||
if ( type.Eq(CBotTypPointer) )
|
||||
{
|
||||
if (type.GetClass() != nullptr)
|
||||
{
|
||||
if (!WriteString(ostr, type.GetClass()->GetName())) return false;
|
||||
}
|
||||
else if (!WriteString(ostr, "")) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadType(std::istream &istr, CBotTypResult &type)
|
||||
{
|
||||
unsigned short w, ww;
|
||||
if ( !ReadWord(pf, w) ) return false;
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
type.SetType(w);
|
||||
|
||||
if ( type.Eq( CBotTypIntrinsic ) )
|
||||
|
@ -154,7 +276,7 @@ bool ReadType(FILE* pf, CBotTypResult &type)
|
|||
if ( type.Eq( CBotTypClass ) )
|
||||
{
|
||||
std::string s;
|
||||
if ( !ReadString(pf, s) ) return false;
|
||||
if (!ReadString(istr, s)) return false;
|
||||
type = CBotTypResult( w, s );
|
||||
}
|
||||
|
||||
|
@ -162,11 +284,45 @@ bool ReadType(FILE* pf, CBotTypResult &type)
|
|||
type.Eq( CBotTypArrayBody ) )
|
||||
{
|
||||
CBotTypResult r;
|
||||
if ( !ReadWord(pf, ww) ) return false;
|
||||
if ( !ReadType(pf, r) ) return false;
|
||||
if (!ReadWord(istr, ww)) return false;
|
||||
if (!ReadType(istr, r)) return false;
|
||||
type = CBotTypResult( w, r );
|
||||
type.SetLimite(static_cast<short>(ww));
|
||||
}
|
||||
|
||||
if ( type.Eq(CBotTypPointer) )
|
||||
{
|
||||
std::string className;
|
||||
if (!ReadString(istr, className)) return false;
|
||||
type = CBotTypResult(w, className);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteStream(std::ostream &ostr, std::istream& istr)
|
||||
{
|
||||
if (!istr.seekg(0, istr.end)) return false;
|
||||
auto size = istr.tellg();
|
||||
|
||||
if (size == 0) return WriteLong(ostr, 0);
|
||||
if (!WriteLong(ostr, size)) return false;
|
||||
|
||||
if (!istr.seekg(0, istr.beg)) return false;
|
||||
if (!(ostr << istr.rdbuf())) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadStream(std::istream& istr, std::ostream &ostr)
|
||||
{
|
||||
long length;
|
||||
if (!ReadLong(istr, length)) return false;
|
||||
if (length == 0) return true;
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
if (!(ostr << istr.get())) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace CBot
|
||||
|
@ -28,128 +28,173 @@ namespace CBot
|
|||
class CBotVar;
|
||||
class CBotTypResult;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// routines for file management (* FILE)
|
||||
|
||||
/*!
|
||||
* \brief fOpen
|
||||
* \param name
|
||||
* \param mode
|
||||
* \return
|
||||
* \brief Save a linked list if variables
|
||||
* \param ostr Output stream
|
||||
* \param pVar First variable in the list
|
||||
* \return true on success
|
||||
*/
|
||||
FILE* fOpen(const char* name, const char* mode);
|
||||
|
||||
/*!
|
||||
* \brief fClose
|
||||
* \param filehandle
|
||||
* \return
|
||||
*/
|
||||
int fClose(FILE* filehandle);
|
||||
|
||||
/*!
|
||||
* \brief fWrite
|
||||
* \param buffer
|
||||
* \param elemsize
|
||||
* \param length
|
||||
* \param filehandle
|
||||
* \return
|
||||
*/
|
||||
std::size_t fWrite(const void *buffer,
|
||||
std::size_t elemsize,
|
||||
std::size_t length,
|
||||
FILE* filehandle);
|
||||
|
||||
/*!
|
||||
* \brief fRead
|
||||
* \param buffer
|
||||
* \param elemsize
|
||||
* \param length
|
||||
* \param filehandle
|
||||
* \return
|
||||
*/
|
||||
std::size_t fRead(void *buffer,
|
||||
std::size_t elemsize,
|
||||
std::size_t length,
|
||||
FILE* filehandle);
|
||||
|
||||
/*!
|
||||
* \brief SaveVars
|
||||
* \param pf
|
||||
* \param pVar
|
||||
* \return
|
||||
*/
|
||||
bool SaveVars(FILE* pf, CBotVar* pVar);
|
||||
bool SaveVars(std::ostream &ostr, CBotVar* pVar);
|
||||
|
||||
/*!
|
||||
* \brief WriteWord
|
||||
* \param pf
|
||||
* \param ostr Output stream
|
||||
* \param w
|
||||
* \return
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteWord(FILE* pf, unsigned short w);
|
||||
bool WriteWord(std::ostream &ostr, unsigned short w);
|
||||
|
||||
/*!
|
||||
* \brief ReadWord
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
* \param istr Input stream
|
||||
* \param[out] w
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadWord(FILE* pf, unsigned short& w);
|
||||
bool ReadWord(std::istream &istr, unsigned short &w);
|
||||
|
||||
/*!
|
||||
* \brief ReadLong
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
* \brief WriteByte
|
||||
* \param ostr Output stream
|
||||
* \param c
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadLong(FILE* pf, long& w);
|
||||
bool WriteByte(std::ostream &ostr, char c);
|
||||
|
||||
/*!
|
||||
* \brief WriteFloat
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
* \brief ReadByte
|
||||
* \param istr Input stream
|
||||
* \param[out] c
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteFloat(FILE* pf, float w);
|
||||
bool ReadByte(std::istream &istr, char& c);
|
||||
|
||||
/*!
|
||||
* \brief WriteShort
|
||||
* \param ostr Output stream
|
||||
* \param s
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteShort(std::ostream &ostr, short s);
|
||||
|
||||
/*!
|
||||
* \brief ReadShort
|
||||
* \param istr Input stream
|
||||
* \param[out] s
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadShort(std::istream &istr, short &s);
|
||||
|
||||
/*!
|
||||
* \brief WriteInt
|
||||
* \param ostr Output stream
|
||||
* \param i
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteInt(std::ostream &ostr, int i);
|
||||
|
||||
/*!
|
||||
* \brief ReadInt
|
||||
* \param istr Input stream
|
||||
* \param[out] i
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadInt(std::istream &istr, int &i);
|
||||
|
||||
/*!
|
||||
* \brief WriteLong
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
* \param ostr Output stream
|
||||
* \param l
|
||||
* \param padTo minimum number of bytes to write
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteLong(FILE* pf, long w);
|
||||
bool WriteLong(std::ostream &ostr, long l, unsigned padTo = 0);
|
||||
|
||||
/*!
|
||||
* \brief ReadLong
|
||||
* \param istr Input stream
|
||||
* \param[out] l
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadLong(std::istream &istr, long &l);
|
||||
|
||||
/*!
|
||||
* \brief WriteFloat
|
||||
* \param ostr Output stream
|
||||
* \param f
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteFloat(std::ostream &ostr, float f);
|
||||
|
||||
/*!
|
||||
* \brief ReadFloat
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
* \param istr Input stream
|
||||
* \param[out] f
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadFloat(FILE* pf, float& w);
|
||||
bool ReadFloat(std::istream &istr, float &f);
|
||||
|
||||
/*!
|
||||
* \brief WriteDouble
|
||||
* \param ostr Output stream
|
||||
* \param d
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteDouble(std::ostream &ostr, double d);
|
||||
|
||||
/*!
|
||||
* \brief ReadDouble
|
||||
* \param istr Input stream
|
||||
* \param[out] d
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadDouble(std::istream &istr, double &d);
|
||||
|
||||
/*!
|
||||
* \brief WriteString
|
||||
* \param ostr Output stream
|
||||
* \param s
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteString(std::ostream &ostr, const std::string &s);
|
||||
|
||||
/*!
|
||||
* \brief ReadString
|
||||
* \param pf
|
||||
* \param s
|
||||
* \return
|
||||
* \param istr Input stream
|
||||
* \param[out] s
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadString(FILE* pf, std::string& s);
|
||||
bool ReadString(std::istream &istr, std::string &s);
|
||||
|
||||
/*!
|
||||
* \brief WriteType
|
||||
* \param pf
|
||||
* \param ostr Output stream
|
||||
* \param type
|
||||
* \return
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteType(FILE* pf, const CBotTypResult &type);
|
||||
bool WriteType(std::ostream &ostr, const CBotTypResult &type);
|
||||
|
||||
/*!
|
||||
* \brief ReadType
|
||||
* \param pf
|
||||
* \param type
|
||||
* \return
|
||||
* \param istr Input stream
|
||||
* \param[out] type
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadType(FILE* pf, CBotTypResult &type);
|
||||
bool ReadType(std::istream &istr, CBotTypResult &type);
|
||||
|
||||
/*!
|
||||
* \brief WriteStream
|
||||
* \param ostr Output stream
|
||||
* \param istr Input stream
|
||||
* \return true on success
|
||||
*/
|
||||
bool WriteStream(std::ostream &ostr, std::istream& istr);
|
||||
|
||||
/*!
|
||||
* \brief ReadStream
|
||||
* \param istr Input stream
|
||||
* \param ostr Output stream
|
||||
* \return true on success
|
||||
*/
|
||||
bool ReadStream(std::istream& istr, std::ostream &ostr);
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "CBot/CBotCStack.h"
|
||||
#include "CBot/CBotClass.h"
|
||||
#include "CBot/CBotUtils.h"
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include "CBot/CBotInstr/CBotFunction.h"
|
||||
|
||||
|
@ -332,51 +331,56 @@ bool CBotProgram::DefineNum(const std::string& name, long val)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotProgram::SaveState(FILE* pf)
|
||||
bool CBotProgram::SaveState(std::ostream &ostr)
|
||||
{
|
||||
if (!WriteWord( pf, CBOTVERSION)) return false;
|
||||
if (!WriteLong(ostr, CBOTVERSION)) return false;
|
||||
|
||||
|
||||
if (m_stack != nullptr )
|
||||
{
|
||||
if (!WriteWord( pf, 1)) return false;
|
||||
if (!WriteString( pf, m_entryPoint->GetName() )) return false;
|
||||
if (!m_stack->SaveState(pf)) return false;
|
||||
if (!WriteWord(ostr, 1)) return false;
|
||||
if (!WriteString(ostr, m_entryPoint->GetName())) return false;
|
||||
if (!m_stack->SaveState(ostr)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteWord( pf, 0)) return false;
|
||||
if (!WriteWord(ostr, 0)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBotProgram::RestoreState(FILE* pf)
|
||||
bool CBotProgram::RestoreState(std::istream &istr)
|
||||
{
|
||||
unsigned short w;
|
||||
std::string s;
|
||||
|
||||
Stop();
|
||||
|
||||
if (!ReadWord( pf, w )) return false;
|
||||
if ( w != CBOTVERSION ) return false;
|
||||
long version;
|
||||
if (!ReadLong(istr, version)) return false;
|
||||
if ( version != CBOTVERSION ) return false;
|
||||
|
||||
if (!ReadWord( pf, w )) return false;
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
if ( w == 0 ) return true;
|
||||
|
||||
if (!ReadString( pf, s )) return false;
|
||||
Start(s); // point de reprise
|
||||
// don't restore if compile error exists
|
||||
if (m_error != CBotNoErr) return false;
|
||||
|
||||
if (m_stack != nullptr)
|
||||
if (!ReadString(istr, s)) return false;
|
||||
if (!Start(s)) return false; // point de reprise
|
||||
// Start() already created the new stack
|
||||
// and called m_stack->SetProgram(this);
|
||||
|
||||
// retrieves the stack from the memory
|
||||
if (!m_stack->RestoreState(istr, m_stack))
|
||||
{
|
||||
m_stack->Delete();
|
||||
m_stack = nullptr;
|
||||
m_stack = CBotStack::AllocateStack(); // start from the top
|
||||
m_stack->SetProgram(this);
|
||||
return false; // signal error
|
||||
}
|
||||
|
||||
// retrieves the stack from the memory
|
||||
m_stack = CBotStack::AllocateStack();
|
||||
if (!m_stack->RestoreState(pf, m_stack)) return false;
|
||||
m_stack->SetProgram(this); // bases for routines
|
||||
|
||||
// restored some states in the stack according to the structure
|
||||
m_entryPoint->RestoreState(nullptr, m_stack, m_thisVar);
|
||||
return true;
|
||||
|
|
|
@ -282,27 +282,20 @@ public:
|
|||
|
||||
/**
|
||||
* \brief Save the current execution status into a file
|
||||
* \param pf
|
||||
* \parblock
|
||||
* file handle
|
||||
*
|
||||
* This file handle must have been opened by this library! Otherwise crashes on Windows
|
||||
*
|
||||
* TODO: Verify this
|
||||
* \endparblock
|
||||
* \param ostr Output stream
|
||||
* \return true on success, false on write error
|
||||
*/
|
||||
bool SaveState(FILE* pf);
|
||||
bool SaveState(std::ostream &ostr);
|
||||
|
||||
/**
|
||||
* \brief Restore the execution state from a file
|
||||
*
|
||||
* The previous program code must already have been recompiled with Compile() before calling this function
|
||||
*
|
||||
* \param pf file handle
|
||||
* \param istr Input stream
|
||||
* \return true on success, false on read error
|
||||
*/
|
||||
bool RestoreState(FILE* pf);
|
||||
bool RestoreState(std::istream &istr);
|
||||
|
||||
/**
|
||||
* \brief GetPosition Gives the position of a routine in the original text
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "CBot/CBotVar/CBotVarPointer.h"
|
||||
#include "CBot/CBotVar/CBotVarClass.h"
|
||||
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
#include "CBot/CBotUtils.h"
|
||||
#include "CBot/CBotExternalCall.h"
|
||||
|
||||
|
@ -687,108 +686,106 @@ CBotVar* CBotStack::GetStackVars(std::string& functionName, int level)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotStack::SaveState(FILE* pf)
|
||||
bool CBotStack::SaveState(std::ostream &ostr)
|
||||
{
|
||||
if (m_next2 != nullptr)
|
||||
{
|
||||
if (!WriteWord(pf, 2)) return false; // a marker of type (m_next2)
|
||||
if (!m_next2->SaveState(pf)) return false; // saves the next element
|
||||
if (!WriteWord(ostr, 2)) return false; // a marker of type (m_next2)
|
||||
if (!m_next2->SaveState(ostr)) return false; // saves the next element
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteWord(pf, 1)) return false; // a marker of type (m_next)
|
||||
if (!WriteWord(ostr, 1)) return false; // a marker of type (m_next)
|
||||
}
|
||||
if (!WriteWord(pf, static_cast<unsigned short>(m_block))) return false;
|
||||
if (!WriteWord(pf, m_state)) return false;
|
||||
if (!WriteWord(pf, 0)) return false; // for backwards combatibility (m_bDontDelete)
|
||||
if (!WriteWord(pf, m_step)) return false;
|
||||
if (!WriteWord(ostr, static_cast<unsigned short>(m_block))) return false;
|
||||
if (!WriteInt(ostr, m_state)) return false;
|
||||
if (!WriteWord(ostr, 0)) return false; // for backwards combatibility (m_bDontDelete)
|
||||
if (!WriteInt(ostr, m_step)) return false;
|
||||
|
||||
|
||||
if (!SaveVars(pf, m_var)) return false; // current result
|
||||
if (!SaveVars(pf, m_listVar)) return false; // local variables
|
||||
if (!SaveVars(ostr, m_var)) return false; // current result
|
||||
if (!SaveVars(ostr, m_listVar)) return false; // local variables
|
||||
|
||||
if (m_next != nullptr)
|
||||
{
|
||||
if (!m_next->SaveState(pf)) return false; // saves the next element
|
||||
if (!m_next->SaveState(ostr)) return false; // saves the next element
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteWord(pf, 0)) return false; // terminator
|
||||
if (!WriteWord(ostr, 0)) return false; // 0 - CBotStack::SaveState terminator
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveVars(FILE* pf, CBotVar* pVar)
|
||||
bool SaveVars(std::ostream &ostr, CBotVar* pVar)
|
||||
{
|
||||
while (pVar != nullptr)
|
||||
{
|
||||
if (!pVar->Save0State(pf)) return false; // common header
|
||||
if (!pVar->Save1State(pf)) return false; // saves the data
|
||||
if (!pVar->Save0State(ostr)) return false; // common header
|
||||
if (!pVar->Save1State(ostr)) return false; // saves the data
|
||||
|
||||
pVar = pVar->GetNext();
|
||||
}
|
||||
return WriteWord(pf, 0); // terminator
|
||||
return WriteWord(ostr, 0); // 0 - CBot::SaveVars terminator
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
|
||||
bool CBotStack::RestoreState(std::istream &istr, CBotStack* &pStack)
|
||||
{
|
||||
unsigned short w;
|
||||
|
||||
if (pStack != this) pStack = nullptr;
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
if ( w == 0 ) return true; // 0 - terminator
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
if ( w == 0 ) return true; // 0 - CBotStack::SaveState terminator
|
||||
|
||||
if (pStack == nullptr) pStack = AddStack();
|
||||
|
||||
if ( w == 2 ) // 2 - m_next2
|
||||
{
|
||||
if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
|
||||
if (!pStack->RestoreState(istr, pStack->m_next2)) return false;
|
||||
}
|
||||
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
if (!ReadWord(istr, w)) return false;
|
||||
pStack->m_block = static_cast<BlockVisibilityType>(w);
|
||||
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
pStack->SetState(static_cast<short>(w));
|
||||
int state;
|
||||
if (!ReadInt(istr, state)) return false;
|
||||
pStack->SetState(state);
|
||||
|
||||
if (!ReadWord(pf, w)) return false; // backwards compatibility (m_bDontDelete)
|
||||
if (!ReadWord(istr, w)) return false; // backwards compatibility (m_bDontDelete)
|
||||
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
pStack->m_step = w;
|
||||
if (!ReadInt(istr, state)) return false;
|
||||
pStack->m_step = state;
|
||||
|
||||
if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable
|
||||
if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables
|
||||
if (!CBotVar::RestoreState(istr, pStack->m_var)) return false; // temp variable
|
||||
if (!CBotVar::RestoreState(istr, pStack->m_listVar)) return false; // local variables
|
||||
|
||||
return pStack->RestoreState(pf, pStack->m_next);
|
||||
return pStack->RestoreState(istr, pStack->m_next);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVar::Save0State(FILE* pf)
|
||||
bool CBotVar::Save0State(std::ostream &ostr)
|
||||
{
|
||||
if (!WriteWord(pf, 100+static_cast<int>(m_mPrivate)))return false; // private variable?
|
||||
if (!WriteWord(pf, m_bStatic))return false; // static variable?
|
||||
if (!WriteWord(pf, m_type.GetType()))return false; // saves the type (always non-zero)
|
||||
if (!WriteWord(ostr, 100+static_cast<int>(m_mPrivate)))return false; // private variable?
|
||||
if (!WriteWord(ostr, m_bStatic))return false; // static variable?
|
||||
if (!WriteWord(ostr, m_type.GetType()))return false; // saves the type (always non-zero)
|
||||
|
||||
if (m_type.Eq(CBotTypPointer) && GetPointer() != nullptr)
|
||||
{
|
||||
if (GetPointer()->m_bConstructor) // constructor was called?
|
||||
{
|
||||
if (!WriteWord(pf, (2000 + static_cast<unsigned short>(m_binit)) )) return false;
|
||||
return WriteString(pf, m_token->GetString()); // and variable name
|
||||
if (!WriteWord(ostr, (2000 + static_cast<unsigned short>(m_binit)) )) return false;
|
||||
return WriteString(ostr, m_token->GetString()); // and variable name
|
||||
}
|
||||
}
|
||||
|
||||
if (!WriteWord(pf, static_cast<unsigned short>(m_binit))) return false; // variable defined?
|
||||
return WriteString(pf, m_token->GetString()); // and variable name
|
||||
if (!WriteWord(ostr, static_cast<unsigned short>(m_binit))) return false; // variable defined?
|
||||
return WriteString(ostr, m_token->GetString()); // and variable name
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||
bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar)
|
||||
{
|
||||
unsigned short w, wi, prv, st;
|
||||
float ww;
|
||||
std::string name, s;
|
||||
|
||||
delete pVar;
|
||||
|
||||
|
@ -798,27 +795,27 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
|||
|
||||
while ( true ) // retrieves a list
|
||||
{
|
||||
if (!ReadWord(pf, w)) return false; // private or type?
|
||||
if ( w == 0 ) return true;
|
||||
if (!ReadWord(istr, w)) return false; // private or type?
|
||||
if ( w == 0 ) return true; // 0 - CBot::SaveVars terminator
|
||||
|
||||
std::string defnum;
|
||||
if ( w == 200 )
|
||||
{
|
||||
if (!ReadString(pf, defnum)) return false; // number with identifier
|
||||
if (!ReadWord(pf, w)) return false; // type
|
||||
if (!ReadString(istr, defnum)) return false; // number with identifier
|
||||
if (!ReadWord(istr, w)) return false; // type
|
||||
}
|
||||
|
||||
prv = 100; st = 0;
|
||||
if ( w >= 100 )
|
||||
{
|
||||
prv = w;
|
||||
if (!ReadWord(pf, st)) return false; // static
|
||||
if (!ReadWord(pf, w)) return false; // type
|
||||
if (!ReadWord(istr, st)) return false; // static
|
||||
if (!ReadWord(istr, w)) return false; // type
|
||||
}
|
||||
|
||||
if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
|
||||
|
||||
if (!ReadWord(pf, wi)) return false; // init ?
|
||||
if (!ReadWord(istr, wi)) return false; // init ?
|
||||
bool bConstructor = false;
|
||||
if (w == CBotTypPointer && wi >= 2000)
|
||||
{
|
||||
|
@ -827,31 +824,40 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
|||
}
|
||||
|
||||
CBotVar::InitType initType = static_cast<CBotVar::InitType>(wi);
|
||||
if (!ReadString(pf, name)) return false; // variable name
|
||||
|
||||
CBotToken token(name, std::string());
|
||||
std::string varname;
|
||||
if (!ReadString(istr, varname)) return false; // variable name
|
||||
CBotToken token(varname, std::string());
|
||||
|
||||
bool isClass = false;
|
||||
|
||||
switch (w)
|
||||
{
|
||||
case CBotTypInt:
|
||||
case CBotTypBoolean:
|
||||
char valByte;
|
||||
if (!ReadByte(istr, valByte)) return false;
|
||||
pNew = CBotVar::Create(token, w); // creates a variable
|
||||
if (!ReadWord(pf, w)) return false;
|
||||
pNew->SetValInt(static_cast<short>(w), defnum);
|
||||
pNew->SetValInt(valByte);
|
||||
break;
|
||||
case CBotTypInt:
|
||||
int valInt;
|
||||
if (!ReadInt(istr, valInt)) return false;
|
||||
pNew = CBotVar::Create(token, w); // creates a variable
|
||||
pNew->SetValInt(valInt, defnum);
|
||||
break;
|
||||
case CBotTypFloat:
|
||||
float valFloat;
|
||||
if (!ReadFloat(istr, valFloat)) return false;
|
||||
pNew = CBotVar::Create(token, w); // creates a variable
|
||||
if (!ReadFloat(pf, ww)) return false;
|
||||
pNew->SetValFloat(ww);
|
||||
pNew->SetValFloat(valFloat);
|
||||
break;
|
||||
case CBotTypString:
|
||||
pNew = CBotVar::Create(token, w); // creates a variable
|
||||
if (!ReadString(pf, s)) return false;
|
||||
pNew->SetValString(s);
|
||||
break;
|
||||
|
||||
{
|
||||
std::string valString;
|
||||
if (!ReadString(istr, valString)) return false;
|
||||
pNew = CBotVar::Create(token, w); // creates a variable
|
||||
pNew->SetValString(valString);
|
||||
break;
|
||||
}
|
||||
// returns an intrinsic object or element of an array
|
||||
case CBotTypIntrinsic:
|
||||
isClass = true;
|
||||
|
@ -859,17 +865,16 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
|||
{
|
||||
CBotTypResult r;
|
||||
long id;
|
||||
if (!ReadType(pf, r)) return false; // complete type
|
||||
if (!ReadLong(pf, id) ) return false;
|
||||
if (!ReadType(istr, r)) return false; // complete type
|
||||
if (!ReadLong(istr, id)) return false;
|
||||
|
||||
// if (!ReadString(pf, s)) return false;
|
||||
{
|
||||
CBotVar* p = nullptr;
|
||||
if ( id ) p = CBotVarClass::Find(id) ;
|
||||
|
||||
pNew = new CBotVarClass(token, r); // directly creates an instance
|
||||
// attention cptuse = 0
|
||||
if ( !RestoreState(pf, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false;
|
||||
if (!RestoreState(istr, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false;
|
||||
pNew->SetIdent(id);
|
||||
|
||||
if (isClass && p == nullptr) // set id for each item in this instance
|
||||
|
@ -895,18 +900,20 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
|||
|
||||
case CBotTypPointer:
|
||||
case CBotTypNullPointer:
|
||||
if (!ReadString(pf, s)) return false; // name of the class
|
||||
{
|
||||
std::string className;
|
||||
if (!ReadString(istr, className)) return false; // name of the class
|
||||
{
|
||||
CBotTypResult ptrType(w, s);
|
||||
pNew = CBotVar::Create(token, ptrType);// creates a variable
|
||||
// CBotVarClass* p = nullptr;
|
||||
long id;
|
||||
ReadLong(pf, id);
|
||||
if (!ReadLong(istr, id)) return false;
|
||||
// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
|
||||
|
||||
CBotTypResult ptrType(w, className);
|
||||
pNew = CBotVar::Create(token, ptrType); // creates a variable
|
||||
// returns a copy of the original instance
|
||||
CBotVar* pInstance = nullptr;
|
||||
if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
|
||||
if (!CBotVar::RestoreState(istr, pInstance)) return false;
|
||||
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
||||
|
||||
if (bConstructor) pNew->ConstructorSet(); // constructor was called
|
||||
|
@ -916,22 +923,22 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
|||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case CBotTypArrayPointer:
|
||||
{
|
||||
CBotTypResult r;
|
||||
if (!ReadType(pf, r)) return false;
|
||||
if (!ReadType(istr, r)) return false;
|
||||
|
||||
pNew = CBotVar::Create(token, r); // creates a variable
|
||||
|
||||
// returns a copy of the original instance
|
||||
CBotVar* pInstance = nullptr;
|
||||
if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
|
||||
if (!CBotVar::RestoreState(istr, pInstance)) return false;
|
||||
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return false; // signal error
|
||||
}
|
||||
|
||||
if ( pPrev != nullptr ) pPrev->m_next = pNew;
|
||||
|
|
|
@ -434,8 +434,8 @@ public:
|
|||
//! \name Write to file
|
||||
//@{
|
||||
|
||||
bool SaveState(FILE* pf);
|
||||
bool RestoreState(FILE* pf, CBotStack* &pStack);
|
||||
bool SaveState(std::ostream &ostr);
|
||||
bool RestoreState(std::istream &istr, CBotStack* &pStack);
|
||||
|
||||
//@}
|
||||
|
||||
|
|
|
@ -108,38 +108,6 @@ CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
|
|||
return type;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool WriteWord(FILE* pf, unsigned short w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool WriteString(FILE* pf, std::string s)
|
||||
{
|
||||
size_t lg1, lg2;
|
||||
|
||||
lg1 = s.size();
|
||||
if (!WriteWord(pf, lg1)) return false;
|
||||
|
||||
lg2 = fwrite(s.c_str(), 1, lg1, pf );
|
||||
return (lg1 == lg2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool WriteFloat(FILE* pf, float w)
|
||||
{
|
||||
size_t lg;
|
||||
|
||||
lg = fwrite(&w, sizeof( float ), 1, pf );
|
||||
|
||||
return (lg == 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
long GetNumInt(const std::string& str)
|
||||
{
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "CBot/CBotTypResult.h"
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
|
@ -31,6 +30,8 @@ namespace CBot
|
|||
class CBotVar;
|
||||
class CBotToken;
|
||||
class CBotCStack;
|
||||
class CBotTypResult;
|
||||
|
||||
|
||||
/*!
|
||||
* \brief MakeListVars Transforms the array of pointers to variables in a
|
||||
|
@ -58,30 +59,6 @@ CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile);
|
|||
*/
|
||||
CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type);
|
||||
|
||||
/*!
|
||||
* \brief WriteWord
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
*/
|
||||
bool WriteWord(FILE* pf, unsigned short w);
|
||||
|
||||
/*!
|
||||
* \brief WriteString
|
||||
* \param pf
|
||||
* \param s
|
||||
* \return
|
||||
*/
|
||||
bool WriteString(FILE* pf, std::string s);
|
||||
|
||||
/*!
|
||||
* \brief WriteFloat
|
||||
* \param pf
|
||||
* \param w
|
||||
* \return
|
||||
*/
|
||||
bool WriteFloat(FILE* pf, float w);
|
||||
|
||||
/*!
|
||||
* \brief GetNumInt Converts a string into integer may be of the form 0xabc123.
|
||||
* \param str
|
||||
|
|
|
@ -134,7 +134,7 @@ void* CBotVar::GetUserPtr()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVar::Save1State(FILE* pf)
|
||||
bool CBotVar::Save1State(std::ostream &ostr)
|
||||
{
|
||||
// this routine "virtual" must never be called,
|
||||
// there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc)
|
||||
|
|
|
@ -623,28 +623,28 @@ public:
|
|||
|
||||
/**
|
||||
* \brief Save common variable header (name, type, etc.)
|
||||
* \param pf file pointer
|
||||
* \param ostr Output stream
|
||||
* \return false on write error
|
||||
*/
|
||||
virtual bool Save0State(FILE* pf);
|
||||
virtual bool Save0State(std::ostream &ostr);
|
||||
|
||||
/**
|
||||
* \brief Save variable data
|
||||
*
|
||||
* Overriden in child classes
|
||||
*
|
||||
* \param pf file pointer
|
||||
* \param ostr Output stream
|
||||
* \return false on write error
|
||||
*/
|
||||
virtual bool Save1State(FILE* pf);
|
||||
virtual bool Save1State(std::ostream &ostr);
|
||||
|
||||
/**
|
||||
* \brief Restore variable
|
||||
* \param pf file pointer
|
||||
* \param istr Input stream
|
||||
* \param[out] pVar Pointer to recieve the variable
|
||||
* \return false on read error
|
||||
*/
|
||||
static bool RestoreState(FILE* pf, CBotVar* &pVar);
|
||||
static bool RestoreState(std::istream &istr, CBotVar* &pVar);
|
||||
|
||||
//@}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "CBot/CBotVar/CBotVarArray.h"
|
||||
#include "CBot/CBotVar/CBotVarClass.h"
|
||||
#include "CBot/CBotToken.h"
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include "CBot/CBotEnums.h"
|
||||
|
||||
|
@ -137,10 +136,10 @@ std::string CBotVarArray::GetValString()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVarArray::Save1State(FILE* pf)
|
||||
bool CBotVarArray::Save1State(std::ostream &ostr)
|
||||
{
|
||||
if ( !WriteType(pf, m_type) ) return false;
|
||||
return SaveVars(pf, m_pInstance); // saves the instance that manages the table
|
||||
if (!WriteType(ostr, m_type)) return false;
|
||||
return SaveVars(ostr, m_pInstance); // saves the instance that manages the table
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
std::string GetValString() override;
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
|
||||
private:
|
||||
//! Array data
|
||||
|
|
|
@ -40,9 +40,9 @@ void CBotVarBoolean::Not()
|
|||
SetValInt(!GetValInt());
|
||||
}
|
||||
|
||||
bool CBotVarBoolean::Save1State(FILE* pf)
|
||||
bool CBotVarBoolean::Save1State(std::ostream &ostr)
|
||||
{
|
||||
return WriteWord(pf, m_val); // the value of the variable
|
||||
return WriteByte(ostr, m_val); // the value of the variable
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
void XOr(CBotVar* left, CBotVar* right) override;
|
||||
void Not() override;
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include "CBot/CBotStack.h"
|
||||
#include "CBot/CBotDefines.h"
|
||||
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include "CBot/CBotInstr/CBotInstr.h"
|
||||
|
||||
#include <cassert>
|
||||
|
@ -464,12 +462,12 @@ bool CBotVarClass::Ne(CBotVar* left, CBotVar* right)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVarClass::Save1State(FILE* pf)
|
||||
bool CBotVarClass::Save1State(std::ostream &ostr)
|
||||
{
|
||||
if ( !WriteType(pf, m_type) ) return false;
|
||||
if ( !WriteLong(pf, m_ItemIdent) ) return false;
|
||||
if (!WriteType(ostr, m_type)) return false;
|
||||
if (!WriteLong(ostr, m_ItemIdent)) return false;
|
||||
|
||||
return SaveVars(pf, m_pVar); // content of the object
|
||||
return SaveVars(ostr, m_pVar); // content of the object
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
CBotVar* GetItemList() override;
|
||||
std::string GetValString() override;
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
|
||||
void Update(void* pUser) override;
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
namespace CBot
|
||||
{
|
||||
|
||||
bool CBotVarFloat::Save1State(FILE* pf)
|
||||
bool CBotVarFloat::Save1State(std::ostream &ostr)
|
||||
{
|
||||
return WriteFloat(pf, m_val); // the value of the variable
|
||||
return WriteFloat(ostr, m_val); // the value of the variable
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -32,7 +32,7 @@ class CBotVarFloat : public CBotVarNumber<float, CBotTypFloat>
|
|||
public:
|
||||
CBotVarFloat(const CBotToken &name) : CBotVarNumber(name) {}
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -45,17 +45,17 @@ std::string CBotVarInt::GetValString()
|
|||
void CBotVarInt::Neg()
|
||||
{
|
||||
CBotVarNumber::Neg();
|
||||
m_defnum.empty();
|
||||
m_defnum.clear();
|
||||
}
|
||||
void CBotVarInt::Inc()
|
||||
{
|
||||
CBotVarNumber::Inc();
|
||||
m_defnum.empty();
|
||||
m_defnum.clear();
|
||||
}
|
||||
void CBotVarInt::Dec()
|
||||
{
|
||||
CBotVarNumber::Dec();
|
||||
m_defnum.empty();
|
||||
m_defnum.clear();
|
||||
}
|
||||
|
||||
void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
|
||||
|
@ -90,22 +90,23 @@ void CBotVarInt::SR(CBotVar* left, CBotVar* right)
|
|||
void CBotVarInt::Not()
|
||||
{
|
||||
m_val = ~m_val;
|
||||
m_defnum.clear();
|
||||
}
|
||||
|
||||
bool CBotVarInt::Save0State(FILE* pf)
|
||||
bool CBotVarInt::Save0State(std::ostream &ostr)
|
||||
{
|
||||
if (!m_defnum.empty())
|
||||
{
|
||||
if(!WriteWord(pf, 200)) return false; // special marker
|
||||
if(!WriteString(pf, m_defnum)) return false;
|
||||
if(!WriteWord(ostr, 200)) return false; // special marker
|
||||
if(!WriteString(ostr, m_defnum)) return false;
|
||||
}
|
||||
|
||||
return CBotVar::Save0State(pf);
|
||||
return CBotVar::Save0State(ostr);
|
||||
}
|
||||
|
||||
bool CBotVarInt::Save1State(FILE* pf)
|
||||
bool CBotVarInt::Save1State(std::ostream &ostr)
|
||||
{
|
||||
return WriteWord(pf, m_val);
|
||||
return WriteInt(ostr, m_val);
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -50,8 +50,8 @@ public:
|
|||
void SR(CBotVar* left, CBotVar* right) override;
|
||||
void ASR(CBotVar* left, CBotVar* right) override;
|
||||
|
||||
bool Save0State(FILE* pf) override;
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save0State(std::ostream &ostr) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
|
||||
protected:
|
||||
//! The name if given by DefineNum.
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include "CBot/CBotEnums.h"
|
||||
#include "CBot/CBotUtils.h"
|
||||
#include "CBot/CBotFileUtils.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
@ -171,21 +170,21 @@ CBotClass* CBotVarPointer::GetClass()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotVarPointer::Save1State(FILE* pf)
|
||||
bool CBotVarPointer::Save1State(std::ostream &ostr)
|
||||
{
|
||||
if ( m_type.GetClass() != nullptr )
|
||||
{
|
||||
if (!WriteString(pf, m_type.GetClass()->GetName())) return false; // name of the class
|
||||
if (!WriteString(ostr, m_type.GetClass()->GetName())) return false; // name of the class
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteString(pf, "")) return false;
|
||||
if (!WriteString(ostr, "")) return false;
|
||||
}
|
||||
|
||||
if (!WriteLong(pf, GetIdent())) return false; // the unique reference
|
||||
if (!WriteLong(ostr, GetIdent())) return false; // the unique reference
|
||||
|
||||
// also saves the proceedings copies
|
||||
return SaveVars(pf, GetPointer());
|
||||
return SaveVars(ostr, GetPointer());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
|
||||
void ConstructorSet() override;
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
|
||||
void Update(void* pUser) override;
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ bool CBotVarString::Ne(CBotVar* left, CBotVar* right)
|
|||
return left->GetValString() != right->GetValString();
|
||||
}
|
||||
|
||||
bool CBotVarString::Save1State(FILE* pf)
|
||||
bool CBotVarString::Save1State(std::ostream &ostr)
|
||||
{
|
||||
return WriteString(pf, m_val);
|
||||
return WriteString(ostr, m_val);
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
bool Eq(CBotVar* left, CBotVar* right) override;
|
||||
bool Ne(CBotVar* left, CBotVar* right) override;
|
||||
|
||||
bool Save1State(FILE* pf) override;
|
||||
bool Save1State(std::ostream &ostr) override;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
|
|
|
@ -86,7 +86,10 @@ template <typename T, CBotType type>
|
|||
class CBotVarNumberBase : public CBotVarValue<T, type>
|
||||
{
|
||||
public:
|
||||
CBotVarNumberBase(const CBotToken &name) : CBotVarValue<T, type>(name) {}
|
||||
CBotVarNumberBase(const CBotToken &name) : CBotVarValue<T, type>(name)
|
||||
{
|
||||
this->m_val = static_cast<T>(0);
|
||||
}
|
||||
|
||||
void SetValInt(int val, const std::string &s = "") override
|
||||
{
|
||||
|
|
|
@ -4449,10 +4449,8 @@ void CRobotMain::SaveOneScript(CObject *obj)
|
|||
}
|
||||
|
||||
//! Saves the stack of the program in execution of a robot
|
||||
bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank)
|
||||
bool CRobotMain::SaveFileStack(CObject *obj, std::ostream &ostr)
|
||||
{
|
||||
if (objRank == -1) return true;
|
||||
|
||||
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
||||
|
||||
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
||||
|
@ -4460,14 +4458,24 @@ bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank)
|
|||
ObjectType type = obj->GetType();
|
||||
if (type == OBJECT_HUMAN) return true;
|
||||
|
||||
return programmable->WriteStack(file);
|
||||
long status = 1;
|
||||
std::stringstream sstr("");
|
||||
|
||||
if (!programmable->WriteStack(sstr))
|
||||
{
|
||||
GetLogger()->Error("WriteStack failed at object id = %i\n", obj->GetID());
|
||||
status = 100; // marked bad
|
||||
}
|
||||
|
||||
if (!CBot::WriteLong(ostr, status)) return false;
|
||||
if (!CBot::WriteStream(ostr, sstr)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Resumes the execution stack of the program in a robot
|
||||
bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
|
||||
bool CRobotMain::ReadFileStack(CObject *obj, std::istream &istr)
|
||||
{
|
||||
if (objRank == -1) return true;
|
||||
|
||||
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
||||
|
||||
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
||||
|
@ -4475,7 +4483,29 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
|
|||
ObjectType type = obj->GetType();
|
||||
if (type == OBJECT_HUMAN) return true;
|
||||
|
||||
return programmable->ReadStack(file);
|
||||
long status;
|
||||
if (!CBot::ReadLong(istr, status)) return false;
|
||||
|
||||
if (status == 100) // was marked bad ?
|
||||
{
|
||||
if (!CBot::ReadLong(istr, status)) return false;
|
||||
if (!istr.seekg(status, istr.cur)) return false;
|
||||
return true; // next program
|
||||
}
|
||||
|
||||
if (status == 1)
|
||||
{
|
||||
std::stringstream sstr("");
|
||||
if (!CBot::ReadStream(istr, sstr)) return false;
|
||||
|
||||
if (!programmable->ReadStack(sstr))
|
||||
{
|
||||
GetLogger()->Error("ReadStack failed at object id = %i\n", obj->GetID());
|
||||
}
|
||||
return true; // next program
|
||||
}
|
||||
|
||||
return false; // error: status == ??
|
||||
}
|
||||
|
||||
std::vector<std::string> CRobotMain::GetNewScriptNames(ObjectType type)
|
||||
|
@ -4670,25 +4700,36 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
|
|||
}
|
||||
|
||||
// Writes the file of stacks of execution.
|
||||
FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "wb");
|
||||
if (file == nullptr) return false;
|
||||
COutputStream ostr(filecbot);
|
||||
if (!ostr.is_open()) return false;
|
||||
|
||||
bool bError = false;
|
||||
long version = 1;
|
||||
CBot::fWrite(&version, sizeof(long), 1, file); // version of COLOBOT
|
||||
CBot::WriteLong(ostr, version); // version of COLOBOT
|
||||
version = CBot::CBotProgram::GetVersion();
|
||||
CBot::fWrite(&version, sizeof(long), 1, file); // version of CBOT
|
||||
CBot::WriteLong(ostr, version); // version of CBOT
|
||||
CBot::WriteWord(ostr, 0); // TODO
|
||||
|
||||
objRank = 0;
|
||||
for (CObject* obj : m_objMan->GetAllObjects())
|
||||
{
|
||||
if (obj->GetType() == OBJECT_TOTO) continue;
|
||||
if (IsObjectBeingTransported(obj)) continue;
|
||||
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
||||
|
||||
if (!SaveFileStack(obj, file, objRank++)) break;
|
||||
if (!SaveFileStack(obj, ostr))
|
||||
{
|
||||
GetLogger()->Error("SaveFileStack failed at object id = %i\n", obj->GetID());
|
||||
bError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CBot::CBotClass::SaveStaticState(file);
|
||||
CBot::fClose(file);
|
||||
|
||||
if (!bError && !CBot::CBotClass::SaveStaticState(ostr))
|
||||
{
|
||||
GetLogger()->Error("CBotClass save static state failed\n");
|
||||
}
|
||||
|
||||
ostr.close();
|
||||
|
||||
if (!emergencySave)
|
||||
{
|
||||
|
@ -4846,29 +4887,48 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
|
|||
m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE);
|
||||
|
||||
// Reads the file of stacks of execution.
|
||||
FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "rb");
|
||||
if (file != nullptr)
|
||||
CInputStream istr(filecbot);
|
||||
|
||||
if (istr.is_open())
|
||||
{
|
||||
long version;
|
||||
CBot::fRead(&version, sizeof(long), 1, file); // version of COLOBOT
|
||||
bool bError = false;
|
||||
long version = 0;
|
||||
CBot::ReadLong(istr, version); // version of COLOBOT
|
||||
if (version == 1)
|
||||
{
|
||||
CBot::fRead(&version, sizeof(long), 1, file); // version of CBOT
|
||||
CBot::ReadLong(istr, version); // version of CBOT
|
||||
if (version == CBot::CBotProgram::GetVersion())
|
||||
{
|
||||
objRank = 0;
|
||||
for (CObject* obj : m_objMan->GetAllObjects())
|
||||
unsigned short flag;
|
||||
CBot::ReadWord(istr, flag); // TODO
|
||||
bError = (flag != 0);
|
||||
|
||||
if (!bError) for (CObject* obj : m_objMan->GetAllObjects())
|
||||
{
|
||||
if (obj->GetType() == OBJECT_TOTO) continue;
|
||||
if (IsObjectBeingTransported(obj)) continue;
|
||||
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
||||
|
||||
if (!ReadFileStack(obj, file, objRank++)) break;
|
||||
if (!ReadFileStack(obj, istr))
|
||||
{
|
||||
GetLogger()->Error("ReadFileStack failed at object id = %i\n", obj->GetID());
|
||||
bError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bError && !CBot::CBotClass::RestoreStaticState(istr))
|
||||
{
|
||||
GetLogger()->Error("CBotClass restore static state failed\n");
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
GetLogger()->Error("cbot.run file is wrong version: %i\n", version);
|
||||
}
|
||||
CBot::CBotClass::RestoreStaticState(file);
|
||||
CBot::fClose(file);
|
||||
|
||||
if (bError) GetLogger()->Error("Restoring CBOT state failed at stream position: %li\n", istr.tellg());
|
||||
istr.close();
|
||||
}
|
||||
|
||||
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
|
||||
|
|
|
@ -308,8 +308,8 @@ public:
|
|||
|
||||
void SaveAllScript();
|
||||
void SaveOneScript(CObject *obj);
|
||||
bool SaveFileStack(CObject *obj, FILE *file, int objRank);
|
||||
bool ReadFileStack(CObject *obj, FILE *file, int objRank);
|
||||
bool SaveFileStack(CObject *obj, std::ostream &ostr);
|
||||
bool ReadFileStack(CObject *obj, std::istream &istr);
|
||||
|
||||
//! Return list of scripts to load to robot created in BotFactory
|
||||
std::vector<std::string> GetNewScriptNames(ObjectType type);
|
||||
|
|
|
@ -143,24 +143,43 @@ bool CProgrammableObjectImpl::IsProgram()
|
|||
|
||||
// Load a stack of script implementation from a file.
|
||||
|
||||
bool CProgrammableObjectImpl::ReadStack(FILE *file)
|
||||
bool CProgrammableObjectImpl::ReadStack(std::istream &istr)
|
||||
{
|
||||
short op;
|
||||
|
||||
CBot::fRead(&op, sizeof(short), 1, file);
|
||||
if (!CBot::ReadShort(istr, op)) return false;
|
||||
if ( op == 1 ) // run ?
|
||||
{
|
||||
CBot::fRead(&op, sizeof(short), 1, file); // program rank
|
||||
if (!CBot::ReadShort(istr, op)) return false; // program rank
|
||||
if ( op >= 0 )
|
||||
{
|
||||
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
||||
{
|
||||
assert(op < static_cast<int>(dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramCount()));
|
||||
int count = static_cast<int>(dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramCount());
|
||||
if (!(op < count))
|
||||
{
|
||||
GetLogger()->Info("Object program count: %i\n", count);
|
||||
GetLogger()->Error("Error in file: program index out of range: %i\n", op);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_currentProgram = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgram(op);
|
||||
if ( !m_currentProgram->script->ReadStack(file) ) return false;
|
||||
if (!m_currentProgram->script->ReadStack(istr))
|
||||
{
|
||||
GetLogger()->Error("Restore state failed at program index: %i\n", op);
|
||||
int errNum = m_currentProgram->script->GetError();
|
||||
if (errNum != 0)
|
||||
{
|
||||
std::string errStr;
|
||||
m_currentProgram->script->GetError(errStr);
|
||||
GetLogger()->Error("Program reports error: %i:(%s)\n", errNum, errStr.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetLogger()->Error("Object is not a program storage object\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +190,7 @@ bool CProgrammableObjectImpl::ReadStack(FILE *file)
|
|||
|
||||
// Save the script implementation stack of a file.
|
||||
|
||||
bool CProgrammableObjectImpl::WriteStack(FILE *file)
|
||||
bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr)
|
||||
{
|
||||
short op;
|
||||
|
||||
|
@ -179,21 +198,25 @@ bool CProgrammableObjectImpl::WriteStack(FILE *file)
|
|||
m_currentProgram->script->IsRunning() )
|
||||
{
|
||||
op = 1; // run
|
||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
||||
if (!CBot::WriteShort(ostr, op)) return false;
|
||||
|
||||
op = -1;
|
||||
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
||||
{
|
||||
op = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramIndex(m_currentProgram);
|
||||
}
|
||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
||||
if (!CBot::WriteShort(ostr, op)) return false;
|
||||
|
||||
return m_currentProgram->script->WriteStack(file);
|
||||
if (!m_currentProgram->script->WriteStack(ostr))
|
||||
{
|
||||
GetLogger()->Error("Save state failed at program index: %i\n", op);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
op = 0; // stop
|
||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
||||
return true;
|
||||
return CBot::WriteShort(ostr, op);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ public:
|
|||
Program* GetCurrentProgram() override;
|
||||
void StopProgram() override;
|
||||
|
||||
bool ReadStack(FILE *file) override;
|
||||
bool WriteStack(FILE *file) override;
|
||||
bool ReadStack(std::istream &istr) override;
|
||||
bool WriteStack(std::ostream &ostr) override;
|
||||
|
||||
void TraceRecordStart() override;
|
||||
void TraceRecordStop() override;
|
||||
|
|
|
@ -53,9 +53,9 @@ public:
|
|||
virtual bool IsProgram() = 0;
|
||||
|
||||
//! Save current execution status to file
|
||||
virtual bool WriteStack(FILE *file) = 0;
|
||||
virtual bool WriteStack(std::ostream &ostr) = 0;
|
||||
//! Read current execution status from file
|
||||
virtual bool ReadStack(FILE *file) = 0;
|
||||
virtual bool ReadStack(std::istream &istr) = 0;
|
||||
|
||||
//! Start recording trace
|
||||
virtual void TraceRecordStart() = 0;
|
||||
|
|
|
@ -1032,16 +1032,16 @@ bool CScript::WriteScript(const char* filename)
|
|||
|
||||
// Reads a stack of script by execution as a file.
|
||||
|
||||
bool CScript::ReadStack(FILE *file)
|
||||
bool CScript::ReadStack(std::istream &istr)
|
||||
{
|
||||
int nb;
|
||||
|
||||
CBot::fRead(&nb, sizeof(int), 1, file);
|
||||
CBot::fRead(&m_ipf, sizeof(int), 1, file);
|
||||
CBot::fRead(&m_errMode, sizeof(int), 1, file);
|
||||
if (!CBot::ReadInt(istr, nb)) return false;
|
||||
if (!CBot::ReadInt(istr, m_ipf)) return false;
|
||||
if (!CBot::ReadInt(istr, m_errMode)) return false;
|
||||
|
||||
if (m_botProg == nullptr) return false;
|
||||
if ( !m_botProg->RestoreState(file) ) return false;
|
||||
if (!m_botProg->RestoreState(istr)) return false;
|
||||
|
||||
m_bRun = true;
|
||||
m_bContinue = false;
|
||||
|
@ -1050,16 +1050,16 @@ bool CScript::ReadStack(FILE *file)
|
|||
|
||||
// Writes a stack of script by execution as a file.
|
||||
|
||||
bool CScript::WriteStack(FILE *file)
|
||||
bool CScript::WriteStack(std::ostream &ostr)
|
||||
{
|
||||
int nb;
|
||||
|
||||
nb = 2;
|
||||
CBot::fWrite(&nb, sizeof(int), 1, file);
|
||||
CBot::fWrite(&m_ipf, sizeof(int), 1, file);
|
||||
CBot::fWrite(&m_errMode, sizeof(int), 1, file);
|
||||
if (!CBot::WriteInt(ostr, nb)) return false;
|
||||
if (!CBot::WriteInt(ostr, m_ipf)) return false;
|
||||
if (!CBot::WriteInt(ostr, m_errMode)) return false;
|
||||
|
||||
return m_botProg->SaveState(file);
|
||||
return m_botProg->SaveState(ostr);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ public:
|
|||
bool SendScript(const char* text);
|
||||
bool ReadScript(const char* filename);
|
||||
bool WriteScript(const char* filename);
|
||||
bool ReadStack(FILE *file);
|
||||
bool WriteStack(FILE *file);
|
||||
bool ReadStack(std::istream &istr);
|
||||
bool WriteStack(std::ostream &ostr);
|
||||
bool Compare(CScript* other);
|
||||
|
||||
void SetFilename(const std::string &filename);
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <stdexcept>
|
||||
|
||||
extern bool g_cbotTestSaveState;
|
||||
bool g_cbotTestSaveState = false;
|
||||
|
||||
using namespace CBot;
|
||||
|
||||
class CBotUT : public testing::Test
|
||||
|
@ -197,6 +200,23 @@ private:
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
static void TestSaveAndRestore(CBotProgram* program)
|
||||
{
|
||||
std::stringstream sstr("");
|
||||
// save
|
||||
if (!program->SaveState(sstr))
|
||||
throw CBotTestFail("CBotProgram::SaveState Failed");
|
||||
|
||||
if (!CBotClass::SaveStaticState(sstr))
|
||||
throw CBotTestFail("CBotClass::SaveStaticState Failed");
|
||||
// restore
|
||||
if (!program->RestoreState(sstr))
|
||||
throw CBotTestFail("CBotProgram::RestoreState Failed");
|
||||
|
||||
if (!CBotClass::RestoreStaticState(sstr))
|
||||
throw CBotTestFail("CBotClass::RestoreStaticState Failed");
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<CBotProgram> ExecuteTest(const std::string& code, CBotError expectedError = CBotNoErr)
|
||||
{
|
||||
|
@ -231,7 +251,17 @@ protected:
|
|||
try
|
||||
{
|
||||
program->Start(test);
|
||||
while (!program->Run());
|
||||
if (g_cbotTestSaveState)
|
||||
{
|
||||
while (!program->Run(nullptr, 0)) // save/restore at each step
|
||||
{
|
||||
TestSaveAndRestore(program.get());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!program->Run(nullptr, 0)); // execute in step mode
|
||||
}
|
||||
program->GetError(error, cursor1, cursor2);
|
||||
if (error != expectedRuntimeError)
|
||||
{
|
||||
|
|
|
@ -21,11 +21,21 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
extern bool g_cbotTestSaveState;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CLogger logger;
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// parse arguments not removed by InitGoogleTest
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::string arg(argv[i]);
|
||||
if (arg == "--CBotUT_TestSaveState")
|
||||
g_cbotTestSaveState = true;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue