Home | History | Annotate | Download | only in webkit
      1 /*
      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 
     17 package android.webkit;
     18 
     19 import android.text.TextUtils;
     20 import java.util.HashMap;
     21 import java.util.regex.Pattern;
     22 import libcore.net.MimeUtils;
     23 
     24 /**
     25  * Two-way map that maps MIME-types to file extensions and vice versa.
     26  *
     27  * <p>See also {@link java.net.URLConnection#guessContentTypeFromName}
     28  * and {@link java.net.URLConnection#guessContentTypeFromStream}. This
     29  * class and {@code URLConnection} share the same MIME-type database.
     30  */
     31 public class MimeTypeMap {
     32     private static final MimeTypeMap sMimeTypeMap = new MimeTypeMap();
     33 
     34     private MimeTypeMap() {
     35     }
     36 
     37     /**
     38      * Returns the file extension or an empty string iff there is no
     39      * extension. This method is a convenience method for obtaining the
     40      * extension of a url and has undefined results for other Strings.
     41      * @param url
     42      * @return The file extension of the given url.
     43      */
     44     public static String getFileExtensionFromUrl(String url) {
     45         if (!TextUtils.isEmpty(url)) {
     46             int fragment = url.lastIndexOf('#');
     47             if (fragment > 0) {
     48                 url = url.substring(0, fragment);
     49             }
     50 
     51             int query = url.lastIndexOf('?');
     52             if (query > 0) {
     53                 url = url.substring(0, query);
     54             }
     55 
     56             int filenamePos = url.lastIndexOf('/');
     57             String filename =
     58                 0 <= filenamePos ? url.substring(filenamePos + 1) : url;
     59 
     60             // if the filename contains special characters, we don't
     61             // consider it valid for our matching purposes:
     62             if (!filename.isEmpty() &&
     63                 Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)\\%]+", filename)) {
     64                 int dotPos = filename.lastIndexOf('.');
     65                 if (0 <= dotPos) {
     66                     return filename.substring(dotPos + 1);
     67                 }
     68             }
     69         }
     70 
     71         return "";
     72     }
     73 
     74     /**
     75      * Return true if the given MIME type has an entry in the map.
     76      * @param mimeType A MIME type (i.e. text/plain)
     77      * @return True iff there is a mimeType entry in the map.
     78      */
     79     public boolean hasMimeType(String mimeType) {
     80         return MimeUtils.hasMimeType(mimeType);
     81     }
     82 
     83     /**
     84      * Return the MIME type for the given extension.
     85      * @param extension A file extension without the leading '.'
     86      * @return The MIME type for the given extension or null iff there is none.
     87      */
     88     public String getMimeTypeFromExtension(String extension) {
     89         return MimeUtils.guessMimeTypeFromExtension(extension);
     90     }
     91 
     92     // Static method called by jni.
     93     private static String mimeTypeFromExtension(String extension) {
     94         return MimeUtils.guessMimeTypeFromExtension(extension);
     95     }
     96 
     97     /**
     98      * Return true if the given extension has a registered MIME type.
     99      * @param extension A file extension without the leading '.'
    100      * @return True iff there is an extension entry in the map.
    101      */
    102     public boolean hasExtension(String extension) {
    103         return MimeUtils.hasExtension(extension);
    104     }
    105 
    106     /**
    107      * Return the registered extension for the given MIME type. Note that some
    108      * MIME types map to multiple extensions. This call will return the most
    109      * common extension for the given MIME type.
    110      * @param mimeType A MIME type (i.e. text/plain)
    111      * @return The extension for the given MIME type or null iff there is none.
    112      */
    113     public String getExtensionFromMimeType(String mimeType) {
    114         return MimeUtils.guessExtensionFromMimeType(mimeType);
    115     }
    116 
    117     /**
    118      * If the given MIME type is null, or one of the "generic" types (text/plain
    119      * or application/octet-stream) map it to a type that Android can deal with.
    120      * If the given type is not generic, return it unchanged.
    121      *
    122      * @param mimeType MIME type provided by the server.
    123      * @param url URL of the data being loaded.
    124      * @param contentDisposition Content-disposition header given by the server.
    125      * @return The MIME type that should be used for this data.
    126      */
    127     /* package */ String remapGenericMimeType(String mimeType, String url,
    128             String contentDisposition) {
    129         // If we have one of "generic" MIME types, try to deduce
    130         // the right MIME type from the file extension (if any):
    131         if ("text/plain".equals(mimeType) ||
    132                 "application/octet-stream".equals(mimeType)) {
    133 
    134             // for attachment, use the filename in the Content-Disposition
    135             // to guess the mimetype
    136             String filename = null;
    137             if (contentDisposition != null) {
    138                 filename = URLUtil.parseContentDisposition(contentDisposition);
    139             }
    140             if (filename != null) {
    141                 url = filename;
    142             }
    143             String extension = getFileExtensionFromUrl(url);
    144             String newMimeType = getMimeTypeFromExtension(extension);
    145             if (newMimeType != null) {
    146                 mimeType = newMimeType;
    147             }
    148         } else if ("text/vnd.wap.wml".equals(mimeType)) {
    149             // As we don't support wml, render it as plain text
    150             mimeType = "text/plain";
    151         } else {
    152             // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
    153             // subtypes are used interchangeably. So treat them the same.
    154             if ("application/vnd.wap.xhtml+xml".equals(mimeType)) {
    155                 mimeType = "application/xhtml+xml";
    156             }
    157         }
    158         return mimeType;
    159     }
    160 
    161     /**
    162      * Get the singleton instance of MimeTypeMap.
    163      * @return The singleton instance of the MIME-type map.
    164      */
    165     public static MimeTypeMap getSingleton() {
    166         return sMimeTypeMap;
    167     }
    168 }
    169