package railo.commons.lang.mimetype; import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import railo.commons.io.CharsetUtil; import railo.commons.lang.StringUtil; import railo.runtime.op.Caster; import railo.runtime.type.UDF; import railo.runtime.type.UDFPlus; import railo.runtime.type.util.ListUtil; public class MimeType { private static int DEFAULT_MXB=100000; private static double DEFAULT_MXT=5; private static double DEFAULT_QUALITY=1; private static Charset DEFAULT_CHARSET=null; public static final MimeType ALL = new MimeType(null,null,null); public static final MimeType APPLICATION_JSON = new MimeType("application","json",null); public static final MimeType APPLICATION_XML = new MimeType("application","xml",null); public static final MimeType APPLICATION_WDDX = new MimeType("application","wddx",null); public static final MimeType APPLICATION_CFML = new MimeType("application","cfml",null); public static final MimeType APPLICATION_PLAIN = new MimeType("application","lazy",null); public static final MimeType IMAGE_GIF = new MimeType("image","gif",null); public static final MimeType IMAGE_JPG = new MimeType("image","jpeg",null); public static final MimeType IMAGE_PNG = new MimeType("image","png",null); public static final MimeType IMAGE_TIFF = new MimeType("image","tiff",null); public static final MimeType IMAGE_BMP = new MimeType("image","bmp",null); public static final MimeType IMAGE_WBMP = new MimeType("image","vnd.wap.wbmp",null); public static final MimeType IMAGE_FBX = new MimeType("image","fbx",null); public static final MimeType IMAGE_PNM = new MimeType("image","x-portable-anymap",null); public static final MimeType IMAGE_PGM = new MimeType("image","x-portable-graymap",null); public static final MimeType IMAGE_PBM = new MimeType("image","x-portable-bitmap",null); public static final MimeType IMAGE_ICO = new MimeType("image","ico",null); public static final MimeType IMAGE_PSD = new MimeType("image","psd",null); public static final MimeType IMAGE_ASTERIX = new MimeType("image",null,null); public static final MimeType APPLICATION_JAVA = new MimeType("application","java",null); public static final MimeType TEXT_HTML = new MimeType("text","html",null); private String type; private String subtype; //private double quality; //private int mxb; //private double mxt; private Map<String,String> properties; private double q=-1; private Charset cs; private boolean initCS=true; private MimeType(String type, String subtype, Map<String,String> properties) { //if(quality<0 || quality>1) // throw new RuntimeException("quality must be a number between 0 and 1, now ["+quality+"]"); this.type=type; this.subtype=subtype; this.properties=properties; //this.quality=quality; //this.mxb=mxb; //this.mxt=mxt; } private static MimeType getInstance(String type, String subtype, Map<String,String> properties) { // TODO read this from a external File if("text".equals(type)) { if("xml".equals(subtype)) return new MimeType("application", "xml", properties); if("x-json".equals(subtype)) return new MimeType("application", "json", properties); if("javascript".equals(subtype)) return new MimeType("application", "json", properties); if("x-javascript".equals(subtype)) return new MimeType("application", "json", properties); if("wddx".equals(subtype)) return new MimeType("application", "wddx", properties); } else if("application".equals(type)) { if("x-json".equals(subtype)) return new MimeType("application", "json", properties); if("javascript".equals(subtype)) return new MimeType("application", "json", properties); if("x-javascript".equals(subtype)) return new MimeType("application", "json", properties); if("jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("x-jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("png".equals(subtype)) return new MimeType("image", "png", properties); if("x-png".equals(subtype)) return new MimeType("image", "png", properties); if("tiff".equals(subtype)) return new MimeType("image", "tiff", properties); if("tif".equals(subtype)) return new MimeType("image", "tiff", properties); if("x-tiff".equals(subtype)) return new MimeType("image", "tiff", properties); if("x-tif".equals(subtype)) return new MimeType("image", "tiff", properties); if("fpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("x-fpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("vnd.fpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("vnd.netfpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("ico".equals(subtype)) return new MimeType("image", "ico", properties); if("x-ico".equals(subtype)) return new MimeType("image", "ico", properties); if("x-icon".equals(subtype)) return new MimeType("image", "ico", properties); if("psd".equals(subtype)) return new MimeType("image", "psd", properties); if("x-photoshop".equals(subtype)) return new MimeType("image", "psd", properties); if("photoshop".equals(subtype)) return new MimeType("image", "psd", properties); } else if("image".equals(type)) { if("gi_".equals(subtype)) return new MimeType("image", "gif", properties); if("pjpeg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("jpg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("jpe".equals(subtype)) return new MimeType("image", "jpeg", properties); if("vnd.swiftview-jpeg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("pipeg".equals(subtype)) return new MimeType("image", "jpeg", properties); if("jp_".equals(subtype)) return new MimeType("image", "jpeg", properties); if("x-png".equals(subtype)) return new MimeType("image", "png", properties); if("tif".equals(subtype)) return new MimeType("image", "tiff", properties); if("x-tif".equals(subtype)) return new MimeType("image", "tiff", properties); if("x-tiff".equals(subtype)) return new MimeType("image", "tiff", properties); if("x-fpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("vnd.fpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("vnd.netfpx".equals(subtype)) return new MimeType("image", "fpx", properties); if("x-portable/graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("portable graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("x-pnm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("pnm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("x-portable/graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("portable graymap".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("x-pgm".equals(subtype)) return new MimeType("image", "x-portable-anymap", properties); if("pgm".equals(subtype)) return new MimeType("image", "x-portable-graymap", properties); if("portable bitmap".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); if("x-portable/bitmap".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); if("x-pbm".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); if("pbm".equals(subtype)) return new MimeType("image", "x-portable-bitmap", properties); if("x-ico".equals(subtype)) return new MimeType("image", "ico", properties); if("x-icon".equals(subtype)) return new MimeType("image", "ico", properties); if("x-photoshop".equals(subtype)) return new MimeType("image", "psd", properties); if("photoshop".equals(subtype)) return new MimeType("image", "psd", properties); } else if("zz-application".equals(type)) { if("zz-winassoc-psd".equals(subtype)) return new MimeType("image", "psd", properties); } /* if("image/x-p".equals(mt)) return "ppm"; if("image/x-ppm".equals(mt)) return "ppm"; if("image/ppm".equals(mt)) return "ppm"; */ return new MimeType(type, subtype, properties); } /** * returns a mimetype that match given string * @param strMimeType * @return */ public static MimeType getInstance(String strMimeType){ if(strMimeType==null) return ALL; strMimeType=strMimeType.trim(); if("*".equals(strMimeType) || strMimeType.length()==0) return ALL; String[] arr = ListUtil.listToStringArray(strMimeType, ';'); if(arr.length==0) return ALL; String[] arrCT = ListUtil.listToStringArray(arr[0].trim(), '/'); // subtype String type=null,subtype=null; // type if(arrCT.length>=1) { type=arrCT[0].trim(); if("*".equals(type)) type=null; if(arrCT.length>=2) { subtype=arrCT[1].trim(); if("*".equals(subtype)) subtype=null; } } if(arr.length==1) return getInstance(type,subtype,null); final Map<String,String> properties=new HashMap<String, String>(); String entry; String[] _arr; for(int i=1;i<arr.length;i++){ entry=arr[i].trim(); _arr = ListUtil.listToStringArray(entry, '='); if(_arr.length>=2) properties.put(_arr[0].trim().toLowerCase(), _arr[1].trim()); else if(_arr.length==1 && !_arr[0].trim().toLowerCase().equals("*")) properties.put(_arr[0].trim().toLowerCase(),""); } return getInstance(type,subtype,properties); } public static MimeType[] getInstances(String strMimeTypes, char delimiter) { if(StringUtil.isEmpty(strMimeTypes,true)) return new MimeType[0]; String[] arr = ListUtil.trimItems(ListUtil.listToStringArray(strMimeTypes, delimiter)); MimeType[] mtes=new MimeType[arr.length]; for(int i=0;i<arr.length;i++){ mtes[i]=getInstance(arr[i]); } return mtes; } /** * @return the type */ public String getType() { return type; } /** * @return the subtype */ public String getSubtype() { return subtype; } public Map<String, String> getProperties() { return properties; } /** * @return the type */ String getTypeNotNull() { return type==null?"*":type; } /** * @return the subtype */ String getSubtypeNotNull() { return subtype==null?"*":subtype; } public double getQuality() { if(q==-1){ if(properties==null) q=DEFAULT_QUALITY; else q= Caster.toDoubleValue(getProperty("q"),DEFAULT_QUALITY); } return q; } public Charset getCharset() { if(initCS){ if(properties==null) cs=DEFAULT_CHARSET; else { String str = getProperty("charset"); cs= StringUtil.isEmpty(str)?DEFAULT_CHARSET:CharsetUtil.toCharset(str); } initCS=false; } return cs; } /* public int getMxb() { return Caster.toIntValue(properties.get("mxb"),DEFAULT_MXB); } public double getMxt() { return Caster.toDoubleValue(properties.get("mxt"),DEFAULT_MXT); }*/ private String getProperty(String name) { if(properties!=null) { String value = properties.get(name); if(value!=null)return value; Iterator<Entry<String, String>> it = properties.entrySet().iterator(); Entry<String, String> e; while(it.hasNext()){ e = it.next(); if(name.equalsIgnoreCase(e.getKey())) return e.getValue(); } } return null; } public boolean hasWildCards() { return type==null || subtype==null; } /** * checks if given mimetype is covered by current mimetype * @param other * @return */ public boolean match(MimeType other){ if(this==other) return true; if(type!=null && other.type!=null && !type.equals(other.type)) return false; if(subtype!=null && other.subtype!=null && !subtype.equals(other.subtype)) return false; return true; } public MimeType bestMatch(MimeType[] others){ MimeType best=null; for(int i=0;i<others.length;i++){ if(match(others[i]) && (best==null || best.getQuality()<others[i].getQuality())) { best=others[i]; } } return best; } /** * checks if other is from the same type, just type and subtype are checked, properties (q,mxb,mxt) are ignored. * @param other * @return */ public boolean same(MimeType other){ if(this==other) return true; return getTypeNotNull().equals(other.getTypeNotNull()) && getSubtypeNotNull().equals(other.getSubtypeNotNull()); } public boolean equals(Object obj){ if(obj==this) return true; MimeType other; if(obj instanceof MimeType) other=(MimeType) obj; else if(obj instanceof String) other=MimeType.getInstance((String)obj); else return false; if(!same(other)) return false; return other.toString().equals(toString()); } public String toString(){ StringBuilder sb=new StringBuilder(); sb.append(type==null?"*":type); sb.append("/"); sb.append(subtype==null?"*":subtype); if(properties!=null){ String[] keys = properties.keySet().toArray(new String[properties.size()]); Arrays.sort(keys); //Iterator<Entry<String, String>> it = properties.entrySet().iterator(); //Entry<String, String> e; for(int i=0;i<keys.length;i++){ sb.append("; "); sb.append(keys[i]); sb.append("="); sb.append(properties.get(keys[i])); } } return sb.toString(); } public static MimeType toMimetype(int format, MimeType defaultValue) { switch(format){ case UDF.RETURN_FORMAT_JSON:return MimeType.APPLICATION_JSON; case UDF.RETURN_FORMAT_WDDX:return MimeType.APPLICATION_WDDX; case UDF.RETURN_FORMAT_SERIALIZE:return MimeType.APPLICATION_CFML; case UDF.RETURN_FORMAT_XML:return MimeType.APPLICATION_XML; case UDF.RETURN_FORMAT_PLAIN:return MimeType.APPLICATION_PLAIN; case UDFPlus.RETURN_FORMAT_JAVA:return MimeType.APPLICATION_JAVA; } return defaultValue; } public static int toFormat(List<MimeType> mimeTypes,int ignore, int defaultValue) { if(mimeTypes==null || mimeTypes.size()==0) return defaultValue; Iterator<MimeType> it = mimeTypes.iterator(); int res; while(it.hasNext()){ res=toFormat(it.next(), -1); if(res!=-1 && res!=ignore) return res; } return defaultValue; } public static int toFormat(MimeType mt, int defaultValue) { if(mt==null) return defaultValue; if(MimeType.APPLICATION_JSON.same(mt)) return UDF.RETURN_FORMAT_JSON; if(MimeType.APPLICATION_WDDX.same(mt)) return UDF.RETURN_FORMAT_WDDX; if(MimeType.APPLICATION_CFML.same(mt)) return UDF.RETURN_FORMAT_SERIALIZE; if(MimeType.APPLICATION_XML.same(mt)) return UDF.RETURN_FORMAT_XML; if(MimeType.APPLICATION_PLAIN.same(mt)) return UDF.RETURN_FORMAT_PLAIN; if(MimeType.APPLICATION_JAVA.same(mt)) return UDFPlus.RETURN_FORMAT_JAVA; return defaultValue; } }