001 package railo.commons.lang.mimetype; 002 003 import java.util.Arrays; 004 import java.util.HashMap; 005 import java.util.Map; 006 007 import railo.commons.lang.StringUtil; 008 import railo.runtime.op.Caster; 009 import railo.runtime.type.UDF; 010 import railo.runtime.type.util.ListUtil; 011 012 public class MimeType { 013 014 private static int DEFAULT_MXB=100000; 015 private static double DEFAULT_MXT=5; 016 private static double DEFAULT_QUALITY=1; 017 018 public static final MimeType ALL = new MimeType(null,null,null); 019 public static final MimeType APPLICATION_JSON = new MimeType("application","json",null); 020 public static final MimeType APPLICATION_XML = new MimeType("application","xml",null); 021 public static final MimeType APPLICATION_WDDX = new MimeType("application","wddx",null); 022 public static final MimeType APPLICATION_CFML = new MimeType("application","cfml",null); 023 public static final MimeType APPLICATION_PLAIN = new MimeType("application","lazy",null); 024 025 public static final MimeType IMAGE_GIF = new MimeType("image","gif",null); 026 public static final MimeType IMAGE_JPG = new MimeType("image","jpeg",null); 027 public static final MimeType IMAGE_PNG = new MimeType("image","png",null); 028 public static final MimeType IMAGE_TIFF = new MimeType("image","tiff",null); 029 public static final MimeType IMAGE_BMP = new MimeType("image","bmp",null); 030 public static final MimeType IMAGE_WBMP = new MimeType("image","vnd.wap.wbmp",null); 031 public static final MimeType IMAGE_FBX = new MimeType("image","fbx",null); 032 public static final MimeType IMAGE_PNM = new MimeType("image","x-portable-anymap",null); 033 public static final MimeType IMAGE_PGM = new MimeType("image","x-portable-graymap",null); 034 public static final MimeType IMAGE_PBM = new MimeType("image","x-portable-bitmap",null); 035 public static final MimeType IMAGE_ICO = new MimeType("image","ico",null); 036 public static final MimeType IMAGE_PSD = new MimeType("image","psd",null); 037 public static final MimeType IMAGE_ASTERIX = new MimeType("image",null,null); 038 public static final MimeType APPLICATION_JAVA = new MimeType("application","java",null); 039 040 private String type; 041 private String subtype; 042 //private double quality; 043 //private int mxb; 044 //private double mxt; 045 private Map<String,String> properties; 046 private double q=-1; 047 048 049 private MimeType(String type, String subtype, Map<String,String> properties) { 050 //if(quality<0 || quality>1) 051 // throw new RuntimeException("quality must be a number between 0 and 1, now ["+quality+"]"); 052 053 054 this.type=type; 055 this.subtype=subtype; 056 this.properties=properties; 057 //this.quality=quality; 058 //this.mxb=mxb; 059 //this.mxt=mxt; 060 } 061 062 063 064 private static MimeType getInstance(String type, String subtype, Map<String,String> properties) { 065 // TODO read this from a external File 066 if("text".equals(type)) { 067 if("xml".equals(subtype)) return new MimeType("application", "xml", properties); 068 if("x-json".equals(subtype)) return new MimeType("application", "json", properties); 069 if("javascript".equals(subtype)) return new MimeType("application", "json", properties); 070 if("x-javascript".equals(subtype)) return new MimeType("application", "json", properties); 071 if("wddx".equals(subtype)) return new MimeType("application", "wddx", properties); 072 } 073 else if("application".equals(type)) { 074 if("x-json".equals(subtype)) return new MimeType("application", "json", properties); 075 if("javascript".equals(subtype)) return new MimeType("application", "json", properties); 076 if("x-javascript".equals(subtype)) return new MimeType("application", "json", properties); 077 078 if("jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); 079 if("x-jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); 080 081 if("png".equals(subtype)) return new MimeType("image", "png", properties); 082 if("x-png".equals(subtype)) return new MimeType("image", "png", properties); 083 084 if("tiff".equals(subtype)) return new MimeType("image", "tiff", properties); 085 if("tif".equals(subtype)) return new MimeType("image", "tiff", properties); 086 if("x-tiff".equals(subtype)) return new MimeType("image", "tiff", properties); 087 if("x-tif".equals(subtype)) return new MimeType("image", "tiff", properties); 088 089 if("fpx".equals(subtype)) return new MimeType("image", "fpx", properties); 090 if("x-fpx".equals(subtype)) return new MimeType("image", "fpx", properties); 091 if("vnd.fpx".equals(subtype)) return new MimeType("image", "fpx", properties); 092 if("vnd.netfpx".equals(subtype)) return new MimeType("image", "fpx", properties); 093 094 if("ico".equals(subtype)) return new MimeType("image", "ico", properties); 095 if("x-ico".equals(subtype)) return new MimeType("image", "ico", properties); 096 if("x-icon".equals(subtype)) return new MimeType("image", "ico", properties); 097 098 if("psd".equals(subtype)) return new MimeType("image", "psd", properties); 099 if("x-photoshop".equals(subtype)) return new MimeType("image", "psd", properties); 100 if("photoshop".equals(subtype)) return new MimeType("image", "psd", properties); 101 } 102 else if("image".equals(type)) { 103 if("gi_".equals(subtype)) return new MimeType("image", "gif", properties); 104 105 if("pjpeg".equals(subtype)) return new MimeType("image", "jpeg", properties); 106 if("jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); 107 if("jpe".equals(subtype)) return new MimeType("image", "jpeg", properties); 108 if("vnd.swiftview-jpeg".equals(subtype)) return new MimeType("image", "jpeg", properties); 109 if("pipeg".equals(subtype)) return new MimeType("image", "jpeg", properties); 110 if("jp_".equals(subtype)) return new MimeType("image", "jpeg", properties); 111 112 if("x-png".equals(subtype)) return new MimeType("image", "png", properties); 113 114 if("tif".equals(subtype)) return new MimeType("image", "tiff", properties); 115 if("x-tif".equals(subtype)) return new MimeType("image", "tiff", properties); 116 if("x-tiff".equals(subtype)) return new MimeType("image", "tiff", properties); 117 118 if("x-fpx".equals(subtype)) return new MimeType("image", "fpx", properties); 119 if("vnd.fpx".equals(subtype)) return new MimeType("image", "fpx", properties); 120 if("vnd.netfpx".equals(subtype)) return new MimeType("image", "fpx", properties); 121 122 if("x-portable/graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 123 if("portable graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 124 if("x-pnm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 125 if("pnm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 126 127 if("x-portable/graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 128 if("portable graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 129 if("x-pgm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); 130 if("pgm".equals(subtype)) return new MimeType("image", "x-portable-graymap", properties); 131 132 if("portable bitmap".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); 133 if("x-portable/bitmap".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); 134 if("x-pbm".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); 135 if("pbm".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); 136 137 if("x-ico".equals(subtype)) return new MimeType("image", "ico", properties); 138 if("x-icon".equals(subtype)) return new MimeType("image", "ico", properties); 139 140 if("x-photoshop".equals(subtype)) return new MimeType("image", "psd", properties); 141 if("photoshop".equals(subtype)) return new MimeType("image", "psd", properties); 142 } 143 else if("zz-application".equals(type)) { 144 if("zz-winassoc-psd".equals(subtype)) return new MimeType("image", "psd", properties); 145 } 146 /* 147 148 if("image/x-p".equals(mt)) return "ppm"; 149 if("image/x-ppm".equals(mt)) return "ppm"; 150 if("image/ppm".equals(mt)) return "ppm"; 151 152 */ 153 return new MimeType(type, subtype, properties); 154 } 155 156 157 /** 158 * returns a mimetype that match given string 159 * @param strMimeType 160 * @return 161 */ 162 public static MimeType getInstance(String strMimeType){ 163 if(strMimeType==null) return ALL; 164 strMimeType=strMimeType.trim(); 165 if("*".equals(strMimeType) || strMimeType.length()==0) return ALL; 166 167 String[] arr = ListUtil.listToStringArray(strMimeType, ';'); 168 169 String[] arrCT = ListUtil.listToStringArray(arr[0].trim(), '/'); 170 171 String type=arrCT[0].trim(); 172 if("*".equals(type)) type=null; 173 174 if(arrCT.length==1) return getInstance(type,null,null); 175 176 String subtype=arrCT[1].trim(); 177 if("*".equals(subtype)) subtype=null; 178 179 if(arr.length==1) return getInstance(type,subtype,null); 180 181 182 final Map<String,String> properties=new HashMap<String, String>(); 183 String entry; 184 String[] _arr; 185 for(int i=1;i<arr.length;i++){ 186 entry=arr[i].trim(); 187 _arr = ListUtil.listToStringArray(entry, '='); 188 if(arr.length<2) continue; 189 properties.put(_arr[0].trim().toLowerCase(), _arr[1].trim()); 190 //if(_arr[0].equals("q")) quality=Caster.toDoubleValue(_arr[1],1); 191 //if(_arr[0].equals("mxb")) mxb=Caster.toIntValue(_arr[1],100000); 192 //if(_arr[0].equals("mxt")) mxt=Caster.toDoubleValue(_arr[1],5); 193 } 194 return getInstance(type,subtype,properties); 195 } 196 197 public static MimeType[] getInstances(String strMimeTypes, char delimiter) { 198 if(StringUtil.isEmpty(strMimeTypes,true)) return new MimeType[0]; 199 String[] arr = ListUtil.trimItems(ListUtil.listToStringArray(strMimeTypes, delimiter)); 200 MimeType[] mtes=new MimeType[arr.length]; 201 for(int i=0;i<arr.length;i++){ 202 mtes[i]=getInstance(arr[i]); 203 } 204 return mtes; 205 } 206 207 208 209 210 /** 211 * @return the type 212 */ 213 public String getType() { 214 return type; 215 } 216 217 /** 218 * @return the subtype 219 */ 220 public String getSubtype() { 221 return subtype; 222 } 223 224 /** 225 * @return the type 226 */ 227 String getTypeNotNull() { 228 return type==null?"*":type; 229 } 230 231 /** 232 * @return the subtype 233 */ 234 String getSubtypeNotNull() { 235 return subtype==null?"*":subtype; 236 } 237 238 239 public double getQuality() { 240 if(q==-1){ 241 if(properties==null) q=DEFAULT_QUALITY; 242 else q= Caster.toDoubleValue(properties.get("q"),DEFAULT_QUALITY); 243 } 244 return q; 245 } 246 /* 247 public int getMxb() { 248 return Caster.toIntValue(properties.get("mxb"),DEFAULT_MXB); 249 } 250 251 public double getMxt() { 252 return Caster.toDoubleValue(properties.get("mxt"),DEFAULT_MXT); 253 }*/ 254 255 public boolean hasWildCards() { 256 return type==null || subtype==null; 257 } 258 259 /** 260 * checks if given mimetype is covered by current mimetype 261 * @param other 262 * @return 263 */ 264 public boolean match(MimeType other){ 265 if(this==other) return true; 266 if(type!=null && other.type!=null && !type.equals(other.type)) return false; 267 if(subtype!=null && other.subtype!=null && !subtype.equals(other.subtype)) return false; 268 return true; 269 } 270 271 public MimeType bestMatch(MimeType[] others){ 272 MimeType best=null; 273 274 for(int i=0;i<others.length;i++){ 275 if(match(others[i]) && (best==null || best.getQuality()<others[i].getQuality())) { 276 best=others[i]; 277 } 278 } 279 return best; 280 } 281 282 283 284 /** 285 * checks if other is from the same type, just type and subtype are checked, properties (q,mxb,mxt) are ignored. 286 * @param other 287 * @return 288 */ 289 public boolean same(MimeType other){ 290 if(this==other) return true; 291 return getTypeNotNull().equals(other.getTypeNotNull()) && getSubtypeNotNull().equals(other.getSubtypeNotNull()); 292 } 293 294 public boolean equals(Object obj){ 295 if(obj==this) return true; 296 297 298 MimeType other; 299 if(obj instanceof MimeType) 300 other=(MimeType) obj; 301 else if(obj instanceof String) 302 other=MimeType.getInstance((String)obj); 303 else 304 return false; 305 306 if(!same(other)) return false; 307 308 return other.toString().equals(toString()); 309 } 310 311 public String toString(){ 312 StringBuilder sb=new StringBuilder(); 313 sb.append(type==null?"*":type); 314 sb.append("/"); 315 sb.append(subtype==null?"*":subtype); 316 if(properties!=null){ 317 String[] keys = properties.keySet().toArray(new String[properties.size()]); 318 Arrays.sort(keys); 319 //Iterator<Entry<String, String>> it = properties.entrySet().iterator(); 320 //Entry<String, String> e; 321 for(int i=0;i<keys.length;i++){ 322 sb.append("; "); 323 sb.append(keys[i]); 324 sb.append("="); 325 sb.append(properties.get(keys[i])); 326 } 327 } 328 return sb.toString(); 329 } 330 331 332 333 public static MimeType toMimetype(int format, MimeType defaultValue) { 334 switch(format){ 335 case UDF.RETURN_FORMAT_JSON:return MimeType.APPLICATION_JSON; 336 case UDF.RETURN_FORMAT_WDDX:return MimeType.APPLICATION_WDDX; 337 case UDF.RETURN_FORMAT_SERIALIZE:return MimeType.APPLICATION_CFML; 338 case UDF.RETURN_FORMAT_XML:return MimeType.APPLICATION_XML; 339 case UDF.RETURN_FORMAT_PLAIN:return MimeType.APPLICATION_PLAIN; 340 341 } 342 return defaultValue; 343 } 344 345 public static int toFormat(MimeType mt, int defaultValue) { 346 if(mt==null) return defaultValue; 347 if(MimeType.APPLICATION_JSON.same(mt)) return UDF.RETURN_FORMAT_JSON; 348 if(MimeType.APPLICATION_WDDX.same(mt)) return UDF.RETURN_FORMAT_WDDX; 349 if(MimeType.APPLICATION_CFML.same(mt)) return UDF.RETURN_FORMAT_SERIALIZE; 350 if(MimeType.APPLICATION_XML.same(mt)) return UDF.RETURN_FORMAT_XML; 351 if(MimeType.APPLICATION_PLAIN.same(mt)) return UDF.RETURN_FORMAT_PLAIN; 352 return defaultValue; 353 } 354 }