001 package org.apache.fulcrum.mimetype.util; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.util.ArrayList; 025 026 /** 027 * This class is used to represent parsed MIME types. 028 * The representation is parsed from a string based 029 * representation of the MIME type, as defined in the RFC1345. 030 * 031 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 032 * @version $Id: MimeType.java 813677 2009-09-11 06:48:11Z tv $ 033 */ 034 public class MimeType 035 implements Cloneable 036 { 037 /** 038 * A list of well known MIME types. 039 */ 040 public static MimeType TEXT_HTML; 041 public static MimeType TEXT_WML; 042 public static MimeType TEXT_HDML; 043 public static MimeType TEXT_CHTML; 044 public static MimeType TEXT_PLAIN; 045 public static MimeType MULTIPART; 046 public static MimeType MULTIPART_FORM_DATA; 047 public static MimeType APPLICATION_POSTSCRIPT; 048 public static MimeType APPLICATION_OCTET_STREAM; 049 public static MimeType APPLICATION_X_JAVA_AGENT; 050 public static MimeType APPLICATION_X_WWW_FORM_URLENCODED; 051 public static MimeType MESSAGE_HTTP; 052 public static MimeType TEXT_CSS; 053 public static MimeType TEXT; 054 public static MimeType IMAGE_PNG; 055 public static MimeType IMAGE_GIF; 056 public static MimeType IMAGE_JPEG; 057 public static MimeType IMAGE_WBMP; 058 static 059 { 060 TEXT_HTML = 061 new MimeType("text/html"); 062 TEXT_WML = 063 new MimeType("text/vnd.wap.wml"); 064 TEXT_HDML = 065 new MimeType("text/x-hdml"); 066 TEXT_CHTML = 067 new MimeType("text/x-chtml"); 068 TEXT_PLAIN = 069 new MimeType("text/plain"); 070 MULTIPART = 071 new MimeType("multipart/*"); 072 MULTIPART_FORM_DATA = 073 new MimeType("multipart/form-data"); 074 APPLICATION_POSTSCRIPT = 075 new MimeType("application/postscript"); 076 APPLICATION_OCTET_STREAM = 077 new MimeType("application/octet-stream"); 078 APPLICATION_X_JAVA_AGENT = 079 new MimeType("application/x-java-agent"); 080 APPLICATION_X_WWW_FORM_URLENCODED = 081 new MimeType("application/x-www-form-urlencoded"); 082 MESSAGE_HTTP = 083 new MimeType("message/http"); 084 TEXT_CSS = 085 new MimeType("text/css"); 086 TEXT = 087 new MimeType("text/*"); 088 IMAGE_PNG = 089 new MimeType("image/png"); 090 IMAGE_GIF = 091 new MimeType("image/gif"); 092 IMAGE_JPEG = 093 new MimeType("image/jpeg"); 094 IMAGE_WBMP = 095 new MimeType("image/vnd.wap.wbmp"); 096 } 097 098 /** 099 * MIME type matching constants. 100 */ 101 public static final int NO_MATCH = 0; 102 public static final int MATCH_TYPE = 1; 103 public static final int MATCH_SUBTYPE = 2; 104 public static final int MATCH_SPECIFIC_SUBTYPE = 3; 105 106 /** 107 * A string representation of the main type. 108 */ 109 private String mimeType; 110 111 /** 112 * A string representation of the subtype. 113 */ 114 private String mimeSubtype; 115 116 /** 117 * Parameter names. 118 */ 119 private String parameterNames[]; 120 121 /** 122 * Parameter values. 123 */ 124 private String parameterValues[]; 125 126 /** 127 * A string representation of the MIME type. 128 */ 129 private String mimeTypeString; 130 131 /** 132 * Constructs a new MIME type by parsing a specification string. 133 * 134 * @param spec a string representing a MIME type. 135 * @throws IllegalArgumentException for parsing errors. 136 */ 137 public MimeType(String spec) 138 { 139 this(spec,true); 140 } 141 142 /** 143 * Constructs a new MIME type by parsing a specification string. 144 * 145 * @param spec a string representing a MIME type. 146 * @param parsep a flag for parsing parameters also. 147 * @throws IllegalArgumentException for parsing errors. 148 */ 149 public MimeType(String spec, 150 boolean parsep) 151 { 152 int start = 0; 153 char look = '\0'; 154 int length = spec.length(); 155 156 // Skip leading/trailing blanks. 157 while ((start < length) && 158 Character.isWhitespace(spec.charAt(start))) 159 { 160 start++; 161 } 162 while ((length > start) && 163 Character.isWhitespace(spec.charAt(length - 1))) 164 { 165 length--; 166 } 167 168 // Get the type. 169 StringBuffer sb = new StringBuffer(); 170 while ((start < length) && 171 ((look = spec.charAt(start)) != '/')) 172 { 173 sb.append(look); 174 start++; 175 } 176 if (look != '/') 177 { 178 throw new IllegalArgumentException( 179 "Syntax error in MIME type " + spec); 180 } 181 mimeType = sb.toString(); 182 183 // Get the subtype. 184 start++; 185 sb.setLength(0); 186 while ((start < length) && 187 ((look = spec.charAt(start)) != ';') && 188 !Character.isWhitespace(look)) 189 { 190 sb.append(look); 191 start++; 192 } 193 mimeSubtype = sb.toString(); 194 195 if (parsep) 196 { 197 // Get parameters, if any. 198 while ((start < length) && 199 Character.isWhitespace(spec.charAt(start))) 200 { 201 start++; 202 } 203 if (start < length) 204 { 205 if (spec.charAt(start) != ';') 206 { 207 throw new IllegalArgumentException( 208 "Syntax error in MIME type parameters " + spec); 209 } 210 start++; 211 ArrayList na = new ArrayList(4); 212 ArrayList va = new ArrayList(4); 213 while (start < length) 214 { 215 // Get the name. 216 while ((start < length) && 217 Character.isWhitespace(spec.charAt(start))) 218 { 219 start++; 220 } 221 sb.setLength(0); 222 while ((start < length) && 223 ((look=spec.charAt(start)) != '=') && 224 !Character.isWhitespace(look)) 225 { 226 sb.append(Character.toLowerCase(look)); 227 start++ ; 228 } 229 String name = sb.toString(); 230 231 // Get the value. 232 while ((start < length) && 233 Character.isWhitespace(spec.charAt(start))) 234 { 235 start++; 236 } 237 if (spec.charAt(start) != '=') 238 { 239 throw new IllegalArgumentException( 240 "Syntax error in MIME type parameters " + spec); 241 } 242 start++ ; 243 while ((start < length) && 244 Character.isWhitespace(spec.charAt(start))) 245 { 246 start++; 247 } 248 sb.setLength(0); 249 char delim = ';'; 250 if (spec.charAt(start) == '"') 251 { 252 start++; 253 delim = '"'; 254 } 255 while ((start < length) && 256 ((look = spec.charAt(start)) != delim) && 257 ((delim == '"') || 258 !Character.isWhitespace(look))) 259 { 260 sb.append(look); 261 start++; 262 } 263 while ((start < length) && 264 (spec.charAt(start) != ';')) 265 { 266 start++; 267 } 268 start++; 269 String value = sb.toString(); 270 271 na.add(name); 272 va.add(value); 273 } 274 parameterNames = (String[]) na.toArray(new String[na.size()]); 275 parameterValues = (String[]) va.toArray(new String[va.size()]); 276 } 277 } 278 } 279 280 /** 281 * Contructs a new MIME type from specified types. 282 * 283 * @param type a type. 284 * @param subtype a subtype. 285 * @throws NullPointerException if type or subtype are nulls. 286 */ 287 public MimeType(String type, 288 String subtype) 289 { 290 this(type,subtype,null,null); 291 } 292 293 /** 294 * Contructs a new MIME type from specified parameters. 295 * 296 * @param type a type. 297 * @param subtype a subtype. 298 * @param names parameters names. 299 * @param values parameter values. 300 * @throws NullPointerException if type or subtype are nulls. 301 */ 302 public MimeType(String type, 303 String subtype, 304 String names[], 305 String values[]) 306 { 307 if ((type == null) || 308 (subtype == null)) 309 { 310 throw new NullPointerException("MIME type or subtype missing"); 311 } 312 mimeType = type.trim(); 313 mimeSubtype = subtype.trim(); 314 parameterNames = names; 315 parameterValues = values; 316 } 317 318 /** 319 * Compares the specified MIME type to this one 320 * and returns a matching level: 321 * NO_MATCH=types do not match, 322 * MATCH_TYPE=types match, 323 * MATCH_SPECIFIC_TYPE=types match exactly, 324 * MATCH_SUBTYPE=types match, subtypes match too, 325 * MATCH_SPECIFIC_SUBTYPE=types match, subtypes match exactly. 326 * 327 * @param other the MimeType to compare. 328 * @return the matching level. 329 */ 330 public int match(MimeType other) 331 { 332 if (mimeType.equals("*") || 333 other.mimeType.equals("*")) 334 { 335 return MATCH_TYPE; 336 } 337 else if (!mimeType.equalsIgnoreCase(other.mimeType)) 338 { 339 return NO_MATCH; 340 } 341 else if (mimeSubtype.equals("*") || 342 other.mimeSubtype.equals("*")) 343 { 344 return MATCH_SUBTYPE; 345 } 346 else if (!mimeSubtype.equalsIgnoreCase(other.mimeSubtype)) 347 { 348 return NO_MATCH; 349 } 350 else 351 { 352 return MATCH_SPECIFIC_SUBTYPE; 353 } 354 } 355 356 /** 357 * Gets the main type of the MIME type. 358 * 359 * @return the main type as a string. 360 */ 361 public String getType() 362 { 363 return mimeType; 364 } 365 366 /** 367 * Gets the subtype of the MIME type. 368 * 369 * @return the subtype as a string. 370 */ 371 public String getSubtype() 372 { 373 return mimeSubtype; 374 } 375 376 /** 377 * Gets the type and the subtype of the MIME type. 378 * 379 * @return the types as a string. 380 */ 381 public String getTypes() 382 { 383 return mimeType + '/' + mimeSubtype; 384 } 385 386 /** 387 * Checks whether the MIME type contains the specified parameter. 388 * 389 * @param param the name opf the parameter. 390 * @return true if the parameter found, otherwise false. 391 */ 392 public boolean hasParameter(String param) 393 { 394 String[] na = parameterNames; 395 if (na != null) 396 { 397 for (int i = 0; i < na.length; i++) 398 { 399 if (na[i].equalsIgnoreCase(param)) 400 { 401 return true; 402 } 403 } 404 } 405 return false; 406 } 407 408 /** 409 * Gets the value of a MIME type parameter. 410 * The first parameter with the specifed name will be returned. 411 * 412 * @param param the name of the parameter. 413 * @return the value of the parameter, or null. 414 */ 415 public String getParameter(String param) 416 { 417 String[] na = parameterNames; 418 if (na != null) 419 { 420 String[] va = parameterValues; 421 for (int i = 0; i < na.length; i++) 422 { 423 if (na[i].equalsIgnoreCase(param)) 424 { 425 return va[i]; 426 } 427 } 428 } 429 return null ; 430 } 431 432 /** 433 * Sets the value of a MIME type parameter replacing the old one. 434 * 435 * @param param the name of the parameter. 436 * @param value the value of the parameter. 437 */ 438 public synchronized void setParameter(String param, 439 String value) 440 { 441 if (parameterNames != null) 442 { 443 for (int i = 0; i < parameterNames.length; i++) 444 { 445 if (parameterNames[i].equalsIgnoreCase(param)) 446 { 447 parameterValues[i] = value; 448 mimeTypeString = null; 449 return; 450 } 451 } 452 } 453 addParameter(param,value); 454 } 455 456 /** 457 * Adds a parameter to the MIME type. 458 * 459 * @param param the name of the parameter. 460 * @param value the value of the parameter. 461 */ 462 public void addParameter(String param, 463 String value) 464 { 465 addParameters(new String[]{ param },new String[]{ value }); 466 } 467 468 /** 469 * Adds parameters to the MIME type. 470 * 471 * @param params an array of parameter names. 472 * @param values an array of parameter values. 473 * @throws IllegalArgumentException for incorrect parameters. 474 */ 475 public synchronized void addParameters(String[] params, 476 String[] values) 477 { 478 if ((params == null) || 479 (values == null) || 480 (params.length != values.length)) 481 throw new IllegalArgumentException("Incorrect MIME type parameters"); 482 483 if (parameterNames != null) 484 { 485 String[] na = new String[parameterNames.length + params.length]; 486 String[] va = new String[parameterValues.length + values.length]; 487 System.arraycopy(parameterNames,0,na,0,parameterNames.length); 488 System.arraycopy(params,0,na,parameterNames.length,params.length); 489 System.arraycopy(parameterValues,0,va,0,parameterValues.length); 490 System.arraycopy(values,0,va,parameterValues.length,values.length); 491 parameterNames = na; 492 parameterValues = va; 493 } 494 else 495 { 496 parameterNames = params; 497 parameterValues = values; 498 } 499 mimeTypeString = null; 500 } 501 502 /** 503 * Converts the MIME type into a string. 504 * 505 * @return the string representation of the MIME type. 506 */ 507 public String toString() 508 { 509 if (mimeTypeString == null) 510 { 511 StringBuffer sb = new StringBuffer(mimeType); 512 sb.append('/'); 513 sb.append(mimeSubtype); 514 String[] na = parameterNames; 515 if (na != null) 516 { 517 String[] va = parameterValues; 518 for (int i = 0; i < va.length; i++) 519 { 520 sb.append(';'); 521 sb.append(na[i]); 522 if (va[i] != null) 523 { 524 sb.append('='); 525 sb.append(va[i]); 526 } 527 } 528 } 529 mimeTypeString = sb.toString(); 530 } 531 return mimeTypeString; 532 } 533 }