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