001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.util;
020:
021: import java.io.ByteArrayInputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.util.Iterator;
025:
026: /**
027: * Protocol Handler for the 'data' protocol.
028: * RFC: 2397
029: * http://www.ietf.org/rfc/rfc2397.txt
030: *
031: * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
032: * @version $Id: ParsedURLDataProtocolHandler.java 475477 2006-11-15 22:44:28Z cam $
033: */
034: public class ParsedURLDataProtocolHandler extends
035: AbstractParsedURLProtocolHandler {
036:
037: static final String DATA_PROTOCOL = "data";
038: static final String BASE64 = "base64";
039: static final String CHARSET = "charset";
040:
041: public ParsedURLDataProtocolHandler() {
042: super (DATA_PROTOCOL);
043: }
044:
045: public ParsedURLData parseURL(ParsedURL baseURL, String urlStr) {
046: // No relative form...
047: return parseURL(urlStr);
048: }
049:
050: public ParsedURLData parseURL(String urlStr) {
051: DataParsedURLData ret = new DataParsedURLData();
052:
053: int pidx = 0, idx;
054: idx = urlStr.indexOf(':');
055: if (idx != -1) {
056: // May have a protocol spec...
057: ret.protocol = urlStr.substring(pidx, idx);
058: if (ret.protocol.indexOf('/') == -1)
059: pidx = idx + 1;
060: else {
061: // Got a slash in protocol probably means
062: // no protocol given, (host and port?)
063: ret.protocol = null;
064: pidx = 0;
065: }
066: }
067:
068: idx = urlStr.indexOf(',', pidx);
069: if ((idx != -1) && (idx != pidx)) {
070: ret.host = urlStr.substring(pidx, idx);
071: pidx = idx + 1;
072:
073: int aidx = ret.host.lastIndexOf(';');
074: if ((aidx == -1) || (aidx == ret.host.length())) {
075: ret.contentType = ret.host;
076: } else {
077: String enc = ret.host.substring(aidx + 1);
078: idx = enc.indexOf('=');
079: if (idx == -1) {
080: // It is an encoding.
081: ret.contentEncoding = enc;
082: ret.contentType = ret.host.substring(0, aidx);
083: } else {
084: ret.contentType = ret.host;
085: }
086: // if theres a charset pull it out.
087: aidx = 0;
088: idx = ret.contentType.indexOf(';', aidx);
089: if (idx != -1) {
090: aidx = idx + 1;
091: while (aidx < ret.contentType.length()) {
092: idx = ret.contentType.indexOf(';', aidx);
093: if (idx == -1)
094: idx = ret.contentType.length();
095: String param = ret.contentType.substring(aidx,
096: idx);
097: int eqIdx = param.indexOf('=');
098: if ((eqIdx != -1)
099: && (CHARSET.equals(param.substring(0,
100: eqIdx))))
101: ret.charset = param.substring(eqIdx + 1);
102: aidx = idx + 1;
103: }
104: }
105: }
106: }
107:
108: if (pidx != urlStr.length())
109: ret.path = urlStr.substring(pidx);
110:
111: return ret;
112: }
113:
114: /**
115: * Overrides some of the methods to support data protocol weirdness
116: */
117: static class DataParsedURLData extends ParsedURLData {
118: String charset = null;
119:
120: public boolean complete() {
121: return (path != null);
122: }
123:
124: public String getPortStr() {
125: String portStr = "data:";
126: if (host != null)
127: portStr += host;
128: portStr += ",";
129: return portStr;
130: }
131:
132: public String toString() {
133: String ret = getPortStr();
134: if (path != null)
135: ret += path;
136: return ret;
137: }
138:
139: /**
140: * Returns the content type if available. This is only available
141: * for some protocols.
142: */
143: public String getContentType(String userAgent) {
144: return contentType;
145: }
146:
147: /**
148: * Returns the content encoding if available. This is only available
149: * for some protocols.
150: */
151: public String getContentEncoding(String userAgent) {
152: return contentEncoding;
153: }
154:
155: protected InputStream openStreamInternal(String userAgent,
156: Iterator mimeTypes, Iterator encodingTypes)
157: throws IOException {
158: if (BASE64.equals(contentEncoding)) {
159: byte[] data = path.getBytes();
160: stream = new ByteArrayInputStream(data);
161: stream = new Base64DecodeStream(stream);
162: } else {
163: stream = decode(path);
164: }
165: return stream;
166: }
167:
168: public static InputStream decode(String s) {
169: int len = s.length();
170: byte[] data = new byte[len];
171: int j = 0;
172: for (int i = 0; i < len; i++) {
173: char c = s.charAt(i);
174: switch (c) {
175: default:
176: data[j++] = (byte) c;
177: break;
178: case '%': {
179: if (i + 2 < len) {
180: i += 2;
181: byte b;
182: char c1 = s.charAt(i - 1);
183: if (c1 >= '0' && c1 <= '9')
184: b = (byte) (c1 - '0');
185: else if (c1 >= 'a' && c1 <= 'z')
186: b = (byte) (c1 - 'a' + 10);
187: else if (c1 >= 'A' && c1 <= 'Z')
188: b = (byte) (c1 - 'A' + 10);
189: else
190: break;
191: b *= 16;
192:
193: char c2 = s.charAt(i);
194: if (c2 >= '0' && c2 <= '9')
195: b += (byte) (c2 - '0');
196: else if (c2 >= 'a' && c2 <= 'z')
197: b += (byte) (c2 - 'a' + 10);
198: else if (c2 >= 'A' && c2 <= 'Z')
199: b += (byte) (c2 - 'A' + 10);
200: else
201: break;
202: data[j++] = b;
203: }
204: }
205: break;
206: }
207: }
208: return new ByteArrayInputStream(data, 0, j);
209: }
210: }
211: }
|