michael@0: function updateDocumentSourceMaps(source) { michael@0: const nsIDOMNode = Components.interfaces.nsIDOMNode; michael@0: michael@0: const nsISAXXMLReader = Components.interfaces.nsISAXXMLReader; michael@0: const saxReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"] michael@0: .createInstance(nsISAXXMLReader); michael@0: try { michael@0: saxReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); michael@0: saxReader.setFeature("http://xml.org/sax/features/namespace", true); michael@0: } michael@0: catch (e) { michael@0: // do nothing, we'll accept it as it is. michael@0: } michael@0: var parseErrorLog = []; michael@0: michael@0: /* XXX ajvincent Because throwing an exception doesn't stop parsing, we need michael@0: * to record errors and handle them after the parsing is finished. michael@0: */ michael@0: function do_parse_check(aCondition, aMsg) { michael@0: if (!aCondition) michael@0: parseErrorLog[parseErrorLog.length] = aMsg; michael@0: } michael@0: michael@0: var contentHandler = { michael@0: startDocument: function startDocument() { michael@0: }, michael@0: michael@0: endDocument: function endDocument() { michael@0: }, michael@0: michael@0: handleAttributes: function handleAttributes(aAttributes) { michael@0: for (var i = 0; i < aAttributes.length; i++) { michael@0: var attrNamespaceURI = aAttributes.getURI(i); michael@0: var attrLocalName = aAttributes.getLocalName(i); michael@0: var attrNodeName = aAttributes.getQName(i); michael@0: var value = aAttributes.getValue(i); michael@0: do_parse_check(attrLocalName, "Missing attribute local name"); michael@0: do_parse_check(attrNodeName, "Missing attribute node name"); michael@0: } michael@0: }, michael@0: michael@0: startElement: function startElement(aNamespaceURI, aLocalName, aNodeName, aAttributes) { michael@0: do_parse_check(aLocalName, "Missing element local name (startElement)"); michael@0: do_parse_check(aNodeName, "Missing element node name (startElement)"); michael@0: do_parse_check(aAttributes, "Missing element attributes"); michael@0: this.handleAttributes(aAttributes); michael@0: }, michael@0: michael@0: endElement: function endElement(aNamespaceURI, aLocalName, aNodeName) { michael@0: do_parse_check(aLocalName, "Missing element local name (endElement)"); michael@0: do_parse_check(aNodeName, "Missing element node name (endElement)"); michael@0: }, michael@0: michael@0: inCDataSection: false, michael@0: michael@0: characters: function characters(aData) { michael@0: }, michael@0: michael@0: processingInstruction: function processingInstruction(aTarget, aData) { michael@0: do_parse_check(aTarget, "Missing processing instruction target"); michael@0: }, michael@0: michael@0: ignorableWhitespace: function ignorableWhitespace(aWhitespace) { michael@0: }, michael@0: michael@0: startPrefixMapping: function startPrefixMapping(aPrefix, aURI) { michael@0: }, michael@0: michael@0: endPrefixMapping: function endPrefixMapping(aPrefix) { michael@0: } michael@0: }; michael@0: michael@0: var lexicalHandler = { michael@0: comment: function comment(aContents) { michael@0: }, michael@0: michael@0: startDTD: function startDTD(aName, aPublicId, aSystemId) { michael@0: do_parse_check(aName, "Missing DTD name"); michael@0: }, michael@0: michael@0: endDTD: function endDTD() { michael@0: }, michael@0: michael@0: startCDATA: function startCDATA() { michael@0: }, michael@0: michael@0: endCDATA: function endCDATA() { michael@0: }, michael@0: michael@0: startEntity: function startEntity(aName) { michael@0: do_parse_check(aName, "Missing entity name (startEntity)"); michael@0: }, michael@0: michael@0: endEntity: function endEntity(aName) { michael@0: do_parse_check(aName, "Missing entity name (endEntity)"); michael@0: } michael@0: }; michael@0: michael@0: var dtdHandler = { michael@0: notationDecl: function notationDecl(aName, aPublicId, aSystemId) { michael@0: do_parse_check(aName, "Missing notation name"); michael@0: }, michael@0: michael@0: unparsedEntityDecl: michael@0: function unparsedEntityDecl(aName, aPublicId, aSystemId, aNotationName) { michael@0: do_parse_check(aName, "Missing entity name (unparsedEntityDecl)"); michael@0: } michael@0: }; michael@0: michael@0: var errorHandler = { michael@0: error: function error(aLocator, aError) { michael@0: do_parse_check(!aError, "XML error"); michael@0: }, michael@0: michael@0: fatalError: function fatalError(aLocator, aError) { michael@0: do_parse_check(!aError, "XML fatal error"); michael@0: }, michael@0: michael@0: ignorableWarning: function ignorableWarning(aLocator, aError) { michael@0: do_parse_check(!aError, "XML ignorable warning"); michael@0: } michael@0: }; michael@0: michael@0: saxReader.contentHandler = contentHandler; michael@0: saxReader.lexicalHandler = lexicalHandler; michael@0: saxReader.dtdHandler = dtdHandler; michael@0: saxReader.errorHandler = errorHandler; michael@0: michael@0: saxReader.parseFromString(source, "application/xml"); michael@0: michael@0: // Just in case it leaks. michael@0: saxReader.contentHandler = null; michael@0: saxReader.lexicalHandler = null; michael@0: saxReader.dtdHandler = null; michael@0: saxReader.errorHandler = null; michael@0: michael@0: return parseErrorLog; michael@0: } michael@0: michael@0: function do_check_true_with_dump(aCondition, aParseLog) { michael@0: if (!aCondition) { michael@0: dump(aParseLog.join("\n")); michael@0: } michael@0: do_check_true(aCondition); michael@0: } michael@0: michael@0: function run_test() { michael@0: var src; michael@0: src = "\n"; michael@0: src += "\n\nfoo"; michael@0: src += "\n"; michael@0: var parseErrorLog = updateDocumentSourceMaps(src); michael@0: michael@0: if (parseErrorLog.length > 0) { michael@0: dump(parseErrorLog.join("\n")); michael@0: } michael@0: do_check_true_with_dump(parseErrorLog.length == 0, parseErrorLog); michael@0: michael@0: // End tag isn't well-formed. michael@0: src = "\n"; michael@0: src += "\n\nfoo"; michael@0: src += "