gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r11652: Drop static data from XML an


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11652: Drop static data from XML and XMLNode. Make them work better.
Date: Thu, 26 Nov 2009 16:20:41 +0100
User-agent: Bazaar (1.16.1)

------------------------------------------------------------
revno: 11652 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Thu 2009-11-26 16:20:41 +0100
message:
  Drop static data from XML and XMLNode. Make them work better.
modified:
  libcore/asobj/Globals.cpp
  libcore/asobj/flash/xml/XMLDocument_as.cpp
  libcore/asobj/flash/xml/XMLDocument_as.h
  libcore/asobj/flash/xml/XMLNode_as.cpp
  libcore/asobj/flash/xml/XMLNode_as.h
  testsuite/actionscript.all/XML.as
  testsuite/actionscript.all/XMLNode.as
  testsuite/swfdec/PASSING
=== modified file 'libcore/asobj/Globals.cpp'
--- a/libcore/asobj/Globals.cpp 2009-11-19 08:08:36 +0000
+++ b/libcore/asobj/Globals.cpp 2009-11-26 11:22:34 +0000
@@ -515,9 +515,9 @@
         (N(xmlsocket_class_init, NSV::CLASS_XMLSOCKET, NSV::CLASS_OBJECT,
            NS_GLOBAL, 5))
         (N(date_class_init, NSV::CLASS_DATE, NSV::CLASS_OBJECT, NS_GLOBAL, 5))
