LCOV - code coverage report
Current view: top level - source/simulation2/system - ParamNode.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 1 100.0 %
Date: 2023-01-19 00:18:29 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* Copyright (C) 2023 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/Errors.h"
      24             : #include "scriptinterface/ScriptTypes.h"
      25             : 
      26             : #include <map>
      27             : #include <string>
      28             : 
      29             : class XMBData;
      30             : class XMBElement;
      31             : 
      32             : class CStrIntern;
      33             : class 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             :  */
     150        1341 : class CParamNode
     151             : {
     152             : public:
     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             :      * Returns the name of this node.
     268             :      */
     269             :     const std::string& GetName() const;
     270             : 
     271             :     /**
     272             :      * Escapes a string so that it is well-formed XML content/attribute text.
     273             :      * (Replaces "&" with "&amp;" etc)
     274             :      */
     275             :     static std::string EscapeXMLString(const std::string& str);
     276             : 
     277             :     std::string m_Name;
     278             :     u32 m_Index;
     279             : 
     280             : private:
     281             : 
     282             :     /**
     283             :      * Overlays the specified data onto this node. See class documentation for the concept and examples.
     284             :      *
     285             :      * @param xmb Representation of the XMB file containing an element with the data to apply.
     286             :      * @param element Element inside the specified @p xmb file containing the data to apply.
     287             :      * @param sourceIdentifier Optional; string you can pass along to indicate the source of
     288             :      *        the data getting applied. Used for output to log messages if an error occurs.
     289             :      */
     290             :     void ApplyLayer(const XMBData& xmb, const XMBElement& element, const wchar_t* sourceIdentifier = NULL);
     291             : 
     292             :     void ResetScriptVal();
     293             : 
     294             :     void ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const;
     295             : 
     296             :     std::string m_Value;
     297             :     ChildrenMap m_Childs;
     298             :     bool m_IsOk;
     299             : 
     300             :     /**
     301             :      * Caches the ToJSVal script representation of this node.
     302             :      */
     303             :     mutable std::shared_ptr<JS::PersistentRootedValue> m_ScriptVal;
     304             : };
     305             : 
     306             : #endif // INCLUDED_PARAMNODE

Generated by: LCOV version 1.13