Author: maartenc Date: Tue Sep 30 15:22:12 2008 New Revision: 700610 URL: http://svn.apache.org/viewvc?rev=700610&view=rev Log: Maven accepts illegal XML for its pom's, Ivy not (IVY-921)
Added: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent Modified: ant/ivy/core/trunk/CHANGES.txt ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java ant/ivy/core/trunk/src/java/org/apache/ivy/util/XMLHelper.java Modified: ant/ivy/core/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=700610&r1=700609&r2=700610&view=diff ============================================================================== --- ant/ivy/core/trunk/CHANGES.txt (original) +++ ant/ivy/core/trunk/CHANGES.txt Tue Sep 30 15:22:12 2008 @@ -82,6 +82,7 @@ - DOCUMENTATION: Filesystem resolver: talks about "patterns" but does not mention these must become absolute file paths (IVY-910) - IMPROVEMENT: Error messages on use of relative paths can be cyrptic (IVY-909) +- IMPROVEMENT: Maven accepts illegal XML for its pom's, Ivy not (IVY-921) - FIX: Cannot configure items with java.io.File attributes (IVY-905) - FIX: Environment properties in ivy settings are no longer resolved (IVY-907) Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java?rev=700610&r1=700609&r2=700610&view=diff ============================================================================== --- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java (original) +++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java Tue Sep 30 15:22:12 2008 @@ -17,7 +17,11 @@ */ package org.apache.ivy.plugins.parser.m2; +import java.io.FilterInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -36,6 +40,8 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -80,14 +86,32 @@ private final Element parentElement; public PomReader(URL descriptorURL, Resource res) throws IOException, SAXException { - Document pomDomDoc = XMLHelper.parseToDom(descriptorURL, res); - projectElement = pomDomDoc.getDocumentElement(); - if (!PROJECT.equals(projectElement.getNodeName())) { - throw new SAXParseException("project must be the root tag" , res.getName() , - res.getName(), 0, 0); + InputStream stream = new AddDTDFilterInputStream(descriptorURL.openStream()); + try { + Document pomDomDoc = XMLHelper.parseToDom(stream, res, new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, + IOException { + if ((systemId != null) && systemId.endsWith("m2-entities.ent")) { + return new InputSource(PomReader.class.getResourceAsStream("m2-entities.ent")); + } + return null; + } + }); + projectElement = pomDomDoc.getDocumentElement(); + if (!PROJECT.equals(projectElement.getNodeName())) { + throw new SAXParseException("project must be the root tag" , res.getName() , + res.getName(), 0, 0); + } + parentElement = getFirstChildElement(projectElement , PARENT); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + // ignore + } + } } - parentElement = getFirstChildElement(projectElement , PARENT); - //TODO read the properties because it must be used to interpret every other field } @@ -471,8 +495,74 @@ return r; } + private static final class AddDTDFilterInputStream extends FilterInputStream { + private static String DOCTYPE = "<!DOCTYPE project SYSTEM \"m2-entities.ent\">\n"; + private int count; + private byte[] prefix = DOCTYPE.getBytes(); + + private AddDTDFilterInputStream(InputStream in) throws IOException { + super(in); + + if (!in.markSupported()) { + throw new IllegalArgumentException("The inputstream doesn't support mark"); + } + + in.mark(10000); + + int bytesToSkip = 0; + LineNumberReader reader = new LineNumberReader(new InputStreamReader(in, "UTF-8")); + String firstLine = reader.readLine(); + if (firstLine != null) { + String trimmed = firstLine.trim(); + if (trimmed.startsWith("<?xml ")) { + int endIndex = trimmed.indexOf("?>"); + String xmlDecl = trimmed.substring(0, endIndex + 2); + prefix = (xmlDecl + "\n" + DOCTYPE).getBytes(); + bytesToSkip = xmlDecl.getBytes().length; + } + } + + in.reset(); + for (int i = 0; i < bytesToSkip; i++) { + in.read(); + } + } + public int read() throws IOException { + if (count < prefix.length) { + return prefix[count++]; + } + + int result = super.read(); + return result; + } + + public int read(byte[] b, int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if ((off < 0) || (off > b.length) || (len < 0) || + ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + int nbrBytesCopied = 0; + + if (count < prefix.length) { + int nbrBytesFromPrefix = Math.min(prefix.length - count, len); + System.arraycopy(prefix, count, b, off, nbrBytesFromPrefix); + nbrBytesCopied = nbrBytesFromPrefix; + } + + if (nbrBytesCopied < len) { + nbrBytesCopied += in.read(b, off + nbrBytesCopied, len - nbrBytesCopied); + } + + count += nbrBytesCopied; + return nbrBytesCopied; + } + } } Added: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent?rev=700610&view=auto ============================================================================== --- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent (added) +++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent Tue Sep 30 15:22:12 2008 @@ -0,0 +1,114 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<!ENTITY nbsp " "> +<!ENTITY iexcl "¡"> +<!ENTITY cent "¢"> +<!ENTITY pound "£"> +<!ENTITY curren "¤"> +<!ENTITY yen "¥"> +<!ENTITY brvbar "¦"> +<!ENTITY sect "§"> +<!ENTITY uml "¨"> +<!ENTITY copy "©"> +<!ENTITY ordf "ª"> +<!ENTITY laquo "«"> +<!ENTITY not "¬"> +<!ENTITY shy "­"> +<!ENTITY reg "®"> +<!ENTITY macr "¯"> +<!ENTITY deg "°"> +<!ENTITY plusmn "±"> +<!ENTITY sup2 "²"> +<!ENTITY sup3 "³"> +<!ENTITY acute "´"> +<!ENTITY micro "µ"> +<!ENTITY para "¶"> +<!ENTITY middot "·"> +<!ENTITY cedil "¸"> +<!ENTITY sup1 "¹"> +<!ENTITY ordm "º"> +<!ENTITY raquo "»"> +<!ENTITY frac14 "¼"> +<!ENTITY frac12 "½"> +<!ENTITY frac34 "¾"> +<!ENTITY iquest "¿"> +<!ENTITY Agrave "À"> +<!ENTITY Aacute "Á"> +<!ENTITY Acirc "Â"> +<!ENTITY Atilde "Ã"> +<!ENTITY Auml "Ä"> +<!ENTITY Aring "Å"> +<!ENTITY AElig "Æ"> +<!ENTITY Ccedil "Ç"> +<!ENTITY Egrave "È"> +<!ENTITY Eacute "É"> +<!ENTITY Ecirc "Ê"> +<!ENTITY Euml "Ë"> +<!ENTITY Igrave "Ì"> +<!ENTITY Iacute "Í"> +<!ENTITY Icirc "Î"> +<!ENTITY Iuml "Ï"> +<!ENTITY ETH "Ð"> +<!ENTITY Ntilde "Ñ"> +<!ENTITY Ograve "Ò"> +<!ENTITY Oacute "Ó"> +<!ENTITY Ocirc "Ô"> +<!ENTITY Otilde "Õ"> +<!ENTITY Ouml "Ö"> +<!ENTITY times "×"> +<!ENTITY Oslash "Ø"> +<!ENTITY Ugrave "Ù"> +<!ENTITY Uacute "Ú"> +<!ENTITY Ucirc "Û"> +<!ENTITY Uuml "Ü"> +<!ENTITY Yacute "Ý"> +<!ENTITY THORN "Þ"> +<!ENTITY szlig "ß"> +<!ENTITY agrave "à"> +<!ENTITY aacute "á"> +<!ENTITY acirc "â"> +<!ENTITY atilde "ã"> +<!ENTITY auml "ä"> +<!ENTITY aring "å"> +<!ENTITY aelig "æ"> +<!ENTITY ccedil "ç"> +<!ENTITY egrave "è"> +<!ENTITY eacute "é"> +<!ENTITY ecirc "ê"> +<!ENTITY euml "ë"> +<!ENTITY igrave "ì"> +<!ENTITY iacute "í"> +<!ENTITY icirc "î"> +<!ENTITY iuml "ï"> +<!ENTITY eth "ð"> +<!ENTITY ntilde "ñ"> +<!ENTITY ograve "ò"> +<!ENTITY oacute "ó"> +<!ENTITY ocirc "ô"> +<!ENTITY otilde "õ"> +<!ENTITY ouml "ö"> +<!ENTITY divide "÷"> +<!ENTITY oslash "ø"> +<!ENTITY ugrave "ù"> +<!ENTITY uacute "ú"> +<!ENTITY ucirc "û"> +<!ENTITY uuml "ü"> +<!ENTITY yacute "ý"> +<!ENTITY thorn "þ"> +<!ENTITY yuml "ÿ"> Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/util/XMLHelper.java URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/XMLHelper.java?rev=700610&r1=700609&r2=700610&view=diff ============================================================================== --- ant/ivy/core/trunk/src/java/org/apache/ivy/util/XMLHelper.java (original) +++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/XMLHelper.java Tue Sep 30 15:22:12 2008 @@ -30,13 +30,15 @@ import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.url.URLHandlerRegistry; import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; -import org.xml.sax.InputSource; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; public abstract class XMLHelper { + private static final SAXParserFactory VALIDATING_FACTORY = SAXParserFactory.newInstance(); private static final SAXParserFactory FACTORY = SAXParserFactory.newInstance(); @@ -193,23 +195,30 @@ } - public static Document parseToDom(URL descriptorURL, Resource res) throws IOException, + public static Document parseToDom(InputStream stream, Resource res, EntityResolver entityResolver) throws IOException, SAXException { - DocumentBuilder docBuilder = getDocBuilder(); - InputStream pomStream = res.openStream(); + DocumentBuilder docBuilder = getDocBuilder(entityResolver); Document pomDomDoc; try { - pomDomDoc = docBuilder.parse(pomStream, res.getName()); + pomDomDoc = docBuilder.parse(stream, res.getName()); + } catch (SAXException e ) { + e.printStackTrace(); + throw e; } finally { - pomStream.close(); + stream.close(); } return pomDomDoc; } - public static DocumentBuilder getDocBuilder() { + public static DocumentBuilder getDocBuilder(EntityResolver entityResolver) { if (docBuilder == null) { try { - docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + docBuilder = factory.newDocumentBuilder(); + if (entityResolver != null) { + docBuilder.setEntityResolver(entityResolver); + } } catch (ParserConfigurationException e) { throw new RuntimeException(e); }