src/share/jaf_classes/javax/activation/MimeTypeParameterList.java

changeset 0
373ffda63c9a
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
1 /*
2 * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.activation;
27
28 import java.util.Hashtable;
29 import java.util.Enumeration;
30 import java.util.Locale;
31
32 /**
33 * A parameter list of a MimeType
34 * as defined in RFC 2045 and 2046. The Primary type of the
35 * object must already be stripped off.
36 *
37 * @see javax.activation.MimeType
38 *
39 * @since 1.6
40 */
41 public class MimeTypeParameterList {
42 private Hashtable parameters;
43
44 /**
45 * A string that holds all the special chars.
46 */
47 private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
48
49
50 /**
51 * Default constructor.
52 */
53 public MimeTypeParameterList() {
54 parameters = new Hashtable();
55 }
56
57 /**
58 * Constructs a new MimeTypeParameterList with the passed in data.
59 *
60 * @param parameterList an RFC 2045, 2046 compliant parameter list.
61 */
62 public MimeTypeParameterList(String parameterList)
63 throws MimeTypeParseException {
64 parameters = new Hashtable();
65
66 // now parse rawdata
67 parse(parameterList);
68 }
69
70 /**
71 * A routine for parsing the parameter list out of a String.
72 *
73 * @param parameterList an RFC 2045, 2046 compliant parameter list.
74 */
75 protected void parse(String parameterList) throws MimeTypeParseException {
76 if (parameterList == null)
77 return;
78
79 int length = parameterList.length();
80 if (length <= 0)
81 return;
82
83 int i;
84 char c;
85 for (i = skipWhiteSpace(parameterList, 0);
86 i < length && (c = parameterList.charAt(i)) == ';';
87 i = skipWhiteSpace(parameterList, i)) {
88 int lastIndex;
89 String name;
90 String value;
91
92 // eat the ';'
93 i++;
94
95 // now parse the parameter name
96
97 // skip whitespace
98 i = skipWhiteSpace(parameterList, i);
99
100 // tolerate trailing semicolon, even though it violates the spec
101 if (i >= length)
102 return;
103
104 // find the end of the token char run
105 lastIndex = i;
106 while ((i < length) && isTokenChar(parameterList.charAt(i)))
107 i++;
108
109 name = parameterList.substring(lastIndex, i).
110 toLowerCase(Locale.ENGLISH);
111
112 // now parse the '=' that separates the name from the value
113 i = skipWhiteSpace(parameterList, i);
114
115 if (i >= length || parameterList.charAt(i) != '=')
116 throw new MimeTypeParseException(
117 "Couldn't find the '=' that separates a " +
118 "parameter name from its value.");
119
120 // eat it and parse the parameter value
121 i++;
122 i = skipWhiteSpace(parameterList, i);
123
124 if (i >= length)
125 throw new MimeTypeParseException(
126 "Couldn't find a value for parameter named " + name);
127
128 // now find out whether or not we have a quoted value
129 c = parameterList.charAt(i);
130 if (c == '"') {
131 // yup it's quoted so eat it and capture the quoted string
132 i++;
133 if (i >= length)
134 throw new MimeTypeParseException(
135 "Encountered unterminated quoted parameter value.");
136
137 lastIndex = i;
138
139 // find the next unescaped quote
140 while (i < length) {
141 c = parameterList.charAt(i);
142 if (c == '"')
143 break;
144 if (c == '\\') {
145 // found an escape sequence
146 // so skip this and the
147 // next character
148 i++;
149 }
150 i++;
151 }
152 if (c != '"')
153 throw new MimeTypeParseException(
154 "Encountered unterminated quoted parameter value.");
155
156 value = unquote(parameterList.substring(lastIndex, i));
157 // eat the quote
158 i++;
159 } else if (isTokenChar(c)) {
160 // nope it's an ordinary token so it
161 // ends with a non-token char
162 lastIndex = i;
163 while (i < length && isTokenChar(parameterList.charAt(i)))
164 i++;
165 value = parameterList.substring(lastIndex, i);
166 } else {
167 // it ain't a value
168 throw new MimeTypeParseException(
169 "Unexpected character encountered at index " + i);
170 }
171
172 // now put the data into the hashtable
173 parameters.put(name, value);
174 }
175 if (i < length) {
176 throw new MimeTypeParseException(
177 "More characters encountered in input than expected.");
178 }
179 }
180
181 /**
182 * Return the number of name-value pairs in this list.
183 *
184 * @return the number of parameters
185 */
186 public int size() {
187 return parameters.size();
188 }
189
190 /**
191 * Determine whether or not this list is empty.
192 *
193 * @return true if there are no parameters
194 */
195 public boolean isEmpty() {
196 return parameters.isEmpty();
197 }
198
199 /**
200 * Retrieve the value associated with the given name, or null if there
201 * is no current association.
202 *
203 * @param name the parameter name
204 * @return the parameter's value
205 */
206 public String get(String name) {
207 return (String)parameters.get(name.trim().toLowerCase(Locale.ENGLISH));
208 }
209
210 /**
211 * Set the value to be associated with the given name, replacing
212 * any previous association.
213 *
214 * @param name the parameter name
215 * @param value the parameter's value
216 */
217 public void set(String name, String value) {
218 parameters.put(name.trim().toLowerCase(Locale.ENGLISH), value);
219 }
220
221 /**
222 * Remove any value associated with the given name.
223 *
224 * @param name the parameter name
225 */
226 public void remove(String name) {
227 parameters.remove(name.trim().toLowerCase(Locale.ENGLISH));
228 }
229
230 /**
231 * Retrieve an enumeration of all the names in this list.
232 *
233 * @return an enumeration of all parameter names
234 */
235 public Enumeration getNames() {
236 return parameters.keys();
237 }
238
239 /**
240 * Return a string representation of this object.
241 */
242 public String toString() {
243 StringBuffer buffer = new StringBuffer();
244 buffer.ensureCapacity(parameters.size() * 16);
245 // heuristic: 8 characters per field
246
247 Enumeration keys = parameters.keys();
248 while (keys.hasMoreElements()) {
249 String key = (String)keys.nextElement();
250 buffer.append("; ");
251 buffer.append(key);
252 buffer.append('=');
253 buffer.append(quote((String)parameters.get(key)));
254 }
255
256 return buffer.toString();
257 }
258
259 // below here be scary parsing related things
260
261 /**
262 * Determine whether or not a given character belongs to a legal token.
263 */
264 private static boolean isTokenChar(char c) {
265 return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
266 }
267
268 /**
269 * return the index of the first non white space character in
270 * rawdata at or after index i.
271 */
272 private static int skipWhiteSpace(String rawdata, int i) {
273 int length = rawdata.length();
274 while ((i < length) && Character.isWhitespace(rawdata.charAt(i)))
275 i++;
276 return i;
277 }
278
279 /**
280 * A routine that knows how and when to quote and escape the given value.
281 */
282 private static String quote(String value) {
283 boolean needsQuotes = false;
284
285 // check to see if we actually have to quote this thing
286 int length = value.length();
287 for (int i = 0; (i < length) && !needsQuotes; i++) {
288 needsQuotes = !isTokenChar(value.charAt(i));
289 }
290
291 if (needsQuotes) {
292 StringBuffer buffer = new StringBuffer();
293 buffer.ensureCapacity((int)(length * 1.5));
294
295 // add the initial quote
296 buffer.append('"');
297
298 // add the properly escaped text
299 for (int i = 0; i < length; ++i) {
300 char c = value.charAt(i);
301 if ((c == '\\') || (c == '"'))
302 buffer.append('\\');
303 buffer.append(c);
304 }
305
306 // add the closing quote
307 buffer.append('"');
308
309 return buffer.toString();
310 } else {
311 return value;
312 }
313 }
314
315 /**
316 * A routine that knows how to strip the quotes and
317 * escape sequences from the given value.
318 */
319 private static String unquote(String value) {
320 int valueLength = value.length();
321 StringBuffer buffer = new StringBuffer();
322 buffer.ensureCapacity(valueLength);
323
324 boolean escaped = false;
325 for (int i = 0; i < valueLength; ++i) {
326 char currentChar = value.charAt(i);
327 if (!escaped && (currentChar != '\\')) {
328 buffer.append(currentChar);
329 } else if (escaped) {
330 buffer.append(currentChar);
331 escaped = false;
332 } else {
333 escaped = true;
334 }
335 }
336
337 return buffer.toString();
338 }
339 }

mercurial