Pyrogenesis trunk
ParamNode.h
Go to the documentation of this file.
1/* Copyright (C) 2022 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#ifndef INCLUDED_PARAMNODE
19#define INCLUDED_PARAMNODE
20
22#include "maths/Fixed.h"
23#include "ps/Errors.h"
25
26#include <map>
27#include <string>
28
29class XMBData;
30class XMBElement;
31
32class CStrIntern;
33class ScriptRequest;
34
35/**
36 * An entity initialisation parameter node.
37 * Each node has a text value, plus a number of named child nodes (in a tree structure).
38 * Child nodes are unordered, and there cannot be more than one with the same name.
39 * Nodes are immutable.
40 *
41 * Nodes can be initialised from XML files. Child elements are mapped onto child nodes.
42 * Attributes are mapped onto child nodes with names prefixed by "@"
43 * (e.g. the XML <code>&lt;a b="c">&lt;d/>&lt;/a></code> is loaded as a node with two
44 * child nodes, one called "@b" and one called "d").
45 *
46 * They can also be initialised from @em multiple XML files,
47 * which is used by ICmpTemplateManager for entity template inheritance.
48 * Loading one XML file like:
49 * @code
50 * <Entity>
51 * <Example1>
52 * <A attr="value">text</A>
53 * </Example1>
54 * <Example2>
55 * <B/>
56 * </Example2>
57 * <Example3>
58 * <C/>
59 * </Example3>
60 * <Example4 datatype="tokens">
61 * one two three
62 * </Example4>
63 * <Example5>
64 * <E/>
65 * <F>
66 * <I>test</I>
67 * </F>
68 * <H>
69 * <J>example</J>
70 * </H>
71 * </Example5>
72 * </Entity>
73 * @endcode
74 * then a second like:
75 * @code
76 * <Entity>
77 * <Example1>
78 * <A>example</A> <!-- replace the content of the old A element -->
79 * <D>new</D> <!-- add a new child to the old Example1 element -->
80 * </Example1>
81 * <Example2 disable=""/> <!-- delete the old Example2 element -->
82 * <Example3 replace=""> <!-- replace all the old children of the Example3 element -->
83 * <D>new</D>
84 * </Example3>
85 * <Example4 datatype="tokens"> <!-- treat as space-separated lists of tokens to merge -->
86 * four <!-- add a token to the parent's set -->
87 * -two <!-- remove a token from the parent's set -->
88 * </Example4>
89 * <Example5 filtered=""> <!-- drop all children of this node that are not in this file -->
90 * <F merge=""> <!-- only add this element if it is also present in the parent -->
91 * <K>example</K> <!-- if F is present merge its children normally -->
92 * </F>
93 * <G merge=""/> <!-- keep the G element of the parent if it exists -->
94 * <H>
95 * <J>text</J>
96 * </H>
97 * </Example5>
98 * </Entity>
99 * @endcode
100 * is equivalent to loading a single file like:
101 * @code
102 * <Entity>
103 * <Example1>
104 * <A attr="value">example</A>
105 * <D>new</D>
106 * </Example1>
107 * <Example3>
108 * <D>new</D>
109 * </Example3>
110 * <Example4>
111 * one three four
112 * </Example4>
113 * <Example5>
114 * <F>
115 * <I>test</I>
116 * <K>example</K>
117 * </F>
118 * <H>
119 * <J>text</J>
120 * </H>
121 * </Example5>
122 * </Entity>
123 * @endcode
124 *
125 * Parameter nodes can be translated to JavaScript objects. The previous example will become the object:
126 * @code
127 * { "Entity": {
128 * "Example1": {
129 * "A": { "@attr": "value", "_string": "example" },
130 * "D": "new"
131 * },
132 * "Example3": {
133 * "D": "new"
134 * },
135 * "Example4": { "@datatype": "tokens", "_string": "one three four" },
136 * "Example5": {
137 * "F": {
138 * "I": "test",
139 * "K": "example"
140 * },
141 * "H": {
142 * "J": "text"
143 * }
144 * }
145 * }
146 * }
147 * @endcode
148 * (Note the special @c _string for the hopefully-rare cases where a node contains both child nodes and text.)
149 */
151{
152public:
153 typedef std::map<std::string, CParamNode> ChildrenMap;
154
155 /**
156 * Constructs a new, empty node.
157 */
158 CParamNode(bool isOk = true);
159
160 /**
161 * Loads the XML data specified by @a file into the node @a ret.
162 * Any existing data in @a ret will be overwritten or else kept, so this
163 * can be called multiple times to build up a node from multiple inputs.
164 *
165 * @param sourceIdentifier Optional; string you can pass along to indicate the source of
166 * the data getting loaded. Used for output to log messages if an error occurs.
167 */
168 static void LoadXML(CParamNode& ret, const XMBData& xmb, const wchar_t* sourceIdentifier = NULL);
169
170 /**
171 * Loads the XML data specified by @a path into the node @a ret.
172 * Any existing data in @a ret will be overwritten or else kept, so this
173 * can be called multiple times to build up a node from multiple inputs.
174 */
175 static void LoadXML(CParamNode& ret, const VfsPath& path, const std::string& validatorName);
176
177 /**
178 * See LoadXML, but parses the XML string @a xml.
179 * @return error code if parsing failed, else @c PSRETURN_OK
180 *
181 * @param sourceIdentifier Optional; string you can pass along to indicate the source of
182 * the data getting loaded. Used for output to log messages if an error occurs.
183 */
184 static PSRETURN LoadXMLString(CParamNode& ret, const char* xml, const wchar_t* sourceIdentifier = NULL);
185
186 /**
187 * Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none.
188 */
189 const CParamNode& GetChild(const char* name) const;
190 // (Children are returned as const in order to allow future optimisations, where we assume
191 // a node is always modified explicitly and not indirectly via its children, e.g. to cache JS::Values)
192
193 /**
194 * Returns the only child node, or a node with IsOk() == false if there is none.
195 * This is mainly useful for the root node.
196 */
197 const CParamNode& GetOnlyChild() const;
198
199 /**
200 * Returns true if this is a valid CParamNode, false if it represents a non-existent node
201 */
202 bool IsOk() const;
203
204 /**
205 * Returns the content of this node as a wstring
206 */
207 const std::wstring ToWString() const;
208
209 /**
210 * Returns the content of this node as an UTF8 string
211 */
212 const std::string& ToString() const;
213
214 /**
215 * Returns the content of this node as an internalized 8-bit string. Should only be used for
216 * predictably small and frequently-used strings.
217 */
218 const CStrIntern ToUTF8Intern() const;
219
220 /**
221 * Parses the content of this node as an integer
222 */
223 int ToInt() const;
224
225 /**
226 * Parses the content of this node as a fixed-point number
227 */
228 fixed ToFixed() const;
229
230 /**
231 * Parses the content of this node as a floating-point number
232 */
233 float ToFloat() const;
234
235 /**
236 * Parses the content of this node as a boolean ("true" == true, anything else == false)
237 */
238 bool ToBool() const;
239
240 /**
241 * Returns the content of this node and its children as an XML string
242 */
243 std::string ToXMLString() const;
244
245 /**
246 * Write the content of this node and its children as an XML string, to the stream
247 */
248 void ToXMLString(std::ostream& strm) const;
249
250 /**
251 * Returns a JS::Value representation of this node and its children.
252 * If @p cacheValue is true, then the same JS::Value will be returned each time
253 * this is called (regardless of whether you passed the same @p cx - be careful
254 * to only use the cache in one context).
255 * When caching, the lifetime of @p cx must be longer than the lifetime of this node.
256 * The cache will be reset if *this* node is modified (e.g. by LoadXML),
257 * but *not* if any child nodes are modified (so don't do that).
258 */
259 void ToJSVal(const ScriptRequest& rq, bool cacheValue, JS::MutableHandleValue ret) const;
260
261 /**
262 * Returns the names/nodes of the children of this node, ordered by name
263 */
264 const ChildrenMap& GetChildren() const;
265
266 /**
267 * Escapes a string so that it is well-formed XML content/attribute text.
268 * (Replaces "&" with "&amp;" etc)
269 */
270 static std::string EscapeXMLString(const std::string& str);
271
272 std::string m_Name;
274
275private:
276
277 /**
278 * Overlays the specified data onto this node. See class documentation for the concept and examples.
279 *
280 * @param xmb Representation of the XMB file containing an element with the data to apply.
281 * @param element Element inside the specified @p xmb file containing the data to apply.
282 * @param sourceIdentifier Optional; string you can pass along to indicate the source of
283 * the data getting applied. Used for output to log messages if an error occurs.
284 */
285 void ApplyLayer(const XMBData& xmb, const XMBElement& element, const wchar_t* sourceIdentifier = NULL);
286
287 void ResetScriptVal();
288
289 void ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const;
290
291 std::string m_Value;
293 bool m_IsOk;
294
295 /**
296 * Caches the ToJSVal script representation of this node.
297 */
298 mutable std::shared_ptr<JS::PersistentRootedValue> m_ScriptVal;
299};
300
301#endif // INCLUDED_PARAMNODE
u32 PSRETURN
Definition: Errors.h:75
A simple fixed-point number class.
Definition: Fixed.h:120
An entity initialisation parameter node.
Definition: ParamNode.h:151
std::string m_Value
Definition: ParamNode.h:291
void ToJSVal(const ScriptRequest &rq, bool cacheValue, JS::MutableHandleValue ret) const
Returns a JS::Value representation of this node and its children.
Definition: ParamNode.cpp:374
void ConstructJSVal(const ScriptRequest &rq, JS::MutableHandleValue ret) const
Definition: ParamNode.cpp:388
const CStrIntern ToUTF8Intern() const
Returns the content of this node as an internalized 8-bit string.
Definition: ParamNode.cpp:277
const ChildrenMap & GetChildren() const
Returns the names/nodes of the children of this node, ordered by name.
Definition: ParamNode.cpp:305
std::string ToXMLString() const
Returns the content of this node and its children as an XML string.
Definition: ParamNode.cpp:335
static PSRETURN LoadXMLString(CParamNode &ret, const char *xml, const wchar_t *sourceIdentifier=NULL)
See LoadXML, but parses the XML string xml.
Definition: ParamNode.cpp:58
std::string m_Name
Definition: ParamNode.h:272
bool m_IsOk
Definition: ParamNode.h:293
static std::string EscapeXMLString(const std::string &str)
Escapes a string so that it is well-formed XML content/attribute text.
Definition: ParamNode.cpp:310
bool ToBool() const
Parses the content of this node as a boolean ("true" == true, anything else == false)
Definition: ParamNode.cpp:297
float ToFloat() const
Parses the content of this node as a floating-point number.
Definition: ParamNode.cpp:292
std::map< std::string, CParamNode > ChildrenMap
Definition: ParamNode.h:153
void ApplyLayer(const XMBData &xmb, const XMBElement &element, const wchar_t *sourceIdentifier=NULL)
Overlays the specified data onto this node.
Definition: ParamNode.cpp:70
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none.
Definition: ParamNode.cpp:254
void ResetScriptVal()
Definition: ParamNode.cpp:454
ChildrenMap m_Childs
Definition: ParamNode.h:292
const std::string & ToString() const
Returns the content of this node as an UTF8 string.
Definition: ParamNode.cpp:272
static void LoadXML(CParamNode &ret, const XMBData &xmb, const wchar_t *sourceIdentifier=NULL)
Loads the XML data specified by file into the node ret.
Definition: ParamNode.cpp:43
int ToInt() const
Parses the content of this node as an integer.
Definition: ParamNode.cpp:282
bool IsOk() const
Returns true if this is a valid CParamNode, false if it represents a non-existent node.
Definition: ParamNode.cpp:262
const CParamNode & GetOnlyChild() const
Returns the only child node, or a node with IsOk() == false if there is none.
Definition: ParamNode.cpp:245
CParamNode(bool isOk=true)
Constructs a new, empty node.
Definition: ParamNode.cpp:38
fixed ToFixed() const
Parses the content of this node as a fixed-point number.
Definition: ParamNode.cpp:287
std::shared_ptr< JS::PersistentRootedValue > m_ScriptVal
Caches the ToJSVal script representation of this node.
Definition: ParamNode.h:298
u32 m_Index
Definition: ParamNode.h:273
const std::wstring ToWString() const
Returns the content of this node as a wstring.
Definition: ParamNode.cpp:267
Interned 8-bit strings.
Definition: CStrIntern.h:38
Definition: path.h:80
Spidermonkey maintains some 'local' state via the JSContext* object.
Definition: ScriptRequest.h:60
Definition: XMBData.h:96
Definition: XMBData.h:136
def xml
Definition: tests.py:138
uint32_t u32
Definition: types.h:39