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