1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 #ifndef STDCOMPILER_H
17 #define STDCOMPILER_H
18
19 // Try to avoid casting NotFoundExceptions for trivial cases (MSVC log flood workaround)
20 #if defined(_MSC_VER)
21 #define STDCOMPILER_EXCEPTION_WORKAROUND
22 #endif
23
24 // Provides an interface of generalized compiling/decompiling
25 // (serialization/deserialization - note that the term "compile" is used for both directions)
26
27 // The interface is designed to allow both text-type (INI) and binary
28 // compilation. Structures that want to support StdCompiler must provide
29 // a function "void CompileFunc(StdCompiler *)" and therein issue calls
30 // to the data, naming and separation functions as appropriate. If the structure
31 // in question cannot be changed, it is equally valid to define a function
32 // void CompileFunc(StdCompiler *, T *) where T is the type of the structure.
33
34 // Most details can be hidden inside adaptors (see StdAdaptors.h), so
35 // the structure can re-use common compiling patterns (namings, arrays...).
36
37 class StdCompiler
38 {
39
40 public:
41
42 StdCompiler() = default;
43
44 // *** Overridables (Interface)
45 virtual ~StdCompiler() = default;
46
47 // * Properties
48
49 // Needs two passes? Binary compiler uses this for calculating the size.
isDoublePass()50 virtual bool isDoublePass() { return false; }
51
52 // Changes the target?
isDeserializer()53 virtual bool isDeserializer() { return false; }
isSerializer()54 inline bool isSerializer() { return !isDeserializer(); }
55
56 // Does the compiler support naming, so values can be omitted without harm to
57 // the data structure? Is separation implemented?
hasNaming()58 virtual bool hasNaming() { return false; }
59
60 // Does the compiler encourage verbosity (like producing more text instead of
61 // just a numerical value)?
isVerbose()62 virtual bool isVerbose() { return hasNaming(); }
63
64 // Is it a registry compiler with special handling for arrays?
isRegistry()65 virtual bool isRegistry() { return false; }
66
67 // callback by runtime-write-allowed adaptor used by compilers that may set runtime values only
setRuntimeWritesAllowed(int32_t iChange)68 virtual void setRuntimeWritesAllowed(int32_t iChange) { }
69
70 // * Naming
71 // Provides extra data for the compiler so he can deal with reordered data.
72 // Note that sections stack and each section will get compiled only once.
73 // StartSection won't fail if the naming isn't found while compiling. Name and
74 // all value compiling functions will fail, though.
75 // Set the NameEnd parameter to true if you are stopping to parse the structure
76 // for whatever reason (suppress warning messages).
Name(const char * szName)77 virtual bool Name(const char *szName) { return true; }
78 virtual void NameEnd(bool fBreak = false) { }
GetNameByIndex(size_t idx)79 virtual const char *GetNameByIndex(size_t idx) const { return nullptr; }
80
81 // Special: A naming that follows to the currently active naming (on the same level).
82 // Note this will end the current naming, so no additional NameEnd() is needed.
83 // Only used to maintain backwards compatibility, should not be used in new code.
FollowName(const char * szName)84 virtual bool FollowName(const char *szName) { NameEnd(); return Name(szName); }
85
86 // Called when a named value omitted because of defaulting (compiler only)
87 // Returns whether the value has been handled
Default(const char * szName)88 virtual bool Default(const char *szName) { return true; }
89
90 // Return count of sub-namings. May be unimplemented.
91 virtual int NameCount(const char *szName = nullptr) { assert(false); return 0; }
92
93
94 // * Separation
95 // Some data types need separation (note that naming makes this unnecessary).
96 // Compilers that implement naming must implement separation. Others may just
97 // always return success.
98 // If a separator wasn't found, some compilers might react by throwing a
99 // NotFound exception for all attempts to read a value. This behaviour will
100 // stop when NoSeparator() is called (which just resets this state) or
101 // Separator() is called successfully. This behaviour will reset after
102 // ending the naming, too.
103 enum Sep
104 {
105 SEP_NONE=0, // No separator ("")
106 SEP_SEP, // Array separation (",")
107 SEP_SEP2, // Array separation 2 (";")
108 SEP_SET, // Map pair separation ("=")
109 SEP_PART, // Value part separation (".")
110 SEP_PART2, // Value part separation 2 (":")
111 SEP_PLUS, // Value separation with a '+' char ("+")
112 SEP_START, // Start some sort of list ('(')
113 SEP_END, // End some sort of list ('(')
114 SEP_START2, // Start some sort of list ('[')
115 SEP_END2, // End some sort of list (']')
116 SEP_VLINE, // Vertical line separator ('|')
117 SEP_DOLLAR // Dollar sign ('$')
118 };
119 virtual bool Separator(Sep eSep = SEP_SEP) { return true; }
NoSeparator()120 virtual void NoSeparator() { }
121
122 // * Data
123 // Compiling functions for different data types
124 virtual void DWord(int32_t &rInt) = 0; // Needs separator!
125 virtual void DWord(uint32_t &rInt) = 0; // Needs separator!
126 virtual void Word(int16_t &rShort) = 0; // Needs separator!
127 virtual void Word(uint16_t &rShort) = 0; // Needs separator!
128 virtual void Byte(int8_t &rByte) = 0; // Needs separator!
129 virtual void Byte(uint8_t &rByte) = 0; // Needs separator!
130 virtual void Boolean(bool &rBool) = 0;
131 virtual void Character(char &rChar) = 0; // Alphanumerical only!
132
133
134 // Compile raw data (strings)
135 enum RawCompileType
136 {
137 RCT_Escaped=0,// Any data allowed, no separator needed (default)
138 RCT_All, // Printable characters only, must be last element in naming.
139 RCT_Idtf, // Alphanumerical characters or '_', separator needed.
140 RCT_IdtfAllowEmpty, // Like RCT_Idtf, but empty strings are also allowed
141 RCT_ID // Like RCT_Idtf (only used for special compilers that treat IDs differently)
142 };
143 // Note that string won't allow '\0' inside the buffer, even with escaped compiling!
144 virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) = 0;
145 virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) = 0;
146 virtual void String(std::string &str, RawCompileType type = RCT_Escaped) = 0;
147 virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) = 0;
148
149 // * Position
150 // May return information about the current position of compilation (used for errors and warnings)
getPosition()151 virtual StdStrBuf getPosition() const { return StdStrBuf(); }
152
153 // * Passes
Begin()154 virtual void Begin() { }
BeginSecond()155 virtual void BeginSecond() { }
End()156 virtual void End() { }
157
158 // *** Composed
159
160 // Generic compiler function (plus specializations)
Value(const T & rStruct)161 template <class T> void Value(const T &rStruct) { rStruct.CompileFunc(this); }
Value(T & rStruct)162 template <class T> void Value(T &rStruct) { CompileFunc(rStruct, this); }
163
Value(int32_t & rInt)164 void Value(int32_t &rInt) { DWord(rInt); }
Value(uint32_t & rInt)165 void Value(uint32_t &rInt) { DWord(rInt); }
Value(int16_t & rInt)166 void Value(int16_t &rInt) { Word(rInt); }
Value(uint16_t & rInt)167 void Value(uint16_t &rInt) { Word(rInt); }
Value(int8_t & rInt)168 void Value(int8_t &rInt) { Byte(rInt); }
Value(uint8_t & rInt)169 void Value(uint8_t &rInt) { Byte(rInt); }
Value(bool & rBool)170 void Value(bool &rBool) { Boolean(rBool); }
171
172 // Compiling/Decompiling (may throw a data format exception!)
Compile(T && rStruct)173 template <class T> inline void Compile(T &&rStruct)
174 {
175 assert(isDeserializer());
176 DoCompilation(rStruct);
177 }
Decompile(const T & rStruct)178 template <class T> inline void Decompile(const T &rStruct)
179 {
180 assert(!isDeserializer());
181 DoCompilation(const_cast<T &>(rStruct));
182 }
183
184 protected:
185
186 // Compilation process
187 template <class T>
DoCompilation(T & rStruct)188 inline void DoCompilation(T &rStruct)
189 {
190 // Start compilation, do first pass
191 Begin();
192 Value(rStruct);
193 // Second pass needed?
194 if (isDoublePass())
195 {
196 BeginSecond();
197 Value(rStruct);
198 }
199 // Finish
200 End();
201 }
202
203 public:
204
205 // Compiler exception - thrown when something is wrong with the data to compile
206 struct Exception
207 {
208 StdStrBuf Pos;
209 StdStrBuf Msg;
210 protected:
ExceptionException211 Exception(StdStrBuf Pos, StdStrBuf Msg) : Pos(std::move(Pos)), Msg(std::move(Msg)) { }
212 private:
213 // do not copy
ExceptionException214 Exception(const Exception &Exc) { }
215 };
216 class NotFoundException : public Exception
217 {
218 friend class StdCompiler;
NotFoundException(StdStrBuf Pos,StdStrBuf Msg)219 NotFoundException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
220 };
221 class EOFException : public Exception
222 {
223 friend class StdCompiler;
EOFException(StdStrBuf Pos,StdStrBuf Msg)224 EOFException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
225 };
226 class CorruptException : public Exception
227 {
228 friend class StdCompiler;
CorruptException(StdStrBuf Pos,StdStrBuf Msg)229 CorruptException(StdStrBuf Pos, StdStrBuf Msg) : Exception(Pos, Msg) { }
230 };
231
232 // Throw helpers (might redirect)
excNotFound(const char * szMessage,...)233 void excNotFound(const char *szMessage, ...)
234 {
235 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
236 // Exception workaround: Just set a flag in failesafe mode.
237 if (fFailSafe) { fFail = true; return; }
238 #endif
239 // Throw the appropriate exception
240 va_list args; va_start(args, szMessage);
241 throw new NotFoundException(getPosition(), FormatStringV(szMessage, args));
242 }
243 void excEOF(const char *szMessage = "EOF", ...)
244 {
245 // Throw the appropriate exception
246 va_list args; va_start(args, szMessage);
247 throw new EOFException(getPosition(), FormatStringV(szMessage, args));
248 }
excCorrupt(const char * szMessage,...)249 void excCorrupt(const char *szMessage, ...)
250 {
251 // Throw the appropriate exception
252 va_list args; va_start(args, szMessage);
253 throw new CorruptException(getPosition(), FormatStringV(szMessage, args));
254 }
255
256 protected:
257
258 // Exception workaround
259 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
260 bool fFailSafe{false}, fFail{false};
261
beginFailSafe()262 void beginFailSafe() { fFailSafe = true; fFail = false; }
endFailSafe()263 bool endFailSafe() { fFailSafe = false; return !fFail; }
264
265 public:
ValueSafe(const T & rStruct)266 template <class T> bool ValueSafe(const T &rStruct) { rStruct.CompileFunc(this); return true; }
ValueSafe(T & rStruct)267 template <class T> bool ValueSafe(T &rStruct) { CompileFunc(rStruct, this); return true; }
268
ValueSafe(int32_t & rInt)269 bool ValueSafe(int32_t &rInt) { beginFailSafe(); DWord(rInt); return endFailSafe(); }
ValueSafe(uint32_t & rInt)270 bool ValueSafe(uint32_t &rInt) { beginFailSafe(); DWord(rInt); return endFailSafe(); }
ValueSafe(int16_t & rInt)271 bool ValueSafe(int16_t &rInt) { beginFailSafe(); Word(rInt); return endFailSafe(); }
ValueSafe(uint16_t & rInt)272 bool ValueSafe(uint16_t &rInt) { beginFailSafe(); Word(rInt); return endFailSafe(); }
ValueSafe(int8_t & rInt)273 bool ValueSafe(int8_t &rInt) { beginFailSafe(); Byte(rInt); return endFailSafe(); }
ValueSafe(uint8_t & rInt)274 bool ValueSafe(uint8_t &rInt) { beginFailSafe(); Byte(rInt); return endFailSafe(); }
ValueSafe(bool & rBool)275 bool ValueSafe(bool &rBool) { beginFailSafe(); Boolean(rBool); return endFailSafe(); }
276 #endif
277
278 public:
279
280 // * Warnings
281 typedef void (*WarnCBT)(void *, const char *, const char *);
setWarnCallback(WarnCBT pnWarnCB,void * pData)282 void setWarnCallback(WarnCBT pnWarnCB, void *pData) { pWarnCB = pnWarnCB; pWarnData = pData; }
283 void Warn(const char *szWarning, ...);
284
285 private:
286
287 // Warnings
288 WarnCBT pWarnCB{nullptr};
289 void *pWarnData{nullptr};
290
291 protected:
292
293 // Standard separator character
294 static char SeparatorToChar(Sep eSep);
295 // String end test depending on encoding type
296 static bool IsStringEnd(char c, RawCompileType eType);
297 };
298
299 // Standard compile funcs
300 template <class T>
CompileFunc(T & rStruct,StdCompiler * pComp)301 inline void CompileFunc(T &rStruct, StdCompiler *pComp)
302 {
303 // If the compiler doesn't like this line, you tried to compile
304 // something the compiler doesn't know how to handle.
305 // Possible reasons:
306 // a) You are compiling a class/structure without a CompileFunc
307 // (you may add a specialization of this function, too)
308 // b) You are trying to compile a pointer. Use a PtrAdapt instead.
309 // c) You are trying to compile a simple value that has no
310 // fixed representation (float, int). Use safe types instead.
311 rStruct.CompileFunc(pComp);
312 }
313
CompileFunc(std::string & s,StdCompiler * comp)314 inline void CompileFunc(std::string &s, StdCompiler *comp)
315 {
316 comp->String(s);
317 }
318
319 template <class T>
CompileNewFunc(T * & pStruct,StdCompiler * pComp)320 void CompileNewFunc(T *&pStruct, StdCompiler *pComp)
321 {
322 // Create new object.
323 // If this line doesn't compile, you either have to
324 // a) Define a standard constructor for T
325 // b) Specialize this function to do whatever the correct
326 // behaviour is to construct the object from compiler data
327 std::unique_ptr<T> temp(new T); // exception-safety
328 // Compile
329 pComp->Value(*temp);
330 pStruct = temp.release();
331 }
332
333 template <class T, typename ... P>
CompileNewFunc(T * & pStruct,StdCompiler * pComp,P &&...pars)334 void CompileNewFunc(T *&pStruct, StdCompiler *pComp, P && ... pars)
335 {
336 // Create new object.
337 // If this line doesn't compile, you either have to
338 // a) Define a standard constructor for T
339 // b) Specialize this function to do whatever the correct
340 // behaviour is to construct the object from compiler data
341 std::unique_ptr<T> temp(new T); // exception-safety
342 // Compile
343 pComp->Value(mkParAdapt(*temp, std::forward<P>(pars)...));
344 pStruct = temp.release();
345 }
346
347 template <class T, class ContextT>
CompileNewFuncCtx(T * & pStruct,StdCompiler * pComp,const ContextT & rCtx)348 void CompileNewFuncCtx(T *&pStruct, StdCompiler *pComp, const ContextT& rCtx)
349 {
350 // Create new object.
351 // If this line doesn't compile, you either have to
352 // a) Define an appropriate constructor for T
353 // b) Specialize this function to do whatever the correct
354 // behaviour is to construct the object from compiler data
355 // and context
356 std::unique_ptr<T> temp(new T(rCtx)); // exception-safety
357 // Compile
358 pComp->Value(*temp);
359 pStruct = temp.release();
360 }
361
362 template <class T, class ContextT, class P>
CompileNewFuncCtx(T * & pStruct,StdCompiler * pComp,const ContextT & rCtx,const P & rPar)363 void CompileNewFuncCtx(T *&pStruct, StdCompiler *pComp, const ContextT& rCtx, const P& rPar)
364 {
365 // Create new object.
366 // If this line doesn't compile, you either have to
367 // a) Define an appropriate constructor for T
368 // b) Specialize this function to do whatever the correct
369 // behaviour is to construct the object from compiler data
370 // and context
371 std::unique_ptr<T> temp(new T(rCtx)); // exception-safety
372 // Compile
373 pComp->Value(mkParAdapt(*temp, rPar));
374 pStruct = temp.release();
375 }
376
377 // Helpers for buffer-based compiling (may throw a data format exception!)
378 template <class CompT, class StructT>
CompileFromBuf(StructT && TargetStruct,const typename CompT::InT & SrcBuf)379 void CompileFromBuf(StructT &&TargetStruct, const typename CompT::InT &SrcBuf)
380 {
381 CompT Compiler;
382 Compiler.setInput(SrcBuf.getRef());
383 Compiler.Compile(TargetStruct);
384 }
385 template <class CompT, class StructT>
CompileFromBufToNew(const typename CompT::InT & SrcBuf)386 StructT * CompileFromBufToNew(const typename CompT::InT &SrcBuf)
387 {
388 StructT *pStruct = nullptr;
389 CompileFromBuf<CompT>(mkPtrAdaptNoNull(pStruct), SrcBuf);
390 return pStruct;
391 }
392 template <class CompT, class StructT>
CompileFromBufToNewNamed(const typename CompT::InT & SrcBuf,const char * szName)393 StructT * CompileFromBufToNewNamed(const typename CompT::InT &SrcBuf, const char *szName)
394 {
395 StructT *pStruct = nullptr;
396 CompileFromBuf<CompT>(mkNamingAdapt(mkPtrAdaptNoNull(pStruct), szName), SrcBuf);
397 return pStruct;
398 }
399 template <class CompT, class StructT>
DecompileToBuf(const StructT & SrcStruct)400 typename CompT::OutT DecompileToBuf(const StructT &SrcStruct)
401 {
402 CompT Compiler;
403 Compiler.Decompile(SrcStruct);
404 return Compiler.getOutput();
405 }
406
407 // *** Null compiler
408
409 // Naming supported, nothing is returned. Used for setting default values.
410
411 class StdCompilerNull : public StdCompiler
412 {
413 public:
414
415 // Properties
isDeserializer()416 bool isDeserializer() override { return true; }
hasNaming()417 bool hasNaming() override { return true; }
418
419 // Naming
Name(const char * szName)420 bool Name(const char *szName) override { return false; }
421 int NameCount(const char *szName = nullptr) override { return 0; }
422
423 // Data readers
DWord(int32_t & rInt)424 void DWord(int32_t &rInt) override { }
DWord(uint32_t & rInt)425 void DWord(uint32_t &rInt) override { }
Word(int16_t & rShort)426 void Word(int16_t &rShort) override { }
Word(uint16_t & rShort)427 void Word(uint16_t &rShort) override { }
Byte(int8_t & rByte)428 void Byte(int8_t &rByte) override { }
Byte(uint8_t & rByte)429 void Byte(uint8_t &rByte) override { }
Boolean(bool & rBool)430 void Boolean(bool &rBool) override { }
Character(char & rChar)431 void Character(char &rChar) override { }
432 void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) override { }
433 void String(char **pszString, RawCompileType eType = RCT_Escaped) override { }
434 void String(std::string &str, RawCompileType eType = RCT_Escaped) override {}
435 void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override { }
436 };
437
438 // *** Binary compiler
439
440 // No naming supported, everything is read/written binary.
441
442
443 // binary writer
444 class StdCompilerBinWrite : public StdCompiler
445 {
446 public:
447
448 // Result
449 typedef StdBuf OutT;
getOutput()450 inline OutT getOutput() { return Buf; }
451
452 // Properties
isDoublePass()453 bool isDoublePass() override { return true; }
454
455 // Data writers
456 void DWord(int32_t &rInt) override;
457 void DWord(uint32_t &rInt) override;
458 void Word(int16_t &rShort) override;
459 void Word(uint16_t &rShort) override;
460 void Byte(int8_t &rByte) override;
461 void Byte(uint8_t &rByte) override;
462 void Boolean(bool &rBool) override;
463 void Character(char &rChar) override;
464 void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) override;
465 void String(char **pszString, RawCompileType eType = RCT_Escaped) override;
466 void String(std::string &str, RawCompileType eType = RCT_Escaped) override;
467 void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override;
468
469 // Passes
470 void Begin() override;
471 void BeginSecond() override;
472
473 protected:
474 // Process data
475 bool fSecondPass;
476 int iPos;
477 StdBuf Buf;
478
479 // Helpers
480 template <class T> void WriteValue(const T &rValue);
481 void WriteData(const void *pData, size_t iSize);
482 };
483
484 // binary read
485 class StdCompilerBinRead : public StdCompiler
486 {
487 public:
488
489 // Input
490 typedef StdBuf InT;
setInput(InT && In)491 void setInput(InT &&In) { Buf = std::move(In); }
492
493 // Properties
isDeserializer()494 bool isDeserializer() override { return true; }
495
496 // Data readers
497 void DWord(int32_t &rInt) override;
498 void DWord(uint32_t &rInt) override;
499 void Word(int16_t &rShort) override;
500 void Word(uint16_t &rShort) override;
501 void Byte(int8_t &rByte) override;
502 void Byte(uint8_t &rByte) override;
503 void Boolean(bool &rBool) override;
504 void Character(char &rChar) override;
505 void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) override;
506 void String(char **pszString, RawCompileType eType = RCT_Escaped) override;
507 void String(std::string &str, RawCompileType eType = RCT_Escaped) override;
508 void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override;
509
510 // Position
511 StdStrBuf getPosition() const override;
512
513 // Passes
514 void Begin() override;
515
516 // Data
getPosition()517 size_t getPosition() { return iPos; }
getRemainingBytes()518 size_t getRemainingBytes() { return Buf.getSize() - iPos; }
519
520 protected:
521 // Process data
522 size_t iPos;
523 StdBuf Buf;
524
525 // Helper
526 template <class T> void ReadValue(T &rValue);
527 };
528
529 // *** INI compiler
530
531 // Naming and separators supported, so defaulting can be used through
532 // the appropriate adaptors.
533
534 // Example:
535
536 // [Sect1]
537 // [Sect1a]
538 // Val1=4
539 // Val2=5
540 // Val4=3,5
541
542 // will result from:
543
544 // int v1=4, v2=5, v3=0, v4[3] = { 3, 5, 0 };
545 // DecompileToBuf<StdCompilerINIWrite>(
546 // mkNamingAdapt(
547 // mkNamingAdapt(
548 // mkNamingAdapt(v1, "Val1", 0) +
549 // mkNamingAdapt(v2, "Val2", 0) +
550 // mkNamingAdapt(v3, "Val3", 0),
551 // "Sect1a") +
552 // mkNamingAdapt(mkArrayAdapt(v4, 3, 0), "Val4", 0),
553 // "Sect1")
554 // )
555
556
557 // text writer
558 class StdCompilerINIWrite : public StdCompiler
559 {
560 public:
561 // Input
562 typedef StdStrBuf OutT;
getOutput()563 inline OutT getOutput() { return Buf; }
564
565 // Properties
hasNaming()566 bool hasNaming() override { return true; }
567
568 // Naming
569 bool Name(const char *szName) override;
570 void NameEnd(bool fBreak = false) override;
571
572 // Separators
573 bool Separator(Sep eSep) override;
574
575 // Data writers
576 void DWord(int32_t &rInt) override;
577 void DWord(uint32_t &rInt) override;
578 void Word(int16_t &rShort) override;
579 void Word(uint16_t &rShort) override;
580 void Byte(int8_t &rByte) override;
581 void Byte(uint8_t &rByte) override;
582 void Boolean(bool &rBool) override;
583 void Character(char &rChar) override;
584 void StringN(const char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
585 void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) override;
586 void String(char **pszString, RawCompileType eType = RCT_Escaped) override;
587 void String(std::string &str, RawCompileType eType = RCT_Escaped) override;
588 void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override;
589
590 // Passes
591 void Begin() override;
592 void End() override;
593
594 protected:
595
596 // Result
597 StdStrBuf Buf;
598
599 // Naming stack
600 struct Naming
601 {
602 StdStrBuf Name;
603 Naming *Parent;
604 };
605 Naming *pNaming;
606 // Recursion depth
607 int iDepth;
608
609 // Name not put yet (it's not clear wether it is a value or a section)
610 bool fPutName,
611 // Currently inside a section, so raw data can't be printed
612 fInSection;
613
614 void PrepareForValue();
615 void WriteEscaped(const char *szString, const char *pEnd);
616 void WriteIndent(bool fSectionName);
617 void PutName(bool fSection);
618 };
619
620 // text reader
621 class StdCompilerINIRead : public StdCompiler
622 {
623 public:
624
625 StdCompilerINIRead();
626 ~StdCompilerINIRead() override;
627
628 // Input
629 typedef StdStrBuf InT;
setInput(const InT & In)630 void setInput(const InT &In) { Buf.Ref(In); lineBreaks.clear(); }
631
632 // Properties
isDeserializer()633 bool isDeserializer() override { return true; }
hasNaming()634 bool hasNaming() override { return true; }
635
636 // Naming
637 bool Name(const char *szName) override;
638 void NameEnd(bool fBreak = false) override;
639 bool FollowName(const char *szName) override;
640 const char *GetNameByIndex(size_t idx) const override;
641
642 // Separators
643 bool Separator(Sep eSep) override;
644 void NoSeparator() override;
645
646 // Counters
647 int NameCount(const char *szName = nullptr) override;
648
649 // Data writers
650 void DWord(int32_t &rInt) override;
651 void DWord(uint32_t &rInt) override;
652 void Word(int16_t &rShort) override;
653 void Word(uint16_t &rShort) override;
654 void Byte(int8_t &rByte) override;
655 void Byte(uint8_t &rByte) override;
656 void Boolean(bool &rBool) override;
657 void Character(char &rChar) override;
658 void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) override;
659 void String(char **pszString, RawCompileType eType = RCT_Escaped) override;
660 void String(std::string &str, RawCompileType eType = RCT_Escaped) override;
661 void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override;
662
663 // Position
664 StdStrBuf getPosition() const override;
665
666 // Passes
667 void Begin() override;
668 void End() override;
669
670 protected:
671
672 // * Data
673
674 // Name tree
675 struct NameNode
676 {
677 // Name
678 StdStrBuf Name;
679 // Section?
680 bool Section{false};
681 // Tree structure
682 NameNode *Parent,
683 *FirstChild{nullptr}, *PrevChild{nullptr}, *NextChild{nullptr}, *LastChild{nullptr};
684 // Indent level
685 int Indent{-1};
686 // Name number in parent map
687 const char *Pos{nullptr};
688 // Constructor
689 NameNode(NameNode *pParent = nullptr) :
ParentNameNode690 Parent(pParent)
691 { }
692 };
693 NameNode *pNameRoot{nullptr}, *pName;
694 // Current depth
695 int iDepth{0};
696 // Real depth (depth of recursive Name()-calls - if iDepth != iRealDepth, we are in a nonexistant namespace)
697 int iRealDepth{0};
698
699 // Data
700 StdStrBuf Buf;
701 // Position
702 const char *pPos;
703
704 // Reenter position (if an nonexistant separator was specified)
705 const char *pReenter;
706
707 // Uppermost name that wasn't found
708 StdCopyStrBuf NotFoundName;
709
710 // * Implementation
711
712 // Name tree
713 void CreateNameTree();
714 void FreeNameTree();
715 void FreeNameNode(NameNode *pNode);
716
717 // Navigation
718 void SkipWhitespace();
719 void SkipNum();
720 long ReadNum();
721 size_t GetStringLength(RawCompileType eTyped);
722 StdBuf ReadString(size_t iLength, RawCompileType eTyped, bool fAppendNull = true);
TestStringEnd(RawCompileType eType)723 bool TestStringEnd(RawCompileType eType) { return IsStringEnd(*pPos, eType); }
724 char ReadEscapedChar();
725 unsigned long ReadUNum();
726
727 void notFound(const char *szWhat);
728
729 private:
730 uint32_t getLineNumberOfPos(const char *pos) const;
731 mutable std::vector<const char *> lineBreaks;
732 };
733
734 void StdCompilerWarnCallback(void *pData, const char *szPosition, const char *szError);
735
736 template <class CompT, class StructT>
CompileFromBuf_Log(StructT && TargetStruct,const typename CompT::InT & SrcBuf,const char * szName)737 bool CompileFromBuf_Log(StructT &&TargetStruct, const typename CompT::InT &SrcBuf, const char *szName)
738 {
739 try
740 {
741 CompileFromBuf<CompT>(TargetStruct, SrcBuf);
742 return true;
743 }
744 catch (StdCompiler::Exception *pExc)
745 {
746 if (!pExc->Pos.getLength())
747 LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
748 else
749 LogF("ERROR: %s (in %s, %s)", pExc->Msg.getData(), pExc->Pos.getData(), szName);
750 delete pExc;
751 return false;
752 }
753 }
754 template <class CompT, class StructT>
CompileFromBuf_LogWarn(StructT && TargetStruct,const typename CompT::InT & SrcBuf,const char * szName)755 bool CompileFromBuf_LogWarn(StructT &&TargetStruct, const typename CompT::InT &SrcBuf, const char *szName)
756 {
757 try
758 {
759 CompT Compiler;
760 Compiler.setInput(SrcBuf.getRef());
761 Compiler.setWarnCallback(StdCompilerWarnCallback, reinterpret_cast<void *>(const_cast<char *>(szName)));
762 Compiler.Compile(TargetStruct);
763 return true;
764 }
765 catch (StdCompiler::Exception *pExc)
766 {
767 if (!pExc->Pos.getLength())
768 LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
769 else
770 LogF("ERROR: %s (in %s, %s)", pExc->Msg.getData(), pExc->Pos.getData(), szName);
771 delete pExc;
772 return false;
773 }
774 }
775 template <class CompT, class StructT>
DecompileToBuf_Log(StructT && TargetStruct,typename CompT::OutT * pOut,const char * szName)776 bool DecompileToBuf_Log(StructT &&TargetStruct, typename CompT::OutT *pOut, const char *szName)
777 {
778 if (!pOut) return false;
779 try
780 {
781 pOut->Take(DecompileToBuf<CompT>(TargetStruct));
782 return true;
783 }
784 catch (StdCompiler::Exception *pExc)
785 {
786 LogF("ERROR: %s (in %s)", pExc->Msg.getData(), szName);
787 delete pExc;
788 return false;
789 }
790 }
791
792 #endif // STDCOMPILER_H
793