blob: 386169528e89390acdac887377fafa1bf5386bb1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
Nate Fischer3442c742017-09-08 17:02:00 -070019import android.annotation.Nullable;
Elliott Hughes0f1169612010-08-02 13:37:48 -070020import android.text.TextUtils;
Nate Fischer0a6140d2017-09-05 12:37:49 -070021
Elliott Hughes0f1169612010-08-02 13:37:48 -070022import libcore.net.MimeUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
Nate Fischer0a6140d2017-09-05 12:37:49 -070024import java.util.regex.Pattern;
25
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026/**
27 * Two-way map that maps MIME-types to file extensions and vice versa.
Elliott Hughes0f1169612010-08-02 13:37:48 -070028 *
29 * <p>See also {@link java.net.URLConnection#guessContentTypeFromName}
30 * and {@link java.net.URLConnection#guessContentTypeFromStream}. This
31 * class and {@code URLConnection} share the same MIME-type database.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032 */
Patrick Scott9f617322009-07-21 13:39:45 -040033public class MimeTypeMap {
Elliott Hughes0f1169612010-08-02 13:37:48 -070034 private static final MimeTypeMap sMimeTypeMap = new MimeTypeMap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 private MimeTypeMap() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 }
38
39 /**
Nate Fischer2be201e2017-10-26 10:43:00 -070040 * Returns the file extension or an empty string if there is no
Patrick Scott9f617322009-07-21 13:39:45 -040041 * extension. This method is a convenience method for obtaining the
42 * extension of a url and has undefined results for other Strings.
43 * @param url
44 * @return The file extension of the given url.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 */
46 public static String getFileExtensionFromUrl(String url) {
Elliott Hughes0f1169612010-08-02 13:37:48 -070047 if (!TextUtils.isEmpty(url)) {
Ben Murdoch18700152010-12-14 16:36:03 +000048 int fragment = url.lastIndexOf('#');
49 if (fragment > 0) {
50 url = url.substring(0, fragment);
51 }
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 int query = url.lastIndexOf('?');
54 if (query > 0) {
55 url = url.substring(0, query);
56 }
Ben Murdoch18700152010-12-14 16:36:03 +000057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 int filenamePos = url.lastIndexOf('/');
59 String filename =
60 0 <= filenamePos ? url.substring(filenamePos + 1) : url;
61
62 // if the filename contains special characters, we don't
63 // consider it valid for our matching purposes:
Elliott Hughes0f1169612010-08-02 13:37:48 -070064 if (!filename.isEmpty() &&
Melanie Clementsf19670a2010-05-01 22:48:20 -040065 Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)\\%]+", filename)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 int dotPos = filename.lastIndexOf('.');
67 if (0 <= dotPos) {
68 return filename.substring(dotPos + 1);
69 }
70 }
71 }
72
73 return "";
74 }
75
76 /**
Nate Fischer0a6140d2017-09-05 12:37:49 -070077 * Return {@code true} if the given MIME type has an entry in the map.
Patrick Scott9f617322009-07-21 13:39:45 -040078 * @param mimeType A MIME type (i.e. text/plain)
Nate Fischer2be201e2017-10-26 10:43:00 -070079 * @return {@code true} if there is a mimeType entry in the map.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 */
81 public boolean hasMimeType(String mimeType) {
Elliott Hughes0f1169612010-08-02 13:37:48 -070082 return MimeUtils.hasMimeType(mimeType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 }
84
85 /**
Patrick Scott9f617322009-07-21 13:39:45 -040086 * Return the MIME type for the given extension.
87 * @param extension A file extension without the leading '.'
Nate Fischer2be201e2017-10-26 10:43:00 -070088 * @return The MIME type for the given extension or {@code null} if there is none.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 */
Nate Fischer3442c742017-09-08 17:02:00 -070090 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 public String getMimeTypeFromExtension(String extension) {
Elliott Hughes0f1169612010-08-02 13:37:48 -070092 return MimeUtils.guessMimeTypeFromExtension(extension);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 }
94
Patrick Scott021b7b42010-01-13 14:12:43 -050095 // Static method called by jni.
96 private static String mimeTypeFromExtension(String extension) {
Elliott Hughes0f1169612010-08-02 13:37:48 -070097 return MimeUtils.guessMimeTypeFromExtension(extension);
Patrick Scott021b7b42010-01-13 14:12:43 -050098 }
99
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 /**
Nate Fischer0a6140d2017-09-05 12:37:49 -0700101 * Return {@code true} if the given extension has a registered MIME type.
Patrick Scott9f617322009-07-21 13:39:45 -0400102 * @param extension A file extension without the leading '.'
Nate Fischer2be201e2017-10-26 10:43:00 -0700103 * @return {@code true} if there is an extension entry in the map.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 */
105 public boolean hasExtension(String extension) {
Elliott Hughes0f1169612010-08-02 13:37:48 -0700106 return MimeUtils.hasExtension(extension);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 }
108
109 /**
Patrick Scott9f617322009-07-21 13:39:45 -0400110 * Return the registered extension for the given MIME type. Note that some
111 * MIME types map to multiple extensions. This call will return the most
112 * common extension for the given MIME type.
113 * @param mimeType A MIME type (i.e. text/plain)
Nate Fischer2be201e2017-10-26 10:43:00 -0700114 * @return The extension for the given MIME type or {@code null} if there is none.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 */
Nate Fischer3442c742017-09-08 17:02:00 -0700116 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 public String getExtensionFromMimeType(String mimeType) {
Elliott Hughes0f1169612010-08-02 13:37:48 -0700118 return MimeUtils.guessExtensionFromMimeType(mimeType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 }
120
121 /**
Nate Fischer0a6140d2017-09-05 12:37:49 -0700122 * If the given MIME type is {@code null}, or one of the "generic" types (text/plain
Iain Merrickd77f9b72010-10-18 18:22:25 +0100123 * or application/octet-stream) map it to a type that Android can deal with.
124 * If the given type is not generic, return it unchanged.
125 *
126 * @param mimeType MIME type provided by the server.
127 * @param url URL of the data being loaded.
128 * @param contentDisposition Content-disposition header given by the server.
129 * @return The MIME type that should be used for this data.
130 */
Nate Fischer3442c742017-09-08 17:02:00 -0700131 /* package */ String remapGenericMimeType(@Nullable String mimeType, String url,
Iain Merrickd77f9b72010-10-18 18:22:25 +0100132 String contentDisposition) {
133 // If we have one of "generic" MIME types, try to deduce
134 // the right MIME type from the file extension (if any):
135 if ("text/plain".equals(mimeType) ||
136 "application/octet-stream".equals(mimeType)) {
137
138 // for attachment, use the filename in the Content-Disposition
139 // to guess the mimetype
140 String filename = null;
141 if (contentDisposition != null) {
142 filename = URLUtil.parseContentDisposition(contentDisposition);
143 }
144 if (filename != null) {
145 url = filename;
146 }
147 String extension = getFileExtensionFromUrl(url);
148 String newMimeType = getMimeTypeFromExtension(extension);
149 if (newMimeType != null) {
150 mimeType = newMimeType;
151 }
152 } else if ("text/vnd.wap.wml".equals(mimeType)) {
153 // As we don't support wml, render it as plain text
154 mimeType = "text/plain";
155 } else {
156 // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
157 // subtypes are used interchangeably. So treat them the same.
158 if ("application/vnd.wap.xhtml+xml".equals(mimeType)) {
159 mimeType = "application/xhtml+xml";
160 }
161 }
162 return mimeType;
163 }
164
165 /**
Patrick Scott9f617322009-07-21 13:39:45 -0400166 * Get the singleton instance of MimeTypeMap.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 * @return The singleton instance of the MIME-type map.
168 */
169 public static MimeTypeMap getSingleton() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 return sMimeTypeMap;
171 }
172}