/*
* MimetypesFileTypeMap.java
* Copyright (C) 2004 The Free Software Foundation
*
* This file is part of GNU Java Activation Framework (JAF), a library.
*
* GNU JAF is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GNU JAF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, if you link this library with other files to
* produce an executable, this library does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* This exception does not however invalidate any other reasons why the
* executable file might be covered by the GNU General Public License.
*/
package javax.activation;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Implementation of FileTypeMap that uses the <tt>mime.types</tt> format.
* File entries are searched for in the following locations and order:
* <ol>
* <li>Programmatically added entries to this instance</li>
* <li>The file <tt>.mime.types</tt> in the user's home directory</li>
* <li>The file <i><java.home></i><tt>/lib/mime.types</tt></li>
* <li>The resource <tt>META-INF/mime.types</tt></li>
* <li>The resource <tt>META-INF/mimetypes.default</tt> in the JAF
* distribution</li>
* </ol>
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
* @version 1.1
*/
public class MimetypesFileTypeMap
extends FileTypeMap
{
private static final int PROG = 0;
private static final int HOME = 1;
private static final int SYS = 2;
private static final int JAR = 3;
private static final int DEF = 4;
private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
private static boolean debug = false;
static
{
try
{
String d = System.getProperty("javax.activation.debug");
debug = Boolean.valueOf(d).booleanValue();
}
catch (SecurityException e)
{
}
}
private Map[] mimetypes;
/**
* Default constructor.
*/
public MimetypesFileTypeMap()
{
init(null);
}
/**
* Constructor specifying a filename.
* @param mimeTypeFileName the name of the file to read mime.types
* entries from
*/
public MimetypesFileTypeMap(String mimeTypeFileName)
throws IOException
{
Reader in = null;
try
{
in = new FileReader(mimeTypeFileName);
init(in);
}
finally
{
if (in != null)
{
in.close();
}
}
}
/**
* Constructor specifying an input stream.
* @param is the input stream to read mime.types entries from
*/
public MimetypesFileTypeMap(InputStream is)
{
init(new InputStreamReader(is));
}
private void init(Reader in)
{
mimetypes = new Map[5];
for (int i = 0; i < mimetypes.length; i++)
{
mimetypes[i] = new HashMap();
}
if (in != null)
{
if (debug)
{
System.out.println("MimetypesFileTypeMap: load PROG");
}
try
{
parse(mimetypes[PROG], in);
}
catch (IOException e)
{
}
}
if (debug)
{
System.out.println("MimetypesFileTypeMap: load HOME");
}
try
{
String home = System.getProperty("user.home");
if (home != null)
{
parseFile(mimetypes[HOME], new StringBuffer(home)
.append(File.separatorChar)
.append(".mime.types")
.toString());
}
}
catch (SecurityException e)
{
}
if (debug)
{
System.out.println("MimetypesFileTypeMap: load SYS");
}
try
{
parseFile(mimetypes[SYS],
new StringBuffer(System.getProperty("java.home"))
.append(File.separatorChar) .append("lib")
.append(File.separatorChar)
.append("mime.types")
.toString());
}
catch (SecurityException e)
{
}
if (debug)
{
System.out.println("MimetypesFileTypeMap: load JAR");
}
List systemResources = getSystemResources("META-INF/mime.types");
int len = systemResources.size();
if (len > 0)
{
for (int i = 0; i < len ; i++)
{
Reader urlIn = null;
URL url = (URL)systemResources.get(i);
try
{
urlIn = new InputStreamReader(url.openStream());
parse(mimetypes[JAR], urlIn);
}
catch (IOException e)
{
}
finally
{
if (urlIn != null)
{
try
{
urlIn.close();
}
catch (IOException e)
{
}
}
}
}
}
else
{
parseResource(mimetypes[JAR], "/META-INF/mime.types");
}
if (debug)
{
System.out.println("MimetypesFileTypeMap: load DEF");
}
parseResource(mimetypes[DEF], "/META-INF/mimetypes.default");
}
/**
* Adds entries prorammatically to the registry.
* @param mime_types a mime.types formatted entries string
*/
public synchronized void addMimeTypes(String mime_types)
{
if (debug)
{
System.out.println("MimetypesFileTypeMap: add to PROG");
}
try
{
parse(mimetypes[PROG], new StringReader(mime_types));
}
catch (IOException e)
{
}
}
/**
* Returns the MIME content type of the file.
* This calls <code>getContentType(f.getName())</code>.
* @param f the file
*/
public String getContentType(File f)
{
return getContentType(f.getName());
}
/**
* Returns the MIME type based on the given filename.
* If no entry is found, returns "application/octet-stream".
* @param filename the filename
*/
public synchronized String getContentType(String filename)
{
int di = filename.lastIndexOf('.');
if (di < 0)
{
return DEFAULT_MIME_TYPE;
}
String tail = filename.substring(di + 1);
if (tail.length() < 1)
{
return DEFAULT_MIME_TYPE;
}
for (int i = 0; i < mimetypes.length; i++)
{
String mimeType = (String)mimetypes[i].get(tail);
if (mimeType != null)
{
return mimeType;
}
}
return DEFAULT_MIME_TYPE;
}
private void parseFile(Map mimetypes, String filename)
{
Reader in = null;
try
{
in = new FileReader(filename);
parse(mimetypes, in);
}
catch (IOException e)
{
}
finally
{
if (in != null)
{
try
{
in.close();
}
catch (IOException e)
{
}
}
}
}
private void parseResource(Map mimetypes, String name)
{
Reader in = null;
try
{
InputStream is = getClass().getResourceAsStream(name);
if (is != null)
{
in = new InputStreamReader(is);
parse(mimetypes, in);
}
}
catch (IOException e)
{
}
finally
{
if (in != null)
{
try
{
in.close();
}
catch (IOException e)
{
}
}
}
}
private void parse(Map mimetypes, Reader in)
throws IOException
{
BufferedReader br = new BufferedReader(in);
StringBuffer buf = null;
for (String line = br.readLine(); line != null; line = br.readLine())
{
line = line.trim();
int len = line.length();
if (len == 0 || line.charAt(0) == '#')
{
continue; // Empty line / comment
}
if (line.charAt(len - 1) == '\\')
{
if (buf == null)
{
buf = new StringBuffer();
}
buf.append(line.substring(0, len - 1));
}
else if (buf != null)
{
buf.append(line);
parseEntry(mimetypes, buf.toString());
buf = null;
}
else
{
parseEntry(mimetypes, line);
}
}
}
private void parseEntry(Map mimetypes, String line)
{
// Tokenize
String mimeType = null;
char[] chars = line.toCharArray();
int len = chars.length;
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < len; i++)
{
char c = chars[i];
if (Character.isWhitespace(c))
{
if (mimeType == null)
{
mimeType = buffer.toString();
}
else if (buffer.length() > 0)
{
mimetypes.put(buffer.toString(), mimeType);
}
buffer.setLength(0);
}
else
buffer.append(c);
}
if (buffer.length() > 0)
{
mimetypes.put(buffer.toString(), mimeType);
}
}
// -- Utility methods --
private List getSystemResources(String name)
{
List acc = new ArrayList();
try
{
for (Enumeration i = ClassLoader.getSystemResources(name);
i.hasMoreElements(); )
acc.add(i.nextElement());
}
catch (IOException e)
{
}
return acc;
}
}