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.io.File; 025 import java.io.FileReader; 026 import java.io.StringReader; 027 import java.io.InputStream; 028 import java.io.InputStreamReader; 029 import java.io.BufferedReader; 030 import java.io.IOException; 031 import java.util.Map; 032 import java.util.HashMap; 033 import java.util.StringTokenizer; 034 035 /** 036 * This class defines mappings between MIME types and the corresponding 037 * file name extensions. The mappings are defined as lines formed 038 * by a MIME type name followed by a list of extensions separated 039 * by a whitespace. 040 * 041 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 042 * @author Daniel Rall 043 * @version $Id: MimeTypeMapper.java 826489 2009-10-18 18:54:59Z tv $ 044 */ 045 public class MimeTypeMapper 046 { 047 /** 048 * Mappings between MIME types and file name extensions. 049 */ 050 private HashMap mimeTypeExtensions = new HashMap(); 051 protected HashMap extensionMimeTypes = new HashMap(); 052 053 /** 054 * Constructs an empty MIME type mapper. 055 */ 056 public MimeTypeMapper() 057 { 058 // do nothing 059 } 060 061 /** 062 * Constructs a mapper reading from a stream. 063 * 064 * @param input an input stream. 065 * @throws IOException for an incorrect stream. 066 */ 067 public MimeTypeMapper(InputStream input) 068 throws IOException 069 { 070 parse(new BufferedReader( 071 new InputStreamReader(input,CharSetMap.DEFAULT_CHARSET))); 072 } 073 074 /** 075 * Constructs a mapper reading from a file. 076 * 077 * @param file an input file. 078 * @throws IOException for an incorrect file. 079 */ 080 public MimeTypeMapper(File file) 081 throws IOException 082 { 083 FileReader freader = new FileReader(file); 084 try 085 { 086 parse(new BufferedReader(freader)); 087 } 088 finally 089 { 090 try 091 { 092 freader.close(); 093 } 094 catch (IOException x) 095 { 096 // ignore 097 } 098 } 099 } 100 101 /** 102 * Constructs a mapper reading from a file path. 103 * 104 * @param path an input file path. 105 * @throws IOException for an incorrect file. 106 */ 107 public MimeTypeMapper(String path) 108 throws IOException 109 { 110 this(new File(path)); 111 } 112 113 /** 114 * Sets a MIME content type mapping to extensions. 115 * 116 * @param spec a MIME type extension specification to parse. 117 */ 118 public void setContentType(String spec) 119 { 120 try 121 { 122 parse(new BufferedReader(new StringReader(spec))); 123 } 124 catch (IOException x) 125 { 126 // ignore 127 } 128 } 129 130 /** 131 * Gets a MIME content type corresponding to a specified file name 132 * extension. If a mapping is initially not found, tries a second 133 * lookup using the provided extension in lower case. 134 * 135 * @param ext The file name extension to resolve. 136 * @return The MIME type, or <code>null</code> if not found. 137 */ 138 public String getContentType(String ext) 139 { 140 String mimeType = (String) mimeTypeExtensions.get(ext); 141 if (mimeType == null && ext != null) 142 { 143 String lcExt = ext.toLowerCase(); 144 if (!ext.equals(lcExt)) 145 { 146 // Original file extension didn't resolve, but was 147 // mixed case. Try it again with lower case chars. 148 mimeType = (String) mimeTypeExtensions.get(lcExt); 149 } 150 } 151 return mimeType; 152 } 153 154 /** 155 * Gets a file name extension corresponding to a specified MIME content type. 156 * 157 * @param type a MIME type as a string. 158 * @return the corresponding file name extension or null. 159 */ 160 public String getExtension(String type) 161 { 162 return (String) extensionMimeTypes.get(type); 163 } 164 165 /** 166 * Parses MIME type extensions. 167 * 168 * @param reader a reader to parse. 169 * @throws IOException for an incorrect reader. 170 */ 171 protected synchronized void parse(BufferedReader reader) 172 throws IOException 173 { 174 int l,count = 0; 175 String next; 176 String str = null; 177 HashMap mimeTypes = (HashMap) extensionMimeTypes.clone(); 178 HashMap extensions = (HashMap) mimeTypeExtensions.clone(); 179 while ((next = reader.readLine()) != null) 180 { 181 str = str == null ? next : str + next; 182 if ((l = str.length()) == 0) 183 { 184 str = null; 185 continue; 186 } 187 // Check for continuation line. 188 if (str.charAt(l - 1) != '\\') 189 { 190 count += parseMimeTypeExtension(str,mimeTypes,extensions); 191 str = null; 192 } 193 else 194 { 195 str = str.substring(0,l - 1); 196 } 197 } 198 if (str != null) 199 { 200 count += parseMimeTypeExtension(str,mimeTypes,extensions); 201 } 202 if (count > 0) 203 { 204 extensionMimeTypes = mimeTypes; 205 mimeTypeExtensions = extensions; 206 } 207 } 208 209 /** 210 * Parses a MIME type extension. 211 * 212 * @param spec an extension specification to parse. 213 * @param mimeTypes a map of MIME types. 214 * @param extensions a map of extensions. 215 * @return the number of file name extensions parsed. 216 */ 217 protected int parseMimeTypeExtension(String spec, 218 Map mimeTypes, 219 Map extensions) 220 { 221 int count = 0; 222 spec = spec.trim(); 223 if ((spec.length() > 0) && 224 (spec.charAt(0) != '#')) 225 { 226 StringTokenizer tokens = new StringTokenizer(spec); 227 String type = tokens.nextToken(); 228 String ext; 229 while (tokens.hasMoreTokens()) 230 { 231 ext = tokens.nextToken(); 232 if (ext.length() == 0) 233 { 234 continue; 235 } 236 extensions.put(ext,type); 237 if (count++ == 0) 238 { 239 mimeTypes.put(type,ext); 240 } 241 } 242 } 243 return count; 244 } 245 }