001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.awt.datatransfer;
019:
020: import java.io.Serializable;
021: import java.util.Enumeration;
022: import java.util.Hashtable;
023:
024: final class MimeTypeProcessor {
025:
026: private static MimeTypeProcessor instance;
027:
028: private MimeTypeProcessor() {
029: super ();
030: }
031:
032: static MimeType parse(String str) {
033: MimeType res;
034:
035: if (instance == null) {
036: instance = new MimeTypeProcessor();
037: }
038:
039: res = new MimeType();
040: if (str != null) {
041: StringPosition pos = new StringPosition();
042:
043: retrieveType(str, res, pos);
044: retrieveParams(str, res, pos);
045: }
046:
047: return res;
048: }
049:
050: static String assemble(MimeType type) {
051: StringBuilder buf = new StringBuilder();
052:
053: buf.append(type.getFullType());
054: for (Enumeration<String> keys = type.parameters.keys(); keys
055: .hasMoreElements();) {
056: String name = keys.nextElement();
057: String value = type.parameters.get(name);
058:
059: buf.append("; "); //$NON-NLS-1$
060: buf.append(name);
061: buf.append("=\""); //$NON-NLS-1$
062: buf.append(value);
063: buf.append('"');
064: }
065:
066: return buf.toString();
067: }
068:
069: private static void retrieveType(String str, MimeType res,
070: StringPosition pos) {
071: res.primaryType = retrieveToken(str, pos).toLowerCase();
072: pos.i = getNextMeaningfulIndex(str, pos.i);
073: if ((pos.i >= str.length()) || (str.charAt(pos.i) != '/')) {
074: throw new IllegalArgumentException();
075: }
076: pos.i++;
077: res.subType = retrieveToken(str, pos).toLowerCase();
078: }
079:
080: private static void retrieveParams(String str, MimeType res,
081: StringPosition pos) {
082: res.parameters = new Hashtable<String, String>();
083: res.systemParameters = new Hashtable<String, Object>();
084: do {
085: pos.i = getNextMeaningfulIndex(str, pos.i);
086: if (pos.i >= str.length()) {
087: return;
088: }
089: if (str.charAt(pos.i) != ';') {
090: throw new IllegalArgumentException();
091: }
092: pos.i++;
093: retrieveParam(str, res, pos);
094: } while (true);
095: }
096:
097: private static void retrieveParam(String str, MimeType res,
098: StringPosition pos) {
099: String name = retrieveToken(str, pos).toLowerCase();
100:
101: pos.i = getNextMeaningfulIndex(str, pos.i);
102: if ((pos.i >= str.length()) || (str.charAt(pos.i) != '=')) {
103: throw new IllegalArgumentException();
104: }
105: pos.i++;
106: pos.i = getNextMeaningfulIndex(str, pos.i);
107: if ((pos.i >= str.length())) {
108: throw new IllegalArgumentException();
109: }
110: String value;
111:
112: if (str.charAt(pos.i) == '"') {
113: value = retrieveQuoted(str, pos);
114: } else {
115: value = retrieveToken(str, pos);
116: }
117: res.parameters.put(name, value);
118: }
119:
120: private static String retrieveQuoted(String str, StringPosition pos) {
121: StringBuilder buf = new StringBuilder();
122: boolean check = true;
123:
124: pos.i++;
125: while ((str.charAt(pos.i) != '"') || !check) {
126: char c = str.charAt(pos.i++);
127:
128: if (!check) {
129: check = true;
130: } else if (c == '\\') {
131: check = false;
132: }
133: if (check) {
134: buf.append(c);
135: }
136: if (pos.i == str.length()) {
137: throw new IllegalArgumentException();
138: }
139: }
140: pos.i++;
141:
142: return buf.toString();
143: }
144:
145: private static String retrieveToken(String str, StringPosition pos) {
146: StringBuilder buf = new StringBuilder();
147:
148: pos.i = getNextMeaningfulIndex(str, pos.i);
149: if ((pos.i >= str.length())
150: || isTSpecialChar(str.charAt(pos.i))) {
151: throw new IllegalArgumentException();
152: }
153: do {
154: buf.append(str.charAt(pos.i++));
155: } while ((pos.i < str.length())
156: && isMeaningfulChar(str.charAt(pos.i))
157: && !isTSpecialChar(str.charAt(pos.i)));
158:
159: return buf.toString();
160: }
161:
162: private static int getNextMeaningfulIndex(String str, int i) {
163: while ((i < str.length()) && !isMeaningfulChar(str.charAt(i))) {
164: i++;
165: }
166:
167: return i;
168: }
169:
170: private static boolean isTSpecialChar(char c) {
171: return ((c == '(') || (c == ')') || (c == '[') || (c == ']')
172: || (c == '<') || (c == '>') || (c == '@') || (c == ',')
173: || (c == ';') || (c == ':') || (c == '\\')
174: || (c == '\"') || (c == '/') || (c == '?') || (c == '='));
175: }
176:
177: private static boolean isMeaningfulChar(char c) {
178: return ((c >= '!') && (c <= '~'));
179: }
180:
181: private static final class StringPosition {
182:
183: int i = 0;
184:
185: }
186:
187: static final class MimeType implements Cloneable, Serializable {
188:
189: private static final long serialVersionUID = -6693571907475992044L;
190: private String primaryType;
191: private String subType;
192: private Hashtable<String, String> parameters;
193: private Hashtable<String, Object> systemParameters;
194:
195: MimeType() {
196: primaryType = null;
197: subType = null;
198: parameters = null;
199: systemParameters = null;
200: }
201:
202: MimeType(String primaryType, String subType) {
203: this .primaryType = primaryType;
204: this .subType = subType;
205: parameters = new Hashtable<String, String>();
206: systemParameters = new Hashtable<String, Object>();
207: }
208:
209: boolean equals(MimeType that) {
210: if (that == null) {
211: return false;
212: }
213: return getFullType().equals(that.getFullType());
214: }
215:
216: String getPrimaryType() {
217: return primaryType;
218: }
219:
220: String getSubType() {
221: return subType;
222: }
223:
224: String getFullType() {
225: return (primaryType + "/" + subType); //$NON-NLS-1$
226: }
227:
228: String getParameter(String name) {
229: return parameters.get(name);
230: }
231:
232: void addParameter(String name, String value) {
233: if (value == null) {
234: return;
235: }
236: if ((value.charAt(0) == '\"')
237: && (value.charAt(value.length() - 1) == '\"')) {
238: value = value.substring(1, value.length() - 2);
239: }
240: if (value.length() == 0) {
241: return;
242: }
243: parameters.put(name, value);
244: }
245:
246: void removeParameter(String name) {
247: parameters.remove(name);
248: }
249:
250: Object getSystemParameter(String name) {
251: return systemParameters.get(name);
252: }
253:
254: void addSystemParameter(String name, Object value) {
255: systemParameters.put(name, value);
256: }
257:
258: @SuppressWarnings("unchecked")
259: @Override
260: public Object clone() {
261: MimeType clone = new MimeType(primaryType, subType);
262: clone.parameters = (Hashtable<String, String>) parameters
263: .clone();
264: clone.systemParameters = (Hashtable<String, Object>) systemParameters
265: .clone();
266: return clone;
267: }
268: }
269:
270: }
|