1 /* 2 * Copyright (c) 1997, 2012, 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.io.*; 29 import java.util.Locale; 30 31 /** 32 * A Multipurpose Internet Mail Extension (MIME) type, as defined 33 * in RFC 2045 and 2046. 34 * 35 * @since 1.6 36 */ 37 public class MimeType implements Externalizable { 38 39 private String primaryType; 40 private String subType; 41 private MimeTypeParameterList parameters; 42 43 /** 44 * A string that holds all the special chars. 45 */ 46 private static final String TSPECIALS = "()<>@,;:/[]?=\\\""; 47 48 /** 49 * Default constructor. 50 */ 51 public MimeType() { 52 primaryType = "application"; 53 subType = "*"; 54 parameters = new MimeTypeParameterList(); 55 } 56 57 /** 58 * Constructor that builds a MimeType from a String. 59 * 60 * @param rawdata the MIME type string 61 */ 62 public MimeType(String rawdata) throws MimeTypeParseException { 63 parse(rawdata); 64 } 65 66 /** 67 * Constructor that builds a MimeType with the given primary and sub type 68 * but has an empty parameter list. 69 * 70 * @param primary the primary MIME type 71 * @param sub the MIME sub-type 72 * @exception MimeTypeParseException if the primary type or subtype 73 * is not a valid token 74 */ 75 public MimeType(String primary, String sub) throws MimeTypeParseException { 76 // check to see if primary is valid 77 if (isValidToken(primary)) { 78 primaryType = primary.toLowerCase(Locale.ENGLISH); 79 } else { 80 throw new MimeTypeParseException("Primary type is invalid."); 81 } 82 83 // check to see if sub is valid 84 if (isValidToken(sub)) { 85 subType = sub.toLowerCase(Locale.ENGLISH); 86 } else { 87 throw new MimeTypeParseException("Sub type is invalid."); 88 } 89 90 parameters = new MimeTypeParameterList(); 91 } 92 93 /** 94 * A routine for parsing the MIME type out of a String. 95 */ 96 private void parse(String rawdata) throws MimeTypeParseException { 97 int slashIndex = rawdata.indexOf('/'); 98 int semIndex = rawdata.indexOf(';'); 99 if ((slashIndex < 0) && (semIndex < 0)) { 100 // neither character is present, so treat it 101 // as an error 102 throw new MimeTypeParseException("Unable to find a sub type."); 103 } else if ((slashIndex < 0) && (semIndex >= 0)) { 104 // we have a ';' (and therefore a parameter list), 105 // but no '/' indicating a sub type is present 106 throw new MimeTypeParseException("Unable to find a sub type."); 107 } else if ((slashIndex >= 0) && (semIndex < 0)) { 108 // we have a primary and sub type but no parameter list 109 primaryType = rawdata.substring(0, slashIndex).trim(). 110 toLowerCase(Locale.ENGLISH); 111 subType = rawdata.substring(slashIndex + 1).trim(). 112 toLowerCase(Locale.ENGLISH); 113 parameters = new MimeTypeParameterList(); 114 } else if (slashIndex < semIndex) { 115 // we have all three items in the proper sequence 116 primaryType = rawdata.substring(0, slashIndex).trim(). 117 toLowerCase(Locale.ENGLISH); 118 subType = rawdata.substring(slashIndex + 1, semIndex).trim(). 119 toLowerCase(Locale.ENGLISH); 120 parameters = new MimeTypeParameterList(rawdata.substring(semIndex)); 121 } else { 122 // we have a ';' lexically before a '/' which means we 123 // have a primary type and a parameter list but no sub type 124 throw new MimeTypeParseException("Unable to find a sub type."); 125 } 126 127 // now validate the primary and sub types 128 129 // check to see if primary is valid 130 if (!isValidToken(primaryType)) 131 throw new MimeTypeParseException("Primary type is invalid."); 132 133 // check to see if sub is valid 134 if (!isValidToken(subType)) 135 throw new MimeTypeParseException("Sub type is invalid."); 136 } 137 138 /** 139 * Retrieve the primary type of this object. 140 * 141 * @return the primary MIME type 142 */ 143 public String getPrimaryType() { 144 return primaryType; 145 } 146 147 /** 148 * Set the primary type for this object to the given String. 149 * 150 * @param primary the primary MIME type 151 * @exception MimeTypeParseException if the primary type 152 * is not a valid token 153 */ 154 public void setPrimaryType(String primary) throws MimeTypeParseException { 155 // check to see if primary is valid 156 if (!isValidToken(primaryType)) 157 throw new MimeTypeParseException("Primary type is invalid."); 158 primaryType = primary.toLowerCase(Locale.ENGLISH); 159 } 160 161 /** 162 * Retrieve the subtype of this object. 163 * 164 * @return the MIME subtype 165 */ 166 public String getSubType() { 167 return subType; 168 } 169 170 /** 171 * Set the subtype for this object to the given String. 172 * 173 * @param sub the MIME subtype 174 * @exception MimeTypeParseException if the subtype 175 * is not a valid token 176 */ 177 public void setSubType(String sub) throws MimeTypeParseException { 178 // check to see if sub is valid 179 if (!isValidToken(subType)) 180 throw new MimeTypeParseException("Sub type is invalid."); 181 subType = sub.toLowerCase(Locale.ENGLISH); 182 } 183 184 /** 185 * Retrieve this object's parameter list. 186 * 187 * @return a MimeTypeParameterList object representing the parameters 188 */ 189 public MimeTypeParameterList getParameters() { 190 return parameters; 191 } 192 193 /** 194 * Retrieve the value associated with the given name, or null if there 195 * is no current association. 196 * 197 * @param name the parameter name 198 * @return the paramter's value 199 */ 200 public String getParameter(String name) { 201 return parameters.get(name); 202 } 203 204 /** 205 * Set the value to be associated with the given name, replacing 206 * any previous association. 207 * 208 * @param name the parameter name 209 * @param value the paramter's value 210 */ 211 public void setParameter(String name, String value) { 212 parameters.set(name, value); 213 } 214 215 /** 216 * Remove any value associated with the given name. 217 * 218 * @param name the parameter name 219 */ 220 public void removeParameter(String name) { 221 parameters.remove(name); 222 } 223 224 /** 225 * Return the String representation of this object. 226 */ 227 public String toString() { 228 return getBaseType() + parameters.toString(); 229 } 230 231 /** 232 * Return a String representation of this object 233 * without the parameter list. 234 * 235 * @return the MIME type and sub-type 236 */ 237 public String getBaseType() { 238 return primaryType + "/" + subType; 239 } 240 241 /** 242 * Determine if the primary and sub type of this object is 243 * the same as what is in the given type. 244 * 245 * @param type the MimeType object to compare with 246 * @return true if they match 247 */ 248 public boolean match(MimeType type) { 249 return primaryType.equals(type.getPrimaryType()) 250 && (subType.equals("*") 251 || type.getSubType().equals("*") 252 || (subType.equals(type.getSubType()))); 253 } 254 255 /** 256 * Determine if the primary and sub type of this object is 257 * the same as the content type described in rawdata. 258 * 259 * @param rawdata the MIME type string to compare with 260 * @return true if they match 261 */ 262 public boolean match(String rawdata) throws MimeTypeParseException { 263 return match(new MimeType(rawdata)); 264 } 265 266 /** 267 * The object implements the writeExternal method to save its contents 268 * by calling the methods of DataOutput for its primitive values or 269 * calling the writeObject method of ObjectOutput for objects, strings 270 * and arrays. 271 * 272 * @param out the ObjectOutput object to write to 273 * @exception IOException Includes any I/O exceptions that may occur 274 */ 275 public void writeExternal(ObjectOutput out) throws IOException { 276 out.writeUTF(toString()); 277 out.flush(); 278 } 279 280 /** 281 * The object implements the readExternal method to restore its 282 * contents by calling the methods of DataInput for primitive 283 * types and readObject for objects, strings and arrays. The 284 * readExternal method must read the values in the same sequence 285 * and with the same types as were written by writeExternal. 286 * 287 * @param in the ObjectInput object to read from 288 * @exception ClassNotFoundException If the class for an object being 289 * restored cannot be found. 290 */ 291 public void readExternal(ObjectInput in) 292 throws IOException, ClassNotFoundException { 293 try { 294 parse(in.readUTF()); 295 } catch (MimeTypeParseException e) { 296 throw new IOException(e.toString()); 297 } 298 } 299 300 // below here be scary parsing related things 301 302 /** 303 * Determine whether or not a given character belongs to a legal token. 304 */ 305 private static boolean isTokenChar(char c) { 306 return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); 307 } 308 309 /** 310 * Determine whether or not a given string is a legal token. 311 */ 312 private boolean isValidToken(String s) { 313 int len = s.length(); 314 if (len > 0) { 315 for (int i = 0; i < len; ++i) { 316 char c = s.charAt(i); 317 if (!isTokenChar(c)) { 318 return false; 319 } 320 } 321 return true; 322 } else { 323 return false; 324 } 325 } 326 327 /** 328 * A simple parser test, 329 * for debugging... 330 * 331 public static void main(String[] args) 332 throws MimeTypeParseException, IOException { 333 for (int i = 0; i < args.length; ++i) { 334 System.out.println("Original: " + args[i]); 335 336 MimeType type = new MimeType(args[i]); 337 338 System.out.println("Short: " + type.getBaseType()); 339 System.out.println("Parsed: " + type.toString()); 340 System.out.println(); 341 } 342 } 343 */ 344 }