forked from Mirrors/openclonk
792 lines
24 KiB
C++
792 lines
24 KiB
C++
/*
|
|
* OpenClonk, http://www.openclonk.org
|
|
*
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
|
* Copyright (c) 2009-2013, The OpenClonk Team and contributors
|
|
*
|
|
* Distributed under the terms of the ISC license; see accompanying file
|
|
* "COPYING" for details.
|
|
*
|
|
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
|
* See accompanying file "TRADEMARK" for details.
|
|
*
|
|
* To redistribute this file separately, substitute the full license texts
|
|
* for the above references.
|
|
*/
|
|
#ifndef STDCOMPILER_H
|
|
#define STDCOMPILER_H
|
|
|
|
#include "StdBuf.h"
|
|
#include "C4Log.h"
|
|
|
|
#include <assert.h>
|
|
#include <memory>
|
|
|
|
// Try to avoid casting NotFoundExceptions for trivial cases (MSVC log flood workaround)
|
|
#if defined(_MSC_VER)
|
|
#define STDCOMPILER_EXCEPTION_WORKAROUND
|
|
#endif
|
|
|
|
// Provides an interface of generalized compiling/decompiling
|
|
// (serialization/deserialization - note that the term "compile" is used for both directions)
|
|
|
|
// The interface is designed to allow both text-type (INI) and binary
|
|
// compilation. Structures that want to support StdCompiler must provide
|
|
// a function "void CompileFunc(StdCompiler *)" and therein issue calls
|
|
// to the data, naming and separation functions as appropriate. If the structure
|
|
// in question cannot be changed, it is equally valid to define a function
|
|
// void CompileFunc(StdCompiler *, T *) where T is the type of the structure.
|
|
|
|
// Most details can be hidden inside adaptors (see StdAdaptors.h), so
|
|
// the structure can re-use common compiling patterns (namings, arrays...).
|
|
|
|
class StdCompiler
|
|
{
|
|
|
|
public:
|
|
|
|
StdCompiler() : pWarnCB(NULL), pWarnData(NULL)
|
|
#ifdef STDCOMPILER_EXCEPTION_WORKAROUND
|
|
, fFailSafe(false), fFail(false)
|
|
#endif
|
|
{}
|
|
|
|
// *** Overridables (Interface)
|
|
virtual ~StdCompiler() {}
|
|
|
|
// * Properties
|
|
|
|
// Needs two passes? Binary compiler uses this for calculating the size.
|
|
virtual bool isDoublePass() { return false; }
|
|
|
|
// Changes the target?
|
|
virtual bool isCompiler() { return false; }
|
|
inline bool isDecompiler() { return !isCompiler(); }
|
|
|
|
// Does the compiler support naming, so values can be omitted without harm to
|
|
// the data structure? Is separation implemented?
|
|
virtual bool hasNaming() { return false; }
|
|
|
|
// Does the compiler encourage verbosity (like producing more text instead of
|
|
// just a numerical value)?
|
|
virtual bool isVerbose() { return hasNaming(); }
|
|
|
|
// Is it a registry compiler with special handling for arrays?
|
|
virtual bool isRegistry() { return false; }
|
|
|
|
// callback by runtime-write-allowed adaptor used by compilers that may set runtime values only
|
|
virtual void setRuntimeWritesAllowed(int32_t iChange) { }
|
|
|
|
// * Naming
|
|
// Provides extra data for the compiler so he can deal with reordered data.
|
|
// Note that sections stack and each section will get compiled only once.
|
|
// StartSection won't fail if the naming isn't found while compiling. Name and
|
|
// all value compiling functions will fail, though.
|
|
// Set the NameEnd parameter to true if you are stopping to parse the structure
|
|
// for whatever reason (suppress warning messages).
|
|
virtual bool Name(const char *szName) { return true; }
|
|
virtual void NameEnd(bool fBreak = false) { }
|
|
virtual const char *GetNameByIndex(size_t idx) const { return NULL; }
|
|
|
|
// Special: A naming that follows to the currently active naming (on the same level).
|
|
// Note this will end the current naming, so no additional NameEnd() is needed.
|
|
// Only used to maintain backwards compatibility, should not be used in new code.
|
|
virtual bool FollowName(const char *szName) { NameEnd(); return Name(szName); }
|
|
|
|
// Called when a named value omitted because of defaulting (compiler only)
|
|
// Returns whether the value has been handled
|
|
virtual bool Default(const char *szName) { return true; }
|
|
|
|
// Return count of sub-namings. May be unimplemented.
|
|
virtual int NameCount(const char *szName = NULL) { assert(false); return 0; }
|
|
|
|
|
|
// * Separation
|
|
// Some data types need separation (note that naming makes this unnecessary).
|
|
// Compilers that implement naming must implement separation. Others may just
|
|
// always return success.
|
|
// If a separator wasn't found, some compilers might react by throwing a
|
|
// NotFound exception for all attempts to read a value. This behaviour will
|
|
// stop when NoSeparator() is called (which just resets this state) or
|
|
// Separator() is called successfully. This behaviour will reset after
|
|
// ending the naming, too.
|
|
enum Sep
|
|
{
|
|
SEP_NONE=0, // No separator ("")
|
|
SEP_SEP, // Array separation (",")
|
|
SEP_SEP2, // Array separation 2 (";")
|
|
SEP_SET, // Map pair separation ("=")
|
|
SEP_PART, // Value part separation (".")
|
|
SEP_PART2, // Value part separation 2 (":")
|
|
SEP_PLUS, // Value separation with a '+' char ("+")
|
|
SEP_START, // Start some sort of list ('(')
|
|
SEP_END, // End some sort of list ('(')
|
|
SEP_START2, // Start some sort of list ('[')
|
|
SEP_END2, // End some sort of list (']')
|
|
SEP_VLINE, // Vertical line separator ('|')
|
|
SEP_DOLLAR // Dollar sign ('$')
|
|
};
|
|
virtual bool Separator(Sep eSep = SEP_SEP) { return true; }
|
|
virtual void NoSeparator() { }
|
|
|
|
// * Data
|
|
// Compiling functions for different data types
|
|
virtual void DWord(int32_t &rInt) = 0; // Needs separator!
|
|
virtual void DWord(uint32_t &rInt) = 0; // Needs separator!
|
|
virtual void Word(int16_t &rShort) = 0; // Needs separator!
|
|
virtual void Word(uint16_t &rShort) = 0; // Needs separator!
|
|
virtual void Byte(int8_t &rByte) = 0; // Needs separator!
|
|
virtual void Byte(uint8_t &rByte) = 0; // Needs separator!
|
|
virtual void Boolean(bool &rBool) = 0;
|
|
virtual void Character(char &rChar) = 0; // Alphanumerical only!
|
|
|
|
|
|
// Compile raw data (strings)
|
|
enum RawCompileType
|
|
{
|
|
RCT_Escaped=0,// Any data allowed, no separator needed (default)
|
|
RCT_All, // Printable characters only, must be last element in naming.
|
|
RCT_Idtf, // Alphanumerical characters or '_', separator needed.
|
|
RCT_IdtfAllowEmpty, // Like RCT_Idtf, but empty strings are also allowed
|
|
RCT_ID // Like RCT_Idtf (only used for special compilers that treat IDs differently)
|
|
};
|
|
// Note that string won't allow '\0' inside the buffer, even with escaped compiling!
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) = 0;
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) = 0;
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) = 0;
|
|
|
|
// * Position
|
|
// May return information about the current position of compilation (used for errors and warnings)
|
|
virtual StdStrBuf getPosition() const { return StdStrBuf(); }
|
|
|
|
// * Passes
|
|
virtual void Begin() { }
|
|
virtual void BeginSecond() { }
|
|
virtual void End() { }
|
|
|
|
// *** Composed
|
|
|
|
// Generic compiler function (plus specializations)
|
|
template <class T> void Value(const T &rStruct) { rStruct.CompileFunc(this); }
|
|
template <class T> void Value(T &rStruct) { CompileFunc(rStruct, this); }
|
|
|
|
void Value(int32_t &rInt) { DWord(rInt); }
|
|
void Value(uint32_t &rInt) { DWord(rInt); }
|
|
void Value(int16_t &rInt) { Word(rInt); }
|
|
void Value(uint16_t &rInt) { Word(rInt); }
|
|
void Value(int8_t &rInt) { Byte(rInt); }
|
|
void Value(uint8_t &rInt) { Byte(rInt); }
|
|
void Value(bool &rBool) { Boolean(rBool); }
|
|
|
|
// Compiling/Decompiling (may throw a data format exception!)
|
|
template <class T> inline void Compile(T RREF rStruct)
|
|
{
|
|
assert(isCompiler());
|
|
DoCompilation(rStruct);
|
|
}
|
|
template <class T> inline void Decompile(const T &rStruct)
|
|
{
|
|
assert(!isCompiler());
|
|
DoCompilation(const_cast<T &>(rStruct));
|
|
}
|
|
|
|
protected:
|
|
|
|
// Compilation process
|
|
template <class T>
|
|
inline void DoCompilation(T &rStruct)
|
|
{
|
|
// Start compilation, do first pass
|
|
Begin();
|
|
Value(rStruct);
|
|
// Second pass needed?
|
|
if (isDoublePass())
|
|
{
|
|
BeginSecond();
|
|
Value(rStruct);
|
|
}
|
|
// Finish
|
|
End();
|
|
}
|
|
|
|
public:
|
|
|
|
// Compiler exception - thrown when something is wrong with the data to compile
|
|
struct Exception
|
|
{
|
|
StdStrBuf Pos;
|
|
StdStrBuf Msg;
|
|
protected:
|
|
Exception(StdStrBuf Pos, StdStrBuf Msg) : Pos(Pos), Msg(Msg) { }
|
|
private:
|
|
// do not copy
|
|
Exception(const Exception &Exc) { }
|
|
};
|
|
class NotFoundException : public Exception
|
|
{
|
|
friend class StdCompiler;
|
|
NotFoundException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
|
|
};
|
|
class EOFException : public Exception
|
|
{
|
|
friend class StdCompiler;
|
|
EOFException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
|
|
};
|
|
class CorruptException : public Exception
|
|
{
|
|
friend class StdCompiler;
|
|
CorruptException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
|
|
};
|
|
|
|
// Throw helpers (might redirect)
|
|
void excNotFound(const char *szMessage, ...)
|
|
{
|
|
#ifdef STDCOMPILER_EXCEPTION_WORKAROUND
|
|
// Exception workaround: Just set a flag in failesafe mode.
|
|
if (fFailSafe) { fFail = true; return; }
|
|
#endif
|
|
// Throw the appropriate exception
|
|
va_list args; va_start(args, szMessage);
|
|
throw new NotFoundException(getPosition(), FormatStringV(szMessage, args));
|
|
}
|
|
void excEOF(const char *szMessage = "EOF", ...)
|
|
{
|
|
// Throw the appropriate exception
|
|
va_list args; va_start(args, szMessage);
|
|
throw new EOFException(getPosition(), FormatStringV(szMessage, args));
|
|
}
|
|
void excCorrupt(const char *szMessage, ...)
|
|
{
|
|
// Throw the appropriate exception
|
|
va_list args; va_start(args, szMessage);
|
|
throw new CorruptException(getPosition(), FormatStringV(szMessage, args));
|
|
}
|
|
|
|
protected:
|
|
|
|
// Exception workaround
|
|
#ifdef STDCOMPILER_EXCEPTION_WORKAROUND
|
|
bool fFailSafe, fFail;
|
|
|
|
void beginFailSafe() { fFailSafe = true; fFail = false; }
|
|
bool endFailSafe() { fFailSafe = false; return !fFail; }
|
|
|
|
public:
|
|
template <class T> bool ValueSafe(const T &rStruct) { rStruct.CompileFunc(this); return true; }
|
|
template <class T> bool ValueSafe(T &rStruct) { CompileFunc(rStruct, this); return true; }
|
|
|
|
bool ValueSafe(int32_t &rInt) { beginFailSafe(); DWord(rInt); return endFailSafe(); }
|
|
bool ValueSafe(uint32_t &rInt) { beginFailSafe(); DWord(rInt); return endFailSafe(); }
|
|
bool ValueSafe(int16_t &rInt) { beginFailSafe(); Word(rInt); return endFailSafe(); }
|
|
bool ValueSafe(uint16_t &rInt) { beginFailSafe(); Word(rInt); return endFailSafe(); }
|
|
bool ValueSafe(int8_t &rInt) { beginFailSafe(); Byte(rInt); return endFailSafe(); }
|
|
bool ValueSafe(uint8_t &rInt) { beginFailSafe(); Byte(rInt); return endFailSafe(); }
|
|
bool ValueSafe(bool &rBool) { beginFailSafe(); Boolean(rBool); return endFailSafe(); }
|
|
#endif
|
|
|
|
public:
|
|
|
|
// * Warnings
|
|
typedef void (*WarnCBT)(void *, const char *, const char *);
|
|
void setWarnCallback(WarnCBT pnWarnCB, void *pData) { pWarnCB = pnWarnCB; pWarnData = pData; }
|
|
void Warn(const char *szWarning, ...);
|
|
|
|
private:
|
|
|
|
// Warnings
|
|
WarnCBT pWarnCB;
|
|
void *pWarnData;
|
|
|
|
protected:
|
|
|
|
// Standard separator character
|
|
static char SeparatorToChar(Sep eSep);
|
|
|
|
};
|
|
|
|
// Standard compile funcs
|
|
template <class T>
|
|
inline void CompileFunc(T &rStruct, StdCompiler *pComp)
|
|
{
|
|
// If the compiler doesn't like this line, you tried to compile
|
|
// something the compiler doesn't know how to handle.
|
|
// Possible reasons:
|
|
// a) You are compiling a class/structure without a CompileFunc
|
|
// (you may add a specialization of this function, too)
|
|
// b) You are trying to compile a pointer. Use a PtrAdapt instead.
|
|
// c) You are trying to compile a simple value that has no
|
|
// fixed representation (float, int). Use safe types instead.
|
|
rStruct.CompileFunc(pComp);
|
|
}
|
|
|
|
template <class T>
|
|
void CompileNewFunc(T *&pStruct, StdCompiler *pComp)
|
|
{
|
|
// Create new object.
|
|
// If this line doesn't compile, you either have to
|
|
// a) Define a standard constructor for T
|
|
// b) Specialize this function to do whatever the correct
|
|
// behaviour is to construct the object from compiler data
|
|
std::unique_ptr<T> temp(new T); // exception-safety
|
|
// Compile
|
|
pComp->Value(*temp);
|
|
pStruct = temp.release();
|
|
}
|
|
|
|
template <class T, class P>
|
|
void CompileNewFunc(T *&pStruct, StdCompiler *pComp, const P& rPar)
|
|
{
|
|
// Create new object.
|
|
// If this line doesn't compile, you either have to
|
|
// a) Define a standard constructor for T
|
|
// b) Specialize this function to do whatever the correct
|
|
// behaviour is to construct the object from compiler data
|
|
std::unique_ptr<T> temp(new T); // exception-safety
|
|
// Compile
|
|
//temp->CompileFunc(pComp, rPar);
|
|
pComp->Value(mkParAdapt(*temp, rPar));
|
|
pStruct = temp.release();
|
|
}
|
|
|
|
template <class T, class ContextT>
|
|
void CompileNewFuncCtx(T *&pStruct, StdCompiler *pComp, const ContextT& rCtx)
|
|
{
|
|
// Create new object.
|
|
// If this line doesn't compile, you either have to
|
|
// a) Define an appropriate constructor for T
|
|
// b) Specialize this function to do whatever the correct
|
|
// behaviour is to construct the object from compiler data
|
|
// and context
|
|
std::unique_ptr<T> temp(new T(rCtx)); // exception-safety
|
|
// Compile
|
|
pComp->Value(*temp);
|
|
pStruct = temp.release();
|
|
}
|
|
|
|
template <class T, class ContextT, class P>
|
|
void CompileNewFuncCtx(T *&pStruct, StdCompiler *pComp, const ContextT& rCtx, const P& rPar)
|
|
{
|
|
// Create new object.
|
|
// If this line doesn't compile, you either have to
|
|
// a) Define an appropriate constructor for T
|
|
// b) Specialize this function to do whatever the correct
|
|
// behaviour is to construct the object from compiler data
|
|
// and context
|
|
std::unique_ptr<T> temp(new T(rCtx)); // exception-safety
|
|
// Compile
|
|
//temp->CompileFunc(pComp, rPar);
|
|
pComp->Value(mkParAdapt(*temp, rPar));
|
|
pStruct = temp.release();
|
|
}
|
|
|
|
// Helpers for buffer-based compiling (may throw a data format exception!)
|
|
template <class CompT, class StructT>
|
|
void CompileFromBuf(StructT RREF TargetStruct, const typename CompT::InT &SrcBuf)
|
|
{
|
|
CompT Compiler;
|
|
Compiler.setInput(SrcBuf.getRef());
|
|
Compiler.Compile(TargetStruct);
|
|
}
|
|
template <class CompT, class StructT>
|
|
StructT * CompileFromBufToNew(const typename CompT::InT &SrcBuf)
|
|
{
|
|
StructT *pStruct = NULL;
|
|
CompileFromBuf<CompT>(mkPtrAdaptNoNull(pStruct), SrcBuf);
|
|
return pStruct;
|
|
}
|
|
template <class CompT, class StructT>
|
|
StructT * CompileFromBufToNewNamed(const typename CompT::InT &SrcBuf, const char *szName)
|
|
{
|
|
StructT *pStruct = NULL;
|
|
CompileFromBuf<CompT>(mkNamingAdapt(mkPtrAdaptNoNull(pStruct), szName), SrcBuf);
|
|
return pStruct;
|
|
}
|
|
template <class CompT, class StructT>
|
|
typename CompT::OutT DecompileToBuf(const StructT &SrcStruct)
|
|
{
|
|
CompT Compiler;
|
|
Compiler.Decompile(SrcStruct);
|
|
return Compiler.getOutput();
|
|
}
|
|
|
|
// *** Null compiler
|
|
|
|
// Naming supported, nothing is returned. Used for setting default values.
|
|
|
|
class StdCompilerNull : public StdCompiler
|
|
{
|
|
public:
|
|
|
|
// Properties
|
|
virtual bool isCompiler() { return true; }
|
|
virtual bool hasNaming() { return true; }
|
|
|
|
// Naming
|
|
virtual bool Name(const char *szName) { return false; }
|
|
virtual int NameCount(const char *szName = NULL) { return 0; }
|
|
|
|
// Data readers
|
|
virtual void DWord(int32_t &rInt) { }
|
|
virtual void DWord(uint32_t &rInt) { }
|
|
virtual void Word(int16_t &rShort) { }
|
|
virtual void Word(uint16_t &rShort) { }
|
|
virtual void Byte(int8_t &rByte) { }
|
|
virtual void Byte(uint8_t &rByte) { }
|
|
virtual void Boolean(bool &rBool) { }
|
|
virtual void Character(char &rChar) { }
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) { }
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) { }
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) { }
|
|
|
|
};
|
|
|
|
// *** Binary compiler
|
|
|
|
// No naming supported, everything is read/written binary.
|
|
|
|
|
|
// binary writer
|
|
class StdCompilerBinWrite : public StdCompiler
|
|
{
|
|
public:
|
|
|
|
// Result
|
|
typedef StdBuf OutT;
|
|
inline OutT getOutput() { return Buf; }
|
|
|
|
// Properties
|
|
virtual bool isDoublePass() { return true; }
|
|
|
|
// Data writers
|
|
virtual void DWord(int32_t &rInt);
|
|
virtual void DWord(uint32_t &rInt);
|
|
virtual void Word(int16_t &rShort);
|
|
virtual void Word(uint16_t &rShort);
|
|
virtual void Byte(int8_t &rByte);
|
|
virtual void Byte(uint8_t &rByte);
|
|
virtual void Boolean(bool &rBool);
|
|
virtual void Character(char &rChar);
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
|
|
|
// Passes
|
|
virtual void Begin();
|
|
virtual void BeginSecond();
|
|
|
|
protected:
|
|
// Process data
|
|
bool fSecondPass;
|
|
int iPos;
|
|
StdBuf Buf;
|
|
|
|
// Helpers
|
|
template <class T> void WriteValue(const T &rValue);
|
|
void WriteData(const void *pData, size_t iSize);
|
|
};
|
|
|
|
// binary read
|
|
class StdCompilerBinRead : public StdCompiler
|
|
{
|
|
public:
|
|
|
|
// Input
|
|
typedef StdBuf InT;
|
|
void setInput(InT RREF In) { Buf = std::move(In); }
|
|
|
|
// Properties
|
|
virtual bool isCompiler() { return true; }
|
|
|
|
// Data readers
|
|
virtual void DWord(int32_t &rInt);
|
|
virtual void DWord(uint32_t &rInt);
|
|
virtual void Word(int16_t &rShort);
|
|
virtual void Word(uint16_t &rShort);
|
|
virtual void Byte(int8_t &rByte);
|
|
virtual void Byte(uint8_t &rByte);
|
|
virtual void Boolean(bool &rBool);
|
|
virtual void Character(char &rChar);
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
|
|
|
// Position
|
|
virtual StdStrBuf getPosition() const;
|
|
|
|
// Passes
|
|
virtual void Begin();
|
|
|
|
// Data
|
|
size_t getPosition() { return iPos; }
|
|
size_t getRemainingBytes() { return Buf.getSize() - iPos; }
|
|
|
|
protected:
|
|
// Process data
|
|
size_t iPos;
|
|
StdBuf Buf;
|
|
|
|
// Helper
|
|
template <class T> void ReadValue(T &rValue);
|
|
};
|
|
|
|
// *** INI compiler
|
|
|
|
// Naming and separators supported, so defaulting can be used through
|
|
// the appropriate adaptors.
|
|
|
|
// Example:
|
|
|
|
// [Sect1]
|
|
// [Sect1a]
|
|
// Val1=4
|
|
// Val2=5
|
|
// Val4=3,5
|
|
|
|
// will result from:
|
|
|
|
// int v1=4, v2=5, v3=0, v4[3] = { 3, 5, 0 };
|
|
// DecompileToBuf<StdCompilerINIWrite>(
|
|
// mkNamingAdapt(
|
|
// mkNamingAdapt(
|
|
// mkNamingAdapt(v1, "Val1", 0) +
|
|
// mkNamingAdapt(v2, "Val2", 0) +
|
|
// mkNamingAdapt(v3, "Val3", 0),
|
|
// "Sect1a") +
|
|
// mkNamingAdapt(mkArrayAdapt(v4, 3, 0), "Val4", 0),
|
|
// "Sect1")
|
|
// )
|
|
|
|
|
|
// text writer
|
|
class StdCompilerINIWrite : public StdCompiler
|
|
{
|
|
public:
|
|
// Input
|
|
typedef StdStrBuf OutT;
|
|
inline OutT getOutput() { return Buf; }
|
|
|
|
// Properties
|
|
virtual bool hasNaming() { return true; }
|
|
|
|
// Naming
|
|
virtual bool Name(const char *szName);
|
|
virtual void NameEnd(bool fBreak = false);
|
|
|
|
// Separators
|
|
virtual bool Separator(Sep eSep);
|
|
|
|
// Data writers
|
|
virtual void DWord(int32_t &rInt);
|
|
virtual void DWord(uint32_t &rInt);
|
|
virtual void Word(int16_t &rShort);
|
|
virtual void Word(uint16_t &rShort);
|
|
virtual void Byte(int8_t &rByte);
|
|
virtual void Byte(uint8_t &rByte);
|
|
virtual void Boolean(bool &rBool);
|
|
virtual void Character(char &rChar);
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
|
|
|
// Passes
|
|
virtual void Begin();
|
|
virtual void End();
|
|
|
|
protected:
|
|
|
|
// Result
|
|
StdStrBuf Buf;
|
|
|
|
// Naming stack
|
|
struct Naming
|
|
{
|
|
StdStrBuf Name;
|
|
Naming *Parent;
|
|
};
|
|
Naming *pNaming;
|
|
// Recursion depth
|
|
int iDepth;
|
|
|
|
// Name not put yet (it's not clear wether it is a value or a section)
|
|
bool fPutName,
|
|
// Currently inside a section, so raw data can't be printed
|
|
fInSection;
|
|
|
|
void PrepareForValue();
|
|
void WriteEscaped(const char *szString, const char *pEnd);
|
|
void WriteIndent(bool fSectionName);
|
|
void PutName(bool fSection);
|
|
};
|
|
|
|
// text reader
|
|
class StdCompilerINIRead : public StdCompiler
|
|
{
|
|
public:
|
|
|
|
StdCompilerINIRead();
|
|
~StdCompilerINIRead();
|
|
|
|
// Input
|
|
typedef StdStrBuf InT;
|
|
void setInput(const InT &In) { Buf.Ref(In); lineBreaks.clear(); }
|
|
|
|
// Properties
|
|
virtual bool isCompiler() { return true; }
|
|
virtual bool hasNaming() { return true; }
|
|
|
|
// Naming
|
|
virtual bool Name(const char *szName);
|
|
virtual void NameEnd(bool fBreak = false);
|
|
virtual bool FollowName(const char *szName);
|
|
virtual const char *GetNameByIndex(size_t idx) const;
|
|
|
|
// Separators
|
|
virtual bool Separator(Sep eSep);
|
|
virtual void NoSeparator();
|
|
|
|
// Counters
|
|
virtual int NameCount(const char *szName = NULL);
|
|
|
|
// Data writers
|
|
virtual void DWord(int32_t &rInt);
|
|
virtual void DWord(uint32_t &rInt);
|
|
virtual void Word(int16_t &rShort);
|
|
virtual void Word(uint16_t &rShort);
|
|
virtual void Byte(int8_t &rByte);
|
|
virtual void Byte(uint8_t &rByte);
|
|
virtual void Boolean(bool &rBool);
|
|
virtual void Character(char &rChar);
|
|
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
|
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
|
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
|
|
|
// Position
|
|
virtual StdStrBuf getPosition() const;
|
|
|
|
// Passes
|
|
virtual void Begin();
|
|
virtual void End();
|
|
|
|
protected:
|
|
|
|
// * Data
|
|
|
|
// Name tree
|
|
struct NameNode
|
|
{
|
|
// Name
|
|
StdStrBuf Name;
|
|
// Section?
|
|
bool Section;
|
|
// Tree structure
|
|
NameNode *Parent,
|
|
*FirstChild, *PrevChild, *NextChild, *LastChild;
|
|
// Indent level
|
|
int Indent;
|
|
// Name number in parent map
|
|
const char *Pos;
|
|
// Constructor
|
|
NameNode(NameNode *pParent = NULL) :
|
|
Section(false), Parent(pParent),
|
|
FirstChild(NULL), PrevChild(NULL), NextChild(NULL), LastChild(NULL),
|
|
Indent(-1), Pos(NULL)
|
|
{ }
|
|
};
|
|
NameNode *pNameRoot, *pName;
|
|
// Current depth
|
|
int iDepth;
|
|
// Real depth (depth of recursive Name()-calls - if iDepth != iRealDepth, we are in a nonexistant namespace)
|
|
int iRealDepth;
|
|
|
|
// Data
|
|
StdStrBuf Buf;
|
|
// Position
|
|
const char *pPos;
|
|
|
|
// Reenter position (if an nonexistant separator was specified)
|
|
const char *pReenter;
|
|
|
|
// Uppermost name that wasn't found
|
|
StdCopyStrBuf NotFoundName;
|
|
|
|
// * Implementation
|
|
|
|
// Name tree
|
|
void CreateNameTree();
|
|
void FreeNameTree();
|
|
void FreeNameNode(NameNode *pNode);
|
|
|
|
// Navigation
|
|
void SkipWhitespace();
|
|
void SkipNum();
|
|
long ReadNum();
|
|
size_t GetStringLength(RawCompileType eTyped);
|
|
StdBuf ReadString(size_t iLength, RawCompileType eTyped, bool fAppendNull = true);
|
|
bool TestStringEnd(RawCompileType eType);
|
|
char ReadEscapedChar();
|
|
unsigned long ReadUNum();
|
|
|
|
void notFound(const char *szWhat);
|
|
|
|
private:
|
|
uint32_t getLineNumberOfPos(const char *pos) const;
|
|
mutable std::vector<const char *> lineBreaks;
|
|
};
|
|
|
|
void StdCompilerWarnCallback(void *pData, const char *szPosition, const char *szError);
|
|
|
|
template <class CompT, class StructT>
|
|
bool CompileFromBuf_Log(StructT &TargetStruct, const typename CompT::InT &SrcBuf, const char *szName)
|
|
{
|
|
try
|
|
{
|
|
CompileFromBuf<CompT>(TargetStruct, SrcBuf);
|
|
return true;
|
|
}
|
|
catch (StdCompiler::Exception *pExc)
|
|
{
|
|
LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
|
|
delete pExc;
|
|
return false;
|
|
}
|
|
}
|
|
template <class CompT, class StructT>
|
|
bool CompileFromBuf_LogWarn(StructT RREF TargetStruct, const typename CompT::InT &SrcBuf, const char *szName)
|
|
{
|
|
try
|
|
{
|
|
CompT Compiler;
|
|
Compiler.setInput(SrcBuf.getRef());
|
|
Compiler.setWarnCallback(StdCompilerWarnCallback, reinterpret_cast<void *>(const_cast<char *>(szName)));
|
|
Compiler.Compile(TargetStruct);
|
|
return true;
|
|
}
|
|
catch (StdCompiler::Exception *pExc)
|
|
{
|
|
if (!pExc->Pos.getLength())
|
|
LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
|
|
else
|
|
LogF("ERROR: %s (in %s, %s)", pExc->Msg.getData(), pExc->Pos.getData(), szName);
|
|
delete pExc;
|
|
return false;
|
|
}
|
|
}
|
|
template <class CompT, class StructT>
|
|
bool DecompileToBuf_Log(StructT RREF TargetStruct, typename CompT::OutT *pOut, const char *szName)
|
|
{
|
|
if (!pOut) return false;
|
|
try
|
|
{
|
|
pOut->Take(DecompileToBuf<CompT>(TargetStruct));
|
|
return true;
|
|
}
|
|
catch (StdCompiler::Exception *pExc)
|
|
{
|
|
LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
|
|
delete pExc;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endif // STDCOMPILER_H
|