1   package org.daisy.pipeline.css.calabash.impl;
2   
3   import java.io.ByteArrayInputStream;
4   import java.net.URI;
5   import java.net.URISyntaxException;
6   
7   import javax.xml.transform.Source;
8   import javax.xml.transform.TransformerException;
9   import javax.xml.transform.URIResolver;
10  import javax.xml.transform.stream.StreamSource;
11  
12  import com.xmlcalabash.core.XProcConstants;
13  import com.xmlcalabash.io.ReadablePipe;
14  import com.xmlcalabash.util.Base64;
15  import com.xmlcalabash.util.S9apiUtils;
16  
17  import net.sf.saxon.s9api.QName;
18  import net.sf.saxon.s9api.SaxonApiException;
19  import net.sf.saxon.s9api.XdmNode;
20  
21  /**
22   * URI resolver that can resolve in-memory documents
23   */
24  class InMemoryURIResolver implements URIResolver {
25  
26  	private ReadablePipe documents = null;
27  
28  	InMemoryURIResolver() {}
29  
30  	void setContext(ReadablePipe documents) {
31  		this.documents = documents;
32  	}
33  
34  	private static final QName c_encoding = new QName("c", XProcConstants.NS_XPROC_STEP, "encoding");
35  	private static final QName _content_type = new QName("content-type");
36  
37  	public Source resolve(String href, String base) throws TransformerException {
38  		if (documents == null) return null;
39  		try {
40  			URI uri = (base != null) ?
41  				new URI(base).resolve(new URI(href)) :
42  				new URI(href);
43  			uri = normalizeUri(uri);
44  			documents.resetReader();
45  			while (documents.moreDocuments()) {
46  				XdmNode doc = documents.read();
47  				URI docUri = normalizeUri(doc.getBaseURI());
48  				if (docUri.equals(uri)) {
49  					XdmNode root = S9apiUtils.getDocumentElement(doc);
50  					if (XProcConstants.c_result.equals(root.getNodeName())
51  					    && root.getAttributeValue(_content_type) != null
52  					    && root.getAttributeValue(_content_type).startsWith("text/"))
53  						return new StreamSource(new ByteArrayInputStream(doc.getStringValue().getBytes()),
54  						                        uri.toASCIIString());
55  					else if ("base64".equals(root.getAttributeValue(c_encoding)))
56  						return new StreamSource(new ByteArrayInputStream(Base64.decode(doc.getStringValue())),
57  						                        uri.toASCIIString());
58  					else if (XProcConstants.c_data.equals(root.getNodeName()))
59  						return new StreamSource(new ByteArrayInputStream(doc.getStringValue().getBytes()),
60  						                        uri.toASCIIString());
61  					else
62  						return doc.asSource(); }}}
63  		catch (URISyntaxException e) {
64  			e.printStackTrace();
65  			throw new TransformerException(e); }
66  		catch (SaxonApiException e) {
67  			e.printStackTrace();
68  			throw new TransformerException(e); }
69  		return null;
70  	}
71  
72  	private static URI normalizeUri(URI uri) {
73  		String s = uri.toASCIIString();
74  
75  		// A URI that starts with "file:///" can be written as "file:/"
76  		if (s.startsWith("file:///"))
77  			s = "file:" + s.substring(7);
78  
79  		// A URI that contains "!/" is a ZIP URI
80  		if (s.startsWith("file:") && s.contains("!/"))
81  			s = "zip:" + s;
82  
83  		// The part of a ZIP URI after the "!" must start with "/"
84  		if (s.startsWith("zip:file:") && !s.contains("!/"))
85  			s = s.replaceFirst("!", "!/");
86  		try {
87  			return new URI(s); }
88  		catch (URISyntaxException e) {
89  			throw new RuntimeException(e); }
90  	}
91  }