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