You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2007/06/29 14:46:15 UTC

svn commit: r551874 - in /xmlgraphics/fop/trunk: src/java/org/apache/fop/apps/ src/java/org/apache/fop/util/ test/java/org/apache/fop/ test/java/org/apache/fop/util/

Author: jeremias
Date: Fri Jun 29 05:46:14 2007
New Revision: 551874

URL: http://svn.apache.org/viewvc?view=rev&rev=551874
Log:
Bugzilla #42278:
Refactoring of color map cache and uri/fo resolution from FopFactory
Submitted by: Adrian Cumiskey <fo...@cumiskey.com>

Changes in addition to the patch by jeremias:
- Moved the color map cache to the util package so it doesn't clutter the API (apps) package.
- Factored out the data URL resolution into its own URIResolver class which can now be used separately.
- Added a utility class for generating RFC2397 data URLs.
- Added a unit test for data URL handling.

Added:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java   (with props)
    xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java   (with props)
    xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java   (with props)
    xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java   (with props)
    xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java   (with props)
Modified:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOURIResolver.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java
    xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOURIResolver.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOURIResolver.java?view=diff&rev=551874&r1=551873&r2=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOURIResolver.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOURIResolver.java Fri Jun 29 05:46:14 2007
@@ -19,7 +19,6 @@
 
 package org.apache.fop.apps;
 
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -30,28 +29,34 @@
 
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
 import javax.xml.transform.stream.StreamSource;
 
 // commons logging
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.util.DataURIResolver;
 
-// base64 support for "data" urls
-import org.apache.xmlgraphics.util.io.Base64DecodeStream;
 import org.apache.xmlgraphics.util.io.Base64EncodeStream;
 
 /**
- * Provides FOP specific URI resolution.
- * This is the default URIResolver {@link FOUserAgent} will use unless overidden.
+ * Provides FOP specific URI resolution. This is the default URIResolver
+ * {@link FOUserAgent} will use unless overidden.
+ * 
  * @see javax.xml.transform.URIResolver
  */
