Introduce vendor.mime.types

Like mime.types and android.mime.types, this file specifies mappings
between MIME types and file extensions. Unlike those files, it can
only be used to define _additional_ mapping but not modify (change,
remove) any mappings defined by those files.

This is done by prepending '?' to every line element from
vendor.mime.types that doesn't already have one; when there is a
leading "?", it is ignored so that it's okay to move a line from
{android,vendor}.mime.types without necessarily changing it.

Test: Checked manually that vendor.mime.types works as expected.
  Specifically, after adding these lines to vendor.mime.type:

    audio/mpeg testmpeg
    audio/testmpeg mp3
    ?mime/foo ?fooext

  the following test passes:

    MimeTypeMap map = MimeTypeMap.getSingleton();
    // Original mapping is unchanged
    assertEquals("mp3", map.getExtensionFromMimeType("audio/mpeg"));
    assertEquals("audio/mpeg", map.getMimeTypeFromExtension("mp3"));

    // Map from the key to existing value is added
    assertEquals("audio/mpeg", map.getMimeTypeFromExtension("testmpeg"));
    assertEquals("mp3", map.getExtensionFromMimeType("audio/testmpeg"));

    // Completely new mapping is added both ways
    assertEquals("mime/foo", map.getMimeTypeFromExtension("fooext"));
    assertEquals("fooext", map.getExtensionFromMimeType("mime/foo"));

Bug: 141842825
Change-Id: Iaf918ce39324709ff58a8e0f9612e4827a673323
This commit is contained in:
Tobias Thierer
2019-09-27 19:22:39 +01:00
parent e25c54f328
commit 324349142c
3 changed files with 78 additions and 10 deletions

View File

@@ -26,6 +26,7 @@ java_library {
java_resources: [
":debian.mime.types",
":android.mime.types",
":vendor.mime.types",
],
sdk_version: "core_platform",
@@ -41,3 +42,14 @@ filegroup {
"java-res/android.mime.types",
],
}
filegroup {
name: "vendor.mime.types",
visibility: [
"//visibility:private",
],
path: "java-res/",
srcs: [
"java-res/vendor.mime.types",
],
}

View File

@@ -0,0 +1,41 @@
###############################################################################
#
# Vendor-specific MIME type <-> extension mappings
#
# Each line below defines a mapping from one MIME type to the first of the
# listed extensions, and from listed extension back to the MIME type.
#
# This file can _add_ additional mappings that are not in the default set,
# but it it cannot _modify_ (replace or remove) any platform default mapping
# (defined in files mime.types and android.mime.types).
#
###############################################################################
#
# EXAMPLES
#
# A line of the form (without the leading '#''):
#
# mime ext1 ext2 ext3
#
# affects the current mappings along the lines of the following pseudo code:
#
# mimeToExt.putIfAbsent("mime", "ext1");
# extToMime.putIfAbsent("ext1", "mime");
# extToMime.putIfAbsent("ext2", "mime");
# extToMime.putIfAbsent("ext3", "mime");
#
# Optionally, MIME types or extensions may be prefixed by a single '?', which
# will be ignored. I.e., the following example lines all have the same semantics:
#
# mime ext1 ext2 ext3
# ?mime ext1 ext2 ext3
# mime ?ext1 ext2 ?ext3
# ?mime ?ext1 ?ext2 ?ext3
#
# By default, this file contains no mappings (which means that the platform
# default mapping is used unmodified).
#
###############################################################################
#
# Add your custom mappings below this line (with no "#" at the start of the line):

View File

@@ -21,6 +21,7 @@ import libcore.net.MimeMap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
@@ -44,20 +45,17 @@ public class DefaultMimeMapFactory {
* Android's default mapping between MIME types and extensions.
*/
public static MimeMap create() {
return parseFromResources("/mime.types", "/android.mime.types");
MimeMap.Builder builder = MimeMap.builder();
parseTypes(builder, true, "/mime.types");
parseTypes(builder, true, "/android.mime.types");
parseTypes(builder, false, "/vendor.mime.types");
return builder.build();
}
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
static MimeMap parseFromResources(String... resourceNames) {
MimeMap.Builder builder = MimeMap.builder();
for (String resourceName : resourceNames) {
parseTypes(builder, resourceName);
}
return builder.build();
}
private static void parseTypes(MimeMap.Builder builder, String resource) {
private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite,
String resource) {
try (BufferedReader r = new BufferedReader(
new InputStreamReader(DefaultMimeMapFactory.class.getResourceAsStream(resource)))) {
String line;
@@ -71,6 +69,12 @@ public class DefaultMimeMapFactory {
continue;
}
List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
if (!allowOverwrite) {
// Pretend that the mimeType and each file extension listed in the line
// carries a "?" prefix, which means that it can add new mappings but
// not modify existing mappings (putIfAbsent() semantics).
specs = ensurePrefix("?", specs);
}
builder.put(specs.get(0), specs.subList(1, specs.size()));
}
} catch (IOException | RuntimeException e) {
@@ -78,4 +82,15 @@ public class DefaultMimeMapFactory {
}
}
private static List<String> ensurePrefix(String prefix, List<String> strings) {
List<String> result = new ArrayList<>(strings.size());
for (String s : strings) {
if (!s.startsWith(prefix)) {
s = prefix + s;
}
result.add(s);
}
return result;
}
}