Make MimeMap final and introduce MimeMap.Builder. am: fd9657d032
am: 821f77fc77
Change-Id: I1225c7975ae3d2d42a0a144b46aef4290d0c5fa2
This commit is contained in:
@@ -21,10 +21,8 @@ import libcore.net.MimeMap;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,96 +34,27 @@ import java.util.regex.Pattern;
|
|||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class MimeMapImpl extends MimeMap {
|
public class MimeMapImpl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new {@link MimeMapImpl} instance that implements.
|
* Creates and returns a new {@link MimeMapImpl} instance that implements.
|
||||||
* Android's default mapping between MIME types and extensions.
|
* Android's default mapping between MIME types and extensions.
|
||||||
*/
|
*/
|
||||||
public static MimeMapImpl createDefaultInstance() {
|
public static MimeMap createDefaultInstance() {
|
||||||
return parseFromResources("/mime.types", "/android.mime.types");
|
return parseFromResources("/mime.types", "/android.mime.types");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
|
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
|
||||||
|
|
||||||
/**
|
static MimeMap parseFromResources(String... resourceNames) {
|
||||||
* Note: These maps only contain lowercase keys/values, regarded as the
|
MimeMap.Builder builder = MimeMap.builder();
|
||||||
* {@link #toLowerCase(String) canonical form}.
|
|
||||||
*
|
|
||||||
* <p>This is the case for both extensions and MIME types. The mime.types
|
|
||||||
* data file contains examples of mixed-case MIME types, but some applications
|
|
||||||
* use the lowercase version of these same types. RFC 2045 section 2 states
|
|
||||||
* that MIME types are case insensitive.
|
|
||||||
*/
|
|
||||||
private final Map<String, String> mMimeTypeToExtension;
|
|
||||||
private final Map<String, String> mExtensionToMimeType;
|
|
||||||
|
|
||||||
public MimeMapImpl(Map<String, String> mimeTypeToExtension,
|
|
||||||
Map<String, String> extensionToMimeType) {
|
|
||||||
this.mMimeTypeToExtension = new HashMap<>(mimeTypeToExtension);
|
|
||||||
for (Map.Entry<String, String> entry : mimeTypeToExtension.entrySet()) {
|
|
||||||
checkValidMimeType(entry.getKey());
|
|
||||||
checkValidExtension(entry.getValue());
|
|
||||||
}
|
|
||||||
this.mExtensionToMimeType = new HashMap<>(extensionToMimeType);
|
|
||||||
for (Map.Entry<String, String> entry : extensionToMimeType.entrySet()) {
|
|
||||||
checkValidExtension(entry.getKey());
|
|
||||||
checkValidMimeType(entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkValidMimeType(String s) {
|
|
||||||
if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
|
|
||||||
throw new IllegalArgumentException("Invalid MIME type: " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkValidExtension(String s) {
|
|
||||||
if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
|
|
||||||
throw new IllegalArgumentException("Invalid extension: " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static MimeMapImpl parseFromResources(String... resourceNames) {
|
|
||||||
Map<String, String> mimeTypeToExtension = new HashMap<>();
|
|
||||||
Map<String, String> extensionToMimeType = new HashMap<>();
|
|
||||||
for (String resourceName : resourceNames) {
|
for (String resourceName : resourceNames) {
|
||||||
parseTypes(mimeTypeToExtension, extensionToMimeType, resourceName);
|
parseTypes(builder, resourceName);
|
||||||
}
|
}
|
||||||
return new MimeMapImpl(mimeTypeToExtension, extensionToMimeType);
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static void parseTypes(MimeMap.Builder builder, String resource) {
|
||||||
* An element of a *mime.types file: A MIME type or an extension, with an optional
|
|
||||||
* prefix of "?" (if not overriding an earlier value).
|
|
||||||
*/
|
|
||||||
private static class Element {
|
|
||||||
public final boolean keepExisting;
|
|
||||||
public final String s;
|
|
||||||
|
|
||||||
Element(boolean keepExisting, String value) {
|
|
||||||
this.keepExisting = keepExisting;
|
|
||||||
this.s = toLowerCase(value);
|
|
||||||
if (value.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return keepExisting ? ("?" + s) : s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String maybePut(Map<String, String> map, Element keyElement, String value) {
|
|
||||||
if (keyElement.keepExisting) {
|
|
||||||
return map.putIfAbsent(keyElement.s, value);
|
|
||||||
} else {
|
|
||||||
return map.put(keyElement.s, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void parseTypes(Map<String, String> mimeTypeToExtension,
|
|
||||||
Map<String, String> extensionToMimeType, String resource) {
|
|
||||||
try (BufferedReader r = new BufferedReader(
|
try (BufferedReader r = new BufferedReader(
|
||||||
new InputStreamReader(MimeMapImpl.class.getResourceAsStream(resource)))) {
|
new InputStreamReader(MimeMapImpl.class.getResourceAsStream(resource)))) {
|
||||||
String line;
|
String line;
|
||||||
@@ -135,60 +64,15 @@ public class MimeMapImpl extends MimeMap {
|
|||||||
line = line.substring(0, commentPos);
|
line = line.substring(0, commentPos);
|
||||||
}
|
}
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
// The first time a MIME type is encountered it is mapped to the first extension
|
if (line.isEmpty()) {
|
||||||
// listed in its line. The first time an extension is encountered it is mapped
|
|
||||||
// to the MIME type.
|
|
||||||
//
|
|
||||||
// When encountering a previously seen MIME type or extension, then by default
|
|
||||||
// the later ones override earlier mappings (put() semantics); however if a MIME
|
|
||||||
// type or extension is prefixed with '?' then any earlier mapping _from_ that
|
|
||||||
// MIME type / extension is kept (putIfAbsent() semantics).
|
|
||||||
final String[] split = SPLIT_PATTERN.split(line);
|
|
||||||
if (split.length <= 1) {
|
|
||||||
// Need mimeType + at least one extension to make a mapping.
|
|
||||||
// "mime.types" files may also contain lines with just a mimeType without
|
|
||||||
// an extension but we skip them as they provide no mapping info.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
List<Element> lineElements = new ArrayList<>(split.length);
|
List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
|
||||||
for (String s : split) {
|
builder.put(specs.get(0), specs.subList(1, specs.size()));
|
||||||
boolean keepExisting = s.startsWith("?");
|
|
||||||
if (keepExisting) {
|
|
||||||
s = s.substring(1);
|
|
||||||
}
|
|
||||||
if (s.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Invalid entry in '" + line + "'");
|
|
||||||
}
|
|
||||||
lineElements.add(new Element(keepExisting, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIME type -> first extension (one mapping)
|
|
||||||
// This will override any earlier mapping from this MIME type to another
|
|
||||||
// extension, unless this MIME type was prefixed with '?'.
|
|
||||||
Element mimeElement = lineElements.get(0);
|
|
||||||
List<Element> extensionElements = lineElements.subList(1, lineElements.size());
|
|
||||||
String firstExtension = extensionElements.get(0).s;
|
|
||||||
maybePut(mimeTypeToExtension, mimeElement, firstExtension);
|
|
||||||
|
|
||||||
// extension -> MIME type (one or more mappings).
|
|
||||||
// This will override any earlier mapping from this extension to another
|
|
||||||
// MIME type, unless this extension was prefixed with '?'.
|
|
||||||
for (Element extensionElement : extensionElements) {
|
|
||||||
maybePut(extensionToMimeType, extensionElement, mimeElement.s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (IOException | RuntimeException e) {
|
} catch (IOException | RuntimeException e) {
|
||||||
throw new RuntimeException("Failed to parse " + resource, e);
|
throw new RuntimeException("Failed to parse " + resource, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String guessExtensionFromLowerCaseMimeType(String mimeType) {
|
|
||||||
return mMimeTypeToExtension.get(mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String guessMimeTypeFromLowerCaseExtension(String extension) {
|
|
||||||
return mExtensionToMimeType.get(extension);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user