aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java')
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java606
1 files changed, 606 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
new file mode 100644
index 0000000..6d45240
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
@@ -0,0 +1,606 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import java.io.Serializable;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.*;
+
+public final class XMLLibImpl extends XMLLib implements Serializable {
+ // TODO Document that this only works with JDK 1.5 or backport its
+ // features to earlier versions
+ private static final long serialVersionUID = 1L;
+
+ //
+ // EXPERIMENTAL Java interface
+ //
+
+ /**
+ This experimental interface is undocumented.
+ */
+ public static org.w3c.dom.Node toDomNode(Object xmlObject) {
+ // Could return DocumentFragment for XMLList
+ // Probably a single node for XMLList with one element
+ if (xmlObject instanceof XML) {
+ return ((XML)xmlObject).toDomNode();
+ } else {
+ throw new IllegalArgumentException("xmlObject is not an XML object in JavaScript.");
+ }
+ }
+
+ public static void init(Context cx, Scriptable scope, boolean sealed) {
+ XMLLibImpl lib = new XMLLibImpl(scope);
+ XMLLib bound = lib.bindToScope(scope);
+ if (bound == lib) {
+ lib.exportToScope(sealed);
+ }
+ }
+
+ private Scriptable globalScope;
+
+ private XML xmlPrototype;
+ private XMLList xmlListPrototype;
+ private Namespace namespacePrototype;
+ private QName qnamePrototype;
+
+ private XmlProcessor options = new XmlProcessor();
+
+ private XMLLibImpl(Scriptable globalScope) {
+ this.globalScope = globalScope;
+ }
+
+ /** @deprecated */
+ QName qnamePrototype() {
+ return qnamePrototype;
+ }
+
+ /** @deprecated */
+ Scriptable globalScope() {
+ return globalScope;
+ }
+
+ XmlProcessor getProcessor() {
+ return options;
+ }
+
+ private void exportToScope(boolean sealed) {
+ xmlPrototype = newXML(XmlNode.createText(options, ""));
+ xmlListPrototype = newXMLList();
+ namespacePrototype = Namespace.create(this.globalScope, null, XmlNode.Namespace.GLOBAL);
+ qnamePrototype = QName.create(this, this.globalScope, null, XmlNode.QName.create(XmlNode.Namespace.create(""), ""));
+
+ xmlPrototype.exportAsJSClass(sealed);
+ xmlListPrototype.exportAsJSClass(sealed);
+ namespacePrototype.exportAsJSClass(sealed);
+ qnamePrototype.exportAsJSClass(sealed);
+ }
+
+ /** @deprecated */
+ XMLName toAttributeName(Context cx, Object nameValue) {
+ if (nameValue instanceof XMLName) {
+ // TODO Will this always be an XMLName of type attribute name?
+ return (XMLName)nameValue;
+ } else if (nameValue instanceof QName) {
+ return XMLName.create( ((QName)nameValue).getDelegate(), true, false );
+ } else if (nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null) {
+ throw badXMLName(nameValue);
+ } else {
+ // TODO Not 100% sure that putting these in global namespace is the right thing to do
+ String localName = null;
+ if (nameValue instanceof String) {
+ localName = (String)nameValue;
+ } else {
+ localName = ScriptRuntime.toString(nameValue);
+ }
+ if (localName != null && localName.equals("*")) localName = null;
+ return XMLName.create(XmlNode.QName.create(XmlNode.Namespace.create(""), localName), true, false);
+ }
+ }
+
+ private static RuntimeException badXMLName(Object value)
+ {
+ String msg;
+ if (value instanceof Number) {
+ msg = "Can not construct XML name from number: ";
+ } else if (value instanceof Boolean) {
+ msg = "Can not construct XML name from boolean: ";
+ } else if (value == Undefined.instance || value == null) {
+ msg = "Can not construct XML name from ";
+ } else {
+ throw new IllegalArgumentException(value.toString());
+ }
+ return ScriptRuntime.typeError(msg+ScriptRuntime.toString(value));
+ }
+
+ XMLName toXMLNameFromString(Context cx, String name) {
+ return XMLName.create( getDefaultNamespaceURI(cx), name );
+ }
+
+ /** @deprecated */
+ XMLName toXMLName(Context cx, Object nameValue) {
+ XMLName result;
+
+ if (nameValue instanceof XMLName) {
+ result = (XMLName)nameValue;
+ } else if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ result = XMLName.formProperty(qname.uri(), qname.localName());
+ } else if (nameValue instanceof String) {
+ result = toXMLNameFromString(cx, (String)nameValue);
+ } else if (nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null) {
+ throw badXMLName(nameValue);
+ } else {
+ String name = ScriptRuntime.toString(nameValue);
+ result = toXMLNameFromString(cx, name);
+ }
+
+ return result;
+ }
+
+ /**
+ * If value represents Uint32 index, make it available through
+ * ScriptRuntime.lastUint32Result(cx) and return null.
+ * Otherwise return the same value as toXMLName(cx, value).
+ */
+ XMLName toXMLNameOrIndex(Context cx, Object value)
+ {
+ XMLName result;
+
+ if (value instanceof XMLName) {
+ result = (XMLName)value;
+ } else if (value instanceof String) {
+ String str = (String)value;
+ long test = ScriptRuntime.testUint32String(str);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ result = null;
+ } else {
+ result = toXMLNameFromString(cx, str);
+ }
+ } else if (value instanceof Number) {
+ double d = ((Number)value).doubleValue();
+ long l = (long)d;
+ if (l == d && 0 <= l && l <= 0xFFFFFFFFL) {
+ ScriptRuntime.storeUint32Result(cx, l);
+ result = null;
+ } else {
+ throw badXMLName(value);
+ }
+ } else if (value instanceof QName) {
+ QName qname = (QName)value;
+ String uri = qname.uri();
+ boolean number = false;
+ result = null;
+ if (uri != null && uri.length() == 0) {
+ // Only in this case qname.toString() can resemble uint32
+ long test = ScriptRuntime.testUint32String(uri);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ number = true;
+ }
+ }
+ if (!number) {
+ result = XMLName.formProperty(uri, qname.localName());
+ }
+ } else if (value instanceof Boolean
+ || value == Undefined.instance
+ || value == null)
+ {
+ throw badXMLName(value);
+ } else {
+ String str = ScriptRuntime.toString(value);
+ long test = ScriptRuntime.testUint32String(str);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ result = null;
+ } else {
+ result = toXMLNameFromString(cx, str);
+ }
+ }
+
+ return result;
+ }
+
+ Object addXMLObjects(Context cx, XMLObject obj1, XMLObject obj2)
+ {
+ XMLList listToAdd = newXMLList();
+
+ if (obj1 instanceof XMLList) {
+ XMLList list1 = (XMLList)obj1;
+ if (list1.length() == 1) {
+ listToAdd.addToList(list1.item(0));
+ } else {
+ // Might be xmlFragment + xmlFragment + xmlFragment + ...;
+ // then the result will be an XMLList which we want to be an
+ // rValue and allow it to be assigned to an lvalue.
+ listToAdd = newXMLListFrom(obj1);
+ }
+ } else {
+ listToAdd.addToList(obj1);
+ }
+
+ if (obj2 instanceof XMLList) {
+ XMLList list2 = (XMLList)obj2;
+ for (int i = 0; i < list2.length(); i++) {
+ listToAdd.addToList(list2.item(i));
+ }
+ } else if (obj2 instanceof XML) {
+ listToAdd.addToList(obj2);
+ }
+
+ return listToAdd;
+ }
+
+ private Ref xmlPrimaryReference(Context cx, XMLName xmlName, Scriptable scope) {
+ XMLObjectImpl xmlObj;
+ XMLObjectImpl firstXml = null;
+ for (;;) {
+ // XML object can only present on scope chain as a wrapper
+ // of XMLWithScope
+ if (scope instanceof XMLWithScope) {
+ xmlObj = (XMLObjectImpl)scope.getPrototype();
+ if (xmlObj.hasXMLProperty(xmlName)) {
+ break;
+ }
+ if (firstXml == null) {
+ firstXml = xmlObj;
+ }
+ }
+ scope = scope.getParentScope();
+ if (scope == null) {
+ xmlObj = firstXml;
+ break;
+ }
+ }
+
+ // xmlObj == null corresponds to undefined as the target of
+ // the reference
+ if (xmlObj != null) {
+ xmlName.initXMLObject(xmlObj);
+ }
+ return xmlName;
+ }
+
+ Namespace castToNamespace(Context cx, Object namespaceObj) {
+ return this.namespacePrototype.castToNamespace(namespaceObj);
+ }
+
+ private String getDefaultNamespaceURI(Context cx) {
+ return getDefaultNamespace(cx).uri();
+ }
+
+ Namespace newNamespace(String uri) {
+ return this.namespacePrototype.newNamespace(uri);
+ }
+
+ Namespace getDefaultNamespace(Context cx) {
+ if (cx == null) {
+ cx = Context.getCurrentContext();
+ if (cx == null) {
+ return namespacePrototype;
+ }
+ }
+
+ Object ns = ScriptRuntime.searchDefaultNamespace(cx);
+ if (ns == null) {
+ return namespacePrototype;
+ } else {
+ if (ns instanceof Namespace) {
+ return (Namespace)ns;
+ } else {
+ // TODO Clarify or remove the following comment
+ // Should not happen but for now it could
+ // due to bad searchDefaultNamespace implementation.
+ return namespacePrototype;
+ }
+ }
+ }
+
+ Namespace[] createNamespaces(XmlNode.Namespace[] declarations) {
+ Namespace[] rv = new Namespace[declarations.length];
+ for (int i=0; i<declarations.length; i++) {
+ rv[i] = this.namespacePrototype.newNamespace(declarations[i].getPrefix(), declarations[i].getUri());
+ }
+ return rv;
+ }
+
+ // See ECMA357 13.3.2
+ QName constructQName(Context cx, Object namespace, Object name) {
+ return this.qnamePrototype.constructQName(this, cx, namespace, name);
+ }
+
+ QName newQName(String uri, String localName, String prefix) {
+ return this.qnamePrototype.newQName(this, uri, localName, prefix);
+ }
+
+ QName constructQName(Context cx, Object nameValue) {
+// return constructQName(cx, Undefined.instance, nameValue);
+ return this.qnamePrototype.constructQName(this, cx, nameValue);
+ }
+
+ QName castToQName(Context cx, Object qnameValue) {
+ return this.qnamePrototype.castToQName(this, cx, qnameValue);
+ }
+
+ QName newQName(XmlNode.QName qname) {
+ return QName.create(this, this.globalScope, this.qnamePrototype, qname);
+ }
+
+ XML newXML(XmlNode node) {
+ return new XML(this, this.globalScope, this.xmlPrototype, node);
+ }
+
+ /**
+ @deprecated I believe this can be replaced by ecmaToXml below.
+ */
+ final XML newXMLFromJs(Object inputObject) {
+ String frag;
+
+ if (inputObject == null || inputObject == Undefined.instance) {
+ frag = "";
+ } else if (inputObject instanceof XMLObjectImpl) {
+ // todo: faster way for XMLObjects?
+ frag = ((XMLObjectImpl) inputObject).toXMLString();
+ } else {
+ frag = ScriptRuntime.toString(inputObject);
+ }
+
+ if (frag.trim().startsWith("<>")) {
+ throw ScriptRuntime.typeError("Invalid use of XML object anonymous tags <></>.");
+ }
+
+ if (frag.indexOf("<") == -1) {
+ // Solo text node
+ return newXML(XmlNode.createText(options, frag));
+ }
+ return parse(frag);
+ }
+
+ private XML parse(String frag) {
+ try {
+ return newXML(XmlNode.createElement(options, getDefaultNamespaceURI(Context.getCurrentContext()), frag));
+ } catch (org.xml.sax.SAXException e) {
+ throw ScriptRuntime.typeError("Cannot parse XML: " + e.getMessage());
+ }
+ }
+
+ final XML ecmaToXml(Object object) {
+ // See ECMA357 10.3
+ if (object == null || object == Undefined.instance) throw ScriptRuntime.typeError("Cannot convert " + object + " to XML");
+ if (object instanceof XML) return (XML)object;
+ if (object instanceof XMLList) {
+ XMLList list = (XMLList)object;
+ if (list.getXML() != null) {
+ return list.getXML();
+ } else {
+ throw ScriptRuntime.typeError("Cannot convert list of >1 element to XML");
+ }
+ }
+ // TODO Technically we should fail on anything except a String, Number or Boolean
+ // See ECMA357 10.3
+ // Extension: if object is a DOM node, use that to construct the XML
+ // object.
+ if (object instanceof Wrapper) {
+ object = ((Wrapper) object).unwrap();
+ }
+ if (object instanceof org.w3c.dom.Node) {
+ org.w3c.dom.Node node = (org.w3c.dom.Node) object;
+ return newXML(XmlNode.createElementFromNode(node));
+ }
+ // Instead we just blindly cast to a String and let them convert anything.
+ String s = ScriptRuntime.toString(object);
+ // TODO Could this get any uglier?
+ if (s.length() > 0 && s.charAt(0) == '<') {
+ return parse(s);
+ } else {
+ return newXML(XmlNode.createText(options, s));
+ }
+ }
+
+ final XML newTextElementXML(XmlNode reference, XmlNode.QName qname, String value) {
+ return newXML(XmlNode.newElementWithText(options, reference, qname, value));
+ }
+
+ XMLList newXMLList() {
+ return new XMLList(this, this.globalScope, this.xmlListPrototype);
+ }
+
+ final XMLList newXMLListFrom(Object inputObject) {
+ XMLList rv = newXMLList();
+
+ if (inputObject == null || inputObject instanceof Undefined) {
+ return rv;
+ } else if (inputObject instanceof XML) {
+ XML xml = (XML) inputObject;
+ rv.getNodeList().add(xml);
+ return rv;
+ } else if (inputObject instanceof XMLList) {
+ XMLList xmll = (XMLList) inputObject;
+ rv.getNodeList().add(xmll.getNodeList());
+ return rv;
+ } else {
+ String frag = ScriptRuntime.toString(inputObject).trim();
+
+ if (!frag.startsWith("<>")) {
+ frag = "<>" + frag + "</>";
+ }
+
+ frag = "<fragment>" + frag.substring(2);
+ if (!frag.endsWith("</>")) {
+ throw ScriptRuntime.typeError("XML with anonymous tag missing end anonymous tag");
+ }
+
+ frag = frag.substring(0, frag.length() - 3) + "</fragment>";
+
+ XML orgXML = newXMLFromJs(frag);
+
+ // Now orphan the children and add them to our XMLList.
+ XMLList children = orgXML.children();
+
+ for (int i = 0; i < children.getNodeList().length(); i++) {
+ // Copy here is so that they'll be orphaned (parent() will be undefined)
+ rv.getNodeList().add(((XML) children.item(i).copy()));
+ }
+ return rv;
+ }
+ }
+
+ XmlNode.QName toNodeQName(Context cx, Object namespaceValue, Object nameValue) {
+ // This is duplication of constructQName(cx, namespaceValue, nameValue)
+ // but for XMLName
+
+ String localName;
+
+ if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ localName = qname.localName();
+ } else {
+ localName = ScriptRuntime.toString(nameValue);
+ }
+
+ XmlNode.Namespace ns;
+ if (namespaceValue == Undefined.instance) {
+ if ("*".equals(localName)) {
+ ns = null;
+ } else {
+ ns = getDefaultNamespace(cx).getDelegate();
+ }
+ } else if (namespaceValue == null) {
+ ns = null;
+ } else if (namespaceValue instanceof Namespace) {
+ ns = ((Namespace)namespaceValue).getDelegate();
+ } else {
+ ns = this.namespacePrototype.constructNamespace(namespaceValue).getDelegate();
+ }
+
+ if (localName != null && localName.equals("*")) localName = null;
+ return XmlNode.QName.create(ns, localName);
+ }
+
+ XmlNode.QName toNodeQName(Context cx, String name, boolean attribute) {
+ XmlNode.Namespace defaultNamespace = getDefaultNamespace(cx).getDelegate();
+ if (name != null && name.equals("*")) {
+ return XmlNode.QName.create(null, null);
+ } else {
+ if (attribute) {
+ return XmlNode.QName.create(XmlNode.Namespace.GLOBAL, name);
+ } else {
+ return XmlNode.QName.create(defaultNamespace, name);
+ }
+ }
+ }
+
+ /**
+ @deprecated Too general; this should be split into overloaded methods.
+ Is that possible?
+ */
+ XmlNode.QName toNodeQName(Context cx, Object nameValue, boolean attribute) {
+ if (nameValue instanceof XMLName) {
+ return ((XMLName)nameValue).toQname();
+ } else if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ return qname.getDelegate();
+ } else if (
+ nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null
+ ) {
+ throw badXMLName(nameValue);
+ } else {
+ String local = null;
+ if (nameValue instanceof String) {
+ local = (String)nameValue;
+ } else {
+ local = ScriptRuntime.toString(nameValue);
+ }
+ return toNodeQName(cx, local, attribute);
+ }
+ }
+
+ //
+ // Override methods from XMLLib
+ //
+
+ public boolean isXMLName(Context _cx, Object nameObj) {
+ return XMLName.accept(nameObj);
+ }
+
+ public Object toDefaultXmlNamespace(Context cx, Object uriValue) {
+ return this.namespacePrototype.constructNamespace(uriValue);
+ }
+
+ public String escapeTextValue(Object o) {
+ return options.escapeTextValue(o);
+ }
+
+ public String escapeAttributeValue(Object o) {
+ return options.escapeAttributeValue(o);
+ }
+
+ public Ref nameRef(Context cx, Object name, Scriptable scope, int memberTypeFlags) {
+ if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) == 0) {
+ // should only be called foir cases like @name or @[expr]
+ throw Kit.codeBug();
+ }
+ XMLName xmlName = toAttributeName(cx, name);
+ return xmlPrimaryReference(cx, xmlName, scope);
+ }
+
+ public Ref nameRef(Context cx, Object namespace, Object name, Scriptable scope, int memberTypeFlags) {
+ XMLName xmlName = XMLName.create(toNodeQName(cx, namespace, name), false, false);
+
+ // No idea what is coming in from the parser in this case; is it detecting the "@"?
+ if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) {
+ if (!xmlName.isAttributeName()) {
+ xmlName.setAttributeName();
+ }
+ }
+
+ return xmlPrimaryReference(cx, xmlName, scope);
+ }
+}