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   "&#160;">
+<!ENTITY iexcl  "&#161;">
+<!ENTITY cent   "&#162;">
+<!ENTITY pound  "&#163;">
+<!ENTITY curren "&#164;">
+<!ENTITY yen    "&#165;">
+<!ENTITY brvbar "&#166;">
+<!ENTITY sect   "&#167;">
+<!ENTITY uml    "&#168;">
+<!ENTITY copy   "&#169;">
+<!ENTITY ordf   "&#170;">
+<!ENTITY laquo  "&#171;">
+<!ENTITY not    "&#172;">
+<!ENTITY shy    "&#173;">
+<!ENTITY reg    "&#174;">
+<!ENTITY macr   "&#175;">
+<!ENTITY deg    "&#176;">
+<!ENTITY plusmn "&#177;">
+<!ENTITY sup2   "&#178;">
+<!ENTITY sup3   "&#179;">
+<!ENTITY acute  "&#180;">
+<!ENTITY micro  "&#181;">
+<!ENTITY para   "&#182;">
+<!ENTITY middot "&#183;">
+<!ENTITY cedil  "&#184;">
+<!ENTITY sup1   "&#185;">
+<!ENTITY ordm   "&#186;">
+<!ENTITY raquo  "&#187;">
+<!ENTITY frac14 "&#188;">
+<!ENTITY frac12 "&#189;">
+<!ENTITY frac34 "&#190;">
+<!ENTITY iquest "&#191;">
+<!ENTITY Agrave "&#192;">
+<!ENTITY Aacute "&#193;">
+<!ENTITY Acirc  "&#194;">
+<!ENTITY Atilde "&#195;">
+<!ENTITY Auml   "&#196;">
+<!ENTITY Aring  "&#197;">
+<!ENTITY AElig  "&#198;">
+<!ENTITY Ccedil "&#199;">
+<!ENTITY Egrave "&#200;">
+<!ENTITY Eacute "&#201;">
+<!ENTITY Ecirc  "&#202;">
+<!ENTITY Euml   "&#203;">
+<!ENTITY Igrave "&#204;">
+<!ENTITY Iacute "&#205;">
+<!ENTITY Icirc  "&#206;">
+<!ENTITY Iuml   "&#207;">
+<!ENTITY ETH    "&#208;">
+<!ENTITY Ntilde "&#209;">
+<!ENTITY Ograve "&#210;">
+<!ENTITY Oacute "&#211;">
+<!ENTITY Ocirc  "&#212;">
+<!ENTITY Otilde "&#213;">
+<!ENTITY Ouml   "&#214;">
+<!ENTITY times  "&#215;">
+<!ENTITY Oslash "&#216;">
+<!ENTITY Ugrave "&#217;">
+<!ENTITY Uacute "&#218;">
+<!ENTITY Ucirc  "&#219;">
+<!ENTITY Uuml   "&#220;">
+<!ENTITY Yacute "&#221;">
+<!ENTITY THORN  "&#222;">
+<!ENTITY szlig  "&#223;">
+<!ENTITY agrave "&#224;">
+<!ENTITY aacute "&#225;">
+<!ENTITY acirc  "&#226;">
+<!ENTITY atilde "&#227;">
+<!ENTITY auml   "&#228;">
+<!ENTITY aring  "&#229;">
+<!ENTITY aelig  "&#230;">
+<!ENTITY ccedil "&#231;">
+<!ENTITY egrave "&#232;">
+<!ENTITY eacute "&#233;">
+<!ENTITY ecirc  "&#234;">
+<!ENTITY euml   "&#235;">
+<!ENTITY igrave "&#236;">
+<!ENTITY iacute "&#237;">
+<!ENTITY icirc  "&#238;">
+<!ENTITY iuml   "&#239;">
+<!ENTITY eth    "&#240;">
+<!ENTITY ntilde "&#241;">
+<!ENTITY ograve "&#242;">
+<!ENTITY oacute "&#243;">
+<!ENTITY ocirc  "&#244;">
+<!ENTITY otilde "&#245;">
+<!ENTITY ouml   "&#246;">
+<!ENTITY divide "&#247;">
+<!ENTITY oslash "&#248;">
+<!ENTITY ugrave "&#249;">
+<!ENTITY uacute "&#250;">
+<!ENTITY ucirc  "&#251;">
+<!ENTITY uuml   "&#252;">
+<!ENTITY yacute "&#253;">
+<!ENTITY thorn  "&#254;">
+<!ENTITY yuml   "&#255;">

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);
             }        


Reply via email to