-public class FOURIResolver
-    implements javax.xml.transform.URIResolver {
-    
+public class FOURIResolver implements javax.xml.transform.URIResolver {
+
     // log
     private Log log = LogFactory.getLog("FOP");
 
-    // true if exceptions are to be thrown if the URIs cannot be resolved.
+    /** URIResolver for RFC 2397 data URLs */
+    private URIResolver dataURIResolver = new DataURIResolver();
+    
+    /** A user settable URI Resolver */
+    private URIResolver uriResolver = null;
+
+    /** true if exceptions are to be thrown if the URIs cannot be resolved. */
     private boolean throwExceptions = false;
 
     /**
@@ -60,23 +65,28 @@
     public FOURIResolver() {
         this(false);
     }
-    
+
     /**
      * Additional constructor
-     * @param throwExceptions true if exceptions are to be thrown if the URIs cannot be
-     *              resolved.
+     * 
+     * @param throwExceptions
+     *            true if exceptions are to be thrown if the URIs cannot be
+     *            resolved.
      */
     public FOURIResolver(boolean throwExceptions) {
         this.throwExceptions = throwExceptions;
     }
-    
+
     /**
      * Handles resolve exceptions appropriately.
-     * @param errorStr error string
-     * @param strict strict user config
+     * 
+     * @param errorStr
+     *            error string
+     * @param strict
+     *            strict user config
      */
     private void handleException(Exception e, String errorStr, boolean strict)
-    throws TransformerException {
+            throws TransformerException {
         if (strict) {
             throw new TransformerException(errorStr, e);
         }
@@ -84,182 +94,220 @@
     }
 
     /**
-     * Called by the processor through {@link FOUserAgent} when it encounters an 
-     * uri in an external-graphic element.
-     * (see also {@link javax.xml.transform.URIResolver#resolve(String, String)}
-     * This resolver will allow URLs without a scheme, i.e. it assumes 'file:' as
-     * the default scheme. It also allows relative URLs with scheme, 
-     * e.g. file:../../abc.jpg which is not strictly RFC compliant as long as the 
-     * scheme is the same as the scheme of the base URL. If the base URL is null 
+     * Called by the processor through {@link FOUserAgent} when it encounters an
+     * uri in an external-graphic element. (see also
+     * {@link javax.xml.transform.URIResolver#resolve(String, String)} This
+     * resolver will allow URLs without a scheme, i.e. it assumes 'file:' as the
+     * default scheme. It also allows relative URLs with scheme, e.g.
+     * file:../../abc.jpg which is not strictly RFC compliant as long as the
+     * scheme is the same as the scheme of the base URL. If the base URL is null
      * a 'file:' URL referencing the current directory is used as the base URL.
-     * If the method is successful it will return a Source of type 
-     * {@link javax.xml.transform.stream.StreamSource} with its SystemID set to 
+     * If the method is successful it will return a Source of type
+     * {@link javax.xml.transform.stream.StreamSource} with its SystemID set to
      * the resolved URL used to open the underlying InputStream.
      * 
-     * @param href An href attribute, which may be relative or absolute.
-     * @param base The base URI against which the first argument will be made 
-     * absolute if the absolute URI is required. 
-     * @return A {@link javax.xml.transform.Source} object, or null if the href 
-     * cannot be resolved. 
-     * @throws javax.xml.transform.TransformerException Never thrown by this implementation.
+     * @param href
+     *            An href attribute, which may be relative or absolute.
+     * @param base
+     *            The base URI against which the first argument will be made
+     *            absolute if the absolute URI is required.
+     * @return A {@link javax.xml.transform.Source} object, or null if the href
+     *         cannot be resolved.
+     * @throws javax.xml.transform.TransformerException
+     *             Never thrown by this implementation.
      * @see javax.xml.transform.URIResolver#resolve(String, String)
      */
-    public Source resolve(String href, String base) throws TransformerException {        
-        // data URLs can be quite long so don't try to build a File (can lead to problems)
-        if (href.startsWith("data:")) {
-            return parseDataURI(href);
+    public Source resolve(String href, String base) throws TransformerException {
+        Source source = null;
+        
+        // data URLs can be quite long so evaluate early and don't try to build a File
+        // (can lead to problems)
+        source = dataURIResolver.resolve(href, base);
+        
+        // Custom uri resolution
+        if (source == null && uriResolver != null) {
+            source = uriResolver.resolve(href, base);
         }
 
-        URL absoluteURL = null;
-        File file = new File(href);
-        if (file.canRead() && file.isFile()) {
-            try {
-                absoluteURL = file.toURL();
-            } catch (MalformedURLException mfue) {
-                handleException(mfue,
-                        "Could not convert filename '" + href + "' to URL", throwExceptions);
-            }
-        } else {
-            // no base provided
-            if (base == null) {
-                // We don't have a valid file protocol based URL
+        // Fallback to default resolution mechanism
+        if (source == null) {
+            URL absoluteURL = null;
+            File file = new File(href);
+            if (file.canRead() && file.isFile()) {
                 try {
-                    absoluteURL = new URL(href);
-                } catch (MalformedURLException mue) {
+                    absoluteURL = file.toURL();
+                } catch (MalformedURLException mfue) {
+                    handleException(mfue, "Could not convert filename '" + href
+                            + "' to URL", throwExceptions);
+                }
+            } else {
+                // no base provided
+                if (base == null) {
+                    // We don't have a valid file protocol based URL
                     try {
-                        // the above failed, we give it another go in case
-                        // the href contains only a path then file: is assumed
-                        absoluteURL = new URL("file:" + href);
-                    } catch (MalformedURLException mfue) {
-                        handleException(mfue,
-                                "Error with URL '" + href + "'", throwExceptions);
+                        absoluteURL = new URL(href);
+                    } catch (MalformedURLException mue) {
+                        try {
+                            // the above failed, we give it another go in case
+                            // the href contains only a path then file: is
+                            // assumed
+                            absoluteURL = new URL("file:" + href);
+                        } catch (MalformedURLException mfue) {
+                            handleException(mfue, "Error with URL '" + href
+                                    + "'", throwExceptions);
+                        }
                     }
-                }
 
-            // try and resolve from context of base
-            } else {
-                URL baseURL = null;
-                try {
-                    baseURL = new URL(base);
-                } catch (MalformedURLException mfue) {
-                    handleException(mfue, "Error with base URL '" + base + "'", throwExceptions);
-                }
+                    // try and resolve from context of base
+                } else {
+                    URL baseURL = null;
+                    try {
+                        baseURL = new URL(base);
+                    } catch (MalformedURLException mfue) {
+                        handleException(mfue, "Error with base URL '" + base
+                                + "'", throwExceptions);
+                    }
 
-                /*
-                 * This piece of code is based on the following statement in
-                 * RFC2396 section 5.2:
-                 * 
-                 * 3) If the scheme component is defined, indicating that the
-                 * reference starts with a scheme name, then the reference is
-                 * interpreted as an absolute URI and we are done. Otherwise,
-                 * the reference URI's scheme is inherited from the base URI's
-                 * scheme component.
-                 * 
-                 * Due to a loophole in prior specifications [RFC1630], some
-                 * parsers allow the scheme name to be present in a relative URI
-                 * if it is the same as the base URI scheme. Unfortunately, this
-                 * can conflict with the correct parsing of non-hierarchical
-                 * URI. For backwards compatibility, an implementation may work
-                 * around such references by removing the scheme if it matches
-                 * that of the base URI and the scheme is known to always use
-                 * the <hier_part> syntax.
-                 * 
-                 * The URL class does not implement this work around, so we do.
-                 */
-                String scheme = baseURL.getProtocol() + ":";
-                if (href.startsWith(scheme)) {
-                    href = href.substring(scheme.length());
-                    if ("file:".equals(scheme)) {
-                        int colonPos = href.indexOf(':');
-                        int slashPos = href.indexOf('/');
-                        if (slashPos >= 0 && colonPos >= 0 && colonPos < slashPos) {
-                            href = "/" + href; // Absolute file URL doesn't
-                                                // have a leading slash
+                    /*
+                     * This piece of code is based on the following statement in
+                     * RFC2396 section 5.2:
+                     * 
+                     * 3) If the scheme component is defined, indicating that
+                     * the reference starts with a scheme name, then the
+                     * reference is interpreted as an absolute URI and we are
+                     * done. Otherwise, the reference URI's scheme is inherited
+                     * from the base URI's scheme component.
+                     * 
+                     * Due to a loophole in prior specifications [RFC1630], some
+                     * parsers allow the scheme name to be present in a relative
+                     * URI if it is the same as the base URI scheme.
+                     * Unfortunately, this can conflict with the correct parsing
+                     * of non-hierarchical URI. For backwards compatibility, an
+                     * implementation may work around such references by
+                     * removing the scheme if it matches that of the base URI
+                     * and the scheme is known to always use the <hier_part>
+                     * syntax.
+                     * 
+                     * The URL class does not implement this work around, so we
+                     * do.
+                     */
+                    String scheme = baseURL.getProtocol() + ":";
+                    if (href.startsWith(scheme)) {
+                        href = href.substring(scheme.length());
+                        if ("file:".equals(scheme)) {
+                            int colonPos = href.indexOf(':');
+                            int slashPos = href.indexOf('/');
+                            if (slashPos >= 0 && colonPos >= 0
+                                    && colonPos < slashPos) {
+                                href = "/" + href; // Absolute file URL doesn't
+                                // have a leading slash
+                            }
                         }
                     }
+                    try {
+                        absoluteURL = new URL(baseURL, href);
+                    } catch (MalformedURLException mfue) {
+                        handleException(mfue, "Error with URL; base '" + base
+                                + "' " + "href '" + href + "'", throwExceptions);
+                    }
                 }
+            }
+
+            if (absoluteURL != null) {
+                String effURL = absoluteURL.toExternalForm();
                 try {
-                    absoluteURL = new URL(baseURL, href);
-                } catch (MalformedURLException mfue) {
-                    handleException(mfue,
-                            "Error with URL; base '" + base + "' " + "href '" + href + "'",
-                            throwExceptions);                        
+                    URLConnection connection = absoluteURL.openConnection();
+                    connection.setAllowUserInteraction(false);
+                    connection.setDoInput(true);
+                    updateURLConnection(connection, href);
+                    connection.connect();
+                    return new StreamSource(connection.getInputStream(), effURL);
+                } catch (FileNotFoundException fnfe) {
+                    // Note: This is on "debug" level since the caller is
+                    // supposed to handle this
+                    log.debug("File not found: " + effURL);
+                } catch (java.io.IOException ioe) {
+                    log.error("Error with opening URL '" + effURL + "': "
+                            + ioe.getMessage());
                 }
             }
         }
-        
-        if (absoluteURL != null) {
-            String effURL = absoluteURL.toExternalForm();
-            try {
-                URLConnection connection = absoluteURL.openConnection();
-                connection.setAllowUserInteraction(false);
-                connection.setDoInput(true);
-                updateURLConnection(connection, href);
-                connection.connect();
-                return new StreamSource(connection.getInputStream(), effURL);
-            } catch (FileNotFoundException fnfe) {
-                //Note: This is on "debug" level since the caller is supposed to handle this
-                log.debug("File not found: " + effURL);
-            } catch (java.io.IOException ioe) {
-                log.error("Error with opening URL '" + effURL + "': " + ioe.getMessage());
-            }
-        }
-        return null;
+        return source;
     }
 
     /**
-     * This method allows you to set special values on a URLConnection just before the connect()
-     * method is called. Subclass FOURIResolver and override this method to do things like
-     * adding the user name and password for HTTP basic authentication.
-     * @param connection the URLConnection instance
-     * @param href the original URI
+     * This method allows you to set special values on a URLConnection just
+     * before the connect() method is called. Subclass FOURIResolver and
+     * override this method to do things like adding the user name and password
+     * for HTTP basic authentication.
+     * 
+     * @param connection
+     *            the URLConnection instance
+     * @param href
+     *            the original URI
      */
     protected void updateURLConnection(URLConnection connection, String href) {
-        //nop
+        // nop
     }
-    
+
     /**
-     * This is a convenience method for users who want to override updateURLConnection for
-     * HTTP basic authentication. Simply call it using the right username and password.
-     * @param connection the URLConnection to set up for HTTP basic authentication
-     * @param username the username
-     * @param password the password
+     * This is a convenience method for users who want to override
+     * updateURLConnection for HTTP basic authentication. Simply call it using
+     * the right username and password.
+     * 
+     * @param connection
+     *            the URLConnection to set up for HTTP basic authentication
+     * @param username
+     *            the username
+     * @param password
+     *            the password
      */
-    protected void applyHttpBasicAuthentication(URLConnection connection, 
+    protected void applyHttpBasicAuthentication(URLConnection connection,
             String username, String password) {
         String combined = username + ":" + password;
         try {
-            ByteArrayOutputStream baout = new ByteArrayOutputStream(combined.length() * 2);
+            ByteArrayOutputStream baout = new ByteArrayOutputStream(combined
+                    .length() * 2);
             Base64EncodeStream base64 = new Base64EncodeStream(baout);
-            //TODO Not sure what charset/encoding can be used with basic authentication
+            // TODO Not sure what charset/encoding can be used with basic
+            // authentication
             base64.write(combined.getBytes("UTF-8"));
             base64.close();
-            connection.setRequestProperty("Authorization", 
-                    "Basic " + new String(baout.toByteArray(), "UTF-8"));
+            connection.setRequestProperty("Authorization", "Basic "
+                    + new String(baout.toByteArray(), "UTF-8"));
         } catch (IOException e) {
-            //won't happen. We're operating in-memory.
-            throw new RuntimeException("Error during base64 encodation of username/password");
+            // won't happen. We're operating in-memory.
+            throw new RuntimeException(
+                    "Error during base64 encodation of username/password");
         }
     }
-    
+
     /**
-     * Parses inline data URIs as generated by MS Word's XML export and FO stylesheet.
-     * @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
+     * Sets the custom URI Resolver. It is used for resolving factory-level URIs like
+     * hyphenation patterns and as backup for URI resolution performed during a
+     * rendering run.
+     * 
+     * @param resolver
+     *            the new URI resolver
      */
-    private Source parseDataURI(String href) {
-        int commaPos = href.indexOf(',');
-        // header is of the form data:[<mediatype>][;base64]
-        String header = href.substring(0, commaPos);
-        String data = href.substring(commaPos + 1);
-        if (header.endsWith(";base64")) {
-            byte[] bytes = data.getBytes();
-            ByteArrayInputStream encodedStream = new ByteArrayInputStream(bytes);
-            Base64DecodeStream decodedStream = new Base64DecodeStream(encodedStream);
-            return new StreamSource(decodedStream);
-        } else {
-            //Note that this is not quite the full story here. But since we are only interested
-            //in base64-encoded binary data, the next line will probably never be called.
-            return new StreamSource(new java.io.StringReader(data));
-        }
+    public void setCustomURIResolver(URIResolver resolver) {
+        this.uriResolver = resolver;
+    }
+
+    /**
+     * Returns the custom URI Resolver.
+     * 
+     * @return the URI Resolver or null, if none is set
+     */
+    public URIResolver getCustomURIResolver() {
+        return this.uriResolver;
+    }
+
+    /**
+     * @param throwExceptions
+     *            Whether or not to throw exceptions on resolution error
+     */
+    public void setThrowExceptions(boolean throwExceptions) {
+        this.throwExceptions = throwExceptions;
     }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java?view=diff&rev=551874&r1=551873&r2=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java Fri Jun 29 05:46:14 2007
@@ -361,26 +361,27 @@
      * Attempts to resolve the given URI.
      * Will use the configured resolver and if not successful fall back
      * to the default resolver.
-     * @param uri URI to access
+     * @param href URI to access
      * @param base the base URI to resolve against
      * @return A {@link javax.xml.transform.Source} object, or null if the URI
      * cannot be resolved. 
      * @see org.apache.fop.apps.FOURIResolver
      */
-    public Source resolveURI(String uri, String base) {
+    public Source resolveURI(String href, String base) {
         Source source = null;
-        //RFC 2397 data URLs don't need to be resolved, just decode them.
-        boolean bypassURIResolution = uri.startsWith("data:");
+        //RFC 2397 data URLs don't need to be resolved, just decode them through FOP's default
+        //URIResolver.
+        boolean bypassURIResolution = href.startsWith("data:");
         if (!bypassURIResolution && uriResolver != null) {
             try {
-                source = uriResolver.resolve(uri, base);
+                source = uriResolver.resolve(href, base);
             } catch (TransformerException te) {
-                log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
+                log.error("Attempt to resolve URI '" + href + "' failed: ", te);
             }
         }
         if (source == null) {
             // URI Resolver not configured or returned null, use default resolver from the factory
-            source = getFactory().resolveURI(uri, base);
+            source = getFactory().resolveURI(href, base);
         }
         return source;
     }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java?view=diff&rev=551874&r1=551873&r2=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java Fri Jun 29 05:46:14 2007
@@ -15,13 +15,11 @@
  * limitations under the License.
  */
 
-/* $Id$ */
+/* $Id: $ */
 
 package org.apache.fop.apps;
 
 import java.awt.color.ColorSpace;
-import java.awt.color.ICC_ColorSpace;
-import java.awt.color.ICC_Profile;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -29,13 +27,11 @@
 import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Map;
 import java.util.Set;
 
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.URIResolver;
-import javax.xml.transform.stream.StreamSource;
 
 import org.xml.sax.SAXException;
 
@@ -52,6 +48,7 @@
 import org.apache.fop.layoutmgr.LayoutManagerMaker;
 import org.apache.fop.render.RendererFactory;
 import org.apache.fop.render.XMLHandlerRegistry;
+import org.apache.fop.util.ColorSpaceCache;
 import org.apache.fop.util.ContentHandlerFactoryRegistry;
 
 /**
@@ -66,10 +63,10 @@
     private static Log log = LogFactory.getLog(FopFactory.class);
     
     /** Factory for Renderers and FOEventHandlers */
-    private RendererFactory rendererFactory = new RendererFactory();
+    private RendererFactory rendererFactory;
     
     /** Registry for XML handlers */
-    private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry();
+    private XMLHandlerRegistry xmlHandlers;
     
     /** The registry for ElementMapping instances */
     private ElementMappingRegistry elementMappingRegistry;
@@ -78,17 +75,13 @@
     private ContentHandlerFactoryRegistry contentHandlerFactoryRegistry 
                 = new ContentHandlerFactoryRegistry();
     
-    /** Our default resolver if none is set */
-    private URIResolver foURIResolver = null;
-    
-    /** A user settable URI Resolver */
-    private URIResolver uriResolver = null;
-
     /** The resolver for user-supplied hyphenation patterns */
-    private HyphenationTreeResolver hyphResolver;
+    private HyphenationTreeResolver hyphResolver = null;
+
+    private ColorSpaceCache colorSpaceCache = null;
     
     /** Image factory for creating fop image objects */
-    private ImageFactory imageFactory = new ImageFactory();
+    private ImageFactory imageFactory;
 
     /** Configuration layer used to configure fop */
     private FopFactoryConfigurator config = null;
@@ -145,11 +138,10 @@
     /** Optional overriding LayoutManagerMaker */
     private LayoutManagerMaker lmMakerOverride = null;
 
-    private Set ignoredNamespaces = new java.util.HashSet();
+    private Set ignoredNamespaces;
+
+    private FOURIResolver foURIResolver;
     
-    /** Map with cached ICC based ColorSpace objects. */
-    private Map colorSpaceMap = null;
-        
     /**
      * Main constructor.
      */
@@ -157,8 +149,11 @@
         this.config = new FopFactoryConfigurator(this);
         this.elementMappingRegistry = new ElementMappingRegistry(this);
         this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
-        // Use a synchronized Map - I am not really sure this is needed, but better safe than sorry.
-        this.colorSpaceMap = Collections.synchronizedMap(new java.util.HashMap());
+        this.colorSpaceCache = new ColorSpaceCache(foURIResolver);
+        this.imageFactory = new ImageFactory();        
+        this.rendererFactory = new RendererFactory();
+        this.xmlHandlers = new XMLHandlerRegistry();
+        this.ignoredNamespaces = new java.util.HashSet();
         setUseCache(FopFactoryConfigurator.DEFAULT_USE_CACHE);
     }
     
@@ -397,11 +392,12 @@
      * */
     public void setHyphenBaseURL(final String hyphenBase) throws MalformedURLException {
         if (hyphenBase != null) {
-            this.hyphResolver = new HyphenationTreeResolver() {
+            setHyphenationTreeResolver(
+            new HyphenationTreeResolver() {
                 public Source resolve(String href) {
                     return resolveURI(href, hyphenBase);
                 }
-            };
+            });
         }
         this.hyphenBase = checkBaseURL(hyphenBase);
     }
@@ -411,8 +407,8 @@
      * patterns and as backup for URI resolution performed during a rendering run. 
      * @param resolver the new URI resolver
      */
-    public void setURIResolver(URIResolver resolver) {
-        this.uriResolver = resolver;
+    public void setURIResolver(URIResolver uriResolver) {
+        foURIResolver.setCustomURIResolver(uriResolver);
     }
 
     /**
@@ -420,7 +416,7 @@
      * @return the URI Resolver
      */
     public URIResolver getURIResolver() {
-        return this.uriResolver;
+        return foURIResolver;
     }
 
     /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */
@@ -429,6 +425,14 @@
     }
     
     /**
+     * sets the HyphenationTreeResolver
+     * @param hyphResolver
+     */
+    public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) {
+        this.hyphResolver = hyphResolver;
+    }
+
+    /**
      * Activates strict XSL content model validation for FOP
      * Default is false (FOP will continue processing where it can)
      * @param validateStrictly true to turn on strict validation
@@ -669,6 +673,7 @@
      */
     public void setStrictUserConfigValidation(boolean strictUserConfigValidation) {
         this.strictUserConfigValidation = strictUserConfigValidation;
+        this.foURIResolver.setThrowExceptions(strictUserConfigValidation);
     }
 
     /**
@@ -708,39 +713,22 @@
         return this.fontCache;
     }
     
-    //------------------------------------------- URI resolution
-
     /**
      * Attempts to resolve the given URI.
      * Will use the configured resolver and if not successful fall back
      * to the default resolver.
-     * @param uri URI to access
+     * @param href URI to access
      * @param baseUri the base URI to resolve against
      * @return A {@link javax.xml.transform.Source} object, or null if the URI
      * cannot be resolved. 
      * @see org.apache.fop.apps.FOURIResolver
      */
-    public Source resolveURI(String uri, String baseUri) {
+    public Source resolveURI(String href, String baseUri) {
         Source source = null;
-        //RFC 2397 data URLs don't need to be resolved, just decode them.
-        boolean bypassURIResolution = uri.startsWith("data:");
-        if (!bypassURIResolution && uriResolver != null) {
-            try {
-                source = uriResolver.resolve(uri, baseUri);
-            } catch (TransformerException te) {
-                log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
-                if (validateUserConfigStrictly()) {
-                    return null;
-                }
-            }
-        }
-        if (source == null) {
-            // URI Resolver not configured or returned null, use default resolver
-            try {
-                source = foURIResolver.resolve(uri, baseUri);
-            } catch (TransformerException te) {
-                log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
-            }
+        try {
+            source = foURIResolver.resolve(href, baseUri);
+        } catch (TransformerException e) {
+            log.error("Attempt to resolve URI '" + href + "' failed: ", e);
         }
         return source;
     }
@@ -759,47 +747,6 @@
      * @return ICC ColorSpace object or null if ColorSpace could not be created 
      */
     public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) {
-        ColorSpace colorSpace = null;
-        if (!this.colorSpaceMap.containsKey(baseUri + iccProfileSrc)) {
-            try {
-                ICC_Profile iccProfile = null;
-                // First attempt to use the FOP URI resolver to locate the ICC
-                // profile
-                Source src = this.resolveURI(iccProfileSrc, baseUri);
-                if (src != null && src instanceof StreamSource) {
-                    // FOP URI resolver found ICC profile - create ICC profile
-                    // from the Source
-                    iccProfile = ICC_Profile.getInstance(((StreamSource) src)
-                            .getInputStream());
-                } else {
-                    // TODO - Would it make sense to fall back on VM ICC
-                    // resolution
-                    // Problem is the cache might be more difficult to maintain
-                    // 
-                    // FOP URI resolver did not find ICC profile - perhaps the
-                    // Java VM can find it?
-                    // iccProfile = ICC_Profile.getInstance(iccProfileSrc);
-                }
-                if (iccProfile != null) {
-                    colorSpace = new ICC_ColorSpace(iccProfile);
-                }
-            } catch (IOException e) {
-                // Ignore exception - will be logged a bit further down
-                // (colorSpace == null case)
-            }
-
-            if (colorSpace != null) {
-                // Put in cache (not when VM resolved it as we can't control
-                this.colorSpaceMap.put(baseUri + iccProfileSrc, colorSpace);
-            } else {
-                // TODO To avoid an excessive amount of warnings perhaps
-                // register a null ColorMap in the colorSpaceMap
-                log.warn("Color profile '" + iccProfileSrc + "' not found.");
-            }
-        } else {
-            colorSpace = (ColorSpace) this.colorSpaceMap.get(baseUri
-                    + iccProfileSrc);
-        }
-        return colorSpace;
+        return colorSpaceCache.get(baseUri, iccProfileSrc);
     }    
 }

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java?view=auto&rev=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java Fri Jun 29 05:46:14 2007
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Map with cached ICC based ColorSpace objects.
+ */
+public class ColorSpaceCache {
+    /** logger instance */
+    private static Log log = LogFactory.getLog(ColorSpaceCache.class);
+
+    private URIResolver resolver;
+    private Map colorSpaceMap = Collections.synchronizedMap(new java.util.HashMap());
+
+    /**
+     * Default constructor
+     * @param resolver uri resolver
+     */
+    public ColorSpaceCache(URIResolver resolver) {
+        this.resolver = resolver;
+    }
+    
+    /**
+     * Create (if needed) and return an ICC ColorSpace instance.
+     * 
+     * The ICC profile source is taken from the src attribute of the color-profile FO element.
+     * If the ICC ColorSpace is not yet in the cache a new one is created and stored in the cache.
+     * 
+     * The FOP URI resolver is used to try and locate the ICC file. 
+     * If that fails null is returned.
+     * 
+     * @param base a base URI to resolve relative URIs
+     * @param iccProfileSrc ICC Profile source to return a ColorSpace for
+     * @return ICC ColorSpace object or null if ColorSpace could not be created 
+     */
+    public ColorSpace get(String base, String iccProfileSrc) {
+        ColorSpace colorSpace = null;
+        if (!colorSpaceMap.containsKey(base + iccProfileSrc)) {
+            try {
+                ICC_Profile iccProfile = null;
+                // First attempt to use the FOP URI resolver to locate the ICC
+                // profile
+                Source src = resolver.resolve(iccProfileSrc, base);
+                if (src != null && src instanceof StreamSource) {
+                    // FOP URI resolver found ICC profile - create ICC profile
+                    // from the Source
+                    iccProfile = ICC_Profile.getInstance(((StreamSource) src)
+                            .getInputStream());
+                } else {
+                    // TODO - Would it make sense to fall back on VM ICC
+                    // resolution
+                    // Problem is the cache might be more difficult to maintain
+                    // 
+                    // FOP URI resolver did not find ICC profile - perhaps the
+                    // Java VM can find it?
+                    // iccProfile = ICC_Profile.getInstance(iccProfileSrc);
+                }
+                if (iccProfile != null) {
+                    colorSpace = new ICC_ColorSpace(iccProfile);
+                }
+            } catch (Exception e) {
+                // Ignore exception - will be logged a bit further down
+                // (colorSpace == null case)
+            }
+
+            if (colorSpace != null) {
+                // Put in cache (not when VM resolved it as we can't control
+                colorSpaceMap.put(base + iccProfileSrc, colorSpace);
+            } else {
+                // TODO To avoid an excessive amount of warnings perhaps
+                // register a null ColorMap in the colorSpaceMap
+                log.warn("Color profile '" + iccProfileSrc + "' not found.");
+            }
+        } else {
+            colorSpace = (ColorSpace)colorSpaceMap.get(base
+                    + iccProfileSrc);
+        }
+        return colorSpace;
+    }        
+}

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java?view=auto&rev=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java Fri Jun 29 05:46:14 2007
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.ByteArrayInputStream;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+// base64 support for "data" urls
+import org.apache.xmlgraphics.util.io.Base64DecodeStream;
+
+/**
+ * Resolves data URLs (described in RFC 2397) returning its data as a StreamSource.
+ * 
+ * @see javax.xml.transform.URIResolver
+ * @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
+ */
+public class DataURIResolver implements URIResolver {
+
+    /**
+     * @see javax.xml.transform.URIResolver#resolve(java.lang.String, java.lang.String)
+     */
+    public Source resolve(String href, String base) throws TransformerException {
+        if (href.startsWith("data:")) {
+            return parseDataURI(href);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Parses inline data URIs as generated by MS Word's XML export and FO
+     * stylesheet.
+     * 
+     * @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
+     */
+    private Source parseDataURI(String href) {
+        int commaPos = href.indexOf(',');
+        // header is of the form data:[<mediatype>][;base64]
+        String header = href.substring(0, commaPos);
+        String data = href.substring(commaPos + 1);
+        if (header.endsWith(";base64")) {
+            byte[] bytes = data.getBytes();
+            ByteArrayInputStream encodedStream = new ByteArrayInputStream(bytes);
+            Base64DecodeStream decodedStream = new Base64DecodeStream(
+                    encodedStream);
+            return new StreamSource(decodedStream);
+        } else {
+            // Note that this is not quite the full story here. But since we are
+            // only interested
+            // in base64-encoded binary data, the next line will probably never
+            // be called.
+            //TODO Handle un-escaping of special URL chars like %20
+            return new StreamSource(new java.io.StringReader(data));
+        }
+    }
+
+}

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURIResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java?view=auto&rev=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java Fri Jun 29 05:46:14 2007
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.xmlgraphics.util.io.Base64EncodeStream;
+
+/**
+ * Utility classes for generating RFC 2397 data URLs.
+ */
+public class DataURLUtil {
+
+    /**
+     * Creates a new data URL and returns it as a String.
+     * @param in the InputStream to read the data from
+     * @param mediatype the MIME type of the content, or null
+     * @return the newly created data URL
+     * @throws IOException if an I/O error occurs
+     */
+    public static String createDataURL(InputStream in, String mediatype) throws IOException {
+        StringWriter writer = new StringWriter();
+        writeDataURL(in, mediatype, writer);
+        return writer.toString();
+    }
+    
+    /**
+     * Generates a data URL and writes it to a Writer.
+     * @param in the InputStream to read the data from
+     * @param mediatype the MIME type of the content, or null
+     * @param writer the Writer to write to
+     * @throws IOException if an I/O error occurs
+     */
+    public static void writeDataURL(InputStream in, String mediatype, Writer writer)
+            throws IOException {
+        writer.write("data:");
+        if (mediatype != null) {
+            writer.write(mediatype);
+        }
+        writer.write(";base64,");
+        Base64EncodeStream out = new Base64EncodeStream(
+                new WriterOutputStream(writer, "US-ASCII"));
+        IOUtils.copy(in, out);
+        out.flush();
+    }
+}

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DataURLUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java?view=auto&rev=551874
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java Fri Jun 29 05:46:14 2007
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * An OutputStream wrapper for a Writer. 
+ */
+public class WriterOutputStream extends OutputStream {
+
+    private Writer writer;
+    private String encoding;
+
+    /**
+     * Creates a new WriterOutputStream.
+     * @param writer the Writer to write to
+     */
+    public WriterOutputStream(Writer writer) {
+        this(writer, null);
+    }
+
+    /**
+     * Creates a new WriterOutputStream.
+     * @param writer the Writer to write to
+     * @param encoding the encoding to use, or null if the default encoding should be used
+     */
+    public WriterOutputStream(Writer writer, String encoding) {
+        this.writer = writer;
+        this.encoding = encoding;
+    }
+
+    /**
+     * @see java.io.OutputStream#close()
+     */
+    public void close() throws IOException {
+        writer.close();
+    }
+
+    /**
+     * @see java.io.OutputStream#flush()
+     */
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    /**
+     * @see java.io.OutputStream#write(byte[], int, int)
+     */
+    public void write(byte[] buf, int offset, int length) throws IOException {
+        if (encoding != null) {
+            writer.write(new String(buf, offset, length, encoding));
+        } else {
+            writer.write(new String(buf, offset, length));
+        }
+    }
+
+    /**
+     * @see java.io.OutputStream#write(byte[])
+     */
+    public void write(byte[] buf) throws IOException {
+        write(buf, 0, buf.length);
+    }
+
+    /**
+     * @see java.io.OutputStream#write(int)
+     */
+    public void write(int b) throws IOException {
+        write(new byte[] {(byte)b});
+    }
+
+}

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/WriterOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java?view=diff&rev=551874&r1=551873&r2=551874
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java Fri Jun 29 05:46:14 2007
@@ -21,6 +21,8 @@
 
 import org.apache.fop.traits.BorderPropsTestCase;
 import org.apache.fop.traits.TraitColorTestCase;
+import org.apache.fop.util.DataURIResolverTestCase;
+import org.apache.fop.util.ElementListUtilsTestCase;
 import org.apache.fop.util.PDFNumberTestCase;
 import org.apache.fop.util.UnitConvTestCase;
 
@@ -44,6 +46,8 @@
         suite.addTest(new TestSuite(UnitConvTestCase.class));
         suite.addTest(new TestSuite(TraitColorTestCase.class));
         suite.addTest(new TestSuite(BorderPropsTestCase.class));
+        suite.addTest(new TestSuite(ElementListUtilsTestCase.class));
+        suite.addTest(new TestSuite(DataURIResolverTestCase.class));
         //$JUnit-END$
         return suite;
     }

Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java?view=auto&rev=551874
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java (added)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java Fri Jun 29 05:46:14 2007
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.ByteArrayInputStream;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.io.IOUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for the RFC 2397 data URL/URI resolver.
+ */
+public class DataURIResolverTestCase extends TestCase {
+
+    private static final byte[] TESTDATA = new byte[] {0, 1, 2, 3, 4, 5};
+    
+    /**
+     * Tests DataURLUtil.
+     * @throws Exception if an error occurs
+     */
+    public void testRFC2397Generator() throws Exception {
+        String url = DataURLUtil.createDataURL(new ByteArrayInputStream(TESTDATA), null);
+        assertEquals("Generated data URL is wrong", "data:;base64,AAECAwQF", url);
+
+        url = DataURLUtil.createDataURL(new ByteArrayInputStream(TESTDATA), "application/pdf");
+        assertEquals("Generated data URL is wrong", "data:application/pdf;base64,AAECAwQF", url);
+    }
+
+    /**
+     * Test the URIResolver contract if the protocol doesn't match. Resolver must return null
+     * in this case.
+     * @throws Exception if an error occurs
+     */
+    public void testNonMatchingContract() throws Exception {
+        URIResolver resolver = new DataURIResolver();
+        Source src;
+        
+        src = resolver.resolve("http://xmlgraphics.apache.org/fop/index.html", null);
+        assertNull(src);
+
+        src = resolver.resolve("index.html", "http://xmlgraphics.apache.org/fop/");
+        assertNull(src);
+    }
+    
+    private static boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) {
+        for (int i = 0, c = cmp.length; i < c; i++) {
+            if (src[srcOffset + i] != cmp[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Test the DataURIResolver with correct values.
+     * @throws Exception if an error occurs
+     */
+    public void testDataURLHandling() throws Exception {
+        URIResolver resolver = new DataURIResolver();
+        Source src;
+        
+        src = resolver.resolve("data:;base64,AAECAwQF", null);
+        assertNotNull(src);
+        StreamSource streamSource = (StreamSource)src;
+        byte[] data = IOUtils.toByteArray(streamSource.getInputStream());
+        assertTrue("Decoded data doesn't match the test data", byteCmp(TESTDATA, 0, data));
+
+        src = resolver.resolve(
+                "data:application/octet-stream;interpreter=fop;base64,AAECAwQF", null);
+        assertNotNull(src);
+        streamSource = (StreamSource)src;
+        assertNotNull(streamSource.getInputStream());
+        assertNull(streamSource.getReader());
+        data = IOUtils.toByteArray(streamSource.getInputStream());
+        assertTrue("Decoded data doesn't match the test data", byteCmp(TESTDATA, 0, data));
+
+        src = resolver.resolve("data:,FOP", null);
+        assertNotNull(src);
+        streamSource = (StreamSource)src;
+        assertNull(streamSource.getInputStream());
+        assertNotNull(streamSource.getReader());
+        String text = IOUtils.toString(streamSource.getReader());
+        assertEquals("FOP", text);
+
+        /* TODO Un-escaping of special URL chars like %20 hasn't been implemented, yet.
+        src = resolver.resolve("data:,A%20brief%20note", null);
+        assertNotNull(src);
+        streamSource = (StreamSource)src;
+        text = IOUtils.toString(streamSource.getReader());
+        assertEquals("A brief note", text);
+        */
+    }
+    
+}

Propchange: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/DataURIResolverTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org