1 package org.apache.turbine.services.mimetype.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23
24 /***
25 * This class is used to represent parsed MIME types.
26 * The representation is parsed from a string based
27 * representation of the MIME type, as defined in the RFC1345.
28 *
29 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
30 * @version $Id: MimeType.java 534527 2007-05-02 16:10:59Z tv $
31 */
32 public class MimeType
33 implements Cloneable
34 {
35 /***
36 * A list of well known MIME types.
37 */
38 public static MimeType TEXT_HTML;
39 public static MimeType TEXT_WML;
40 public static MimeType TEXT_HDML;
41 public static MimeType TEXT_CHTML;
42 public static MimeType TEXT_PLAIN;
43 public static MimeType MULTIPART;
44 public static MimeType MULTIPART_FORM_DATA;
45 public static MimeType APPLICATION_POSTSCRIPT;
46 public static MimeType APPLICATION_OCTET_STREAM;
47 public static MimeType APPLICATION_X_JAVA_AGENT;
48 public static MimeType APPLICATION_X_WWW_FORM_URLENCODED;
49 public static MimeType MESSAGE_HTTP;
50 public static MimeType TEXT_CSS;
51 public static MimeType TEXT;
52 public static MimeType IMAGE_GIF;
53 public static MimeType IMAGE_JPEG;
54 public static MimeType IMAGE_WBMP;
55
56 static
57 {
58 TEXT_HTML =
59 new MimeType("text/html");
60 TEXT_WML =
61 new MimeType("text/vnd.wap.wml");
62 TEXT_HDML =
63 new MimeType("text/x-hdml");
64 TEXT_CHTML =
65 new MimeType("text/x-chtml");
66 TEXT_PLAIN =
67 new MimeType("text/plain");
68 MULTIPART =
69 new MimeType("multipart/*");
70 MULTIPART_FORM_DATA =
71 new MimeType("multipart/form-data");
72 APPLICATION_POSTSCRIPT =
73 new MimeType("application/postscript");
74 APPLICATION_OCTET_STREAM =
75 new MimeType("application/octet-stream");
76 APPLICATION_X_JAVA_AGENT =
77 new MimeType("application/x-java-agent");
78 APPLICATION_X_WWW_FORM_URLENCODED =
79 new MimeType("application/x-www-form-urlencoded");
80 MESSAGE_HTTP =
81 new MimeType("message/http");
82 TEXT_CSS =
83 new MimeType("text/css");
84 TEXT =
85 new MimeType("text/*");
86 IMAGE_GIF =
87 new MimeType("image/gif");
88 IMAGE_JPEG =
89 new MimeType("image/jpeg");
90 IMAGE_WBMP =
91 new MimeType("image/vnd.wap.wbmp");
92 }
93
94 /***
95 * MIME type matching constants.
96 */
97 public static final int NO_MATCH = 0;
98 public static final int MATCH_TYPE = 1;
99 public static final int MATCH_SUBTYPE = 2;
100 public static final int MATCH_SPECIFIC_SUBTYPE = 3;
101
102 /***
103 * A string representation of the main type.
104 */
105 private String mimeType;
106
107 /***
108 * A string representation of the subtype.
109 */
110 private String mimeSubtype;
111
112 /***
113 * Parameter names.
114 */
115 private String parameterNames[];
116
117 /***
118 * Parameter values.
119 */
120 private String parameterValues[];
121
122 /***
123 * A string representation of the MIME type.
124 */
125 private String mimeTypeString;
126
127 /***
128 * Constructs a new MIME type by parsing a specification string.
129 *
130 * @param spec a string representing a MIME type.
131 */
132 public MimeType(String spec)
133 {
134 this(spec, true);
135 }
136
137 /***
138 * Constructs a new MIME type by parsing a specification string.
139 *
140 * @param spec a string representing a MIME type.
141 * @param parsep a flag for parsing parameters also.
142 * @throws IllegalArgumentException for parsing errors.
143 */
144 public MimeType(String spec,
145 boolean parsep)
146 {
147 int start = 0;
148 char look = '\0';
149 int length = spec.length();
150
151
152 while ((start < length) &&
153 Character.isWhitespace(spec.charAt(start)))
154 {
155 start++;
156 }
157 while ((length > start) &&
158 Character.isWhitespace(spec.charAt(length - 1)))
159 {
160 length--;
161 }
162
163
164 StringBuffer sb = new StringBuffer();
165 while ((start < length) &&
166 ((look = spec.charAt(start)) != '/'))
167 {
168 sb.append((char) look);
169 start++;
170 }
171 if (look != '/')
172 {
173 throw new IllegalArgumentException(
174 "Syntax error in MIME type " + spec);
175 }
176 mimeType = sb.toString();
177
178
179 start++;
180 sb.setLength(0);
181 while ((start < length) &&
182 ((look = spec.charAt(start)) != ';') &&
183 !Character.isWhitespace(look))
184 {
185 sb.append((char) look);
186 start++;
187 }
188 mimeSubtype = sb.toString();
189
190 if (parsep)
191 {
192
193 while ((start < length) &&
194 Character.isWhitespace(spec.charAt(start)))
195 {
196 start++;
197 }
198 if (start < length)
199 {
200 if (spec.charAt(start) != ';')
201 {
202 throw new IllegalArgumentException(
203 "Syntax error in MIME type parameters " + spec);
204 }
205 start++;
206 ArrayList na = new ArrayList(4);
207 ArrayList va = new ArrayList(4);
208 while (start < length)
209 {
210
211 while ((start < length) &&
212 Character.isWhitespace(spec.charAt(start)))
213 {
214 start++;
215 }
216 sb.setLength(0);
217 while ((start < length) &&
218 ((look = spec.charAt(start)) != '=') &&
219 !Character.isWhitespace(look))
220 {
221 sb.append(Character.toLowerCase((char) look));
222 start++;
223 }
224 String name = sb.toString();
225
226
227 while ((start < length) &&
228 Character.isWhitespace(spec.charAt(start)))
229 {
230 start++;
231 }
232 if (spec.charAt(start) != '=')
233 {
234 throw new IllegalArgumentException(
235 "Syntax error in MIME type parameters " + spec);
236 }
237 start++;
238 while ((start < length) &&
239 Character.isWhitespace(spec.charAt(start)))
240 {
241 start++;
242 }
243 sb.setLength(0);
244 char delim = ';';
245 if (spec.charAt(start) == '"')
246 {
247 start++;
248 delim = '"';
249 }
250 while ((start < length) &&
251 ((look = spec.charAt(start)) != delim) &&
252 ((delim == '"') ||
253 !Character.isWhitespace(look)))
254 {
255 sb.append((char) look);
256 start++;
257 }
258 while ((start < length) &&
259 (spec.charAt(start) != ';'))
260 {
261 start++;
262 }
263 start++;
264 String value = sb.toString();
265
266 na.add(name);
267 va.add(value);
268 }
269 parameterNames = (String[]) na.toArray(new String[na.size()]);
270 parameterValues = (String[]) va.toArray(new String[va.size()]);
271 }
272 }
273 }
274
275 /***
276 * Contructs a new MIME type from specified types.
277 *
278 * @param type a type.
279 * @param subtype a subtype.
280 * @throws NullPointerException if type or subtype are nulls.
281 */
282 public MimeType(String type,
283 String subtype)
284 {
285 this(type, subtype, null, null);
286 }
287
288 /***
289 * Contructs a new MIME type from specified parameters.
290 *
291 * @param type a type.
292 * @param subtype a subtype.
293 * @param names parameters names.
294 * @param values parameter values.
295 * @throws NullPointerException if type or subtype are nulls.
296 */
297 public MimeType(String type,
298 String subtype,
299 String names[],
300 String values[])
301 {
302 if ((type == null) ||
303 (subtype == null))
304 {
305 throw new NullPointerException("MIME type or subtype missing");
306 }
307 mimeType = type.trim();
308 mimeSubtype = subtype.trim();
309 parameterNames = names;
310 parameterValues = values;
311 }
312
313 /***
314 * Compares the specified MIME type to this one
315 * and returns a matching level:
316 * NO_MATCH=types do not match,
317 * MATCH_TYPE=types match,
318 * MATCH_SPECIFIC_TYPE=types match exactly,
319 * MATCH_SUBTYPE=types match, subtypes match too,
320 * MATCH_SPECIFIC_SUBTYPE=types match, subtypes match exactly.
321 *
322 * @param other the MimeType to compare.
323 * @return the matching level.
324 */
325 public int match(MimeType other)
326 {
327 if (mimeType.equals("*") ||
328 other.mimeType.equals("*"))
329 {
330 return MATCH_TYPE;
331 }
332 else if (!mimeType.equalsIgnoreCase(other.mimeType))
333 {
334 return NO_MATCH;
335 }
336 else if (mimeSubtype.equals("*") ||
337 other.mimeSubtype.equals("*"))
338 {
339 return MATCH_SUBTYPE;
340 }
341 else if (!mimeSubtype.equalsIgnoreCase(other.mimeSubtype))
342 {
343 return NO_MATCH;
344 }
345 else
346 {
347 return MATCH_SPECIFIC_SUBTYPE;
348 }
349 }
350
351 /***
352 * Gets the main type of the MIME type.
353 *
354 * @return the main type as a string.
355 */
356 public String getType()
357 {
358 return mimeType;
359 }
360
361 /***
362 * Gets the subtype of the MIME type.
363 *
364 * @return the subtype as a string.
365 */
366 public String getSubtype()
367 {
368 return mimeSubtype;
369 }
370
371 /***
372 * Gets the type and the subtype of the MIME type.
373 *
374 * @return the types as a string.
375 */
376 public String getTypes()
377 {
378 return mimeType + '/' + mimeSubtype;
379 }
380
381 /***
382 * Checks whether the MIME type contains the specified parameter.
383 *
384 * @param param the name opf the parameter.
385 * @return true if the parameter found, otherwise false.
386 */
387 public boolean hasParameter(String param)
388 {
389 String[] na = parameterNames;
390 if (na != null)
391 {
392 for (int i = 0; i < na.length; i++)
393 {
394 if (na[i].equalsIgnoreCase(param))
395 {
396 return true;
397 }
398 }
399 }
400 return false;
401 }
402
403 /***
404 * Gets the value of a MIME type parameter.
405 * The first parameter with the specifed name will be returned.
406 *
407 * @param param the name of the parameter.
408 * @return the value of the parameter, or null.
409 */
410 public String getParameter(String param)
411 {
412 String[] na = parameterNames;
413 if (na != null)
414 {
415 String[] va = parameterValues;
416 for (int i = 0; i < na.length; i++)
417 {
418 if (na[i].equalsIgnoreCase(param))
419 {
420 return va[i];
421 }
422 }
423 }
424 return null;
425 }
426
427 /***
428 * Sets the value of a MIME type parameter replacing the old one.
429 *
430 * @param param the name of the parameter.
431 * @param value the value of the parameter.
432 */
433 public synchronized void setParameter(String param,
434 String value)
435 {
436 if (parameterNames != null)
437 {
438 for (int i = 0; i < parameterNames.length; i++)
439 {
440 if (parameterNames[i].equalsIgnoreCase(param))
441 {
442 parameterValues[i] = value;
443 mimeTypeString = null;
444 return;
445 }
446 }
447 }
448 addParameter(param, value);
449 }
450
451 /***
452 * Adds a parameter to the MIME type.
453 *
454 * @param param the name of the parameter.
455 * @param value the value of the parameter.
456 */
457 public void addParameter(String param,
458 String value)
459 {
460 addParameters(new String[]{param}, new String[]{value});
461 }
462
463 /***
464 * Adds parameters to the MIME type.
465 *
466 * @param params an array of parameter names.
467 * @param values an array of parameter values.
468 * @throw IllegalArgumentException for incorrect parameters.
469 */
470 public synchronized void addParameters(String[] params,
471 String[] values)
472 {
473 if ((params == null) ||
474 (values == null) ||
475 (params.length != values.length))
476 throw new IllegalArgumentException("Incorrect MIME type parameters");
477
478 if (parameterNames != null)
479 {
480 String[] na = new String[parameterNames.length + params.length];
481 String[] va = new String[parameterValues.length + values.length];
482 System.arraycopy(parameterNames, 0, na, 0, parameterNames.length);
483 System.arraycopy(params, 0, na, parameterNames.length, params.length);
484 System.arraycopy(parameterValues, 0, va, 0, parameterValues.length);
485 System.arraycopy(values, 0, va, parameterValues.length, values.length);
486 parameterNames = na;
487 parameterValues = va;
488 }
489 else
490 {
491 parameterNames = params;
492 parameterValues = values;
493 }
494 mimeTypeString = null;
495 }
496
497 /***
498 * Converts the MIME type into a string.
499 *
500 * @return the string representation of the MIME type.
501 */
502 public String toString()
503 {
504 if (mimeTypeString == null)
505 {
506 StringBuffer sb = new StringBuffer(mimeType);
507 sb.append('/');
508 sb.append(mimeSubtype);
509 String[] na = parameterNames;
510 if (na != null)
511 {
512 String[] va = parameterValues;
513 for (int i = 0; i < va.length; i++)
514 {
515 sb.append(';');
516 sb.append(na[i]);
517 if (va[i] != null)
518 {
519 sb.append('=');
520 sb.append(va[i]);
521 }
522 }
523 }
524 mimeTypeString = sb.toString();
525 }
526 return mimeTypeString;
527 }
528 }