Bug 812302 - nsSAXXMLReader::HandleXMLDeclaration should report its results. r+sr=smaug
authorAlexander J. Vincent <ajvincent@gmail.com>
Mon, 17 Dec 2012 20:53:38 -0500
changeset 116368 b627cef1d7d2a7bf1cd0a9ee74defbcd0e114830
parent 116367 143ce885103aadf146e516eb97474adb9e935dd3
child 116369 92b58637064edb3bd8ac5b869d1146db7ff7f1ee
push id19880
push userryanvm@gmail.com
push dateTue, 18 Dec 2012 01:53:42 +0000
treeherdermozilla-inbound@ab006da8f88d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs812302
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 812302 - nsSAXXMLReader::HandleXMLDeclaration should report its results. r+sr=smaug
parser/xml/public/Makefile.in
parser/xml/public/nsIMozSAXXMLDeclarationHandler.idl
parser/xml/public/nsISAXXMLReader.idl
parser/xml/src/nsSAXXMLReader.cpp
parser/xml/src/nsSAXXMLReader.h
parser/xml/test/unit/test_xml_declaration.js
parser/xml/test/unit/xpcshell.ini
--- a/parser/xml/public/Makefile.in
+++ b/parser/xml/public/Makefile.in
@@ -17,11 +17,12 @@ XPIDLSRCS	= \
                 nsISAXMutableAttributes.idl \
                 nsISAXContentHandler.idl \
                 nsISAXDTDHandler.idl \
                 nsISAXErrorHandler.idl \
                 nsISAXLexicalHandler.idl \
                 nsISAXLocator.idl \
                 nsISAXXMLReader.idl \
                 nsISAXXMLFilter.idl \
+                nsIMozSAXXMLDeclarationHandler.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/parser/xml/public/nsIMozSAXXMLDeclarationHandler.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+/* This is a helper for the XML declaration in a document:
+ * <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+ */
+
+[scriptable, function, uuid(c0e461cb-0e5e-284c-b97d-cffeec467eba)]
+interface nsIMozSAXXMLDeclarationHandler: nsISupports {
+  void handleXMLDeclaration(in AString version, in AString encoding, in boolean standalone);
+};
--- a/parser/xml/public/nsISAXXMLReader.idl
+++ b/parser/xml/public/nsISAXXMLReader.idl
@@ -9,27 +9,28 @@ interface nsIInputStream;
 interface nsIRequestObserver;
 interface nsIURI;
 
 interface nsISAXContentHandler;
 interface nsISAXDTDHandler;
 interface nsISAXEntityResolver;
 interface nsISAXErrorHandler;
 interface nsISAXLexicalHandler;
+interface nsIMozSAXXMLDeclarationHandler;
 
 /**
  * Interface for reading an XML document using callbacks.
  *
  * nsISAXXMLReader is the interface that an XML parser's SAX2
  * driver must implement.  This interface allows an application to set
  * and query features and properties in the parser, to register event
  * handlers for document processing, and to initiate a document
  * parse.
  */
-[scriptable, uuid(5556997e-d816-4218-8b54-803d4261206e)]
+[scriptable, uuid(5b1de802-9091-454f-9972-5753c0d0c70e)]
 interface nsISAXXMLReader : nsIStreamListener {
 
   /**
    * The base URI.
    */
   attribute nsIURI baseURI;
 
   /**
@@ -63,16 +64,24 @@ interface nsISAXXMLReader : nsIStreamLis
    *
    * Applications may register a new or different handler in the
    * middle of a parse, and the SAX parser must begin using the new
    * handler immediately.
    */
   attribute nsISAXErrorHandler errorHandler;
 
   /**
+   * A handler for the (optional) XML declaration of a document.
+   * <?xml version='1.0'?>
+   *
+   * @note This is not part of the SAX standard.
+   */
+  attribute nsIMozSAXXMLDeclarationHandler declarationHandler;
+
+  /**
    * If the application does not register a lexical handler, all
    * lexical events (e.g. startDTD) reported by the SAX parser will be
    * silently ignored.
    *
    * Applications may register a new or different handler in the
    * middle of a parse, and the SAX parser must begin using the new
    * handler immediately.
    */
--- a/parser/xml/src/nsSAXXMLReader.cpp
+++ b/parser/xml/src/nsSAXXMLReader.cpp
@@ -19,21 +19,22 @@
 #include "mozilla/dom/EncodingUtils.h"
 
 using mozilla::dom::EncodingUtils;
 
 #define XMLNS_URI "http://www.w3.org/2000/xmlns/"
 
 static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
 
-NS_IMPL_CYCLE_COLLECTION_7(nsSAXXMLReader,
+NS_IMPL_CYCLE_COLLECTION_8(nsSAXXMLReader,
                            mContentHandler,
                            mDTDHandler,
                            mErrorHandler,
                            mLexicalHandler,
+                           mDeclarationHandler,
                            mBaseURI,
                            mListener,
                            mParserObserver)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSAXXMLReader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSAXXMLReader)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSAXXMLReader)
   NS_INTERFACE_MAP_ENTRY(nsISAXXMLReader)
   NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