-        (N(XMLDocument_as::init, NSV::CLASS_XML, NSV::CLASS_OBJECT,
+        (N(xmlnode_class_init, NSV::CLASS_XMLNODE, NSV::CLASS_OBJECT,
            NS_GLOBAL, 5))
-        (N(XMLNode_as::init, NSV::CLASS_XMLNODE, NSV::CLASS_OBJECT,
+        (N(xml_class_init, NSV::CLASS_XML, NSV::CLASS_OBJECT,
            NS_GLOBAL, 5))
         (N(mouse_class_init, NSV::CLASS_MOUSE, NSV::CLASS_OBJECT, NS_GLOBAL, 
5))
         (N(number_class_init, NSV::CLASS_NUMBER, NSV::CLASS_OBJECT,
@@ -677,9 +677,9 @@
         // Error classes
         
         // XML classes
-        (N(XMLDocument_as::init, st.find("XMLDocument"), NSV::CLASS_OBJECT,
+        (N(xmlnode_class_init, NSV::CLASS_XMLNODE, NSV::CLASS_OBJECT,
            NSV::NS_FLASH_XML, 5))
-        (N(XMLNode_as::init, NSV::CLASS_XMLNODE, NSV::CLASS_OBJECT,
+        (N(xml_class_init, st.find("XMLDocument"), NSV::CLASS_OBJECT,
            NSV::NS_FLASH_XML, 5))
 
         // UI classes
@@ -1550,8 +1550,8 @@
     // LoadableObject has natives shared between LoadVars and XML, so 
     // should be registered first.
     registerLoadableNative(global);
-    XMLDocument_as::registerNative(global);
-    XMLNode_as::registerNative(global);
+    registerXMLNative(global);
+    registerXMLNodeNative(global);
 
 }
 

=== modified file 'libcore/asobj/flash/xml/XMLDocument_as.cpp'
--- a/libcore/asobj/flash/xml/XMLDocument_as.cpp        2009-11-18 13:05:53 
+0000
+++ b/libcore/asobj/flash/xml/XMLDocument_as.cpp        2009-11-26 14:30:42 
+0000
@@ -51,9 +51,7 @@
 
 // Forward declarations
 namespace {
-    as_object* getXMLInterface();
-       void attachXMLInterface(as_object& o);
-       void attachXMLProperties(as_object& o);
+
     as_value xml_new(const fn_call& fn);
     as_value xml_createElement(const fn_call& fn);
     as_value xml_createTextNode(const fn_call& fn);
@@ -75,47 +73,179 @@
             std::string& content);
        
        
+    typedef std::map<std::string, std::string> Entities;
+    const Entities& getEntities();
+
     void attachXMLProperties(as_object& o);
        void attachXMLInterface(as_object& o);
-    as_object* getXMLInterface();
 
 }
 
-XMLDocument_as::XMLDocument_as() 
+
+/// Implements XML (AS2) and flash.xml.XMLDocument (AS3) class.
+//
+/// This class interface is identical in AS3 and AS2; it is probably 
+/// included in AS3 for backward compatibility.
+class XMLDocument_as : public XMLNode_as
+{
+public:
+
+    enum ParseStatus {
+            XML_OK = 0,
+            XML_UNTERMINATED_CDATA = -2,
+            XML_UNTERMINATED_XML_DECL = -3,
+            XML_UNTERMINATED_DOCTYPE_DECL = -4,
+            XML_UNTERMINATED_COMMENT = -5,
+            XML_UNTERMINATED_ELEMENT = -6,
+            XML_OUT_OF_MEMORY = -7,
+            XML_UNTERMINATED_ATTRIBUTE = -8,
+            XML_MISSING_CLOSE_TAG = -9,
+            XML_MISSING_OPEN_TAG = -10
+    };
+
+    enum LoadStatus {
+        XML_LOADED_UNDEFINED = -1,
+        XML_LOADED_FALSE = false,
+        XML_LOADED_TRUE = true
+    };
+
+    /// Create an XML object.
+    //
+    /// An XMLDocument is always user-created, so always starts with an
+    /// associated object.
+    XMLDocument_as(as_object& object);
+
+    XMLDocument_as(as_object& object, const std::string& xml);
+
+    ~XMLDocument_as() {};
+    
+    /// Convert the XML object to a string
+    //
+    /// This calls XMLNode::toString after adding an xmlDecl and
+    /// docTypeDecl
+    //
+    /// @param o        The ostream to write the string to.
+    /// @param encode   Whether to URL encode the node values.
+    void toString(std::ostream& o, bool encode) const;
+
+    const std::string& getXMLDecl() const {
+        return _xmlDecl;
+    }
+
+    void setXMLDecl(const std::string& xml) {
+        _xmlDecl = xml;
+    }
+
+    const std::string& getDocTypeDecl() const {
+        return _docTypeDecl;
+    }
+
+    void setDocTypeDecl(const std::string& docType) {
+        _docTypeDecl = docType;
+    }
+
+    // Methods
+
+    /// Parses an XML document into the specified XML object tree.
+    //
+    /// This reads in an XML file from disk and parses into into a memory
+    /// resident tree which can be walked through later.
+    ///
+    /// Calls to this function clear any precedently parsed data.
+    ///
+    void parseXML(const std::string& xml);
+
+    XMLNode_as* createElement(const std::string& name);
+
+    XMLNode_as* createTextNode(const std::string& name);
+
+    ParseStatus status() const {
+        return _status;
+    }
+
+    void setStatus(ParseStatus st) {
+        _status = st;
+    }
+
+    LoadStatus loaded() const {
+        return _loaded;
+    }
+
+    void setLoaded(LoadStatus st) {
+        _loaded = st;
+    }
+
+private:
+
+    typedef std::map<std::string, std::string, StringNoCaseLessThan> 
Attributes;
+
+    void parseTag(XMLNode_as*& node, const std::string& xml, 
+            std::string::const_iterator& it);
+
+    void parseAttribute(XMLNode_as* node, const std::string& xml, 
+            std::string::const_iterator& it, Attributes& attributes);
+
+    void parseDocTypeDecl(const std::string& xml, 
+            std::string::const_iterator& it);
+
+    void parseText(XMLNode_as* node, const std::string& xml, 
+            std::string::const_iterator& it);
+
+    void parseXMLDecl(const std::string& xml, 
+            std::string::const_iterator& it);
+
+    void parseComment(XMLNode_as* node, const std::string& xml, 
+            std::string::const_iterator& it);
+
+    void parseCData(XMLNode_as* node, const std::string& xml, 
+            std::string::const_iterator& it);
+ 
+    /// Clear all properties.
+    //
+    /// This removes all children, resets doctype and xml decls, and
+    /// sets status to XML.
+    void clear();
+  
+    /// \brief
+    /// Return true if ignoreWhite property was set to anything evaluating
+    /// to true.
+    bool ignoreWhite();
+
+    // -1 if never asked to load anything
+    //  0 if asked to load but not yet loaded (or failure)
+    //  1 if successfully loaded
+    LoadStatus _loaded;
+
+    ParseStatus _status;       
+ 
+    std::string _docTypeDecl;
+
+    std::string _xmlDecl;
+
+};
+
+XMLDocument_as::XMLDocument_as(as_object& object) 
     :
+    XMLNode_as(getGlobal(object)),
     _loaded(XML_LOADED_UNDEFINED), 
     _status(XML_OK)
 {
-    set_prototype(getXMLInterface());
+    setObject(&object);
 }
 
 // Parse the ASCII XML string into an XMLNode tree
-XMLDocument_as::XMLDocument_as(const std::string& xml)
+XMLDocument_as::XMLDocument_as(as_object& object, const std::string& xml)
     :
+    XMLNode_as(getGlobal(object)),
     _loaded(XML_LOADED_UNDEFINED), 
     _status(XML_OK)
 {
-    set_prototype(getXMLInterface());
+    setObject(&object);
     parseXML(xml);
 }
 
-const XMLDocument_as::Entities&
-XMLDocument_as::getEntities()
-{
-
-    static Entities entities = boost::assign::map_list_of
-        ("&amp;", "&")
-        ("&quot;", "\"")
-        ("&lt;", "<")
-        ("&gt;", ">")
-        ("&apos;", "'");
-
-    return entities;
-
-}
-
 void
-XMLDocument_as::escape(std::string& text)
+escapeXML(std::string& text)
 {
     const Entities& ent = getEntities();
 
@@ -127,7 +257,7 @@
 }
 
 void
-XMLDocument_as::unescape(std::string& text)
+unescapeXML(std::string& text)
 {
     const Entities& ent = getEntities();
 
@@ -208,7 +338,7 @@
     std::string value(it, end);
 
     // Replace entities in the value.
-    unescape(value);
+    unescapeXML(value);
 
     //log_debug("adding attribute to node %s: %s, %s", node->nodeName(),
     //        name, value);
@@ -328,7 +458,7 @@
 
     if (!closing) {
 
-        XMLNode_as* childNode = new XMLNode_as;
+        XMLNode_as* childNode = new XMLNode_as(_global);
         childNode->nodeNameSet(tagName);
         childNode->nodeTypeSet(Element);
 
@@ -368,7 +498,7 @@
             childNode->setAttribute(i->first, i->second);
         }
 
-        node->appendChild(childNode);
+        node->appendChild(childNode, false);
         if (*it == '/') ++it;
         else node = childNode;
 
@@ -424,15 +554,15 @@
     if (ignoreWhite() && 
         content.find_first_not_of("\t\r\n ") == std::string::npos) return;
 
-    XMLNode_as* childNode = new XMLNode_as;
+    XMLNode_as* childNode = new XMLNode_as(_global);
 
     childNode->nodeTypeSet(XMLNode_as::Text);
 
     // Replace any entitites.
-    unescape(content);
+    unescapeXML(content);
 
     childNode->nodeValueSet(content);
-    node->appendChild(childNode);
+    node->appendChild(childNode, false);
 
     //log_debug("appended text node: %s", content);
 }
@@ -466,10 +596,10 @@
         return;
     }
 
-    XMLNode_as* childNode = new XMLNode_as;
+    XMLNode_as* childNode = new XMLNode_as(_global);
     childNode->nodeValueSet(content);
     childNode->nodeTypeSet(Text);
-    node->appendChild(childNode);
+    node->appendChild(childNode, false);
     
 }
 
@@ -478,17 +608,14 @@
 void
 XMLDocument_as::parseXML(const std::string& xml)
 {
-    //GNASH_REPORT_FUNCTION; 
 
-    if (xml.empty())
-    {
+    if (xml.empty()) {
         log_error(_("XML data is empty"));
         return;
     }
 
     // Clear current data
     clear(); 
-    _status = XML_OK;
 
     std::string::const_iterator it = xml.begin();
     XMLNode_as* node = this;
@@ -535,33 +662,46 @@
 XMLDocument_as::clear()
 {
     // TODO: should set childs's parent to NULL ?
-    _children.clear();
+    clearChildren();
     _docTypeDecl.clear();
     _xmlDecl.clear();
+    _status = XML_OK;
 }
 
 bool
-XMLDocument_as::ignoreWhite() const
+XMLDocument_as::ignoreWhite() 
 {
 
-    string_table::key propnamekey = getStringTable(*this).find("ignoreWhite");
+    const string_table::key propnamekey =
+        getStringTable(_global).find("ignoreWhite");
     as_value val;
-    if (!const_cast<XMLDocument_as*>(this)->get_member(propnamekey, &val)) {
+    if (!object()->get_member(propnamekey, &val)) {
         return false;
     }
     return val.to_bool();
 }
 
-// TODO: XML.prototype is assigned after the class has been constructed, so it
+// XML.prototype is assigned after the class has been constructed, so it
 // replaces the original prototype and does not have a 'constructor'
 // property.
 void
-XMLDocument_as::init(as_object& where, const ObjectURI& uri)
+xml_class_init(as_object& where, const ObjectURI& uri)
 {
 
     Global_as& gl = getGlobal(where);
-    as_object* proto = getXMLInterface();
-    as_object* cl = gl.createClass(&xml_new, proto);
+    as_object* cl = gl.createClass(&xml_new, 0);
+
+    as_function* ctor = gl.getMember(NSV::CLASS_XMLNODE).to_function();
+
+    if (ctor) {
+        // XML.prototype is an XMLNode(1, "");
+        fn_call::Args args;
+        args += 1, "";
+        as_object* proto =
+            ctor->constructInstance(as_environment(getVM(where)), args);
+        attachXMLInterface(*proto);
+        cl->init_member(NSV::PROP_PROTOTYPE, proto);
+    }
     
     where.init_member(getName(uri), cl, as_object::DefaultFlags,
             getNamespace(uri));
@@ -569,7 +709,7 @@
 }
 
 void
-XMLDocument_as::registerNative(as_object& where)
+registerXMLNative(as_object& where)
 {
     VM& vm = getVM(where);
     vm.registerNative(xml_escape, 100, 5);
@@ -579,15 +719,20 @@
 }
 
 namespace {
+
 void
 attachXMLProperties(as_object& o)
 {
-    const int flags = 0;
-    o.init_property("xmlDecl", &xml_xmlDecl, &xml_xmlDecl, flags);
-    o.init_property("docTypeDecl", &xml_docTypeDecl, &xml_docTypeDecl, flags);
 
     as_object* proto = o.get_prototype();
     if (!proto) return;
+    const int flags = 0;
+    proto->init_member("ignoreWhite", false, flags);
+    proto->init_member("contentType", "application/x-www-form-urlencoded",
+            flags);
+    proto->init_property("xmlDecl", &xml_xmlDecl, &xml_xmlDecl, flags);
+    proto->init_property("docTypeDecl", &xml_docTypeDecl, &xml_docTypeDecl,
+            flags);
     proto->init_property("loaded", xml_loaded, xml_loaded);
     proto->init_property("status", xml_status, xml_status);
 
@@ -619,67 +764,43 @@
 
 }
 
-as_object*
-getXMLInterface()
-{
-    static boost::intrusive_ptr<as_object> o;
-    if ( o == NULL )
-    {
-        Global_as& gl = *VM::get().getGlobal();
-        as_function* ctor = gl.getMember(NSV::CLASS_XMLNODE).to_function();
-        if (!ctor) return 0;
-
-        // XML.prototype is an XMLNode(1, "");
-        fn_call::Args args;
-        args += 1, "";
-        o = ctor->constructInstance(as_environment(VM::get()), args);
-
-        VM::get().addStatic(o.get());
-        attachXMLInterface(*o);
-    }
-    return o.get();
-}
-
 as_value
 xml_new(const fn_call& fn)
 {
 
-    XMLDocument_as* xml_obj;
+    as_object* obj = ensure<ValidThis>(fn);
 
     if (fn.nargs > 0) {
 
         // Copy constructor clones nodes.
         if (fn.arg(0).is_object()) {
-            as_object* obj = fn.arg(0).to_object(getGlobal(fn));
-            xml_obj = dynamic_cast<XMLDocument_as*>(obj);
-
-            if (xml_obj) {
-                as_object* clone = xml_obj->cloneNode(true).get();
+            as_object* other = fn.arg(0).to_object(getGlobal(fn));
+            XMLDocument_as* xml;
+            if (isNativeType(other, xml)) {
+                as_object* clone = xml->cloneNode(true)->object();
                 attachXMLProperties(*clone);
                 return as_value(clone);
             }
         }
 
         const std::string& xml_in = fn.arg(0).to_string();
-        if (xml_in.empty())
-        {
+        if (xml_in.empty()) {
             IF_VERBOSE_ASCODING_ERRORS(
             log_aserror(_("First arg given to XML constructor (%s) "
                     "evaluates to the empty string"), fn.arg(0));
             );
         }
-        else
-        {
-            xml_obj = new XMLDocument_as(xml_in);
-            attachXMLProperties(*xml_obj);
-            return as_value(xml_obj);
+        else {
+            obj->setRelay(new XMLDocument_as(*obj, xml_in));
+            attachXMLProperties(*obj);
+            return as_value();
         }
     }
 
-    xml_obj = new XMLDocument_as;
-    attachXMLProperties(*xml_obj);
+    obj->setRelay(new XMLDocument_as(*obj));
+    attachXMLProperties(*obj);
 
-    return as_value(xml_obj);
+    return as_value();
 }
 
 /// This is attached to the prototype (an XMLNode) on construction of XML
@@ -690,7 +811,7 @@
 as_value
 xml_loaded(const fn_call& fn)
 {
-    XMLDocument_as* ptr = ensure<ThisIs<XMLDocument_as> >(fn);
+    XMLDocument_as* ptr = ensure<ThisIsNative<XMLDocument_as> >(fn);
 
     if (!fn.nargs) {
         XMLDocument_as::LoadStatus ls = ptr->loaded();
@@ -705,7 +826,7 @@
 as_value
 xml_status(const fn_call& fn)
 {
-    XMLDocument_as* ptr = ensure<ThisIs<XMLDocument_as> >(fn);
+    XMLDocument_as* ptr = ensure<ThisIsNative<XMLDocument_as> >(fn);
     
     if (!fn.nargs) {
         return as_value(ptr->status());
@@ -731,7 +852,7 @@
     if (!fn.nargs) return as_value();
 
     std::string escaped = fn.arg(0).to_string();
-    XMLDocument_as::escape(escaped);
+    escapeXML(escaped);
     return as_value(escaped);
 }
 
@@ -750,11 +871,11 @@
     if (fn.nargs > 0)
     {
         const std::string& text = fn.arg(0).to_string();
-        XMLNode_as *xml_obj = new XMLNode_as;
+        XMLNode_as *xml_obj = new XMLNode_as(getGlobal(fn));
         xml_obj->nodeNameSet(text);
         xml_obj->nodeTypeSet(XMLNode_as::Text);
 
-        return as_value(xml_obj);
+        return as_value(xml_obj->object());
         
     }
     else {
@@ -778,10 +899,10 @@
 
     if (fn.nargs > 0) {
         const std::string& text = fn.arg(0).to_string();
-        XMLNode_as* xml_obj = new XMLNode_as;
+        XMLNode_as* xml_obj = new XMLNode_as(getGlobal(fn));
         xml_obj->nodeValueSet(text);
         xml_obj->nodeTypeSet(XMLNode_as::Text);
-        return as_value(xml_obj);
+        return as_value(xml_obj->object());
     }
     else {
         log_error(_("no text for text node creation"));
@@ -794,7 +915,7 @@
 xml_parseXML(const fn_call& fn)
 {
 
-    XMLDocument_as* ptr = ensure<ThisIs<XMLDocument_as> >(fn);
+    XMLDocument_as* ptr = ensure<ThisIsNative<XMLDocument_as> >(fn);
 
     if (fn.nargs < 1)
     {
@@ -813,7 +934,7 @@
 as_value
 xml_xmlDecl(const fn_call& fn)
 {
-    XMLDocument_as* ptr = ensure<ThisIs<XMLDocument_as> >(fn);
+    XMLDocument_as* ptr = ensure<ThisIsNative<XMLDocument_as> >(fn);
 
     if (!fn.nargs)
     {
@@ -835,7 +956,7 @@
 as_value
 xml_docTypeDecl(const fn_call& fn)
 {
-    XMLDocument_as* ptr = ensure<ThisIs<XMLDocument_as> >(fn);
+    XMLDocument_as* ptr = ensure<ThisIsNative<XMLDocument_as> >(fn);
 
     if (!fn.nargs)
     {
@@ -947,6 +1068,21 @@
     return true;
 }
 
+const Entities&
+getEntities()
+{
+
+    static const Entities entities = boost::assign::map_list_of
+        ("&amp;", "&")
+        ("&quot;", "\"")
+        ("&lt;", "<")
+        ("&gt;", ">")
+        ("&apos;", "'");
+
+    return entities;
+
+}
+
 } // anonymous namespace 
 } // gnash namespace
 

=== modified file 'libcore/asobj/flash/xml/XMLDocument_as.h'
--- a/libcore/asobj/flash/xml/XMLDocument_as.h  2009-11-24 09:55:47 +0000
+++ b/libcore/asobj/flash/xml/XMLDocument_as.h  2009-11-26 11:22:34 +0000
@@ -40,160 +40,24 @@
 class fn_call;
 class URL;
 
-/// Implements XML (AS2) and flash.xml.XMLDocument (AS3) class.
-//
-/// This class interface is identical in AS3 and AS2; it is probably 
-/// included in AS3 for backward compatibility.
-class XMLDocument_as : public XMLNode_as
-{
-public:
-
-    enum ParseStatus {
-            XML_OK = 0,
-            XML_UNTERMINATED_CDATA = -2,
-            XML_UNTERMINATED_XML_DECL = -3,
-            XML_UNTERMINATED_DOCTYPE_DECL = -4,
-            XML_UNTERMINATED_COMMENT = -5,
-            XML_UNTERMINATED_ELEMENT = -6,
-            XML_OUT_OF_MEMORY = -7,
-            XML_UNTERMINATED_ATTRIBUTE = -8,
-            XML_MISSING_CLOSE_TAG = -9,
-            XML_MISSING_OPEN_TAG = -10
-    };
-
-    enum LoadStatus {
-        XML_LOADED_UNDEFINED = -1,
-        XML_LOADED_FALSE = false,
-        XML_LOADED_TRUE = true
-    };
-
-    XMLDocument_as();
-
-    XMLDocument_as(const std::string& xml);
-
-    ~XMLDocument_as() {};
-    
-    static void init(as_object& where, const ObjectURI& uri);
-    static void registerNative(as_object& where);
-
-    /// Convert the XML object to a string
-    //
-    /// This calls XMLNode::toString after adding an xmlDecl and
-    /// docTypeDecl
-    //
-    /// @param o        The ostream to write the string to.
-    /// @param encode   Whether to URL encode the node values.
-    void toString(std::ostream& o, bool encode) const;
-
-    const std::string& getXMLDecl() const {
-        return _xmlDecl;
-    }
-
-    void setXMLDecl(const std::string& xml) {
-        _xmlDecl = xml;
-    }
-
-    const std::string& getDocTypeDecl() const {
-        return _docTypeDecl;
-    }
-
-    void setDocTypeDecl(const std::string& docType) {
-        _docTypeDecl = docType;
-    }
-
-    // Methods
-
-    /// Parses an XML document into the specified XML object tree.
-    //
-    /// This reads in an XML file from disk and parses into into a memory
-    /// resident tree which can be walked through later.
-    ///
-    /// Calls to this function clear any precedently parsed data.
-    ///
-    void parseXML(const std::string& xml);
-
-    /// Escape using XML entities.
-    //
-    /// Note this is not the same as a URL escape.
-    static void escape(std::string& text);
-
-    /// Unescape XML entities.
-    //
-    /// Note this is not the same as a URL unescape.
-    static void unescape(std::string& text);
-
-    XMLNode_as* createElement(const std::string& name);
-
-    XMLNode_as* createTextNode(const std::string& name);
-
-    ParseStatus status() const {
-        return _status;
-    }
-
-    void setStatus(ParseStatus st) {
-        _status = st;
-    }
-
-    LoadStatus loaded() const {
-        return _loaded;
-    }
-
-    void setLoaded(LoadStatus st) {
-        _loaded = st;
-    }
-
-private:
-
-    typedef std::map<std::string, std::string> Entities;
-
-    static const Entities& getEntities();
-
-    typedef std::map<std::string, std::string, StringNoCaseLessThan> 
Attributes;
-
-    void parseTag(XMLNode_as*& node, const std::string& xml, 
-            std::string::const_iterator& it);
-
-    void parseAttribute(XMLNode_as* node, const std::string& xml, 
-            std::string::const_iterator& it, Attributes& attributes);
-
-    void parseDocTypeDecl(const std::string& xml, 
-            std::string::const_iterator& it);
-
-    void parseText(XMLNode_as* node, const std::string& xml, 
-            std::string::const_iterator& it);
-
-    void parseXMLDecl(const std::string& xml, 
-            std::string::const_iterator& it);
-
-    void parseComment(XMLNode_as* node, const std::string& xml, 
-            std::string::const_iterator& it);
-
-    void parseCData(XMLNode_as* node, const std::string& xml, 
-            std::string::const_iterator& it);
- 
-    /// Remove all children
-    void clear();
-  
-    /// \brief
-    /// Return true if ignoreWhite property was set to anything evaluating
-    /// to true.
-    bool ignoreWhite() const;
-
-    // -1 if never asked to load anything
-    //  0 if asked to load but not yet loaded (or failure)
-    //  1 if successfully loaded
-    LoadStatus _loaded;
-
-    ParseStatus _status;       
- 
-    std::string _docTypeDecl;
-
-    std::string _xmlDecl;
-
-};
+
+/// Escape using XML entities.
+//
+/// Note this is not the same as a URL escape.
+void escapeXML(std::string& text);
+
+/// Unescape XML entities.
+//
+/// Note this is not the same as a URL unescape.
+void unescapeXML(std::string& text);
+
+/// Register the XML class.
+void xml_class_init(as_object& where, const ObjectURI& uri);
+
+/// Register XML native functions.
+void registerXMLNative(as_object& where);
 
 }      // namespace gnash
-// GNASH_ASOBJ3_XMLDOCUMENT_H
 #endif
 
 // local Variables:

=== modified file 'libcore/asobj/flash/xml/XMLNode_as.cpp'
--- a/libcore/asobj/flash/xml/XMLNode_as.cpp    2009-11-24 09:57:07 +0000
+++ b/libcore/asobj/flash/xml/XMLNode_as.cpp    2009-11-26 15:02:01 +0000
@@ -34,6 +34,7 @@
 #include "PropertyList.h"
 #include "Global_as.h"
 #include "Object.h"
+#include "Array_as.h"
 
 #include <boost/bind.hpp>
 #include <string>
@@ -52,6 +53,7 @@
     bool namespaceMatches(
             const PropertyList::SortedPropertyList::value_type& val,
             const std::string& ns);    
+
     as_value xmlnode_new(const fn_call& fn);
     as_value xmlnode_nodeName(const fn_call& fn);
     as_value xmlnode_nodeValue(const fn_call& fn);
@@ -74,36 +76,37 @@
     as_value xmlnode_toString(const fn_call& fn);
     as_value xmlnode_localName(const fn_call& fn);
     as_value xmlnode_prefix(const fn_call& fn);
-    as_value xmlnode_ctor(const fn_call& fn);
     void attachXMLNodeInterface(as_object& o);
     void attachXMLNodeStaticInterface(as_object& o);
-    as_object* getXMLNodeInterface();
 }
 
-XMLNode_as::XMLNode_as()
+XMLNode_as::XMLNode_as(Global_as& gl)
     :
+    _global(gl),
+    _object(0),
     _parent(0),
     _attributes(new as_object),
+    _childNodes(0),
     _type(Element)
 {
-    set_prototype(getXMLNodeInterface());
 }
 
 XMLNode_as::XMLNode_as(const XMLNode_as& tpl, bool deep)
     :
-    _parent(0), // _parent is never implicitly copied
-    _attributes(0),
+    _global(tpl._global),
+    _object(0),
+    _parent(0), 
+    _attributes(new as_object),
+    _childNodes(0),
     _name(tpl._name),
     _value(tpl._value),
     _type(tpl._type)
 {
-    set_prototype(getXMLNodeInterface());
     // only clone children if in deep mode
     if (deep) {
         const Children& from=tpl._children;
         for (Children::const_iterator it=from.begin(), itEnd=from.end();
                         it != itEnd; ++it) {
-
             _children.push_back(new XMLNode_as(*(*it), deep));
         }
     }
@@ -111,34 +114,87 @@
 
 XMLNode_as::~XMLNode_as()
 {
-#ifdef DEBUG_MEMORY_ALLOCATION
-    log_debug(_("\tDeleting XMLNode data %s with as_value %s at %p"),
-            this->_name, this->as_value, this);
-#endif
-}
-       
+    clearChildren();
+}
+
+as_object*
+XMLNode_as::object() 
+{
+
+    // This is almost the same as if the XMLNode constructor were called,
+    // but not quite. There is no __constructor__ property, and when we
+    // override _global.XMLNode, we can show that it is not called.
+    if (!_object) {
+        as_object* o = _global.createObject();
+        as_object* xn =
+            _global.getMember(NSV::CLASS_XMLNODE).to_object(_global);
+        if (xn) {
+            o->set_prototype(xn->getMember(NSV::PROP_PROTOTYPE));
+            o->init_member(NSV::PROP_CONSTRUCTOR, xn);
+        }
+        o->setRelay(this);
+        setObject(o);
+    }
+    return _object;
+}
+
+void
+XMLNode_as::updateChildNodes()
+{
+    if (!_childNodes) {
+        _childNodes = _global.createArray();
+    }
+
+    // Clear array of all elements.
+    _childNodes->set_member(NSV::PROP_LENGTH, 0.0);
+
+    if (_children.empty()) return;
+
+    string_table& st = getStringTable(_global);
+
+    // Set up the array without calling push()!
+    const size_t size = _children.size();
+    Children::const_iterator it = _children.begin();
+    for (size_t i = 0; i != size; ++i, ++it) {
+        XMLNode_as* node = *it;
+        const string_table::key key = arrayKey(st, i);
+        _childNodes->set_member(key, node->object());
+
+        // All elements are set to readonly.
+        _childNodes->set_member_flags(key, PropFlags::readOnly);
+    }
+}
+
+as_object*
+XMLNode_as::childNodes()
+{
+    if (!_childNodes) {
+        updateChildNodes();
+    }
+    return _childNodes;
+}
+
 bool
 XMLNode_as::hasChildNodes()
 {
-    if (_children.size()) return true;
-    return false;
+    return !_children.empty();
 }
 
-boost::intrusive_ptr<XMLNode_as>
+XMLNode_as*
 XMLNode_as::firstChild()
 {
-    if ( _children.empty() ) return NULL;
+    if (_children.empty()) return 0;
     return _children.front();
 }
 
-boost::intrusive_ptr<XMLNode_as>
+XMLNode_as*
 XMLNode_as::cloneNode(bool deep)
 {
-    boost::intrusive_ptr<XMLNode_as> newnode = new XMLNode_as(*this, deep);
+    XMLNode_as* newnode = new XMLNode_as(*this, deep);
     return newnode;
 }
 
-boost::intrusive_ptr<XMLNode_as>
+XMLNode_as*
 XMLNode_as::lastChild()
 {
        if (_children.empty()) {
@@ -149,23 +205,27 @@
 }
 
 void
-XMLNode_as::appendChild(boost::intrusive_ptr<XMLNode_as> node)
+XMLNode_as::removeChild(XMLNode_as* node)
 {
-    assert (node);
+    node->setParent(0);
+    _children.remove(node);
+    updateChildNodes();
+}
 
-    boost::intrusive_ptr<XMLNode_as> oldparent = node->getParent();
+void
+XMLNode_as::appendChild(XMLNode_as* node, bool update)
+{
+    assert(node);
     node->setParent(this);
     _children.push_back(node);
-    if ( oldparent ) {
-        oldparent->_children.remove(node);
-    }
-
+    if (update) updateChildNodes();
 }
 
 void
-XMLNode_as::insertBefore(boost::intrusive_ptr<XMLNode_as> newnode,
-        boost::intrusive_ptr<XMLNode_as> pos)
+XMLNode_as::insertBefore(XMLNode_as* newnode, XMLNode_as* pos)
 {
+    assert(_object);
+
        // find iterator for positional parameter
     Children::iterator it = std::find(_children.begin(), _children.end(), pos);
     if (it == _children.end()) {
@@ -177,23 +237,14 @@
     }
 
     _children.insert(it, newnode);
-    boost::intrusive_ptr<XMLNode_as> oldparent = newnode->getParent();
+
+    XMLNode_as* parent = newnode->getParent();
+    if (parent) {
+        parent->removeChild(newnode);
+    }
+    
     newnode->setParent(this);
-    if (oldparent) {
-        oldparent->_children.remove(newnode);
-    }
-}
-
-// \brief removes the specified XML object from its parent. Also
-// deletes all descendants of the node.
-void
-XMLNode_as::removeNode()
-{
-    boost::intrusive_ptr<XMLNode_as> oldparent = getParent();
-    if (oldparent) {
-        oldparent->_children.remove(this);
-    }
-    _parent = 0;
+    updateChildNodes();
 }
 
 XMLNode_as *
@@ -206,9 +257,9 @@
     for (Children::iterator itx = _parent->_children.begin();
             itx != _parent->_children.end(); itx++) {
 
-        if (itx->get() == this) return previous_node;
+        if (*itx == this) return previous_node;
                
-        previous_node = itx->get();
+        previous_node = *itx;
     }
 
     return 0;
@@ -226,8 +277,8 @@
     for (Children::reverse_iterator itx = _parent->_children.rbegin();
             itx != _parent->_children.rend(); ++itx) {
 
-        if (itx->get() == this) return previous_node;
-               previous_node = itx->get();
+        if (*itx == this) return previous_node;
+               previous_node = *itx;
     }
 
     return 0;
@@ -243,7 +294,7 @@
 XMLNode_as::setAttribute(const std::string& name, const std::string& value)
 {
     if (_attributes) {
-        string_table& st = getStringTable(*this);
+        string_table& st = getStringTable(_global);
         _attributes->set_member(st.find(name), value);
     }
 }
@@ -329,6 +380,22 @@
 }
 
 void
+XMLNode_as::clearChildren()
+{
+    for (Children::const_iterator it = _children.begin(), e = _children.end();
+            it != e; ++it) {
+        const XMLNode_as* node = *it;
+        if (!node->_object) {
+            delete node;
+        }
+    }
+    _children.clear();
+
+    // Reset so that it is reinitialized on next access.
+    _childNodes = 0;
+}
+
+void
 XMLNode_as::stringify(const XMLNode_as& xml, std::ostream& xmlout, bool 
encode) 
 {
 
@@ -354,13 +421,13 @@
 
             for (PropertyList::SortedPropertyList::iterator i = 
                     attrs.begin(), e = attrs.end(); i != e; ++i) { 
-                XMLDocument_as::escape(i->second);
+                escapeXML(i->second);
                 xmlout << " " << i->first << "=\"" << i->second << "\"";
             }
         }
 
        // If the node has no content, just close the tag now
-       if ( nodeValue.empty() && xml._children.empty() ) {
+       if (nodeValue.empty() && xml._children.empty()) {
                xmlout << " />";
             return;
        }
@@ -374,14 +441,13 @@
     // Node as_value first, then children
     if (type == Text)
     {
-        as_object* global = getVM(xml).getGlobal();
-        assert(global);
+        Global_as& gl = xml._global;
 
         // Insert entities.
         std::string escaped(nodeValue);
-        XMLDocument_as::escape(escaped);
+        escapeXML(escaped);
         const std::string& val = encode ? 
-            callMethod(global, NSV::PROP_ESCAPE, escaped).to_string() :
+            callMethod(&gl, NSV::PROP_ESCAPE, escaped).to_string() :
             escaped;
 
            xmlout << val;
@@ -399,26 +465,23 @@
     }
 }
 
-#ifdef GNASH_USE_GC
 void
-XMLNode_as::markReachableResources() const
+XMLNode_as::setReachable() 
 {
        // Mark children
     std::for_each(_children.begin(), _children.end(),
-            boost::mem_fn(&as_object::setReachable));
-
-       // Mark parent
-       if (_parent) _parent->setReachable();
+            boost::mem_fn(&XMLNode_as::setReachable));
 
        // Mark attributes object
        if (_attributes) _attributes->setReachable();
 
-       markAsObjectReachable();
+    if (_object) _object->setReachable();
+
+    if (_childNodes) _childNodes->setReachable();
 }
-#endif // GNASH_USE_GC
 
 void
-XMLNode_as::registerNative(as_object& where)
+registerXMLNodeNative(as_object& where)
 {
     VM& vm = getVM(where);
     vm.registerNative(xmlnode_cloneNode, 253, 1);
@@ -432,10 +495,11 @@
 }
 
 void
-XMLNode_as::init(as_object& where, const ObjectURI& uri)
+xmlnode_class_init(as_object& where, const ObjectURI& uri)
 {
     Global_as& gl = getGlobal(where);
-    as_object* proto = getXMLNodeInterface();
+    as_object* proto = gl.createObject();
+    attachXMLNodeInterface(*proto);
     as_object* cl = gl.createClass(&xmlnode_new, proto);
 
     where.init_member(getName(uri), cl, as_object::DefaultFlags,
@@ -445,19 +509,6 @@
 
 namespace {
 
-as_object*
-getXMLNodeInterface()
-{
-    static boost::intrusive_ptr<as_object> o;
-    if ( o == NULL ) {
-        o = new as_object();
-        o->set_prototype(getObjectInterface());
-        attachXMLNodeInterface(*o);
-    }
-    return o.get();
-}
-
-
 void
 attachXMLNodeInterface(as_object& o)
 {
@@ -506,69 +557,86 @@
 xmlnode_new(const fn_call& fn)
 {
     
-    XMLNode_as *xml_obj = new XMLNode_as;
-    if ( fn.nargs > 0 )
-    {
-        xml_obj->nodeTypeSet(XMLNode_as::NodeType(fn.arg(0).to_int()));
-        if (fn.nargs > 1)
+    as_object* obj = ensure<ValidThis>(fn);
+
+    if (!fn.nargs) {
+        return as_value();
+    }
+
+    std::auto_ptr<XMLNode_as> xml(new XMLNode_as(getGlobal(fn)));
+    xml->nodeTypeSet(XMLNode_as::NodeType(fn.arg(0).to_int()));
+
+    if (fn.nargs > 1) {
+        const std::string& str = fn.arg(1).to_string();
+        switch (xml->nodeType())
         {
-            xml_obj->nodeValueSet(fn.arg(1).to_string());
+            case XMLNode_as::Element:
+                xml->nodeNameSet(str);
+                break;
+            default:
+                xml->nodeValueSet(str);
+                break;
         }
     }
     
-    return as_value(xml_obj);
+    // This sets the relay!
+    xml->setObject(obj);
+    obj->setRelay(xml.release());
+
+    return as_value();
 }
 
 
 as_value
 xmlnode_appendChild(const fn_call& fn)
 {
-//    GNASH_REPORT_FUNCTION;
-
-       boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
-
-       if ( ! fn.nargs )
-       {
-               IF_VERBOSE_ASCODING_ERRORS(
-               log_aserror(_("XMLNode::appendChild() needs at least one 
argument"));
-               );
-               return as_value();
-       }
-
-       boost::intrusive_ptr<XMLNode_as> xml_obj = 
-        dynamic_cast<XMLNode_as*>(fn.arg(0).to_object(getGlobal(fn)));
-
-       if ( ! xml_obj )
-       {
-               IF_VERBOSE_ASCODING_ERRORS(
-               log_aserror(_("First argument to XMLNode::appendChild() is not "
-                "an XMLNode"));
-               );
-               return as_value();
-       }
-
-       ptr->appendChild(xml_obj);
-       return as_value(); // undefined
+
+       XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
+
+       if (!fn.nargs) {
+               IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("XMLNode::appendChild() needs at least one "
+                    "argument"));
+               );
+               return as_value();
+       }
+
+       XMLNode_as* node;
+    if (!isNativeType(fn.arg(0).to_object(getGlobal(fn)), node)) {
+               IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("First argument to XMLNode::appendChild() is not "
+                    "an XMLNode"));
+               );
+               return as_value();
+       }
+
+    XMLNode_as* parent = node->getParent();
+    if (parent) {
+        parent->removeChild(node);
+    }
+       ptr->appendChild(node);
+
+       return as_value(); 
 
 }
 
 as_value
 xmlnode_cloneNode(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
     bool deep = false;
     if (fn.nargs > 0) deep = fn.arg(0).to_bool();
 
-    boost::intrusive_ptr<XMLNode_as> newnode = ptr->cloneNode(deep);
-    return as_value(newnode.get());
+    as_object* newnode = ptr->cloneNode(deep)->object();
+    return as_value(newnode);
 }
 
 
 as_value
 xmlnode_insertBefore(const fn_call& fn)
 {
-       boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+       XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
        if ( fn.nargs < 2 )
        {
@@ -580,10 +648,9 @@
                return as_value();
        }
 
-       boost::intrusive_ptr<XMLNode_as> newnode = 
-        dynamic_cast<XMLNode_as*>(fn.arg(0).to_object(getGlobal(fn)));
+       XMLNode_as* newnode;
 
-       if (!newnode) {
+    if (!isNativeType(fn.arg(0).to_object(getGlobal(fn)), newnode)) {
                IF_VERBOSE_ASCODING_ERRORS(
                std::stringstream ss; fn.dump_args(ss);
                log_aserror(_("First argument to XMLNode.insertBefore(%s) is 
not "
@@ -592,10 +659,9 @@
                return as_value();
        }
 
-       boost::intrusive_ptr<XMLNode_as> pos = 
-        dynamic_cast<XMLNode_as*>(fn.arg(1).to_object(getGlobal(fn)));
+       XMLNode_as* pos;
 
-       if (!pos) {
+    if (!isNativeType(fn.arg(1).to_object(getGlobal(fn)), pos)) {
                IF_VERBOSE_ASCODING_ERRORS(
         std::stringstream ss; fn.dump_args(ss);
                log_aserror(_("Second argument to XMLNode.insertBefore(%s) is 
not "
@@ -613,7 +679,7 @@
 as_value
 xmlnode_getNamespaceForPrefix(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     if (!fn.nargs) {
         return as_value();
     }
@@ -629,7 +695,7 @@
 as_value
 xmlnode_getPrefixForNamespace(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     if (!fn.nargs) {
         return as_value();
     }
@@ -656,7 +722,7 @@
 as_value
 xmlnode_namespaceURI(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
     // Read-only property
     
@@ -677,7 +743,7 @@
 
     // Search recursively for a namespace. Return an empty string
     // if none found.
-    XMLNode_as* node = ptr.get();
+    XMLNode_as* node = ptr;
     while (node && node->getNamespaceURI().empty()) {
         node = node->getParent();
     }
@@ -693,7 +759,7 @@
 as_value
 xmlnode_prefix(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
     // Read-only property
     
@@ -715,7 +781,7 @@
 as_value
 xmlnode_localName(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
     // Read-only property
     
@@ -740,9 +806,10 @@
 as_value
 xmlnode_removeNode(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     
-    ptr->removeNode();
+    XMLNode_as* parent = ptr->getParent();
+    if (parent) parent->removeChild(ptr);
     return as_value();
 }
 
@@ -750,9 +817,8 @@
 as_value
 xmlnode_toString(const fn_call& fn)
 {
-    //GNASH_REPORT_FUNCTION;
     
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     
     std::stringstream ss;
     ptr->toString(ss);
@@ -764,7 +830,7 @@
 as_value
 xmlnode_hasChildNodes(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     return as_value(ptr->hasChildNodes());
 }
 
@@ -772,7 +838,7 @@
 as_value
 xmlnode_nodeValue(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     as_value rv;
     rv.set_null();
     
@@ -792,7 +858,7 @@
 as_value
 xmlnode_nodeName(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     as_value rv;
     rv.set_null();
 
@@ -800,8 +866,7 @@
         const std::string& val = ptr->nodeName();
         if ( ! val.empty() ) rv = val;
     }
-    else
-    {
+    else {
         ptr->nodeNameSet(fn.arg(0).to_string());
     }
     return rv;
@@ -811,7 +876,7 @@
 as_value
 xmlnode_nodeType(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     return as_value(ptr->nodeType());
 }
 
@@ -819,7 +884,7 @@
 as_value
 xmlnode_attributes(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
 
     as_object* attrs = ptr->getAttributes();
     if (attrs) return as_value(attrs);
@@ -838,13 +903,13 @@
 as_value
 xmlnode_firstChild(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     as_value rv;
     rv.set_null();
 
-    boost::intrusive_ptr<XMLNode_as> node = ptr->firstChild();
+    XMLNode_as* node = ptr->firstChild();
     if (node) {
-       rv = node.get();
+        rv = node->object();
     }
 
     return rv;
@@ -860,12 +925,14 @@
 as_value
 xmlnode_lastChild(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     as_value rv;
     rv.set_null();
 
-    boost::intrusive_ptr<XMLNode_as> node = ptr->lastChild();
-    if (node) rv = node.get();
+    XMLNode_as* node = ptr->lastChild();
+    if (node) {
+        rv = node->object();
+    }
 
     return rv;
 }
@@ -877,10 +944,10 @@
     as_value rv;
     rv.set_null();
 
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     XMLNode_as *node = ptr->nextSibling();
     if (node) {
-       rv = node;
+        rv = node->object();
     }
     return rv;
 }
@@ -892,10 +959,10 @@
     as_value rv;
     rv.set_null();
 
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     XMLNode_as *node = ptr->previousSibling();
     if (node) {
-       rv = node;
+        rv = node->object();
     }
     return rv;
 }
@@ -907,40 +974,25 @@
     as_value rv;
     rv.set_null();
 
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
     XMLNode_as *node = ptr->getParent();
     if (node) {
-       rv = node;
+        rv = node->object();
     }
     return rv;
 }
 
-
 as_value
 xmlnode_childNodes(const fn_call& fn)
 {
-    boost::intrusive_ptr<XMLNode_as> ptr = ensure<ThisIs<XMLNode_as> >(fn);
- 
-    Global_as& gl = getGlobal(fn);
-    as_object* ary = gl.createArray();
-
-    typedef XMLNode_as::Children Children;
-
-    Children& child = ptr->childNodes();
-    for ( Children::const_iterator it=child.begin(), itEnd=child.end();
-                    it != itEnd; ++it )
-    {
-        boost::intrusive_ptr<XMLNode_as> node = *it;
-        callMethod(ary, NSV::PROP_PUSH, node.get());
-    }
-
-    return as_value(ary);
+    XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
+    return ptr->childNodes();
 }
 
 
 void
 enumerateAttributes(const XMLNode_as& node,
-            PropertyList::SortedPropertyList& attrs)
+        PropertyList::SortedPropertyList& attrs)
 {
     attrs.clear();
     const as_object* obj = node.getAttributes();
@@ -981,14 +1033,6 @@
     return noCaseCompare(prefix, name.substr(6));
 }
 
-as_value
-xmlnode_ctor(const fn_call& /*fn*/)
-{
-    boost::intrusive_ptr<as_object> obj = new XMLNode_as;
-
-    return as_value(obj.get()); // will keep alive
-}
-
 } // anonymous namespace 
 } // gnash namespace
 // local Variables:

=== modified file 'libcore/asobj/flash/xml/XMLNode_as.h'
--- a/libcore/asobj/flash/xml/XMLNode_as.h      2009-11-16 12:51:33 +0000
+++ b/libcore/asobj/flash/xml/XMLNode_as.h      2009-11-26 14:30:42 +0000
@@ -34,7 +34,24 @@
 #include <sstream>
 
 namespace gnash {
-class XMLNode_as : public virtual as_object
+
+
+/// A node in an XML tree.
+//
+/// This class has various complications to reduce memory usage when parsing
+/// very large XML documents.
+//
+/// 1. It is a Relay class that can be attached to an as_object.
+/// 2. It does not have to have an associated object. This is only created
+///    once the XMLNode is accessed in ActionScript.
+/// 3. The top node of an XML tree is always accessible in ActionScript, either
+///    as an XMLDocument_as or a user-created XMLNode_as.
+/// 4. XMLNodes consequently mark their children as reachable, but not their
+///    parent.
+/// 5. When an XMLNode is destroyed, any children without an associated object
+///    are also deleted. Children with an associated object will be destroyed
+///    when the GC destroys the object.
+class XMLNode_as : public Relay
 {
 public:
 
@@ -53,16 +70,10 @@
         Notation = 12
     };
 
-    XMLNode_as();
+    XMLNode_as(Global_as& gl);
 
     virtual ~XMLNode_as();
 
-    // Initialize the global XMLNode class
-    static void init(as_object& where, const ObjectURI& uri);
-
-    /// Register ASnative methods
-    static void registerNative(as_object& where);
-
     size_t length() const { return _children.size(); }
 
     const std::string& nodeName() const { return _name; }
@@ -108,13 +119,13 @@
     ///  returns false.
     bool hasChildNodes();
 
-    boost::intrusive_ptr<XMLNode_as> firstChild();
-    boost::intrusive_ptr<XMLNode_as> lastChild();
+    XMLNode_as* firstChild();
+    XMLNode_as* lastChild();
     
     // Use a list for quick erasing
-    typedef std::list<boost::intrusive_ptr<XMLNode_as> > Children;
+    typedef std::list<XMLNode_as*> Children;
 
-    Children& childNodes() { return _children; }
+    as_object* childNodes();
 
     XMLNode_as* previousSibling();
     XMLNode_as* nextSibling();
@@ -125,32 +136,31 @@
     /// name, value, and attributes as the specified XML object. If deep
     /// is set to true, all child nodes are recursively cloned, resulting
     /// in an exact copy of the original object's document tree. 
-    boost::intrusive_ptr<XMLNode_as> cloneNode(bool deep);
-
-    /// Append a child node the the XML object
-    //
-    /// Appends the specified node to the XML object's child
-    /// list. This method operates directly on the node referenced by the
-    /// childNode parameter; it does not append a copy of the node. If the
-    /// node to be appended already exists in another tree structure,
-    /// appending the node to the new location will remove it from its
-    /// current location. If the childNode parameter refers to a node that
-    /// already exists in another XML tree structure, the appended child
-    /// node is placed in the new tree structure after it is removed from
-    /// its existing parent node. 
-    ///
-    /// @param childNode    The XMLNode_as object to append as a child.
-
-       void appendChild(boost::intrusive_ptr<XMLNode_as> childNode);
-
-    /// Set the parent XMLNode_as of this node.
-    //
-    /// @param node     The new parent of this node. May be 0.
-    void setParent(XMLNode_as* node) { _parent = node; }
+    XMLNode_as* cloneNode(bool deep);
+
+    /// Append a child node to this XML object
+    //
+    /// The child node's parent is set to this object, the node is added to
+    /// this object's children, the _childNodes array may be updated.
+    //
+    /// @param node     The node to add as a child
+    /// @param update   Whether to update the array of childNodes. When XML
+    ///                 trees are automatically created, e.g. during parseXML,
+    ///                 there is no need to create or update the array on
+    ///                 each append. Omitting the update reduces CPU usage
+    ///                 and memory usage (creating the array means creating
+    ///                 a referenceable object).
+       void appendChild(XMLNode_as* node, bool update = true);
+
+    /// Remove a child node from this XML object
+    //
+    /// The child node's parent is set to 0, the node is removed from
+    /// this object's children, the _childNodes array is updated.
+    void removeChild(XMLNode_as* node);
 
     /// Get the parent XMLNode_as of this node. Can be 0.
-    XMLNode_as *getParent() const {
-        return _parent.get();
+    XMLNode_as* getParent() const {
+        return _parent;
     }
 
     /// Insert a node before a node
@@ -161,20 +171,14 @@
     /// method. If beforeNode is not a child of my_xml, the insertion
     /// fails.
     ///
-    /// @param newnoe
+    /// @param newnode
     ///     The node to insert, moving from its current tree
     ///
     /// @param beforeWhich
     ///     The node before which to insert the new one.
     ///     Must be a child of this XMLNode or the operation will fail.
     ///
-    void insertBefore(boost::intrusive_ptr<XMLNode_as> newnode, 
-            boost::intrusive_ptr<XMLNode_as> pos);
-
-    /// Removes the specified XML object from its parent.
-    //
-    /// Also deletes all descendants of the node.
-    void removeNode();
+    void insertBefore(XMLNode_as* newnode, XMLNode_as* pos);
 
     /// Convert the XMLNode to a string
     //
@@ -198,30 +202,62 @@
     /// @param value    The value to set the named attribute to.
     void setAttribute(const std::string& name, const std::string& value);
 
+    /// Associate an as_object with this XMLNode_as.
+    //
+    /// An XMLNode_as with an associated object is regarded as being owned
+    /// by that object, so make sure it is! Using as_object::setRelay will
+    /// achieve that.
+    void setObject(as_object* o) {
+        assert(!_object);
+        assert(o);
+        _object = o;
+    }
+
+    /// Return the object associated with this XMLNode_as.
+    //
+    /// The object will be created if it does not already exist.
+    as_object* object();
+
 protected:
 
-#ifdef GNASH_USE_GC
-       /// Mark XMLNode-specific reachable resources and invoke
-       /// the parent's class version (markAsObjectReachable)
-       //
-       /// XMLNode-specific reachable resources are:
-       ///     - The child elements (_children)
-       ///     - The parent elements (_parent)
-       ///
-       virtual void markReachableResources() const;
-#endif // GNASH_USE_GC
-
-    Children _children;
+    /// Mark reachable elements
+    //
+    /// These are: children, attributes object, associated as_object.
+       virtual void setReachable();
+
+    Global_as& _global;
+
+    /// Clear all children, making sure unreferenced children are deleted.
+    //
+    /// AS-referenced child nodes will no longer be marked as reachable, so
+    /// the GC will remove them on the next run.
+    void clearChildren();
 
 private:
 
+    /// Set the parent XMLNode_as of this node.
+    //
+    /// @param node     The new parent of this node. May be 0.
+    void setParent(XMLNode_as* node) { _parent = node; }
+
+    /// Reset the array of childNodes to match the actual children.
+    //
+    /// Only called when the XML structure changes.
+    void updateChildNodes();
+
     /// A non-trivial copy-constructor for cloning nodes.
     XMLNode_as(const XMLNode_as &node, bool deep);
 
-    boost::intrusive_ptr<XMLNode_as> _parent;
+    Children _children;
+
+    as_object* _object;
+
+    XMLNode_as* _parent;
 
     as_object* _attributes;
 
+    as_object* _childNodes;
+
     std::string _name;
 
     std::string _value;
@@ -235,6 +271,12 @@
 
 };
 
+// Initialize the global XMLNode class
+void xmlnode_class_init(as_object& where, const ObjectURI& uri);
+
+/// Register ASnative methods
+void registerXMLNodeNative(as_object& where);
+
 } // gnash namespace
 
 // GNASH_ASOBJ3_XMLNODE_H

=== modified file 'testsuite/actionscript.all/XML.as'
--- a/testsuite/actionscript.all/XML.as 2009-08-26 07:59:32 +0000
+++ b/testsuite/actionscript.all/XML.as 2009-11-26 12:26:07 +0000
@@ -60,6 +60,11 @@
 check(XML.prototype.hasOwnProperty("send") );
 check(XML.prototype.hasOwnProperty("sendAndLoad") );
 
+check(!XML.prototype.hasOwnProperty("docTypeDecl") );
+check(!XML.prototype.hasOwnProperty("xmlDecl") );
+// ignoreWhite is undefined by default, but is used when set to true
+check(!XML.prototype.hasOwnProperty("ignoreWhite") );
+
 check(!XML.hasOwnProperty("createElement") );
 check(!XML.hasOwnProperty("addRequestHeader") );
 check(!XML.hasOwnProperty("createTextNode") );
@@ -71,8 +76,8 @@
 check(!XML.hasOwnProperty("sendAndLoad") );
 check(!XML.hasOwnProperty("nodeValue"));
 check(!XML.hasOwnProperty("_customHeaders"));
-// ignoreWhite is undefined by default, but is used when set to true
-check(!XML.prototype.hasOwnProperty("ignoreWhite") );
+check(!XML.hasOwnProperty("docTypeDecl") );
+check(!XML.hasOwnProperty("xmlDecl") );
 
 check(XMLNode.prototype.hasOwnProperty("appendChild") );
 check(XMLNode.prototype.hasOwnProperty("cloneNode") );
@@ -111,6 +116,15 @@
 
 var tmp = new XML();
 
+
+// These properties are added to the prototype here.
+check(!tmp.hasOwnProperty("docTypeDecl") );
+check(!tmp.hasOwnProperty("xmlDecl") );
+check(XML.prototype.hasOwnProperty("docTypeDecl") );
+check(XML.prototype.hasOwnProperty("xmlDecl") );
+check(XML.prototype.hasOwnProperty("contentType") );
+check(XML.prototype.hasOwnProperty("ignoreWhite") );
+
 #if OUTPUT_VERSION >= 6
  check( ! tmp.hasOwnProperty("nodeValue") );
 #endif
@@ -895,12 +909,12 @@
 #endif
        {
 #if OUTPUT_VERSION < 6
-               check_totals(419);
+               check_totals(429);
 #else
 # if OUTPUT_VERSION < 8
-               check_totals(454);
+               check_totals(464);
 # else
-               check_totals(435);
+               check_totals(445);
 # endif
 #endif
                play();

=== modified file 'testsuite/actionscript.all/XMLNode.as'
--- a/testsuite/actionscript.all/XMLNode.as     2009-08-26 06:52:28 +0000
+++ b/testsuite/actionscript.all/XMLNode.as     2009-11-26 14:30:42 +0000
@@ -123,29 +123,29 @@
 
 // Now it has 4, but the latest element is not an XMLNode
 node1.childNodes.push("not a node");
-xcheck_equals(node1.childNodes.length, 4);
+check_equals(node1.childNodes.length, 4);
 check(!node1.childNodes[3] instanceOf XMLNode);
 
 // Now 5. The latest element is an XMLNode, but it does not become
 // lastChild
 node1.childNodes.push(new XMLNode (1, "an XMLNode"));
-xcheck_equals(node1.childNodes.length, 5);
-xcheck(node1.childNodes[4] instanceOf XMLNode);
+check_equals(node1.childNodes.length, 5);
+check(node1.childNodes[4] instanceOf XMLNode);
 check_equals(node1.lastChild.toString(), "<node3>third text node</node3>");
 
 // childNodes really is just an array: it can be sorted
 check_equals(node1.childNodes[0].toString(), "first text node");
 check_equals(node1.childNodes[2].toString(), "<node3>third text node</node3>");
-xcheck_equals(node1.childNodes[3].toString(), "not a node");
+check_equals(node1.childNodes[3].toString(), "not a node");
 node1.childNodes.sort();
 xcheck_equals(node1.childNodes[0].toString(), "<an XMLNode />");
 check_equals(node1.childNodes[2].toString(), "<node3>third text node</node3>");
-xcheck_equals(node1.childNodes[3].toString(), "first text node");
+check_equals(node1.childNodes[3].toString(), "first text node");
 
 // It can store anything
 node1.childNodes.push(new Date());
-xcheck_equals(node1.childNodes.length, 6);
-xcheck(node1.childNodes[5] instanceOf Date);
+check_equals(node1.childNodes.length, 6);
+check(node1.childNodes[5] instanceOf Date);
 check_equals(node1.childNodes.childNodes[5].hasChildNodes(), undefined);
 
 node1.childNodes.lastChild.appendChild(new XMLNode(1, "datenode"));
@@ -156,10 +156,10 @@
     return "o.toString()";
 };
 
-xcheck_equals(node1.childNodes.length, 6);
+check_equals(node1.childNodes.length, 6);
 node1.childNodes.push(o);
-xcheck_equals(node1.childNodes.length, 7);
-xcheck_equals(node1.childNodes[6].toString(), "o.toString()");
+check_equals(node1.childNodes.length, 7);
+check_equals(node1.childNodes[6].toString(), "o.toString()");
 
 // The last child is still node3
 check(node1.lastChild != node1.childNodes[6]);

=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING  2009-11-23 17:22:36 +0000
+++ b/testsuite/swfdec/PASSING  2009-11-26 14:30:42 +0000
@@ -1479,7 +1479,16 @@
 xml-escape-8.swf:cbd1f724a3dc3e73697535468443171d
 xml-init-5.swf:2ba1da174f2b1958749fede5667a60c4
 xml-init-5.swf:bb54cac64e38396084a147266f7d9711
+xml-init-6.swf:d82535b95268d2f426800229232697fd
+xml-init-7.swf:6ff05f6dd1b9085988ceb3899ebb9431
+xml-init-8.swf:9f48a710d96b55ed605062be8f14de61
 xml-node-init-5.swf:12fd3762a2bfa787b01fc0b8abfaa492
+xml-properties2-5.swf:775eeab1ca99591990db2f8fc79e5ce3
+xml-properties2-6.swf:39bbce190960c16c62b9a5fdd7b5d847
+xml-properties2-7.swf:ee74aae83eeb596faa9329556dbfc216
+xml-properties2-8.swf:0133ae45104b53e477fe0b1850c4408e
+xml-properties-7.swf:d8f9fcf53355cbd5d39fde61f0dde923
+xml-properties-8.swf:de9730de8b3db0efca105863d9eca999
 xml-socket-properties-5.swf:856b75b9d2e45a688649afd247224176
 xml-socket-properties-6.swf:c2a153377e55fd70aed74a5711dc8bfd
 xml-socket-properties-7.swf:ad8a3f3b1ed9a4b6f068f74f003f2260


reply via email to

[Prev in Thread] Current Thread [Next in Thread]