001: /*
002:
003: ============================================================================
004: The Apache Software License, Version 1.1
005: ============================================================================
006:
007: Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
008:
009: Redistribution and use in source and binary forms, with or without modifica-
010: tion, are permitted provided that the following conditions are met:
011:
012: 1. Redistributions of source code must retain the above copyright notice,
013: this list of conditions and the following disclaimer.
014:
015: 2. Redistributions in binary form must reproduce the above copyright notice,
016: this list of conditions and the following disclaimer in the documentation
017: and/or other materials provided with the distribution.
018:
019: 3. The end-user documentation included with the redistribution, if any, must
020: include the following acknowledgment: "This product includes software
021: developed by the Apache Software Foundation (http://www.apache.org/)."
022: Alternately, this acknowledgment may appear in the software itself, if
023: and wherever such third-party acknowledgments normally appear.
024:
025: 4. The names "Batik" and "Apache Software Foundation" must not be
026: used to endorse or promote products derived from this software without
027: prior written permission. For written permission, please contact
028: apache@apache.org.
029:
030: 5. Products derived from this software may not be called "Apache", nor may
031: "Apache" appear in their name, without prior written permission of the
032: Apache Software Foundation.
033:
034: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
035: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
036: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
037: APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
038: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
039: DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
040: OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
041: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
042: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
043: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: This software consists of voluntary contributions made by many individuals
046: on behalf of the Apache Software Foundation. For more information on the
047: Apache Software Foundation, please see <http://www.apache.org/>.
048:
049: */
050:
051: package org.apache.batik.util;
052:
053: import java.io.ByteArrayInputStream;
054: import java.io.IOException;
055: import java.io.InputStream;
056: import java.util.Iterator;
057:
058: /**
059: * Protocol Handler for the 'data' protocol.
060: * RFC: 2397
061: * http://www.ietf.org/rfc/rfc2397.txt
062: *
063: * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
064: * @version $Id$
065: */
066: public class ParsedURLDataProtocolHandler extends
067: AbstractParsedURLProtocolHandler {
068:
069: static final String DATA_PROTOCOL = "data";
070: static final String BASE64 = "base64";
071: static final String CHARSET = "charset";
072:
073: public ParsedURLDataProtocolHandler() {
074: super (DATA_PROTOCOL);
075: }
076:
077: public ParsedURLData parseURL(ParsedURL baseURL, String urlStr) {
078: // No relative form...
079: return parseURL(urlStr);
080: }
081:
082: public ParsedURLData parseURL(String urlStr) {
083: DataParsedURLData ret = new DataParsedURLData();
084:
085: int pidx = 0, idx;
086: idx = urlStr.indexOf(':');
087: if (idx != -1) {
088: // May have a protocol spec...
089: ret.protocol = urlStr.substring(pidx, idx);
090: if (ret.protocol.indexOf('/') == -1)
091: pidx = idx + 1;
092: else {
093: // Got a slash in protocol probably means
094: // no protocol given, (host and port?)
095: ret.protocol = null;
096: pidx = 0;
097: }
098: }
099:
100: idx = urlStr.indexOf(',', pidx);
101: if ((idx != -1) && (idx != pidx)) {
102: ret.host = urlStr.substring(pidx, idx);
103: pidx = idx + 1;
104:
105: int aidx = ret.host.lastIndexOf(';');
106: if ((aidx == -1) || (aidx == ret.host.length())) {
107: ret.contentType = ret.host;
108: } else {
109: String enc = ret.host.substring(aidx + 1);
110: idx = enc.indexOf('=');
111: if (idx == -1) {
112: // It is an encoding.
113: ret.contentEncoding = enc;
114: ret.contentType = ret.host.substring(0, aidx);
115: } else {
116: ret.contentType = ret.host;
117: }
118: // if theres a charset pull it out.
119: aidx = 0;
120: idx = ret.contentType.indexOf(';', aidx);
121: if (idx != -1) {
122: aidx = idx + 1;
123: while (aidx < ret.contentType.length()) {
124: idx = ret.contentType.indexOf(';', aidx);
125: if (idx == -1)
126: idx = ret.contentType.length();
127: String param = ret.contentType.substring(aidx,
128: idx);
129: int eqIdx = param.indexOf('=');
130: if ((eqIdx != -1)
131: && (CHARSET.equals(param.substring(0,
132: eqIdx))))
133: ret.charset = param.substring(eqIdx + 1);
134: aidx = idx + 1;
135: }
136: }
137: }
138: }
139:
140: if (pidx != urlStr.length())
141: ret.path = urlStr.substring(pidx);
142:
143: return ret;
144: }
145:
146: /**
147: * Overrides some of the methods to support data protocol weirdness
148: */
149: static class DataParsedURLData extends ParsedURLData {
150: String charset = null;
151:
152: public boolean complete() {
153: return (path != null);
154: }
155:
156: public String getPortStr() {
157: String portStr = "data:";
158: if (host != null)
159: portStr += host;
160: portStr += ",";
161: return portStr;
162: }
163:
164: public String toString() {
165: String ret = getPortStr();
166: if (path != null)
167: ret += path;
168: return ret;
169: }
170:
171: /**
172: * Returns the content type if available. This is only available
173: * for some protocols.
174: */
175: public String getContentType(String userAgent) {
176: return contentType;
177: }
178:
179: /**
180: * Returns the content encoding if available. This is only available
181: * for some protocols.
182: */
183: public String getContentEncoding(String userAgent) {
184: return contentEncoding;
185: }
186:
187: protected InputStream openStreamInternal(String userAgent,
188: Iterator mimeTypes, Iterator encodingTypes)
189: throws IOException {
190: if (BASE64.equals(contentEncoding)) {
191: byte[] data = path.getBytes();
192: stream = new ByteArrayInputStream(data);
193: stream = new Base64DecodeStream(stream);
194: } else {
195: stream = decode(path);
196: }
197: return stream;
198: }
199:
200: public static InputStream decode(String s) {
201: int len = s.length();
202: byte[] data = new byte[len];
203: int j = 0;
204: for (int i = 0; i < len; i++) {
205: char c = s.charAt(i);
206: switch (c) {
207: default:
208: data[j++] = (byte) c;
209: break;
210: case '%': {
211: if (i + 2 < len) {
212: i += 2;
213: byte b;
214: char c1 = s.charAt(i - 1);
215: if (c1 >= '0' && c1 <= '9')
216: b = (byte) (c1 - '0');
217: else if (c1 >= 'a' && c1 <= 'z')
218: b = (byte) (c1 - 'a' + 10);
219: else if (c1 >= 'A' && c1 <= 'Z')
220: b = (byte) (c1 - 'A' + 10);
221: else
222: break;
223: b *= 16;
224:
225: char c2 = s.charAt(i);
226: if (c2 >= '0' && c2 <= '9')
227: b += (byte) (c2 - '0');
228: else if (c2 >= 'a' && c2 <= 'z')
229: b += (byte) (c2 - 'a' + 10);
230: else if (c2 >= 'A' && c2 <= 'Z')
231: b += (byte) (c2 - 'A' + 10);
232: else
233: break;
234: data[j++] = b;
235: }
236: }
237: break;
238: }
239: }
240: return new ByteArrayInputStream(data, 0, j);
241: }
242: }
243: }
|