0N/A/*
3261N/A * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.net.www;
0N/Aimport java.io.*;
0N/Aimport java.util.Calendar;
0N/Aimport java.util.Date;
0N/Aimport java.text.SimpleDateFormat;
0N/Aimport java.net.URL;
0N/Aimport java.net.FileNameMap;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Properties;
0N/Aimport java.util.StringTokenizer;
0N/A
0N/Apublic class MimeTable implements FileNameMap {
0N/A /** Keyed by content type, returns MimeEntries */
28N/A private Hashtable<String, MimeEntry> entries
28N/A = new Hashtable<String, MimeEntry>();
0N/A
0N/A /** Keyed by file extension (with the .), returns MimeEntries */
28N/A private Hashtable<String, MimeEntry> extensionMap
28N/A = new Hashtable<String, MimeEntry>();
0N/A
0N/A // Will be reset if in the platform-specific data file
0N/A private static String tempFileTemplate;
0N/A
0N/A static {
0N/A java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedAction<Void>() {
28N/A public Void run() {
0N/A tempFileTemplate =
0N/A System.getProperty("content.types.temp.file.template",
0N/A "/tmp/%s");
0N/A
0N/A mailcapLocations = new String[] {
0N/A System.getProperty("user.mailcap"),
0N/A System.getProperty("user.home") + "/.mailcap",
0N/A "/etc/mailcap",
0N/A "/usr/etc/mailcap",
0N/A "/usr/local/etc/mailcap",
0N/A System.getProperty("hotjava.home",
28N/A "/usr/local/hotjava")
28N/A + "/lib/mailcap",
0N/A };
0N/A return null;
0N/A }
0N/A });
0N/A }
0N/A
0N/A
0N/A private static final String filePreamble = "sun.net.www MIME content-types table";
0N/A private static final String fileMagic = "#" + filePreamble;
0N/A
0N/A MimeTable() {
0N/A load();
0N/A }
0N/A
2921N/A private static class DefaultInstanceHolder {
2921N/A static final MimeTable defaultInstance = getDefaultInstance();
2921N/A
2921N/A static MimeTable getDefaultInstance() {
2921N/A return java.security.AccessController.doPrivileged(
2921N/A new java.security.PrivilegedAction<MimeTable>() {
2921N/A public MimeTable run() {
2921N/A MimeTable instance = new MimeTable();
2921N/A URLConnection.setFileNameMap(instance);
2921N/A return instance;
2921N/A }
2921N/A });
2921N/A }
2921N/A }
2921N/A
0N/A /**
0N/A * Get the single instance of this class. First use will load the
0N/A * table from a data file.
0N/A */
0N/A public static MimeTable getDefaultTable() {
2921N/A return DefaultInstanceHolder.defaultInstance;
0N/A }
0N/A
0N/A /**
0N/A *
0N/A */
0N/A public static FileNameMap loadTable() {
0N/A MimeTable mt = getDefaultTable();
0N/A return (FileNameMap)mt;
0N/A }
0N/A
0N/A public synchronized int getSize() {
0N/A return entries.size();
0N/A }
0N/A
0N/A public synchronized String getContentTypeFor(String fileName) {
0N/A MimeEntry entry = findByFileName(fileName);
0N/A if (entry != null) {
0N/A return entry.getType();
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A public synchronized void add(MimeEntry m) {
0N/A entries.put(m.getType(), m);
0N/A
0N/A String exts[] = m.getExtensions();
0N/A if (exts == null) {
0N/A return;
0N/A }
0N/A
0N/A for (int i = 0; i < exts.length; i++) {
0N/A extensionMap.put(exts[i], m);
0N/A }
0N/A }
0N/A
0N/A public synchronized MimeEntry remove(String type) {
28N/A MimeEntry entry = entries.get(type);
0N/A return remove(entry);
0N/A }
0N/A
0N/A public synchronized MimeEntry remove(MimeEntry entry) {
0N/A String[] extensionKeys = entry.getExtensions();
0N/A if (extensionKeys != null) {
0N/A for (int i = 0; i < extensionKeys.length; i++) {
0N/A extensionMap.remove(extensionKeys[i]);
0N/A }
0N/A }
0N/A
28N/A return entries.remove(entry.getType());
0N/A }
0N/A
0N/A public synchronized MimeEntry find(String type) {
28N/A MimeEntry entry = entries.get(type);
0N/A if (entry == null) {
0N/A // try a wildcard lookup
28N/A Enumeration<MimeEntry> e = entries.elements();
0N/A while (e.hasMoreElements()) {
28N/A MimeEntry wild = e.nextElement();
0N/A if (wild.matches(type)) {
0N/A return wild;
0N/A }
0N/A }
0N/A }
0N/A
0N/A return entry;
0N/A }
0N/A
0N/A /**
0N/A * Locate a MimeEntry by the file extension that has been associated
0N/A * with it. Parses general file names, and URLs.
0N/A */
0N/A public MimeEntry findByFileName(String fname) {
0N/A String ext = "";
0N/A
0N/A int i = fname.lastIndexOf('#');
0N/A
0N/A if (i > 0) {
0N/A fname = fname.substring(0, i - 1);
0N/A }
0N/A
0N/A i = fname.lastIndexOf('.');
0N/A // REMIND: OS specific delimters appear here
0N/A i = Math.max(i, fname.lastIndexOf('/'));
0N/A i = Math.max(i, fname.lastIndexOf('?'));
0N/A
0N/A if (i != -1 && fname.charAt(i) == '.') {
0N/A ext = fname.substring(i).toLowerCase();
0N/A }
0N/A
0N/A return findByExt(ext);
0N/A }
0N/A
0N/A /**
0N/A * Locate a MimeEntry by the file extension that has been associated
0N/A * with it.
0N/A */
0N/A public synchronized MimeEntry findByExt(String fileExtension) {
28N/A return extensionMap.get(fileExtension);
0N/A }
0N/A
0N/A public synchronized MimeEntry findByDescription(String description) {
28N/A Enumeration<MimeEntry> e = elements();
0N/A while (e.hasMoreElements()) {
28N/A MimeEntry entry = e.nextElement();
0N/A if (description.equals(entry.getDescription())) {
0N/A return entry;
0N/A }
0N/A }
0N/A
0N/A // We failed, now try treating description as type
0N/A return find(description);
0N/A }
0N/A
0N/A String getTempFileTemplate() {
0N/A return tempFileTemplate;
0N/A }
0N/A
28N/A public synchronized Enumeration<MimeEntry> elements() {
0N/A return entries.elements();
0N/A }
0N/A
0N/A // For backward compatibility -- mailcap format files
0N/A // This is not currently used, but may in the future when we add ability
0N/A // to read BOTH the properties format and the mailcap format.
0N/A protected static String[] mailcapLocations;
0N/A
0N/A public synchronized void load() {
0N/A Properties entries = new Properties();
0N/A File file = null;
0N/A try {
0N/A InputStream is;
0N/A // First try to load the user-specific table, if it exists
0N/A String userTablePath =
0N/A System.getProperty("content.types.user.table");
0N/A if (userTablePath != null) {
0N/A file = new File(userTablePath);
0N/A if (!file.exists()) {
0N/A // No user-table, try to load the default built-in table.
0N/A file = new File(System.getProperty("java.home") +
0N/A File.separator +
0N/A "lib" +
0N/A File.separator +
0N/A "content-types.properties");
0N/A }
0N/A }
0N/A else {
0N/A // No user table, try to load the default built-in table.
0N/A file = new File(System.getProperty("java.home") +
0N/A File.separator +
0N/A "lib" +
0N/A File.separator +
0N/A "content-types.properties");
0N/A }
0N/A
0N/A is = new BufferedInputStream(new FileInputStream(file));
0N/A entries.load(is);
0N/A is.close();
0N/A }
0N/A catch (IOException e) {
0N/A System.err.println("Warning: default mime table not found: " +
0N/A file.getPath());
0N/A return;
0N/A }
0N/A parse(entries);
0N/A }
0N/A
0N/A void parse(Properties entries) {
0N/A // first, strip out the platform-specific temp file template
0N/A String tempFileTemplate = (String)entries.get("temp.file.template");
0N/A if (tempFileTemplate != null) {
0N/A entries.remove("temp.file.template");
0N/A this.tempFileTemplate = tempFileTemplate;
0N/A }
0N/A
0N/A // now, parse the mime-type spec's
28N/A Enumeration<?> types = entries.propertyNames();
0N/A while (types.hasMoreElements()) {
0N/A String type = (String)types.nextElement();
0N/A String attrs = entries.getProperty(type);
0N/A parse(type, attrs);
0N/A }
0N/A }
0N/A
0N/A //
0N/A // Table format:
0N/A //
0N/A // <entry> ::= <table_tag> | <type_entry>
0N/A //
0N/A // <table_tag> ::= <table_format_version> | <temp_file_template>
0N/A //
0N/A // <type_entry> ::= <type_subtype_pair> '=' <type_attrs_list>
0N/A //
0N/A // <type_subtype_pair> ::= <type> '/' <subtype>
0N/A //
0N/A // <type_attrs_list> ::= <attr_value_pair> [ ';' <attr_value_pair> ]*
0N/A // | [ <attr_value_pair> ]+
0N/A //
0N/A // <attr_value_pair> ::= <attr_name> '=' <attr_value>
0N/A //
0N/A // <attr_name> ::= 'description' | 'action' | 'application'
0N/A // | 'file_extensions' | 'icon'
0N/A //
0N/A // <attr_value> ::= <legal_char>*
0N/A //
0N/A // Embedded ';' in an <attr_value> are quoted with leading '\' .
0N/A //
0N/A // Interpretation of <attr_value> depends on the <attr_name> it is
0N/A // associated with.
0N/A //
0N/A
0N/A void parse(String type, String attrs) {
0N/A MimeEntry newEntry = new MimeEntry(type);
0N/A
0N/A // REMIND handle embedded ';' and '|' and literal '"'
0N/A StringTokenizer tokenizer = new StringTokenizer(attrs, ";");
0N/A while (tokenizer.hasMoreTokens()) {
0N/A String pair = tokenizer.nextToken();
0N/A parse(pair, newEntry);
0N/A }
0N/A
0N/A add(newEntry);
0N/A }
0N/A
0N/A void parse(String pair, MimeEntry entry) {
0N/A // REMIND add exception handling...
0N/A String name = null;
0N/A String value = null;
0N/A
0N/A boolean gotName = false;
0N/A StringTokenizer tokenizer = new StringTokenizer(pair, "=");
0N/A while (tokenizer.hasMoreTokens()) {
0N/A if (gotName) {
0N/A value = tokenizer.nextToken().trim();
0N/A }
0N/A else {
0N/A name = tokenizer.nextToken().trim();
0N/A gotName = true;
0N/A }
0N/A }
0N/A
0N/A fill(entry, name, value);
0N/A }
0N/A
0N/A void fill(MimeEntry entry, String name, String value) {
0N/A if ("description".equalsIgnoreCase(name)) {
0N/A entry.setDescription(value);
0N/A }
0N/A else if ("action".equalsIgnoreCase(name)) {
0N/A entry.setAction(getActionCode(value));
0N/A }
0N/A else if ("application".equalsIgnoreCase(name)) {
0N/A entry.setCommand(value);
0N/A }
0N/A else if ("icon".equalsIgnoreCase(name)) {
0N/A entry.setImageFileName(value);
0N/A }
0N/A else if ("file_extensions".equalsIgnoreCase(name)) {
0N/A entry.setExtensions(value);
0N/A }
0N/A
0N/A // else illegal name exception
0N/A }
0N/A
0N/A String[] getExtensions(String list) {
0N/A StringTokenizer tokenizer = new StringTokenizer(list, ",");
0N/A int n = tokenizer.countTokens();
0N/A String[] extensions = new String[n];
0N/A for (int i = 0; i < n; i++) {
0N/A extensions[i] = tokenizer.nextToken();
0N/A }
0N/A
0N/A return extensions;
0N/A }
0N/A
0N/A int getActionCode(String action) {
0N/A for (int i = 0; i < MimeEntry.actionKeywords.length; i++) {
0N/A if (action.equalsIgnoreCase(MimeEntry.actionKeywords[i])) {
0N/A return i;
0N/A }
0N/A }
0N/A
0N/A return MimeEntry.UNKNOWN;
0N/A }
0N/A
0N/A public synchronized boolean save(String filename) {
0N/A if (filename == null) {
0N/A filename = System.getProperty("user.home" +
0N/A File.separator +
0N/A "lib" +
0N/A File.separator +
0N/A "content-types.properties");
0N/A }
0N/A
0N/A return saveAsProperties(new File(filename));
0N/A }
0N/A
0N/A public Properties getAsProperties() {
0N/A Properties properties = new Properties();
28N/A Enumeration<MimeEntry> e = elements();
0N/A while (e.hasMoreElements()) {
28N/A MimeEntry entry = e.nextElement();
0N/A properties.put(entry.getType(), entry.toProperty());
0N/A }
0N/A
0N/A return properties;
0N/A }
0N/A
0N/A protected boolean saveAsProperties(File file) {
0N/A FileOutputStream os = null;
0N/A try {
0N/A os = new FileOutputStream(file);
0N/A Properties properties = getAsProperties();
0N/A properties.put("temp.file.template", tempFileTemplate);
0N/A String tag;
0N/A String user = System.getProperty("user.name");
0N/A if (user != null) {
0N/A tag = "; customized for " + user;
0N/A properties.save(os, filePreamble + tag);
0N/A }
0N/A else {
0N/A properties.save(os, filePreamble);
0N/A }
0N/A }
0N/A catch (IOException e) {
0N/A e.printStackTrace();
0N/A return false;
0N/A }
0N/A finally {
0N/A if (os != null) {
0N/A try { os.close(); } catch (IOException e) {}
0N/A }
0N/A }
0N/A
0N/A return true;
0N/A }
0N/A /*
0N/A * Debugging utilities
0N/A *
0N/A public void list(PrintStream out) {
0N/A Enumeration keys = entries.keys();
0N/A while (keys.hasMoreElements()) {
0N/A String key = (String)keys.nextElement();
0N/A MimeEntry entry = (MimeEntry)entries.get(key);
0N/A out.println(key + ": " + entry);
0N/A }
0N/A }
0N/A
0N/A public static void main(String[] args) {
0N/A MimeTable testTable = MimeTable.getDefaultTable();
0N/A
0N/A Enumeration e = testTable.elements();
0N/A while (e.hasMoreElements()) {
0N/A MimeEntry entry = (MimeEntry)e.nextElement();
0N/A System.out.println(entry);
0N/A }
0N/A
0N/A testTable.save(File.separator + "tmp" +
0N/A File.separator + "mime_table.save");
0N/A }
0N/A */
0N/A}