[Top][All Lists]
[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
- ("&", "&")
- (""", "\"")
- ("<", "<")
- (">", ">")
- ("'", "'");
-
- 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
+ ("&", "&")
+ (""", "\"")
+ ("<", "<")
+ (">", ">")
+ ("'", "'");
+
+ 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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r11652: Drop static data from XML and XMLNode. Make them work better.,
Benjamin Wolsey <=