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