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 STDADAPTORS_H
17 #define STDADAPTORS_H
18 
19 #include "lib/StdCompiler.h"
20 
21 // * Wrappers for C4Compiler-types
22 
23 // Whole-line string, automatic size deduction (C4Compiler-String)
24 #define toC4CStr(szString) mkStringAdaptMA(szString)
25 #define toC4CStrBuf(rBuf) mkParAdapt(rBuf, StdCompiler::RCT_All)
26 
27 // Integer-array with default 0, automatic size deduction
28 #define toC4CArr(rArr) mkArrayAdaptDM(rArr, 0)
29 #define toC4CArrU(rArr) mkArrayAdaptDM(rArr, 0u)
30 
31 // * Null Adaptor
32 // Doesn't compile anything
33 struct StdNullAdapt
34 {
CompileFuncStdNullAdapt35 	inline void CompileFunc(StdCompiler *pComp) const { }
36 };
37 
38 // * Defaulting Adaptor
39 // Sets default if CompileFunc fails with a Exception of type NotFoundException
40 template <class T, class D>
41 struct StdDefaultAdapt
42 {
43 	T &rValue; const D &rDefault;
StdDefaultAdaptStdDefaultAdapt44 	StdDefaultAdapt(T &rValue, const D &rDefault) : rValue(rValue), rDefault(rDefault) { }
CompileFuncStdDefaultAdapt45 	inline void CompileFunc(StdCompiler *pComp) const
46 	{
47 		try
48 		{
49 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
50 			if (!pComp->ValueSafe(rValue))
51 				rValue = rDefault;
52 #else
53 			pComp->Value(rValue);
54 #endif
55 		}
56 		catch (StdCompiler::NotFoundException *pEx)
57 		{
58 			rValue = rDefault;
59 			delete pEx;
60 		}
61 	}
62 };
63 template <class T, class D>
mkDefaultAdapt(T && rValue,const D & rDefault)64 inline StdDefaultAdapt<T, D> mkDefaultAdapt(T &&rValue, const D &rDefault) { return StdDefaultAdapt<T, D>(rValue, rDefault); }
65 
66 // * Naming Adaptor
67 // Embeds a value into a named section, failsafe
68 // (use for values that do defaulting themselves - e.g. objects using naming)
69 template <class T>
70 struct StdNamingAdapt
71 {
72 	T &rValue; const char *szName;
StdNamingAdaptStdNamingAdapt73 	StdNamingAdapt(T &rValue, const char *szName) : rValue(rValue), szName(szName) { }
CompileFuncStdNamingAdapt74 	inline void CompileFunc(StdCompiler *pComp) const
75 	{
76 		pComp->Name(szName);
77 		try
78 		{
79 			pComp->Value(rValue);
80 		}
81 		catch (StdCompiler::Exception *)
82 		{
83 			pComp->NameEnd(true);
84 			throw;
85 		}
86 		pComp->NameEnd();
87 	}
88 	template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
89 	template <class D> inline StdNamingAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
90 };
91 template <class T>
mkNamingAdapt(T && rValue,const char * szName)92 inline StdNamingAdapt<T> mkNamingAdapt(T &&rValue, const char *szName) { return StdNamingAdapt<T>(rValue, szName); }
93 
94 // * Naming Adaptor (defaulting)
95 // Embeds a value into a named section, sets default on fail
96 template <class T, class D>
97 struct StdNamingDefaultAdapt
98 {
99 	T &rValue; const char *szName; const D &rDefault; bool fPrefillDefault; bool fStoreDefault;
StdNamingDefaultAdaptStdNamingDefaultAdapt100 	StdNamingDefaultAdapt(T &rValue, const char *szName, const D &rDefault, bool fPrefillDefault, bool fStoreDefault) : rValue(rValue), szName(szName), rDefault(rDefault), fPrefillDefault(fPrefillDefault), fStoreDefault(fStoreDefault) { }
CompileFuncStdNamingDefaultAdapt101 	inline void CompileFunc(StdCompiler *pComp) const
102 	{
103 		// Default check
104 		if (pComp->hasNaming() && pComp->isSerializer() && rValue == rDefault && !fStoreDefault)
105 		{
106 			if (pComp->Default(szName)) return;
107 		}
108 		try
109 		{
110 			// Search named section, set default if not found
111 			if (pComp->Name(szName))
112 			{
113 				if (fPrefillDefault && pComp->isDeserializer()) rValue = rDefault; // default prefill if desired
114 				pComp->Value(mkDefaultAdapt(rValue, rDefault));
115 			}
116 			else
117 				rValue = rDefault;
118 		}
119 		catch (StdCompiler::Exception *)
120 		{
121 			pComp->NameEnd(true);
122 			throw;
123 		}
124 		// End section
125 		pComp->NameEnd();
126 	}
127 };
128 template <class T, class D>
129 inline StdNamingDefaultAdapt<T,D> mkNamingAdapt(T &&rValue, const char *szName, const D &rDefault, bool fPrefillDefault=false, bool fStoreDefault=false) { return StdNamingDefaultAdapt<T,D>(rValue, szName, rDefault, fPrefillDefault, fStoreDefault); }
130 
131 // * Decompiling Adaptor
132 // Allows to use const objects if the compiler won't change the targets
133 template <class T>
134 struct StdDecompileAdapt
135 {
136 	const T &rValue;
StdDecompileAdaptStdDecompileAdapt137 	explicit StdDecompileAdapt(const T &rValue) : rValue(rValue) { }
CompileFuncStdDecompileAdapt138 	inline void CompileFunc(StdCompiler *pComp) const
139 	{
140 		assert(pComp->isSerializer());
141 		pComp->Value(const_cast<T &>(rValue));
142 	}
143 
144 	// make this work with in combination with StdParameterAdapt
145 	template<typename ... P>
CompileFuncStdDecompileAdapt146 	inline void CompileFunc(StdCompiler* pComp, P && ... pars) const
147 	{
148 		assert(pComp->isSerializer());
149 		pComp->Value(mkParAdapt(const_cast<T &>(rValue), std::forward<P>(pars)...));
150 	}
151 };
152 template <class T>
mkDecompileAdapt(const T & rValue)153 inline StdDecompileAdapt<T> mkDecompileAdapt(const T& rValue) { return StdDecompileAdapt<T>(rValue); }
154 
155 // * Runtime value Adaptor
156 // Allows the C4ValueSetCompiler to set the value
157 template <class T>
158 struct StdRuntimeValueAdapt
159 {
160 	T &rValue;
StdRuntimeValueAdaptStdRuntimeValueAdapt161 	explicit StdRuntimeValueAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdRuntimeValueAdapt162 	inline void CompileFunc(StdCompiler *pComp) const
163 	{
164 		pComp->setRuntimeWritesAllowed(+1);
165 		pComp->Value(rValue);
166 		pComp->setRuntimeWritesAllowed(-1);
167 	}
168 	template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
169 	template <class D> inline StdRuntimeValueAdapt<T> &operator = (const D &nValue) { rValue = nValue; return *this; }
170 };
171 template <class T>
mkRuntimeValueAdapt(T && rValue)172 inline StdRuntimeValueAdapt<T> mkRuntimeValueAdapt(T &&rValue) { return StdRuntimeValueAdapt<T>(rValue); }
173 
174 // * String adaptor
175 struct StdStringAdapt
176 {
177 	char *szString; int iMaxLength; StdCompiler::RawCompileType eRawType;
178 	StdStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
szStringStdStringAdapt179 			: szString(szString), iMaxLength(iMaxLength), eRawType(eRawType) { }
CompileFuncStdStringAdapt180 	inline void CompileFunc(StdCompiler *pComp) const
181 	{
182 		pComp->String(szString, iMaxLength, eRawType);
183 	}
184 	inline bool operator == (const char *szDefault) const { return SEqual(szString, szDefault); }
185 	inline StdStringAdapt &operator = (const char *szDefault) { SCopy(szDefault, szString, iMaxLength); return *this; }
186 };
187 inline StdStringAdapt mkStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
188 { return StdStringAdapt(szString, iMaxLength, eRawType); }
189 #define mkStringAdaptM(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1)
190 #define mkStringAdaptMA(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_All)
191 #define mkStringAdaptMI(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_Idtf)
192 #define mkStringAdaptMIE(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_IdtfAllowEmpty)
193 
194 // * std::string adaptor
195 struct StdStdStringAdapt
196 {
197 	std::string& string; StdCompiler::RawCompileType eRawType;
198 	StdStdStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
stringStdStdStringAdapt199 		: string(string), eRawType(eRawType) { }
CompileFuncStdStdStringAdapt200 	inline void CompileFunc(StdCompiler *pComp) const
201 	{
202 		pComp->String(string, eRawType);
203 	}
204 	inline bool operator == (const char *szDefault) const { return string == szDefault; }
205 	inline StdStdStringAdapt &operator = (const char *szDefault) { string = szDefault; return *this; }
206 };
207 inline StdStdStringAdapt mkStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
208 { return StdStdStringAdapt(string, eRawType); }
mkStringAdaptA(std::string & string)209 inline StdStdStringAdapt mkStringAdaptA(std::string& string)
210 { return StdStdStringAdapt(string, StdCompiler::RCT_All); }
211 
212 // * Raw adaptor
213 struct StdRawAdapt
214 {
215 	void *pData; size_t iSize; StdCompiler::RawCompileType eRawType;
216 	StdRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
pDataStdRawAdapt217 			: pData(pData), iSize(iSize), eRawType(eRawType) { }
CompileFuncStdRawAdapt218 	inline void CompileFunc(StdCompiler *pComp) const
219 	{
220 		pComp->Raw(pData, iSize, eRawType);
221 	}
222 	inline bool operator == (const void *pDefault) const { return !memcmp(pDefault, pData, iSize); }
223 	inline StdRawAdapt &operator = (const void *pDefault) { memcpy(pData, pDefault, iSize); return *this; }
224 };
225 inline StdRawAdapt mkRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
226 { return StdRawAdapt(pData, iSize, eRawType); }
227 #define mkRawAdaptM(X) mkRawAdapt(&X, sizeof(X))
228 
229 // * Integer Adaptor
230 // Stores Integer-like datatypes (Enumerations)
231 template <class T, class int_t = int32_t>
232 struct StdIntAdapt
233 {
234 	T &rValue;
StdIntAdaptStdIntAdapt235 	explicit StdIntAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdIntAdapt236 	inline void CompileFunc(StdCompiler *pComp) const
237 	{
238 		// Cast
239 		int_t iVal = int_t(rValue);
240 		pComp->Value(iVal);
241 		rValue = T(iVal);
242 	}
243 	// Operators for default checking/setting
244 	template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
245 	template <class D> inline StdIntAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
246 };
mkIntAdapt(T & rValue)247 template <class T> inline StdIntAdapt<T> mkIntAdapt(T &rValue) { return StdIntAdapt<T>(rValue); }
mkIntAdaptT(T & rValue)248 template <class int_t, class T> StdIntAdapt<T, int_t> mkIntAdaptT(T &rValue) { return StdIntAdapt<T, int_t>(rValue); }
249 
250 // * Casting Adaptor
251 // Does a reinterprete_cast
252 template <class T, class to_t>
253 struct StdCastAdapt
254 {
255 	T &rValue;
StdCastAdaptStdCastAdapt256 	explicit StdCastAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdCastAdapt257 	inline void CompileFunc(StdCompiler *pComp) const
258 	{
259 		// Cast
260 		static_assert(sizeof(to_t) == sizeof(T), "CastAdapt sanity: sizes match");
261 		static_assert(std::is_pod<to_t>::value, "CastAdapt sanity: to-type is POD");
262 		static_assert(std::is_pod<T>::value, "CastAdapt sanity: from-type is POD");
263 		to_t vVal;
264 		std::memcpy(&vVal, &rValue, sizeof(to_t));
265 		pComp->Value(vVal);
266 		std::memcpy(&rValue, &vVal, sizeof(T));
267 	}
268 	// Operators for default checking/setting
269 	template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
270 	template <class D> inline StdCastAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
271 };
mkCastAdapt(T & rValue)272 template <class to_t, class T> StdCastAdapt<T, to_t> mkCastAdapt(T &rValue) { return StdCastAdapt<T, to_t>(rValue); }
mkCastIntAdapt(T & rValue)273 template <class T> StdCastAdapt<T, int32_t> mkCastIntAdapt(T &rValue) { return StdCastAdapt<T, int32_t>(rValue); }
274 
275 // Helper: Identity function class
276 template <class T>
277 struct _IdFuncClass
278 {
operator_IdFuncClass279 	T &operator ()(T &rValue) const { return rValue; }
280 };
281 
282 // * Array Adaptor
283 // Stores a separated list
284 template <class T, class M = _IdFuncClass<T> >
285 struct StdArrayAdapt
286 {
287 	StdArrayAdapt(T *pArray, int iSize, M && map = M())
pArrayStdArrayAdapt288 			: pArray(pArray), iSize(iSize), map(std::forward<M>(map))
289 	{ }
290 	T *pArray; int iSize; M && map;
CompileFuncStdArrayAdapt291 	inline void CompileFunc(StdCompiler *pComp) const
292 	{
293 		for (int i = 0; i < iSize; i++)
294 		{
295 			if (i) pComp->Separator(StdCompiler::SEP_SEP);
296 			pComp->Value(map(pArray[i]));
297 		}
298 	}
299 	// Operators for default checking/setting
300 	inline bool operator == (const T &rDefault) const
301 	{
302 		for (int i = 0; i < iSize; i++)
303 			if (pArray[i] != rDefault)
304 				return false;
305 		return true;
306 	}
307 	inline StdArrayAdapt &operator = (const T &rDefault)
308 	{
309 		for (int i = 0; i < iSize; i++)
310 			pArray[i] = rDefault;
311 		return *this;
312 	}
313 	inline bool operator == (const T *pDefaults) const
314 	{
315 		for (int i = 0; i < iSize; i++)
316 			if (pArray[i] != pDefaults[i])
317 				return false;
318 		return true;
319 	}
320 	inline StdArrayAdapt &operator = (const T *pDefaults)
321 	{
322 		for (int i = 0; i < iSize; i++)
323 			pArray[i] = pDefaults[i];
324 		return *this;
325 	}
326 };
327 template <class T>
mkArrayAdapt(T * pArray,int iSize)328 inline StdArrayAdapt<T> mkArrayAdapt(T *pArray, int iSize) { return StdArrayAdapt<T>(pArray, iSize); }
329 #define mkArrayAdaptM(A) mkArrayAdapt(A, sizeof(A) / sizeof(*(A)))
330 template <class T, class M>
mkArrayAdaptMap(T * pArray,int iSize,M && map)331 inline StdArrayAdapt<T, M> mkArrayAdaptMap(T *pArray, int iSize, M && map) { return StdArrayAdapt<T, M>(pArray, iSize, std::forward<M>(map)); }
332 #define mkArrayAdaptMapM(A, M) mkArrayAdaptMap(A, sizeof(A) / sizeof(*(A)), M)
333 
334 // * Array Adaptor (defaulting)
335 // Stores a separated list, sets defaults if a value or separator is missing.
336 template <class T, class D, class M = _IdFuncClass<T> >
337 struct StdArrayDefaultAdapt
338 {
339 	StdArrayDefaultAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M())
pArrayStdArrayDefaultAdapt340 			: pArray(pArray), iSize(iSize), rDefault(rDefault), map(map)
341 	{ }
342 	T *pArray; size_t iSize; const D &rDefault; const M map;
CompileFuncStdArrayDefaultAdapt343 	inline void CompileFunc(StdCompiler *pComp) const
344 	{
345 		size_t i, iWrite = iSize;
346 		bool deserializing = pComp->isDeserializer();
347 		// Decompiling: Omit defaults
348 		if (!deserializing && pComp->hasNaming())
349 			while (iWrite > 0 && pArray[iWrite - 1] == rDefault)
350 				iWrite--;
351 		// Read/write values
352 		for (i = 0; i < iWrite; i++)
353 		{
354 			// Separator?
355 			if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break;
356 			// Expect a value. Default if not found.
357 			pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault));
358 		}
359 		// Fill rest of array
360 		if (deserializing)
361 			for (; i < iSize; i++)
362 				pArray[i] = rDefault;
363 	}
364 	// Additional defaulting (whole array)
365 	inline bool operator == (const T *pDefaults) const
366 	{
367 		for (size_t i = 0; i < iSize; i++)
368 			if (pArray[i] != pDefaults[i])
369 				return false;
370 		return true;
371 	}
372 	inline StdArrayDefaultAdapt &operator = (const T *pDefaults)
373 	{
374 		for (size_t i = 0; i < iSize; i++)
375 			pArray[i] = pDefaults[i];
376 		return *this;
377 	}
378 };
379 template <class T, class D>
mkArrayAdapt(T * pArray,size_t iSize,const D & rDefault)380 inline StdArrayDefaultAdapt<T, D> mkArrayAdapt(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultAdapt<T, D>(pArray, iSize, rDefault); }
381 #define mkArrayAdaptDM(A, D) mkArrayAdapt(A, sizeof(A) / sizeof(*(A)), D)
382 template <class T, class D, class M>
mkArrayAdaptMap(T * pArray,size_t iSize,const D & rDefault,M map)383 inline StdArrayDefaultAdapt<T, D, M> mkArrayAdaptMap(T *pArray, size_t iSize, const D &rDefault, M map) { return StdArrayDefaultAdapt<T, D, M>(pArray, iSize, rDefault, map); }
384 #define mkArrayAdaptMapDM(A, D, M) mkArrayAdaptMap(A, sizeof(A) / sizeof(*(A)), D, M)
385 
386 // * Array Adaptor (defaulting to another array)
387 // Stores a separated list, sets defaults if a value or separator is missing.
388 template <class T, class D, class M = _IdFuncClass<T> >
389 struct StdArrayDefaultArrayAdapt
390 {
391 	StdArrayDefaultArrayAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M())
pArrayStdArrayDefaultArrayAdapt392 			: pArray(pArray), iSize(iSize), rDefault(rDefault), map(map)
393 	{ }
394 	T *pArray; size_t iSize; const D &rDefault; const M map;
CompileFuncStdArrayDefaultArrayAdapt395 	inline void CompileFunc(StdCompiler *pComp) const
396 	{
397 		size_t i, iWrite = iSize;
398 		bool deserializing = pComp->isDeserializer();
399 		// Decompiling: Omit defaults
400 		if (!deserializing && pComp->hasNaming())
401 			while (iWrite > 0 && pArray[iWrite - 1] == rDefault[iWrite - 1])
402 				iWrite--;
403 		// Read/write values
404 		for (i = 0; i < iWrite; i++)
405 		{
406 			// Separator?
407 			if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break;
408 			// Expect a value. Default if not found.
409 			pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault[i]));
410 		}
411 		// Fill rest of array
412 		if (deserializing)
413 			for (; i < iSize; i++)
414 				pArray[i] = rDefault[i];
415 	}
416 	// Additional defaulting (whole array)
417 	inline bool operator == (const T *pDefaults) const
418 	{
419 		for (size_t i = 0; i < iSize; i++)
420 			if (pArray[i] != pDefaults[i])
421 				return false;
422 		return true;
423 	}
424 	inline StdArrayDefaultArrayAdapt &operator = (const T *pDefaults)
425 	{
426 		for (size_t i = 0; i < iSize; i++)
427 			pArray[i] = pDefaults[i];
428 		return *this;
429 	}
430 };
431 template <class T, class D>
mkArrayAdaptDefArr(T * pArray,size_t iSize,const D & rDefault)432 inline StdArrayDefaultArrayAdapt<T, D> mkArrayAdaptDefArr(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultArrayAdapt<T, D>(pArray, iSize, rDefault); }
433 #define mkArrayAdaptDMA(A, D) mkArrayAdaptDefArr(A, sizeof(A) / sizeof(*(A)), D)
434 template <class T, class D, class M>
mkArrayAdaptDefArrMap(T * pArray,size_t iSize,const D & rDefault,const M & map)435 inline StdArrayDefaultArrayAdapt<T, D, M> mkArrayAdaptDefArrMap(T *pArray, size_t iSize, const D &rDefault, const M &map) { return StdArrayDefaultArrayAdapt<T, D, M>(pArray, iSize, rDefault, map); }
436 #define mkArrayAdaptDMAM(A, D, M) mkArrayAdaptDefArrMap(A, sizeof(A) / sizeof(*(A)), D, M)
437 
438 // * Insertion Adaptor
439 // Compile a value before / after another
440 template <class T, class I>
441 struct StdInsertAdapt
442 {
443 	StdInsertAdapt(T &rObj, I &rIns, bool fBefore = true)
rObjStdInsertAdapt444 			: rObj(rObj), rIns(rIns), fBefore(fBefore)
445 	{ }
446 	T &rObj; I &rIns; bool fBefore;
CompileFuncStdInsertAdapt447 	void CompileFunc(StdCompiler *pComp) const
448 	{
449 		if (fBefore) pComp->Value(rIns);
450 		pComp->Value(rObj);
451 		if (!fBefore) pComp->Value(rIns);
452 	}
453 };
454 template <class T, class I>
455 inline StdInsertAdapt<T, I> mkInsertAdapt(T &&rObj, I &&rIns, bool fBefore = true) { return StdInsertAdapt<T,I>(rObj, rIns, fBefore); }
456 
457 // * Parameter Adaptor
458 // Specify a second parameter for the CompileFunc
459 template <class T, class P>
460 struct StdParameterAdapt
461 {
StdParameterAdaptStdParameterAdapt462 	StdParameterAdapt(T && rObj, P && rPar) : rObj(std::forward<T>(rObj)), Par(std::forward<P>(rPar)) { }
463 	T && rObj; P && Par;
CompileFuncStdParameterAdapt464 	void CompileFunc(StdCompiler *pComp) const
465 	{
466 		std::forward<T>(rObj).CompileFunc(pComp, std::forward<P>(Par));
467 	}
468 	// Operators for default checking/setting
469 	template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
470 	template <class D> inline StdParameterAdapt &operator = (const D &nValue) { rObj = nValue; return *this; }
471 
472 	// getting value
GetObjStdParameterAdapt473 	inline T && GetObj() { return std::forward<T>(rObj); }
474 };
475 template <class T, class P>
mkParAdapt(T && rObj,P && rPar)476 inline StdParameterAdapt<T, P> mkParAdapt(T && rObj, P && rPar)
477 { return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(rPar)); }
478 
479 // for mkArrayAdaptMap
480 template <class P>
481 struct StdParameterAdaptMaker
482 {
483 	P && Par;
StdParameterAdaptMakerStdParameterAdaptMaker484 	StdParameterAdaptMaker(P && rPar) : Par(std::forward<P>(rPar)) { }
485 	template <class T>
operatorStdParameterAdaptMaker486 	StdParameterAdapt<T, P> operator ()(T && rObj) const { return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(Par)); }
487 };
488 template <class P>
mkParAdaptMaker(P && rPar)489 inline StdParameterAdaptMaker<P> mkParAdaptMaker(P && rPar) { return StdParameterAdaptMaker<P>(std::forward<P>(rPar)); }
490 
491 // * Parameter Adaptor 2
492 // Specify a second and a third parameter for the CompileFunc
493 template <class T, class P1, class P2>
494 struct StdParameter2Adapt
495 {
StdParameter2AdaptStdParameter2Adapt496 	StdParameter2Adapt(T && rObj, P1 && rPar1, P2 && rPar2) :
497 		rObj(std::forward<T>(rObj)), rPar1(std::forward<P1>(rPar1)), rPar2(std::forward<P2>(rPar2)) { }
498 	T && rObj; P1 && rPar1; P2 && rPar2;
CompileFuncStdParameter2Adapt499 	void CompileFunc(StdCompiler *pComp) const
500 	{
501 		std::forward<T>(rObj).CompileFunc(pComp, std::forward<P1>(rPar1), std::forward<P2>(rPar2));
502 	}
503 	// Operators for default checking/setting
504 	template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
505 	template <class D> inline StdParameter2Adapt &operator = (const D &nValue) { rObj = nValue; return *this; }
506 };
507 template <class T, class P1, class P2>
mkParAdapt(T && rObj,P1 && rPar1,P2 && rPar2)508 inline StdParameter2Adapt<T, P1, P2> mkParAdapt(T && rObj, P1 && rPar1, P2 && rPar2)
509 { return StdParameter2Adapt<T, P1, P2>(std::forward<T>(rObj), std::forward<P1>(rPar1), std::forward<P2>(rPar2)); }
510 
511 template <class T>
512 struct StdBasicPtrAdapt
513 {
514 	StdBasicPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data")
rpObjStdBasicPtrAdapt515 		: rpObj(rpObj), fAllowNull(fAllowNull), szNaming(szNaming) {}
516 	T *&rpObj; bool fAllowNull; const char *szNaming;
517 
518 	// Operators for default checking/setting
519 	inline bool operator == (const T &nValue) const { return rpObj && *rpObj == nValue; }
520 	inline StdBasicPtrAdapt &operator = (const T &nValue) { delete rpObj; rpObj = new T(nValue); return *this; }
521 	inline bool operator == (const T *pValue) const { return rpObj == pValue; }
522 	inline StdBasicPtrAdapt &operator = (const T *pValue) { delete rpObj; rpObj = pValue; return *this; }
523 };
524 
525 // * Store pointer (contents)
526 // Defaults to null
527 template <class T>
528 struct StdPtrAdapt: StdBasicPtrAdapt<T>
529 {
530 	StdPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data")
531 			: StdBasicPtrAdapt<T>(rpObj, fAllowNull, szNaming)
532 	{ }
533 
CompileFuncStdPtrAdapt534 	void CompileFunc(StdCompiler *pComp) const
535 	{
536 		StdPtrAdaptCompileFunc(pComp, *this);
537 	}
538 
539 	// For use with StdParAdapt
540 	template<typename ... P>
CompileFuncStdPtrAdapt541 	void CompileFunc(StdCompiler *pComp, P && ...pars)
542 	{
543 		StdPtrAdaptCompileFunc(pComp, *this, std::forward<P>(pars)...);
544 	}
545 };
546 
547 template <class T, class ContextT>
548 struct StdContextPtrAdapt: StdBasicPtrAdapt<T>
549 {
550 	StdContextPtrAdapt(T *&rpObj, const ContextT& rCtx, bool fAllowNull = true, const char *szNaming = "Data")
551 		: StdBasicPtrAdapt<T>(rpObj, fAllowNull, szNaming), pCtx(&rCtx)
552 	{ }
553 
554 	const ContextT* pCtx;
555 
CompileFuncStdContextPtrAdapt556 	void CompileFunc(StdCompiler *pComp) const
557 	{
558 		StdPtrAdaptCompileFunc(pComp, *this);
559 	}
560 
561 	// For use with StdParAdapt
562 	template<class P>
CompileFuncStdContextPtrAdapt563 	void CompileFunc(StdCompiler *pComp, const P& p)
564 	{
565 		StdPtrAdaptCompileFunc(pComp, *this, p);
566 	}
567 };
568 
569 template <class T, typename ... P>
StdPtrAdaptCompileFunc(StdCompiler * pComp,const T & adapt,P &&...pars)570 void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt, P && ...pars)
571 {
572 	bool deserializing = pComp->isDeserializer(),
573 		fNaming = pComp->hasNaming();
574 	// Compiling? Clear object before
575 	if(deserializing) { delete adapt.rpObj; adapt.rpObj = nullptr; }
576 	// Null checks - different with naming support.
577 	if(adapt.fAllowNull)
578 		if(fNaming)
579 		{
580 			// Null check: just omit when writing
581 			if(!deserializing && !adapt.rpObj) return;
582 			// Set up naming
583 			if(!pComp->Name(adapt.szNaming)) { assert(deserializing); pComp->NameEnd(); return; }
584 		}
585 		else
586 		{
587 			bool fNull = !! adapt.rpObj;
588 			pComp->Value(fNull);
589 			// Null? Nothing further to do
590 			if(fNull) return;
591 		}
592 	else if(!deserializing)
593 		assert(adapt.rpObj);
594 	// Compile value
595 	if(deserializing)
596 		StdPtrAdaptCompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
597 	else
598 		StdPtrAdaptDecompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
599 
600 	// Close naming
601 	if(adapt.fAllowNull && fNaming) pComp->NameEnd();
602 }
603 
604 
605 template <class T, typename ... P>
StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp,P &&...pars)606 void StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFunc(adapt.rpObj, pComp, std::forward<P>(pars)...); }
607 template <class T, class ContextT, typename ... P>
StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp,P &&...pars)608 void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx, std::forward<P>(pars)...); }
609 
610 template <class T>
StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp)611 void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
612 template <class T, class ContextT>
StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp)613 void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
614 template <class T, typename ... P>
StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp,P &&...pars)615 void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
616 template <class T, class ContextT, typename ... P>
StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp,P &&...pars)617 void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
618 
619 template <class T>
620 inline StdPtrAdapt<T> mkPtrAdapt(T *&rpObj, bool fAllowNull = true) { return StdPtrAdapt<T>(rpObj, fAllowNull); }
621 template <class T>
mkNamingPtrAdapt(T * & rpObj,const char * szNaming)622 inline StdPtrAdapt<T> mkNamingPtrAdapt(T *&rpObj, const char *szNaming) { return StdPtrAdapt<T>(rpObj, true, szNaming); }
623 template <class T>
mkPtrAdaptNoNull(T * & rpObj)624 inline StdPtrAdapt<T> mkPtrAdaptNoNull(T *&rpObj) { return mkPtrAdapt<T>(rpObj, false); }
625 
626 template <class T, class ContextT>
627 inline StdContextPtrAdapt<T, ContextT> mkContextPtrAdapt(T *&rpObj, const ContextT& ctx, bool fAllowNull = true) { return StdContextPtrAdapt<T, ContextT>(rpObj, ctx, fAllowNull); }
628 template <class T, class ContextT>
mkNamingContextPtrAdapt(T * & rpObj,const ContextT & ctx,const char * szNaming)629 inline StdContextPtrAdapt<T, ContextT> mkNamingContextPtrAdapt(T *&rpObj, const ContextT& ctx, const char* szNaming) { return StdContextPtrAdapt<T, ContextT>(rpObj, ctx, true, szNaming); }
630 template <class T, class ContextT>
mkContextPtrAdaptNoNull(T * & rpObj,const ContextT & ctx)631 inline StdContextPtrAdapt<T, ContextT> mkContextPtrAdaptNoNull(T *&rpObj, const ContextT& ctx) { return mkContextPtrAdapt<T, ContextT>(rpObj, ctx, false); }
632 
633 // * Adaptor for STL containers
634 // Writes a comma-separated list for compilers that support it. Otherwise, the size is calculated and safed.
635 // The defaulting uses the standard STL operators (full match)
636 template <class C>
637 struct StdSTLContainerAdapt
638 {
639 	StdSTLContainerAdapt(C &rStruct, StdCompiler::Sep eSep = StdCompiler::SEP_SEP)
rStructStdSTLContainerAdapt640 			: rStruct(rStruct), eSep(eSep) { }
641 	C &rStruct; const StdCompiler::Sep eSep;
CompileFuncStdSTLContainerAdapt642 	inline void CompileFunc(StdCompiler *pComp) const
643 	{
644 		typedef typename C::value_type T;
645 		// Get compiler specs
646 		bool deserializing = pComp->isDeserializer();
647 		bool fNaming = pComp->hasNaming();
648 		// Decompiling?
649 		if (!deserializing)
650 		{
651 			// Write size (binary only)
652 			if (!fNaming)
653 			{
654 				int32_t iSize = rStruct.size();
655 				pComp->Value(iSize);
656 			}
657 			// Write all entries
658 			for (typename C::const_iterator i = rStruct.begin(); i != rStruct.end(); ++i)
659 			{
660 				if (i != rStruct.begin() && eSep) pComp->Separator(eSep);
661 				pComp->Value(const_cast<T &>(*i));
662 			}
663 		}
664 		else
665 		{
666 			// Compiling: Empty previous
667 			rStruct.clear();
668 			// Read size (binary only)
669 			uint32_t iSize;
670 			if (!fNaming) pComp->Value(iSize);
671 			// Read new
672 			do
673 			{
674 				// No entries left to read?
675 				if (!fNaming && !iSize--)
676 					break;
677 				// Read entries
678 				try
679 				{
680 					T val;
681 					pComp->Value(val);
682 					rStruct.push_back(val);
683 				}
684 				catch (StdCompiler::NotFoundException *pEx)
685 				{
686 					// No value found: Stop reading loop
687 					delete pEx;
688 					break;
689 				}
690 			}
691 			while (!eSep || pComp->Separator(eSep));
692 		}
693 	}
694 	// Operators for default checking/setting
695 	inline bool operator == (const C &nValue) const { return rStruct == nValue; }
696 	inline StdSTLContainerAdapt &operator = (const C &nValue) { rStruct = nValue; return *this; }
697 };
698 template <class C>
699 inline StdSTLContainerAdapt<C> mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep = StdCompiler::SEP_SEP) { return StdSTLContainerAdapt<C>(rTarget, eSep); }
700 
701 // Write an integer that is supposed to be small most of the time. The adaptor writes it in
702 // 7-bit-pieces, bit 8 being a continuation marker: If it's set, more data is following, if not,
703 // all following bits are 0.
704 // Code lengths for uint32_t:
705 // 0x00000000 (0)         - 0x0000007F (127)        : 1 byte
706 // 0x00000080 (128)       - 0x00003FFF (16383)      : 2 byte
707 // 0x00004000 (16384)     - 0x001FFFFF (2097151)    : 3 byte
708 // 0x00200000 (2097152)   - 0x0FFFFFFF (268435456)  : 4 byte
709 // 0x10000000 (268435456) - 0xFFFFFFFF (4294967295) : 5 byte
710 // So this sort of packing is always useful when the integer in question is almost impossible to
711 // grow bigger than 2,097,151.
712 template <class T>
713 struct StdIntPackAdapt
714 {
StdIntPackAdaptStdIntPackAdapt715 	StdIntPackAdapt(T &rVal) : rVal(rVal) { }
716 	T &rVal;
717 
clearUpperStdIntPackAdapt718 	inline T clearUpper(T x) const
719 	{
720 		const int CLEARBITS = 8 * sizeof(T) - 7;
721 		return (x << CLEARBITS) >> CLEARBITS;
722 	}
723 
CompileFuncStdIntPackAdapt724 	void CompileFunc(StdCompiler *pComp) const
725 	{
726 		// simply write for textual compilers
727 		if (pComp->hasNaming())
728 		{
729 			pComp->Value(rVal);
730 			return;
731 		}
732 		T val; uint8_t tmp;
733 		// writing?
734 		if (!pComp->isDeserializer())
735 		{
736 			val = rVal;
737 			for (;;)
738 			{
739 				tmp = uint8_t(clearUpper(val));
740 				// last byte?
741 				if (clearUpper(val) == val)
742 					break;
743 				// write byte
744 				tmp ^= 0x80; pComp->Value(tmp);
745 				// advance
746 				val >>= 7;
747 			}
748 			// write last byte
749 			pComp->Value(tmp);
750 		}
751 		// reading?
752 		else
753 		{
754 			// read first byte
755 			pComp->Value(tmp);
756 			val = clearUpper(T(tmp));
757 			// read remaining bytes
758 			int i = 7; T data = val;
759 			while ( uint8_t(data) != tmp )
760 			{
761 				// read byte
762 				pComp->Value(tmp);
763 				// add to value
764 				data = clearUpper(T(tmp));
765 				val = (data << i) | (val & ((1 << i) - 1));
766 				// next byte
767 				i+=7;
768 			}
769 			// write
770 			rVal = val;
771 		}
772 	}
773 	template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
774 	template <class D> inline StdIntPackAdapt &operator = (const D &nValue) { rVal = nValue; return *this; }
775 };
776 template <class T>
mkIntPackAdapt(T & rVal)777 StdIntPackAdapt<T> mkIntPackAdapt(T &rVal) { return StdIntPackAdapt<T>(rVal); }
778 
779 template <class T>
780 struct StdEnumEntry
781 {
782 	const char *Name;
783 	T Val;
784 };
785 
786 // Enumeration: For text compilers, write a given name for a value.
787 // For everything else, just write an integer of given type.
788 template <class T, class int_t = int32_t>
789 struct StdEnumAdapt
790 {
791 	typedef StdEnumEntry<T> Entry;
792 
StdEnumAdaptStdEnumAdapt793 	StdEnumAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); }
794 	T &rVal; const Entry *pNames;
795 
CompileFuncStdEnumAdapt796 	void CompileFunc(StdCompiler *pComp) const
797 	{
798 		// Write as int
799 		if (!pComp->isVerbose())
800 		{
801 			pComp->Value(mkIntAdaptT<int_t>(rVal));
802 			return;
803 		}
804 		// writing?
805 		if (!pComp->isDeserializer())
806 		{
807 			// Find value
808 			const Entry *pName = pNames;
809 			for (; pName->Name; pName++)
810 				if (pName->Val == rVal)
811 				{
812 					// Put name
813 					pComp->String(const_cast<char **>(&pName->Name), StdCompiler::RCT_Idtf);
814 					break;
815 				}
816 			// No name found?
817 			if (!pName->Name)
818 				// Put value as integer
819 				pComp->Value(mkIntAdaptT<int_t>(rVal));
820 		}
821 		// reading?
822 		else
823 		{
824 			int_t val = 0;
825 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
826 			// Try to read as number
827 			if (!pComp->ValueSafe(val))
828 			{
829 				rVal = T(val);
830 #else
831 			// Try to read as number
832 			try
833 			{
834 				pComp->Value(val);
835 				rVal = T(val);
836 			}
837 			catch (StdCompiler::NotFoundException *pEx)
838 			{
839 				delete pEx;
840 #endif
841 				// Try to read as string
842 				StdStrBuf Name;
843 				pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf));
844 				// Search in name list
845 				const Entry *pName = pNames;
846 				for (; pName->Name; pName++)
847 					if (Name == pName->Name)
848 					{
849 						rVal = pName->Val;
850 						break;
851 					}
852 				// Not found? Warn
853 				if (!pName->Name)
854 					pComp->Warn("Unknown bit name: %s", Name.getData());
855 			}
856 		}
857 	}
858 
859 	template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
860 	template <class D> inline StdEnumAdapt<T, int_t> &operator = (const D &nValue) { rVal = nValue; return *this; }
861 };
862 template <class T, class int_t>
mkEnumAdapt(T & rVal,const StdEnumEntry<T> * pNames)863 StdEnumAdapt<T, int_t> mkEnumAdapt(T &rVal, const StdEnumEntry<T> *pNames) { return StdEnumAdapt<T, int_t>(rVal, pNames); }
864 template <class int_t, class T>
mkEnumAdaptT(T & rVal,const StdEnumEntry<T> * pNames)865 StdEnumAdapt<T, int_t> mkEnumAdaptT(T &rVal, const StdEnumEntry<T> *pNames) { return StdEnumAdapt<T, int_t>(rVal, pNames); }
866 
867 template <class T>
868 struct StdBitfieldEntry
869 {
870 	const char *Name;
871 	T Val;
872 };
873 
874 // Convert a bitfield into/from something like "foo | bar | baz", where "foo", "bar" and "baz" are given constants.
875 template <class T>
876 struct StdBitfieldAdapt
877 {
878 	typedef StdBitfieldEntry<T> Entry;
879 
StdBitfieldAdaptStdBitfieldAdapt880 	StdBitfieldAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); }
881 	T &rVal; const Entry *pNames;
882 
CompileFuncStdBitfieldAdapt883 	void CompileFunc(StdCompiler *pComp) const
884 	{
885 		// simply write for non-verbose compilers
886 		if (!pComp->isVerbose())
887 		{
888 			pComp->Value(rVal);
889 			return;
890 		}
891 		// writing?
892 		if (!pComp->isDeserializer())
893 		{
894 			T val = rVal, orig_val = rVal;
895 			// Write until value is comsumed
896 			bool fFirst = true;
897 			for (const Entry *pName = pNames; pName->Name; pName++)
898 				if ((pName->Val & val) == pName->Val)
899 				{
900 					// Avoid writing meaningless none-values (e.g. Category=C4D_None|C4D_Object)
901 					if (orig_val && !pName->Val) continue;
902 					// Put "|"
903 					if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE);
904 					// Put name
905 					pComp->String(const_cast<char **>(&pName->Name), StdCompiler::RCT_Idtf);
906 					fFirst = false;
907 					// Remove bits
908 					val &= ~pName->Val;
909 				}
910 			// Anything left is written as number, or a simple 0 in case no default was used
911 			if (val || fFirst)
912 			{
913 				// Put "|"
914 				if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE);
915 				// Put value
916 				pComp->Value(val);
917 			}
918 		}
919 		// reading?
920 		else
921 		{
922 			T val = 0;
923 			// Read
924 			do
925 			{
926 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
927 				T tmp;
928 				// Try to read as number
929 				if (pComp->ValueSafe(tmp))
930 					val |= tmp;
931 				else
932 				{
933 #else
934 				// Try to read as number
935 				try
936 				{
937 					T tmp;
938 					pComp->Value(tmp);
939 					val |= tmp;
940 				}
941 				catch (StdCompiler::NotFoundException *pEx)
942 				{
943 					delete pEx;
944 #endif
945 					// Try to read as string
946 					StdStrBuf Name;
947 					pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf));
948 					// Search in name list
949 					const Entry *pName = pNames;
950 					for (; pName->Name; pName++)
951 						if (Name == pName->Name)
952 						{
953 							val |= pName->Val;
954 							break;
955 						}
956 					// Not found? Warn
957 					if (!pName->Name)
958 						pComp->Warn("Unknown bit name: %s", Name.getData());
959 				}
960 				// Expect separation
961 			} while (pComp->Separator(StdCompiler::SEP_VLINE));
962 			// Write value back
963 			rVal = val;
964 		}
965 	}
966 
967 	template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
968 	template <class D> inline StdBitfieldAdapt<T> &operator = (const D &nValue) { rVal = nValue; return *this; }
969 };
970 template <class T>
mkBitfieldAdapt(T & rVal,const StdBitfieldEntry<T> * pNames)971 StdBitfieldAdapt<T> mkBitfieldAdapt(T &rVal, const StdBitfieldEntry<T> *pNames) { return StdBitfieldAdapt<T>(rVal, pNames); }
972 
973 // * Name count adapter
974 // For compilers without name support, this just compiles the given value. Otherwise, the count
975 // of given namings is returned on compiling, and nothing is done for decompiling (The caller
976 // has to make sure that an appropriate number of namings will be created)
977 template <class int_t>
978 struct StdNamingCountAdapt
979 {
980 	int_t &iCount; const char *szName;
StdNamingCountAdaptStdNamingCountAdapt981 	StdNamingCountAdapt(int_t &iCount, const char *szName) : iCount(iCount), szName(szName) { }
CompileFuncStdNamingCountAdapt982 	inline void CompileFunc(StdCompiler *pComp) const
983 	{
984 		if (pComp->hasNaming())
985 		{
986 			if (pComp->isDeserializer())
987 				iCount = pComp->NameCount(szName);
988 		}
989 		else
990 			pComp->Value(mkIntPackAdapt(iCount));
991 	}
992 };
993 template <class int_t>
mkNamingCountAdapt(int_t & iCount,const char * szName)994 inline StdNamingCountAdapt<int_t> mkNamingCountAdapt(int_t &iCount, const char *szName) { return StdNamingCountAdapt<int_t>(iCount, szName); }
995 
996 // * Hex adapter
997 // Writes raw binary data in hexadecimal
998 class StdHexAdapt
999 {
1000 	void *pData; size_t iSize;
1001 public:
StdHexAdapt(void * pData,size_t iSize)1002 	StdHexAdapt(void *pData, size_t iSize) : pData(pData), iSize(iSize) { }
CompileFunc(StdCompiler * pComp)1003 	inline void CompileFunc(StdCompiler *pComp) const
1004 	{
1005 		if (!pComp->isVerbose())
1006 			pComp->Raw(pData, iSize);
1007 		char szData[2+1]; bool deserializing = pComp->isDeserializer();
1008 		for (size_t i = 0; i < iSize; i++)
1009 		{
1010 			uint8_t *pByte = reinterpret_cast<uint8_t *>(pData) + i;
1011 			if (!deserializing) sprintf(szData, "%02x", *pByte);
1012 			pComp->String(szData, 2, StdCompiler::RCT_Idtf);
1013 			if (deserializing)
1014 			{
1015 				unsigned int b;
1016 				if (sscanf(szData, "%02x", &b) != 1)
1017 					pComp->excNotFound(i ? "hexadecimal data: bytes missing!" : "hexadecimal data missing!");
1018 				*pByte = b;
1019 			}
1020 		}
1021 	}
1022 };
mkHexAdapt(void * pData,size_t iSize)1023 inline StdHexAdapt mkHexAdapt(void *pData, size_t iSize) { return StdHexAdapt(pData, iSize); }
1024 template <class T>
mkHexAdapt(T & rData)1025 inline StdHexAdapt mkHexAdapt(T &rData) { return StdHexAdapt(&rData, sizeof(rData)); }
1026 
1027 
1028 #endif //STDADAPTORS_H
1029