mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-18 00:00:03 -04:00
312 lines
12 KiB
Java
Executable File
312 lines
12 KiB
Java
Executable File
/*
|
|
* Copyright (c) 2008, Harald Kuhr
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name "TwelveMonkeys" nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
package com.twelvemonkeys.net;
|
|
|
|
import com.twelvemonkeys.lang.StringUtil;
|
|
import com.twelvemonkeys.lang.SystemUtil;
|
|
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Contains mappings from file extension to mime-types and from mime-type to file-types.
|
|
* <p/>
|
|
*
|
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/net/MIMEUtil.java#5 $
|
|
*
|
|
* @see <A href="http://www.iana.org/assignments/media-types/">MIME Media Types</A>
|
|
*/
|
|
public final class MIMEUtil {
|
|
// TODO: Piggy-back on the mappings form the JRE? (1.6 comes with javax.activation)
|
|
// TODO: Piggy-back on mappings from javax.activation?
|
|
// See: http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/activation/MimetypesFileTypeMap.html
|
|
// See: http://java.sun.com/javase/6/docs/api/javax/activation/MimetypesFileTypeMap.html
|
|
// TODO: Use the format (and lookup) specified by the above URLs
|
|
// TODO: Allow 3rd party to add mappings? Will need application context support to do it safe.. :-P
|
|
|
|
private static Map<String, List<String>> sExtToMIME = new HashMap<String, List<String>>();
|
|
private static Map<String, List<String>> sUnmodifiableExtToMIME = Collections.unmodifiableMap(sExtToMIME);
|
|
|
|
private static Map<String, List<String>> sMIMEToExt = new HashMap<String, List<String>>();
|
|
private static Map<String, List<String>> sUnmodifiableMIMEToExt = Collections.unmodifiableMap(sMIMEToExt);
|
|
|
|
static {
|
|
// Load mapping for MIMEUtil
|
|
try {
|
|
Properties mappings = SystemUtil.loadProperties(MIMEUtil.class);
|
|
|
|
for (Map.Entry entry : mappings.entrySet()) {
|
|
// Convert and break up extensions and mimeTypes
|
|
String extStr = StringUtil.toLowerCase((String) entry.getKey());
|
|
List<String> extensions =
|
|
Collections.unmodifiableList(Arrays.asList(StringUtil.toStringArray(extStr, ";, ")));
|
|
|
|
String typeStr = StringUtil.toLowerCase((String) entry.getValue());
|
|
List<String> mimeTypes =
|
|
Collections.unmodifiableList(Arrays.asList(StringUtil.toStringArray(typeStr, ";, ")));
|
|
|
|
// TODO: Handle duplicates in MIME to extension mapping, like
|
|
// xhtml=application/xhtml+xml;application/xml
|
|
// xml=text/xml;application/xml
|
|
|
|
// Populate normal and reverse MIME-mappings
|
|
for (String extension : extensions) {
|
|
sExtToMIME.put(extension, mimeTypes);
|
|
}
|
|
|
|
for (String mimeType : mimeTypes) {
|
|
sMIMEToExt.put(mimeType, extensions);
|
|
}
|
|
}
|
|
}
|
|
catch (IOException e) {
|
|
System.err.println("Could not read properties for MIMEUtil: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
// Disallow construction
|
|
private MIMEUtil() {
|
|
}
|
|
|
|
/**
|
|
* Returns the default MIME type for the given file extension.
|
|
*
|
|
* @param pFileExt the file extension
|
|
*
|
|
* @return a {@code String} containing the MIME type, or {@code null} if
|
|
* there are no known MIME types for the given file extension.
|
|
*/
|
|
public static String getMIMEType(final String pFileExt) {
|
|
List<String> types = sExtToMIME.get(StringUtil.toLowerCase(pFileExt));
|
|
return (types == null || types.isEmpty()) ? null : types.get(0);
|
|
}
|
|
|
|
/**
|
|
* Returns all MIME types for the given file extension.
|
|
*
|
|
* @param pFileExt the file extension
|
|
*
|
|
* @return a {@link List} of {@code String}s containing the MIME types, or an empty
|
|
* list, if there are no known MIME types for the given file extension.
|
|
*/
|
|
public static List<String> getMIMETypes(final String pFileExt) {
|
|
List<String> types = sExtToMIME.get(StringUtil.toLowerCase(pFileExt));
|
|
return maskNull(types);
|
|
}
|
|
|
|
/**
|
|
* Returns an unmodifiabale {@link Map} view of the extension to
|
|
* MIME mapping, to use as the default mapping in client applications.
|
|
*
|
|
* @return an unmodifiabale {@code Map} view of the extension to
|
|
* MIME mapping.
|
|
*/
|
|
public static Map<String, List<String>> getMIMETypeMappings() {
|
|
return sUnmodifiableExtToMIME;
|
|
}
|
|
|
|
/**
|
|
* Returns the default file extension for the given MIME type.
|
|
* Specifying a wildcard type will return {@code null}.
|
|
*
|
|
* @param pMIME the MIME type
|
|
*
|
|
* @return a {@code String} containing the file extension, or {@code null}
|
|
* if there are no known file extensions for the given MIME type.
|
|
*/
|
|
public static String getExtension(final String pMIME) {
|
|
String mime = bareMIME(StringUtil.toLowerCase(pMIME));
|
|
List<String> extensions = sMIMEToExt.get(mime);
|
|
return (extensions == null || extensions.isEmpty()) ? null : extensions.get(0);
|
|
}
|
|
|
|
/**
|
|
* Returns all file extension for the given MIME type.
|
|
* The default extension will be the first in the list.
|
|
* Note that no specific order is given for wildcard types (image/*, */* etc).
|
|
*
|
|
* @param pMIME the MIME type
|
|
*
|
|
* @return a {@link List} of {@code String}s containing the MIME types, or an empty
|
|
* list, if there are no known file extensions for the given MIME type.
|
|
*/
|
|
public static List<String> getExtensions(final String pMIME) {
|
|
String mime = bareMIME(StringUtil.toLowerCase(pMIME));
|
|
if (mime.endsWith("/*")) {
|
|
return getExtensionForWildcard(mime);
|
|
}
|
|
List<String> extensions = sMIMEToExt.get(mime);
|
|
return maskNull(extensions);
|
|
}
|
|
|
|
// Gets all extensions for a wildcard MIME type
|
|
private static List<String> getExtensionForWildcard(final String pMIME) {
|
|
final String family = pMIME.substring(0, pMIME.length() - 1);
|
|
Set<String> extensions = new LinkedHashSet<String>();
|
|
for (Map.Entry<String, List<String>> mimeToExt : sMIMEToExt.entrySet()) {
|
|
if ("*/".equals(family) || mimeToExt.getKey().startsWith(family)) {
|
|
extensions.addAll(mimeToExt.getValue());
|
|
}
|
|
}
|
|
return Collections.unmodifiableList(new ArrayList<String>(extensions));
|
|
}
|
|
|
|
/**
|
|
* Returns an unmodifiabale {@link Map} view of the MIME to
|
|
* extension mapping, to use as the default mapping in client applications.
|
|
*
|
|
* @return an unmodifiabale {@code Map} view of the MIME to
|
|
* extension mapping.
|
|
*/
|
|
public static Map<String, List<String>> getExtensionMappings() {
|
|
return sUnmodifiableMIMEToExt;
|
|
}
|
|
|
|
/**
|
|
* Tests wehter the type is a subtype of the type family.
|
|
*
|
|
* @param pTypeFamily the MIME type family ({@code image/*, */*}, etc)
|
|
* @param pType the MIME type
|
|
* @return {@code true} if {@code pType} is a subtype of {@code pTypeFamily}, otherwise {@code false}
|
|
*/
|
|
// TODO: Rename? isSubtype?
|
|
// TODO: Make public
|
|
static boolean includes(final String pTypeFamily, final String pType) {
|
|
// TODO: Handle null in a well-defined way
|
|
// - Is null family same as */*?
|
|
// - Is null subtype of any family? Subtype of no family?
|
|
|
|
String type = bareMIME(pType);
|
|
return type.equals(pTypeFamily)
|
|
|| "*/*".equals(pTypeFamily)
|
|
|| pTypeFamily.endsWith("/*") && pTypeFamily.startsWith(type.substring(0, type.indexOf('/')));
|
|
}
|
|
|
|
/**
|
|
* Removes any charset or extra info from the mime-type string (anything after a semicolon, {@code ;}, inclusive).
|
|
*
|
|
* @param pMIME the mime-type string
|
|
* @return the bare mime-type
|
|
*/
|
|
public static String bareMIME(final String pMIME) {
|
|
int idx;
|
|
if (pMIME != null && (idx = pMIME.indexOf(';')) >= 0) {
|
|
return pMIME.substring(0, idx);
|
|
}
|
|
return pMIME;
|
|
}
|
|
|
|
// Returns the list or empty list if list is null
|
|
private static List<String> maskNull(List<String> pTypes) {
|
|
return (pTypes == null) ? Collections.<String>emptyList() : pTypes;
|
|
}
|
|
|
|
/**
|
|
* For debugging. Prints all known MIME types and file extensions.
|
|
*
|
|
* @param pArgs command line arguments
|
|
*/
|
|
public static void main(String[] pArgs) {
|
|
if (pArgs.length > 1) {
|
|
String type = pArgs[0];
|
|
String family = pArgs[1];
|
|
boolean incuded = includes(family, type);
|
|
System.out.println(
|
|
"Mime type family " + family
|
|
+ (incuded ? " includes " : " does not include ")
|
|
+ "type " + type
|
|
);
|
|
}
|
|
if (pArgs.length > 0) {
|
|
String str = pArgs[0];
|
|
|
|
if (str.indexOf('/') >= 0) {
|
|
// MIME
|
|
String extension = getExtension(str);
|
|
System.out.println("Default extension for MIME type '" + str + "' is "
|
|
+ (extension != null ? ": '" + extension + "'" : "unknown") + ".");
|
|
System.out.println("All possible: " + getExtensions(str));
|
|
}
|
|
else {
|
|
// EXT
|
|
String mimeType = getMIMEType(str);
|
|
System.out.println("Default MIME type for extension '" + str + "' is "
|
|
+ (mimeType != null ? ": '" + mimeType + "'" : "unknown") + ".");
|
|
System.out.println("All possible: " + getMIMETypes(str));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Set set = sMIMEToExt.keySet();
|
|
String[] mimeTypes = new String[set.size()];
|
|
int i = 0;
|
|
for (Iterator iterator = set.iterator(); iterator.hasNext(); i++) {
|
|
String mime = (String) iterator.next();
|
|
mimeTypes[i] = mime;
|
|
}
|
|
Arrays.sort(mimeTypes);
|
|
|
|
System.out.println("Known MIME types (" + mimeTypes.length + "):");
|
|
for (int j = 0; j < mimeTypes.length; j++) {
|
|
String mimeType = mimeTypes[j];
|
|
|
|
if (j != 0) {
|
|
System.out.print(", ");
|
|
}
|
|
|
|
System.out.print(mimeType);
|
|
}
|
|
|
|
System.out.println("\n");
|
|
|
|
set = sExtToMIME.keySet();
|
|
String[] extensions = new String[set.size()];
|
|
i = 0;
|
|
for (Iterator iterator = set.iterator(); iterator.hasNext(); i++) {
|
|
String ext = (String) iterator.next();
|
|
extensions[i] = ext;
|
|
}
|
|
Arrays.sort(extensions);
|
|
|
|
System.out.println("Known file types (" + extensions.length + "):");
|
|
for (int j = 0; j < extensions.length; j++) {
|
|
String extension = extensions[j];
|
|
|
|
if (j != 0) {
|
|
System.out.print(", ");
|
|
}
|
|
|
|
System.out.print(extension);
|
|
}
|
|
System.out.println();
|
|
}
|
|
} |