Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
NMTCreator.h
Go to the documentation of this file.
1/* Copyright (C) 2020 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Serialization.h"
19#include <vector>
20
21// If included from within the NMT Creation process, perform a pass
22#ifdef CREATING_NMT
23
24#include NMT_CREATE_HEADER_NAME
25
26#undef START_NMTS
27#undef END_NMTS
28#undef START_NMT_CLASS
29#undef START_NMT_CLASS_DERIVED
30#undef NMT_FIELD_INT
31#undef NMT_FIELD
32#undef NMT_FIELD_SECRET
33#undef NMT_START_ARRAY
34#undef NMT_END_ARRAY
35#undef END_NMT_CLASS
36
37#else
38// If not within the creation process, and called with argument, perform the
39// creation process with the header specified
40#ifdef NMT_CREATE_HEADER_NAME
41
42#ifndef ARRAY_STRUCT_PREFIX
43#define ARRAY_STRUCT_PREFIX(_nm) S_##_nm
44#endif
45
46#define CREATING_NMT
47
48#ifndef NMT_CREATOR_IMPLEMENT
49
50/*************************************************************************/
51// Pass 1, class definition
52#define NMT_CREATOR_PASS_CLASSDEF
53#define START_NMTS()
54#define END_NMTS()
55
56#define START_NMT_CLASS(_nm, _tp) \
57 START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
58
59/**
60 * Start the definition of a network message type.
61 *
62 * @param _base The name of the base class of the message
63 * @param _nm The name of the class
64 * @param _tp The NetMessageType associated with the class. It is *not* safe to
65 * have several classes with the same value of _tp in the same executable
66 */
67#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
68CNetMessage *Deserialize##_nm(const u8 *, size_t); \
69class _nm: public _base \
70{ \
71protected: \
72 _nm(NetMessageType type): _base(type) {}\
73 \
74 /* This one is for subclasses that want to use the base class' string */ \
75 /* converters to get SubMessage { <parent fields>, ... } */ \
76 CStr ToStringRaw() const;\
77public: \
78 _nm(): _base(_tp) {} \
79 virtual size_t GetSerializedLength() const; \
80 virtual u8 *Serialize(u8 *buffer) const; \
81 virtual const u8 *Deserialize(const u8 *pos, const u8 *end); \
82 virtual CStr ToString() const; \
83 inline operator CStr () const \
84 { return ToString(); }
85
86/**
87 * Add an integer field to the message type.
88 *
89 * @param _nm The name of the field
90 * @param _hosttp The local type of the field (the data type used in the field
91 * definition)
92 * @param _netsz The number of bytes that should be serialized. If the variable
93 * has a value larger than the maximum value of the specified network size,
94 * higher order bytes will be discarded.
95 */
96#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \
97 _hosttp _nm;
98
99/**
100 * Add a generic field to the message type. The data type must be a class
101 * implementing the ISerializable interface
102 *
103 * @param _tp The local data type of the field
104 * @param _nm The name of the field
105 * @see ISerializable
106 */
107#define NMT_FIELD(_tp, _nm) \
108 _tp _nm;
109
110/**
111 * Likewise, but the string representation is hidden.
112 * NB: the data length is not hidden, so make sure to use fixed-length data if confidentiality is desirable.
113 */
114#define NMT_FIELD_SECRET(_tp, _nm) \
115 _tp _nm;
116
117#define NMT_START_ARRAY(_nm) \
118 struct ARRAY_STRUCT_PREFIX(_nm); \
119 std::vector <ARRAY_STRUCT_PREFIX(_nm)> _nm; \
120 struct ARRAY_STRUCT_PREFIX(_nm) {
121
122#define NMT_END_ARRAY() \
123 };
124
125#define END_NMT_CLASS() };
126
127#include "NMTCreator.h"
128#undef NMT_CREATOR_PASS_CLASSDEF
129
130#else // NMT_CREATOR_IMPLEMENT
131
132#include "StringConverters.h"
133
134/*************************************************************************/
135// Pass 2, GetSerializedLength
136#define NMT_CREATOR_PASS_GETLENGTH
137#define START_NMTS()
138#define END_NMTS()
139
140#define START_NMT_CLASS(_nm, _tp) \
141 START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
142#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
143size_t _nm::GetSerializedLength() const \
144{ \
145 size_t ret=_base::GetSerializedLength(); \
146 const _nm *thiz=this;\
147 UNUSED2(thiz); // preempt any "unused" warning
148
149#define NMT_START_ARRAY(_nm) \
150 std::vector <ARRAY_STRUCT_PREFIX(_nm)>::const_iterator it=_nm.begin(); \
151 while (it != _nm.end()) \
152 { \
153 const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\
154 UNUSED2(thiz); // preempt any "unused" warning
155
156#define NMT_END_ARRAY() \
157 ++it; \
158 }
159
160#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \
161 ret += _netsz;
162
163#define NMT_FIELD(_tp, _nm) \
164 ret += thiz->_nm.GetSerializedLength();
165
166#define NMT_FIELD_SECRET(_tp, _nm) \
167 ret += thiz->_nm.GetSerializedLength();
168
169#define END_NMT_CLASS() \
170 return ret; \
171};
172
173#include "NMTCreator.h"
174#undef NMT_CREATOR_PASS_GETLENGTH
175
176/*************************************************************************/
177// Pass 3, Serialize
178
179#define NMT_CREATOR_PASS_SERIALIZE
180
181#define START_NMTS()
182#define END_NMTS()
183
184#define START_NMT_CLASS(_nm, _tp) \
185 START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
186#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
187u8 *_nm::Serialize(u8 *buffer) const \
188{ \
189 /*printf("In " #_nm "::Serialize()\n");*/ \
190 u8 *pos=_base::Serialize(buffer); \
191 const _nm *thiz=this;\
192 UNUSED2(thiz); // preempt any "unused" warning
193
194#define NMT_START_ARRAY(_nm) \
195 std::vector <ARRAY_STRUCT_PREFIX(_nm)>::const_iterator it=_nm.begin(); \
196 while (it != _nm.end()) \
197 { \
198 const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\
199 UNUSED2(thiz); // preempt any "unused" warning
200
201#define NMT_END_ARRAY() \
202 ++it; \
203 }
204
205#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \
206 Serialize_int_##_netsz(pos, thiz->_nm); \
207
208#define NMT_FIELD(_tp, _nm) \
209 pos=thiz->_nm.Serialize(pos);
210
211#define NMT_FIELD_SECRET(_tp, _nm) \
212 pos=thiz->_nm.Serialize(pos);
213
214#define END_NMT_CLASS() \
215 return pos; \
216}
217
218#include "NMTCreator.h"
219
220#undef NMT_CREATOR_PASS_SERIALIZE
221
222/*************************************************************************/
223// Pass 4, Deserialize
224
225#define NMT_CREATOR_PASS_DESERIALIZE
226
227#define START_NMTS()
228#define END_NMTS()
229
230#define BAIL_DESERIALIZER return NULL
231
232#define START_NMT_CLASS(_nm, _tp) \
233 START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
234#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
235const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \
236{ \
237 pos=_base::Deserialize(pos, end); \
238 if (pos == NULL) BAIL_DESERIALIZER;\
239 _nm *thiz=this; \
240 /*printf("In Deserialize" #_nm "\n"); */\
241 UNUSED2(thiz); // preempt any "unused" warning
242
243
244#define NMT_START_ARRAY(_nm) \
245 while (pos < end) \
246 { \
247 ARRAY_STRUCT_PREFIX(_nm) *thiz=&*_nm.insert(_nm.end(), ARRAY_STRUCT_PREFIX(_nm)());\
248 UNUSED2(thiz); // preempt any "unused" warning
249
250#define NMT_END_ARRAY() \
251 }
252
253#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \
254 if (pos+_netsz > end) BAIL_DESERIALIZER; \
255 Deserialize_int_##_netsz(pos, thiz->_nm); \
256 /*printf("\t" #_nm " == 0x%x\n", thiz->_nm);*/
257
258#define NMT_FIELD(_tp, _nm) \
259 if ((pos=thiz->_nm.Deserialize(pos, end)) == NULL) BAIL_DESERIALIZER;
260
261#define NMT_FIELD_SECRET(_tp, _nm) \
262 if ((pos=thiz->_nm.Deserialize(pos, end)) == NULL) BAIL_DESERIALIZER;
263
264#define END_NMT_CLASS() \
265 return pos; \
266}
267
268#include "NMTCreator.h"
269
270#undef BAIL_DESERIALIZER
271
272#undef NMT_CREATOR_PASS_DESERIALIZE
273
274/*************************************************************************/
275// Pass 5, String Representation
276
277#define START_NMTS()
278#define END_NMTS()
279
280#define START_NMT_CLASS(_nm, _tp) \
281CStr _nm::ToString() const \
282{ \
283 CStr ret=#_nm " { "; \
284 return ret + ToStringRaw() + " }"; \
285} \
286CStr _nm::ToStringRaw() const \
287{ \
288 CStr ret; \
289 const _nm *thiz=this;\
290 UNUSED2(thiz); // preempt any "unused" warning
291
292#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
293CStr _nm::ToString() const \
294{ \
295 CStr ret=#_nm " { "; \
296 return ret + ToStringRaw() + " }"; \
297} \
298CStr _nm::ToStringRaw() const \
299{ \
300 CStr ret=_base::ToStringRaw() + ", "; \
301 const _nm *thiz=this;\
302 UNUSED2(thiz); // preempt any "unused" warning
303
304#define NMT_START_ARRAY(_nm) \
305 ret+=#_nm ": { "; \
306 std::vector < ARRAY_STRUCT_PREFIX(_nm) >::const_iterator it=_nm.begin(); \
307 while (it != _nm.end()) \
308 { \
309 ret+=" { "; \
310 const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\
311 UNUSED2(thiz); // preempt any "unused" warning
312
313#define NMT_END_ARRAY() \
314 ++it; \
315 ret=ret.substr(0, ret.length()-2)+" }, "; \
316 } \
317 ret=ret.substr(0, ret.length()-2)+" }, ";
318
319#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \
320 ret += #_nm ": "; \
321 ret += NetMessageStringConvert(thiz->_nm); \
322 ret += ", ";
323
324#define NMT_FIELD(_tp, _nm) \
325 ret += #_nm ": "; \
326 ret += NetMessageStringConvert(thiz->_nm); \
327 ret += ", ";
328
329#define NMT_FIELD_SECRET(_tp, _nm) \
330 ret += #_nm ": [secret], ";
331
332#define END_NMT_CLASS() \
333 return ret.substr(0, ret.length()-2); \
334}
335
336#include "NMTCreator.h"
337
338#endif // #ifdef NMT_CREATOR_IMPLEMENT
339
340/*************************************************************************/
341// Cleanup
342#undef NMT_CREATE_HEADER_NAME
343#undef NMT_CREATOR_IMPLEMENT
344#undef CREATING_NMT
345
346#endif // #ifdef NMT_CREATE_HEADER_NAME
347#endif // #ifndef CREATING_NMT