1 // XMLNode_as.h: ActionScript 3 "XMLNode" class, for Gnash. 2 // 3 // Copyright (C) 2009, 2010, 2011. 2012 Free Software Foundation, Inc. 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 // 19 20 #ifndef GNASH_ASOBJ3_XMLNODE_H 21 #define GNASH_ASOBJ3_XMLNODE_H 22 23 #include <list> 24 #include <string> 25 #include <cassert> 26 27 #include "Relay.h" 28 29 namespace gnash { 30 class as_object; 31 class Global_as; 32 struct ObjectURI; 33 } 34 35 namespace gnash { 36 37 38 /// A node in an XML tree. 39 // 40 /// This class has various complications to reduce memory usage when parsing 41 /// very large XML documents. 42 // 43 /// 1. It is a Relay class that can be attached to an as_object. 44 /// 2. It does not have to have an associated object. This is only created 45 /// once the XMLNode is accessed in ActionScript. 46 /// 3. The top node of an XML tree is always accessible in ActionScript, either 47 /// as an XML_as or a user-created XMLNode_as. 48 /// 4. XMLNodes consequently mark their children as reachable, but not their 49 /// parent. 50 /// 5. When an XMLNode is destroyed, any children without an associated object 51 /// are also deleted. Children with an associated object will be destroyed 52 /// when the GC destroys the object. 53 class XMLNode_as : public Relay 54 { 55 public: 56 57 enum NodeType { 58 Element = 1, 59 Attribute = 2, 60 Text = 3, 61 Cdata = 4, 62 EntityRef = 5, 63 Entity = 6, 64 ProcInstr = 7, 65 Comment = 8, 66 Document = 9, 67 DocType = 10, 68 DocFragment = 11, 69 Notation = 12 70 }; 71 72 XMLNode_as(Global_as& gl); 73 74 virtual ~XMLNode_as(); 75 length()76 size_t length() const { return _children.size(); } 77 nodeName()78 const std::string& nodeName() const { return _name; } 79 nodeValue()80 const std::string& nodeValue() const { return _value; } 81 82 /// Get the type of an XML Node. nodeType()83 NodeType nodeType() const { return _type; } 84 85 /// Set the type of an XML Node. nodeTypeSet(NodeType type)86 void nodeTypeSet(NodeType type) { 87 _type = type; 88 } 89 90 /// Set name of this node nodeNameSet(const std::string & name)91 void nodeNameSet(const std::string& name) { _name = name; } 92 93 bool extractPrefix(std::string& prefix) const; 94 95 /// Set value of this node nodeValueSet(const std::string & value)96 void nodeValueSet(const std::string& value) { _value = value; } 97 98 /// Performs a recursive search of node attributes to find a match 99 void getNamespaceForPrefix(const std::string& prefix, std::string& ns) 100 const; 101 102 /// Performs a recursive search of node attributes to find a match 103 // 104 /// @return false if no match found. 105 bool getPrefixForNamespace(const std::string& ns, std::string& prefix) 106 const; 107 setNamespaceURI(const std::string & value)108 void setNamespaceURI(const std::string& value) { 109 _namespaceURI = value; 110 } 111 getNamespaceURI()112 const std::string& getNamespaceURI() const { 113 return _namespaceURI; 114 } 115 116 /// Returns true if 'this' descends from the specified node. 117 bool descendsFrom(XMLNode_as* node) const; 118 119 /// Returns true if the specified node has child nodes; otherwise, 120 /// returns false. 121 bool hasChildNodes() const; 122 123 XMLNode_as* firstChild() const; 124 XMLNode_as* lastChild() const; 125 126 // Use a list for quick erasing 127 typedef std::list<XMLNode_as*> Children; 128 129 as_object* childNodes(); 130 131 XMLNode_as* previousSibling() const; 132 XMLNode_as* nextSibling() const; 133 134 /// Copy a node 135 // 136 /// Method; constructs and returns a new XML node of the same type, 137 /// name, value, and attributes as the specified XML object. If deep 138 /// is set to true, all child nodes are recursively cloned, resulting 139 /// in an exact copy of the original object's document tree. 140 XMLNode_as* cloneNode(bool deep) const; 141 142 /// Append a child node to this XML object 143 // 144 /// The child node's parent is set to this object, the node is added to 145 /// this object's children. 146 // 147 /// The childNodes array will be updated if it exists. 148 // 149 /// @param node The node to add as a child 150 void appendChild(XMLNode_as* node); 151 152 /// Remove a child node from this XML object 153 // 154 /// The child node's parent is set to 0, the node is removed from 155 /// this object's children. 156 // 157 /// The childNodes array will be updated if it exists. 158 // 159 /// @param node The node to remove. 160 void removeChild(XMLNode_as* node); 161 162 /// Get the parent XMLNode_as of this node. Can be 0. getParent()163 XMLNode_as* getParent() const { 164 return _parent; 165 } 166 167 /// Insert a node before a node 168 // 169 /// Method; inserts a new child node into the XML object's child 170 /// list, before the beforeNode node. If the beforeNode parameter is 171 /// undefined or null, the node is added using the appendChild() 172 /// method. If beforeNode is not a child of my_xml, the insertion 173 /// fails. 174 /// 175 /// @param newnode 176 /// The node to insert, moving from its current tree 177 /// 178 /// @param pos 179 /// The node before which to insert the new one. 180 /// Must be a child of this XMLNode or the operation will fail. 181 /// 182 void insertBefore(XMLNode_as* newnode, XMLNode_as* pos); 183 184 /// Convert the XMLNode to a string 185 // 186 /// @param o The ostream to write the string to. 187 /// @param encode Whether to URL encode the node values. This 188 /// is false by default, as it is only necessary 189 /// for XML.sendAndLoad. 190 virtual void toString(std::ostream& str, bool encode = false) const; 191 192 /// Return the attributes object associated with this node. getAttributes()193 as_object* getAttributes() const { return _attributes; } 194 195 /// Set a named attribute to a value. 196 // 197 /// @param name The name of the attribute to set. If already present, 198 /// the value is changed. If not present, the attribute is 199 /// added. 200 /// @param value The value to set the named attribute to. 201 void setAttribute(const std::string& name, const std::string& value); 202 203 /// Associate an as_object with this XMLNode_as. 204 // 205 /// An XMLNode_as with an associated object is regarded as being owned 206 /// by that object, so make sure it is! Using as_object::setRelay will 207 /// achieve that. setObject(as_object * o)208 void setObject(as_object* o) { 209 assert(!_object); 210 assert(o); 211 _object = o; 212 } 213 214 /// Return the object associated with this XMLNode_as. 215 // 216 /// The object will be created if it does not already exist. 217 as_object* object(); 218 219 protected: 220 221 /// Mark reachable elements 222 // 223 /// These are: children, attributes object, associated as_object. 224 virtual void setReachable(); 225 226 Global_as& _global; 227 228 /// Clear all children, making sure unreferenced children are deleted. 229 // 230 /// AS-referenced child nodes will no longer be marked as reachable, so 231 /// the GC will remove them on the next run. 232 void clearChildren(); 233 234 private: 235 236 /// Set the parent XMLNode_as of this node. 237 // 238 /// @param node The new parent of this node. May be 0. setParent(XMLNode_as * node)239 void setParent(XMLNode_as* node) { _parent = node; } 240 241 /// Reset the array of childNodes to match the actual children. 242 // 243 /// Only called when the XML structure changes, and only once the 244 /// childNodes array has been created. Before this point it is not 245 /// referenceable, so we don't need to do anything. 246 void updateChildNodes(); 247 248 /// A non-trivial copy-constructor for cloning nodes. 249 XMLNode_as(const XMLNode_as &node, bool deep); 250 251 Children _children; 252 253 as_object* _object; 254 255 XMLNode_as* _parent; 256 257 as_object* _attributes; 258 259 as_object* _childNodes; 260 261 std::string _name; 262 263 std::string _value; 264 265 NodeType _type; 266 267 std::string _namespaceURI; 268 269 static void stringify(const XMLNode_as& xml, std::ostream& xmlout, 270 bool encode); 271 }; 272 273 // Initialize the global XMLNode class 274 void xmlnode_class_init(as_object& where, const ObjectURI& uri); 275 276 /// Register ASnative methods 277 void registerXMLNodeNative(as_object& where); 278 279 } // gnash namespace 280 281 // GNASH_ASOBJ3_XMLNODE_H 282 #endif 283 284 // local Variables: 285 // mode: C++ 286 // indent-tabs-mode: t 287 // End: 288 289 290