@@ -284,18 +285,25 @@ nsSAXXMLReader::HandleUnparsedEntityDecl
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSAXXMLReader::HandleXMLDeclaration(const PRUnichar *aVersion,
                                      const PRUnichar *aEncoding,
                                      int32_t aStandalone)
 {
-  // XXX need to decide what to do with this. It's a separate
-  // optional interface in SAX.
+  NS_ASSERTION(aVersion, "null passed to handler");
+  if (mDeclarationHandler) {
+    PRUnichar nullChar = PRUnichar(0);
+    if (!aEncoding)
+      aEncoding = &nullChar;
+    mDeclarationHandler->HandleXMLDeclaration(nsDependentString(aVersion),
+                                              nsDependentString(aEncoding),
+                                              aStandalone > 0);
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSAXXMLReader::ReportError(const PRUnichar* aErrorText,
                             const PRUnichar* aSourceText,
                             nsIScriptError *aError,
                             bool *_retval)
@@ -404,16 +412,28 @@ nsSAXXMLReader::GetFeature(const nsAStri
   if (aName.EqualsLiteral("http://xml.org/sax/features/namespace-prefixes")) {
     *aResult = mEnableNamespacePrefixes;
     return NS_OK;
   }
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsSAXXMLReader::GetDeclarationHandler(nsIMozSAXXMLDeclarationHandler **aDeclarationHandler) {
+  NS_IF_ADDREF(*aDeclarationHandler = mDeclarationHandler);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSAXXMLReader::SetDeclarationHandler(nsIMozSAXXMLDeclarationHandler *aDeclarationHandler) {
+  mDeclarationHandler = aDeclarationHandler;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsSAXXMLReader::GetLexicalHandler(nsISAXLexicalHandler **aLexicalHandler)
 {
   NS_IF_ADDREF(*aLexicalHandler = mLexicalHandler);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSAXXMLReader::SetLexicalHandler(nsISAXLexicalHandler *aLexicalHandler)
--- a/parser/xml/src/nsSAXXMLReader.h
+++ b/parser/xml/src/nsSAXXMLReader.h
@@ -11,16 +11,17 @@
 #include "nsIExtendedExpatSink.h"
 #include "nsIParser.h"
 #include "nsIURI.h"
 #include "nsISAXXMLReader.h"
 #include "nsISAXContentHandler.h"
 #include "nsISAXDTDHandler.h"
 #include "nsISAXErrorHandler.h"
 #include "nsISAXLexicalHandler.h"
+#include "nsIMozSAXXMLDeclarationHandler.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
 #define NS_SAXXMLREADER_CONTRACTID "@mozilla.org/saxparser/xmlreader;1"
 #define NS_SAXXMLREADER_CLASSNAME "SAX XML Reader"
 #define NS_SAXXMLREADER_CID  \
 { 0xab1da296, 0x6125, 0x40ba, \
 { 0x96, 0xd0, 0x47, 0xa8, 0x28, 0x2a, 0xe3, 0xdb} }
@@ -74,16 +75,17 @@ public:
     return nullptr;
   }
 
 private:
   nsCOMPtr<nsISAXContentHandler> mContentHandler;
   nsCOMPtr<nsISAXDTDHandler> mDTDHandler;
   nsCOMPtr<nsISAXErrorHandler> mErrorHandler;
   nsCOMPtr<nsISAXLexicalHandler> mLexicalHandler;
+  nsCOMPtr<nsIMozSAXXMLDeclarationHandler> mDeclarationHandler;
   nsCOMPtr<nsIURI> mBaseURI;
   nsCOMPtr<nsIStreamListener> mListener;
   nsCOMPtr<nsIRequestObserver> mParserObserver;
   bool mIsAsyncParse;
   static bool TryChannelCharset(nsIChannel *aChannel,
                                   int32_t& aCharsetSource,
                                   nsACString& aCharset);
   nsresult EnsureBaseURI();
new file mode 100644
--- /dev/null
+++ b/parser/xml/test/unit/test_xml_declaration.js
@@ -0,0 +1,82 @@
+function noop() {}
+
+function run_test() {
+  var evts;
+
+  var contentHandler = {
+    attrs: null,
+    startDocument: function() {
+      evts.push("startDocument");
+    },
+    endDocument: noop,
+
+    startElement: function startElement() {
+      evts.push("startElement");
+    },
+
+    endElement: noop,
+    characters: noop,
+    processingInstruction: noop,
+    ignorableWhitespace: noop,
+    startPrefixMapping: noop,
+    endPrefixMapping: noop
+  };
+
+  function XMLDeclHandler(version, encoding, standalone) {
+    evts.splice(evts.length, 0, version, encoding, standalone);
+  }
+
+  const nsISAXXMLReader = Components.interfaces.nsISAXXMLReader;
+  var saxReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"]
+                            .createInstance(nsISAXXMLReader);
+  saxReader.contentHandler = contentHandler;
+  saxReader.declarationHandler = XMLDeclHandler;
+
+  evts = [];
+  saxReader.parseFromString("<root/>", "application/xml");
+  do_check_eq(evts.length, 2);
+  do_check_eq(evts[0], "startDocument");
+  do_check_eq(evts[1], "startElement");
+
+  evts = [];
+  saxReader.parseFromString("<?xml version='1.0'?><root/>", "application/xml");
+  do_check_eq(evts.length, 5);
+  do_check_eq(evts[0], "startDocument");
+  do_check_eq(evts[1], "1.0");
+  do_check_eq(evts[2], "");
+  do_check_false(evts[3]);
+  do_check_eq(evts[4], "startElement");
+
+  evts = [];
+  saxReader.parseFromString("<?xml version='1.0' encoding='UTF-8'?><root/>", "application/xml");
+  do_check_eq(evts.length, 5);
+  do_check_eq(evts[0], "startDocument");
+  do_check_eq(evts[1], "1.0");
+  do_check_eq(evts[2], "UTF-8");
+  do_check_false(evts[3]);
+  do_check_eq(evts[4], "startElement");
+
+  evts = [];
+  saxReader.parseFromString("<?xml version='1.0' standalone='yes'?><root/>", "application/xml");
+  do_check_eq(evts.length, 5);
+  do_check_eq(evts[0], "startDocument");
+  do_check_eq(evts[1], "1.0");
+  do_check_eq(evts[2], "");
+  do_check_true(evts[3]);
+  do_check_eq(evts[4], "startElement");
+
+  evts = [];
+  saxReader.parseFromString("<?xml version='1.0' encoding='UTF-8' standalone='yes'?><root/>", "application/xml");
+  do_check_eq(evts.length, 5);
+  do_check_eq(evts[0], "startDocument");
+  do_check_eq(evts[1], "1.0");
+  do_check_eq(evts[2], "UTF-8");
+  do_check_true(evts[3]);
+  do_check_eq(evts[4], "startElement");
+
+  evts = [];
+  // Not well-formed
+  saxReader.parseFromString("<?xml encoding='UTF-8'?><root/>", "application/xml");
+  do_check_eq(evts.length, 1);
+  do_check_eq(evts[0], "startDocument");  
+}
--- a/parser/xml/test/unit/xpcshell.ini
+++ b/parser/xml/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_parser.js]
 [test_namespace_support.js]
+[test_xml_declaration.js]