1/*
2 * Copyright (C) 2006, 2008, 2009 Apple Inc.  All rights reserved.
3 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "MIMETypeRegistry.h"
29
30#include "MediaPlayer.h"
31#include <wtf/HashMap.h>
32#include <wtf/HashSet.h>
33#include <wtf/MainThread.h>
34#include <wtf/StdLibExtras.h>
35#include <wtf/text/StringHash.h>
36
37#if USE(CG)
38#include "ImageSourceCG.h"
39#include <ApplicationServices/ApplicationServices.h>
40#include <wtf/RetainPtr.h>
41#endif
42
43#if PLATFORM(QT)
44#include <QImageReader>
45#include <QImageWriter>
46#endif
47
48#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
49#include "ArchiveFactory.h"
50#endif
51
52namespace WebCore {
53
54namespace {
55struct TypeExtensionPair {
56    const char* type;
57    const char* extension;
58};
59}
60
61// A table of common media MIME types and file extenstions used when a platform's
62// specific MIME type lookup doesn't have a match for a media file extension.
63static const TypeExtensionPair commonMediaTypes[] = {
64
65    // Ogg
66    { "application/ogg", "ogx" },
67    { "audio/ogg", "ogg" },
68    { "audio/ogg", "oga" },
69    { "video/ogg", "ogv" },
70
71    // Annodex
72    { "application/annodex", "anx" },
73    { "audio/annodex", "axa" },
74    { "video/annodex", "axv" },
75    { "audio/speex", "spx" },
76
77    // WebM
78    { "video/webm", "webm" },
79    { "audio/webm", "webm" },
80
81    // MPEG
82    { "audio/mpeg", "m1a" },
83    { "audio/mpeg", "m2a" },
84    { "audio/mpeg", "m1s" },
85    { "audio/mpeg", "mpa" },
86    { "video/mpeg", "mpg" },
87    { "video/mpeg", "m15" },
88    { "video/mpeg", "m1s" },
89    { "video/mpeg", "m1v" },
90    { "video/mpeg", "m75" },
91    { "video/mpeg", "mpa" },
92    { "video/mpeg", "mpeg" },
93    { "video/mpeg", "mpm" },
94    { "video/mpeg", "mpv" },
95
96    // MPEG playlist
97    { "application/vnd.apple.mpegurl", "m3u8" },
98    { "application/mpegurl", "m3u8" },
99    { "application/x-mpegurl", "m3u8" },
100    { "audio/mpegurl", "m3url" },
101    { "audio/x-mpegurl", "m3url" },
102    { "audio/mpegurl", "m3u" },
103    { "audio/x-mpegurl", "m3u" },
104
105    // MPEG-4
106    { "video/x-m4v", "m4v" },
107    { "audio/x-m4a", "m4a" },
108    { "audio/x-m4b", "m4b" },
109    { "audio/x-m4p", "m4p" },
110    { "audio/mp4", "m4a" },
111
112    // MP3
113    { "audio/mp3", "mp3" },
114    { "audio/x-mp3", "mp3" },
115    { "audio/x-mpeg", "mp3" },
116
117    // MPEG-2
118    { "video/x-mpeg2", "mp2" },
119    { "video/mpeg2", "vob" },
120    { "video/mpeg2", "mod" },
121    { "video/m2ts", "m2ts" },
122    { "video/x-m2ts", "m2t" },
123    { "video/x-m2ts", "ts" },
124
125    // 3GP/3GP2
126    { "audio/3gpp", "3gpp" },
127    { "audio/3gpp2", "3g2" },
128    { "application/x-mpeg", "amc" },
129
130    // AAC
131    { "audio/aac", "aac" },
132    { "audio/aac", "adts" },
133    { "audio/x-aac", "m4r" },
134
135    // CoreAudio File
136    { "audio/x-caf", "caf" },
137    { "audio/x-gsm", "gsm" },
138
139    // ADPCM
140    { "audio/x-wav", "wav" }
141};
142
143static const char textPlain[] = "text/plain";
144static const char textHtml[] = "text/html";
145static const char imageJpeg[] = "image/jpeg";
146static const char octetStream[] = "application/octet-stream";
147
148// A table of well known MIME types used when we don't want to leak to the
149// caller information about types known to underlying platform.
150static const TypeExtensionPair wellKnownMimeTypes[] = {
151    { textPlain, "txt" },
152    { textPlain, "text" },
153    { textHtml, "html" },
154    { textHtml, "htm" },
155    { "text/css", "css" },
156    { "text/xml", "xml" },
157    { "text/xsl", "xsl" },
158    { "image/gif", "gif" },
159    { "image/png", "png" },
160    { imageJpeg, "jpeg" },
161    { imageJpeg, "jpg" },
162    { imageJpeg, "jfif" },
163    { imageJpeg, "pjpeg" },
164    { "image/webp", "webp" },
165    { "image/bmp", "bmp" },
166    { "application/xhtml+xml", "xhtml" },
167    { "application/x-javascript", "js" },
168    { "application/json", "json" },
169    { octetStream, "exe" },
170    { octetStream, "com" },
171    { octetStream, "bin" },
172    { "application/zip", "zip" },
173    { "application/gzip", "gz" },
174    { "application/pdf", "pdf" },
175    { "application/postscript", "ps" },
176    { "image/x-icon", "ico" },
177    { "image/tiff", "tiff" },
178    { "image/x-xbitmap", "xbm" },
179    { "image/svg+xml", "svg" },
180    { "application/rss+xml", "rss" },
181    { "application/rdf+xml", "rdf" },
182    { "application/x-shockwave-flash", "swf" },
183};
184
185static HashSet<String>* supportedImageResourceMIMETypes;
186static HashSet<String>* supportedImageMIMETypes;
187static HashSet<String>* supportedImageMIMETypesForEncoding;
188static HashSet<String>* supportedJavaScriptMIMETypes;
189static HashSet<String>* supportedNonImageMIMETypes;
190static HashSet<String>* supportedMediaMIMETypes;
191static HashSet<String>* pdfAndPostScriptMIMETypes;
192static HashSet<String>* unsupportedTextMIMETypes;
193
194typedef HashMap<String, Vector<String>*, CaseFoldingHash> MediaMIMETypeMap;
195
196static void initializeSupportedImageMIMETypes()
197{
198#if USE(CG)
199    RetainPtr<CFArrayRef> supportedTypes = adoptCF(CGImageSourceCopyTypeIdentifiers());
200    CFIndex count = CFArrayGetCount(supportedTypes.get());
201    for (CFIndex i = 0; i < count; i++) {
202        CFStringRef supportedType = reinterpret_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i));
203        String mimeType = MIMETypeForImageSourceType(supportedType);
204        if (!mimeType.isEmpty()) {
205            supportedImageMIMETypes->add(mimeType);
206            supportedImageResourceMIMETypes->add(mimeType);
207        }
208    }
209
210    // On Tiger and Leopard, com.microsoft.bmp doesn't have a MIME type in the registry.
211    supportedImageMIMETypes->add("image/bmp");
212    supportedImageResourceMIMETypes->add("image/bmp");
213
214    // Favicons don't have a MIME type in the registry either.
215    supportedImageMIMETypes->add("image/vnd.microsoft.icon");
216    supportedImageMIMETypes->add("image/x-icon");
217    supportedImageResourceMIMETypes->add("image/vnd.microsoft.icon");
218    supportedImageResourceMIMETypes->add("image/x-icon");
219
220    //  We only get one MIME type per UTI, hence our need to add these manually
221    supportedImageMIMETypes->add("image/pjpeg");
222    supportedImageResourceMIMETypes->add("image/pjpeg");
223
224    //  We don't want to try to treat all binary data as an image
225    supportedImageMIMETypes->remove("application/octet-stream");
226    supportedImageResourceMIMETypes->remove("application/octet-stream");
227
228    //  Don't treat pdf/postscript as images directly
229    supportedImageMIMETypes->remove("application/pdf");
230    supportedImageMIMETypes->remove("application/postscript");
231
232#else
233    // assume that all implementations at least support the following standard
234    // image types:
235    static const char* types[] = {
236        "image/jpeg",
237        "image/png",
238        "image/gif",
239        "image/bmp",
240        "image/vnd.microsoft.icon",    // ico
241        "image/x-icon",    // ico
242        "image/x-xbitmap"  // xbm
243    };
244    for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
245        supportedImageMIMETypes->add(types[i]);
246        supportedImageResourceMIMETypes->add(types[i]);
247    }
248
249#if USE(WEBP)
250    supportedImageMIMETypes->add("image/webp");
251    supportedImageResourceMIMETypes->add("image/webp");
252#endif
253
254#if PLATFORM(QT)
255#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
256    QList<QByteArray> mimeTypes = QImageReader::supportedMimeTypes();
257    Q_FOREACH(const QByteArray& mimeType, mimeTypes) {
258        supportedImageMIMETypes->add(mimeType.constData());
259        supportedImageResourceMIMETypes->add(mimeType.constData());
260    }
261#else
262    QList<QByteArray> formats = QImageReader::supportedImageFormats();
263    for (int i = 0; i < formats.size(); ++i) {
264        String mimeType = MIMETypeRegistry::getMIMETypeForExtension(formats.at(i).constData());
265        if (!mimeType.isEmpty()) {
266            supportedImageMIMETypes->add(mimeType);
267            supportedImageResourceMIMETypes->add(mimeType);
268        }
269    }
270#endif // QT_VERSION
271#if ENABLE(SVG)
272    // Do not treat SVG as images directly if WebKit can handle them.
273    supportedImageMIMETypes->remove("image/svg+xml");
274    supportedImageResourceMIMETypes->remove("image/svg+xml");
275#endif
276#endif // PLATFORM(QT)
277#endif // USE(CG)
278}
279
280static void initializeSupportedImageMIMETypesForEncoding()
281{
282    supportedImageMIMETypesForEncoding = new HashSet<String>;
283
284#if USE(CG)
285#if PLATFORM(MAC)
286    RetainPtr<CFArrayRef> supportedTypes = adoptCF(CGImageDestinationCopyTypeIdentifiers());
287    CFIndex count = CFArrayGetCount(supportedTypes.get());
288    for (CFIndex i = 0; i < count; i++) {
289        CFStringRef supportedType = reinterpret_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i));
290        String mimeType = MIMETypeForImageSourceType(supportedType);
291        if (!mimeType.isEmpty())
292            supportedImageMIMETypesForEncoding->add(mimeType);
293    }
294#else
295    // FIXME: Add Windows support for all the supported UTI's when a way to convert from MIMEType to UTI reliably is found.
296    // For now, only support PNG, JPEG and GIF.  See <rdar://problem/6095286>.
297    supportedImageMIMETypesForEncoding->add("image/png");
298    supportedImageMIMETypesForEncoding->add("image/jpeg");
299    supportedImageMIMETypesForEncoding->add("image/gif");
300#endif
301#elif PLATFORM(QT)
302#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
303    QList<QByteArray> mimeTypes = QImageWriter::supportedMimeTypes();
304    Q_FOREACH(const QByteArray& mimeType, mimeTypes) {
305        supportedImageMIMETypesForEncoding->add(mimeType.constData());
306    }
307#else
308    QList<QByteArray> formats = QImageWriter::supportedImageFormats();
309    for (int i = 0; i < formats.size(); ++i) {
310        String mimeType = MIMETypeRegistry::getMIMETypeForExtension(formats.at(i).constData());
311        if (!mimeType.isEmpty())
312            supportedImageMIMETypesForEncoding->add(mimeType);
313    }
314#endif // QT_VERSION
315#elif PLATFORM(GTK)
316    supportedImageMIMETypesForEncoding->add("image/png");
317    supportedImageMIMETypesForEncoding->add("image/jpeg");
318    supportedImageMIMETypesForEncoding->add("image/tiff");
319    supportedImageMIMETypesForEncoding->add("image/bmp");
320    supportedImageMIMETypesForEncoding->add("image/ico");
321#elif USE(CAIRO)
322    supportedImageMIMETypesForEncoding->add("image/png");
323#elif PLATFORM(BLACKBERRY)
324    supportedImageMIMETypesForEncoding->add("image/png");
325    supportedImageMIMETypesForEncoding->add("image/jpeg");
326#endif
327}
328
329static void initializeSupportedJavaScriptMIMETypes()
330{
331    /*
332        Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
333        Mozilla 1.8 accepts application/javascript, application/ecmascript, and application/x-javascript, but WinIE 7 doesn't.
334        WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and text/livescript, but Mozilla 1.8 doesn't.
335        Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
336        Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a whitespace-only string.
337        We want to accept all the values that either of these browsers accept, but not other values.
338     */
339    static const char* types[] = {
340        "text/javascript",
341        "text/ecmascript",
342        "application/javascript",
343        "application/ecmascript",
344        "application/x-javascript",
345        "text/javascript1.1",
346        "text/javascript1.2",
347        "text/javascript1.3",
348        "text/jscript",
349        "text/livescript",
350    };
351    for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i)
352      supportedJavaScriptMIMETypes->add(types[i]);
353}
354
355static void initializePDFAndPostScriptMIMETypes()
356{
357    const char* const types[] = {
358        "application/pdf",
359        "text/pdf",
360        "application/postscript",
361    };
362    for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i)
363        pdfAndPostScriptMIMETypes->add(types[i]);
364}
365
366static void initializeSupportedNonImageMimeTypes()
367{
368    static const char* types[] = {
369        "text/html",
370        "text/xml",
371        "text/xsl",
372        "text/plain",
373        "text/",
374        "application/xml",
375        "application/xhtml+xml",
376        "application/vnd.wap.xhtml+xml",
377        "application/rss+xml",
378        "application/atom+xml",
379        "application/json",
380#if ENABLE(SVG)
381        "image/svg+xml",
382#endif
383#if ENABLE(FTPDIR)
384        "application/x-ftp-directory",
385#endif
386        "multipart/x-mixed-replace"
387        // Note: ADDING a new type here will probably render it as HTML. This can
388        // result in cross-site scripting.
389    };
390    COMPILE_ASSERT(sizeof(types) / sizeof(types[0]) <= 16,
391                   nonimage_mime_types_must_be_less_than_or_equal_to_16);
392
393    for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i)
394        supportedNonImageMIMETypes->add(types[i]);
395
396#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
397    ArchiveFactory::registerKnownArchiveMIMETypes();
398#endif
399}
400
401static MediaMIMETypeMap& mediaMIMETypeMap()
402{
403    DEFINE_STATIC_LOCAL(MediaMIMETypeMap, mediaMIMETypeForExtensionMap, ());
404
405    if (!mediaMIMETypeForExtensionMap.isEmpty())
406        return mediaMIMETypeForExtensionMap;
407
408    const unsigned numPairs = sizeof(commonMediaTypes) / sizeof(commonMediaTypes[0]);
409    for (unsigned ndx = 0; ndx < numPairs; ++ndx) {
410
411        if (mediaMIMETypeForExtensionMap.contains(commonMediaTypes[ndx].extension))
412            mediaMIMETypeForExtensionMap.get(commonMediaTypes[ndx].extension)->append(commonMediaTypes[ndx].type);
413        else {
414            Vector<String>* synonyms = new Vector<String>;
415
416            // If there is a system specific type for this extension, add it as the first type so
417            // getMediaMIMETypeForExtension will always return it.
418            String systemType = MIMETypeRegistry::getMIMETypeForExtension(commonMediaTypes[ndx].extension);
419            if (!systemType.isEmpty() && commonMediaTypes[ndx].type != systemType)
420                synonyms->append(systemType);
421            synonyms->append(commonMediaTypes[ndx].type);
422            mediaMIMETypeForExtensionMap.add(commonMediaTypes[ndx].extension, synonyms);
423        }
424    }
425
426    return mediaMIMETypeForExtensionMap;
427}
428
429String MIMETypeRegistry::getMediaMIMETypeForExtension(const String& ext)
430{
431    // Look in the system-specific registry first.
432    String type = getMIMETypeForExtension(ext);
433    if (!type.isEmpty())
434        return type;
435
436    Vector<String>* typeList = mediaMIMETypeMap().get(ext);
437    if (typeList)
438        return (*typeList)[0];
439
440    return String();
441}
442
443Vector<String> MIMETypeRegistry::getMediaMIMETypesForExtension(const String& ext)
444{
445    Vector<String>* typeList = mediaMIMETypeMap().get(ext);
446    if (typeList)
447        return *typeList;
448
449    // Only need to look in the system-specific registry if mediaMIMETypeMap() doesn't contain
450    // the extension at all, because it always contains the system-specific type if the
451    // extension is in the static mapping table.
452    String type = getMIMETypeForExtension(ext);
453    if (!type.isEmpty()) {
454        Vector<String> typeList;
455        typeList.append(type);
456        return typeList;
457    }
458
459    return Vector<String>();
460}
461
462static void initializeSupportedMediaMIMETypes()
463{
464    supportedMediaMIMETypes = new HashSet<String>;
465#if ENABLE(VIDEO)
466    MediaPlayer::getSupportedTypes(*supportedMediaMIMETypes);
467#endif
468}
469
470static void initializeUnsupportedTextMIMETypes()
471{
472    static const char* types[] = {
473        "text/calendar",
474        "text/x-calendar",
475        "text/x-vcalendar",
476        "text/vcalendar",
477        "text/vcard",
478        "text/x-vcard",
479        "text/directory",
480        "text/ldif",
481        "text/qif",
482        "text/x-qif",
483        "text/x-csv",
484        "text/x-vcf",
485        "text/rtf",
486    };
487    for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i)
488      unsupportedTextMIMETypes->add(types[i]);
489}
490
491static void initializeMIMETypeRegistry()
492{
493    supportedJavaScriptMIMETypes = new HashSet<String>;
494    initializeSupportedJavaScriptMIMETypes();
495
496    supportedNonImageMIMETypes = new HashSet<String>(*supportedJavaScriptMIMETypes);
497    initializeSupportedNonImageMimeTypes();
498
499    supportedImageResourceMIMETypes = new HashSet<String>;
500    supportedImageMIMETypes = new HashSet<String>;
501    initializeSupportedImageMIMETypes();
502
503    pdfAndPostScriptMIMETypes = new HashSet<String>;
504    initializePDFAndPostScriptMIMETypes();
505
506    unsupportedTextMIMETypes = new HashSet<String>;
507    initializeUnsupportedTextMIMETypes();
508}
509
510static String findMimeType(const TypeExtensionPair* pairs, unsigned numPairs, const String& extension)
511{
512    if (!extension.isEmpty()) {
513      for (unsigned i = 0; i < numPairs; ++i, ++pairs) {
514          if (equalIgnoringCase(extension, pairs->extension))
515              return String(pairs->type);
516      }
517    }
518    return String();
519}
520
521String MIMETypeRegistry::getWellKnownMIMETypeForExtension(const String& extension)
522{
523    // This method must be thread safe and should not consult the OS/registry.
524    String found = findMimeType(wellKnownMimeTypes, sizeof(wellKnownMimeTypes) / sizeof(wellKnownMimeTypes[0]), extension);
525    if (!found.isEmpty())
526        return found;
527    return findMimeType(commonMediaTypes, sizeof(commonMediaTypes) / sizeof(commonMediaTypes[0]), extension);
528}
529
530#if !PLATFORM(QT)
531String MIMETypeRegistry::getMIMETypeForPath(const String& path)
532{
533    size_t pos = path.reverseFind('.');
534    if (pos != notFound) {
535        String extension = path.substring(pos + 1);
536        String result = getMIMETypeForExtension(extension);
537        if (result.length())
538            return result;
539    }
540    return defaultMIMEType();
541}
542#endif
543
544bool MIMETypeRegistry::isSupportedImageMIMEType(const String& mimeType)
545{
546    if (mimeType.isEmpty())
547        return false;
548    if (!supportedImageMIMETypes)
549        initializeMIMETypeRegistry();
550    return supportedImageMIMETypes->contains(getNormalizedMIMEType(mimeType));
551}
552
553bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType)
554{
555    if (mimeType.isEmpty())
556        return false;
557    if (!supportedImageResourceMIMETypes)
558        initializeMIMETypeRegistry();
559    return supportedImageResourceMIMETypes->contains(getNormalizedMIMEType(mimeType));
560}
561
562bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeType)
563{
564    ASSERT(isMainThread());
565
566    if (mimeType.isEmpty())
567        return false;
568    if (!supportedImageMIMETypesForEncoding)
569        initializeSupportedImageMIMETypesForEncoding();
570    return supportedImageMIMETypesForEncoding->contains(mimeType);
571}
572
573bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType)
574{
575    if (mimeType.isEmpty())
576        return false;
577    if (!supportedJavaScriptMIMETypes)
578        initializeMIMETypeRegistry();
579    return supportedJavaScriptMIMETypes->contains(mimeType);
580}
581
582bool MIMETypeRegistry::isSupportedNonImageMIMEType(const String& mimeType)
583{
584    if (mimeType.isEmpty())
585        return false;
586    if (!supportedNonImageMIMETypes)
587        initializeMIMETypeRegistry();
588    return supportedNonImageMIMETypes->contains(mimeType);
589}
590
591bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType)
592{
593    if (mimeType.isEmpty())
594        return false;
595    if (!supportedMediaMIMETypes)
596        initializeSupportedMediaMIMETypes();
597    return supportedMediaMIMETypes->contains(mimeType);
598}
599
600bool MIMETypeRegistry::isUnsupportedTextMIMEType(const String& mimeType)
601{
602    if (mimeType.isEmpty())
603        return false;
604    if (!unsupportedTextMIMETypes)
605        initializeMIMETypeRegistry();
606    return unsupportedTextMIMETypes->contains(mimeType);
607}
608
609bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType)
610{
611    // Since this set is very limited and is likely to remain so we won't bother with the overhead
612    // of using a hash set.
613    // Any of the MIME types below may be followed by any number of specific versions of the JVM,
614    // which is why we use startsWith()
615    return mimeType.startsWith("application/x-java-applet", false)
616        || mimeType.startsWith("application/x-java-bean", false)
617        || mimeType.startsWith("application/x-java-vm", false);
618}
619
620bool MIMETypeRegistry::isPDFOrPostScriptMIMEType(const String& mimeType)
621{
622    if (mimeType.isEmpty())
623        return false;
624    if (!pdfAndPostScriptMIMETypes)
625        initializeMIMETypeRegistry();
626    return pdfAndPostScriptMIMETypes->contains(mimeType);
627}
628
629bool MIMETypeRegistry::canShowMIMEType(const String& mimeType)
630{
631    if (isSupportedImageMIMEType(mimeType) || isSupportedNonImageMIMEType(mimeType) || isSupportedMediaMIMEType(mimeType))
632        return true;
633
634    if (mimeType.startsWith("text/", false))
635        return !MIMETypeRegistry::isUnsupportedTextMIMEType(mimeType);
636
637    return false;
638}
639
640HashSet<String>& MIMETypeRegistry::getSupportedImageMIMETypes()
641{
642    if (!supportedImageMIMETypes)
643        initializeMIMETypeRegistry();
644    return *supportedImageMIMETypes;
645}
646
647HashSet<String>& MIMETypeRegistry::getSupportedImageResourceMIMETypes()
648{
649    if (!supportedImageResourceMIMETypes)
650        initializeMIMETypeRegistry();
651    return *supportedImageResourceMIMETypes;
652}
653
654HashSet<String>& MIMETypeRegistry::getSupportedImageMIMETypesForEncoding()
655{
656    if (!supportedImageMIMETypesForEncoding)
657        initializeSupportedImageMIMETypesForEncoding();
658    return *supportedImageMIMETypesForEncoding;
659}
660
661HashSet<String>& MIMETypeRegistry::getSupportedNonImageMIMETypes()
662{
663    if (!supportedNonImageMIMETypes)
664        initializeMIMETypeRegistry();
665    return *supportedNonImageMIMETypes;
666}
667
668HashSet<String>& MIMETypeRegistry::getSupportedMediaMIMETypes()
669{
670    if (!supportedMediaMIMETypes)
671        initializeSupportedMediaMIMETypes();
672    return *supportedMediaMIMETypes;
673}
674
675HashSet<String>& MIMETypeRegistry::getPDFAndPostScriptMIMETypes()
676{
677    if (!pdfAndPostScriptMIMETypes)
678        initializeMIMETypeRegistry();
679    return *pdfAndPostScriptMIMETypes;
680}
681
682HashSet<String>& MIMETypeRegistry::getUnsupportedTextMIMETypes()
683{
684    if (!unsupportedTextMIMETypes)
685        initializeMIMETypeRegistry();
686    return *unsupportedTextMIMETypes;
687}
688
689const String& defaultMIMEType()
690{
691    DEFINE_STATIC_LOCAL(const String, defaultMIMEType, (ASCIILiteral("application/octet-stream")));
692    return defaultMIMEType;
693}
694
695#if !PLATFORM(QT) && !PLATFORM(BLACKBERRY) && !USE(CURL)
696String MIMETypeRegistry::getNormalizedMIMEType(const String& mimeType)
697{
698    return mimeType;
699}
700#endif
701
702#if PLATFORM(BLACKBERRY) || USE(CURL)
703typedef HashMap<String, String> MIMETypeAssociationMap;
704
705static const MIMETypeAssociationMap& mimeTypeAssociationMap()
706{
707    static MIMETypeAssociationMap* mimeTypeMap = 0;
708    if (mimeTypeMap)
709        return *mimeTypeMap;
710
711    mimeTypeMap = new MIMETypeAssociationMap;
712
713    mimeTypeMap->add(ASCIILiteral("image/x-ms-bmp"), ASCIILiteral("image/bmp"));
714    mimeTypeMap->add(ASCIILiteral("image/x-windows-bmp"), ASCIILiteral("image/bmp"));
715    mimeTypeMap->add(ASCIILiteral("image/x-bmp"), ASCIILiteral("image/bmp"));
716    mimeTypeMap->add(ASCIILiteral("image/x-bitmap"), ASCIILiteral("image/bmp"));
717    mimeTypeMap->add(ASCIILiteral("image/x-ms-bitmap"), ASCIILiteral("image/bmp"));
718    mimeTypeMap->add(ASCIILiteral("image/jpg"), ASCIILiteral("image/jpeg"));
719    mimeTypeMap->add(ASCIILiteral("image/pjpeg"), ASCIILiteral("image/jpeg"));
720    mimeTypeMap->add(ASCIILiteral("image/x-png"), ASCIILiteral("image/png"));
721    mimeTypeMap->add(ASCIILiteral("image/vnd.rim.png"), ASCIILiteral("image/png"));
722    mimeTypeMap->add(ASCIILiteral("image/ico"), ASCIILiteral("image/vnd.microsoft.icon"));
723    mimeTypeMap->add(ASCIILiteral("image/icon"), ASCIILiteral("image/vnd.microsoft.icon"));
724    mimeTypeMap->add(ASCIILiteral("text/ico"), ASCIILiteral("image/vnd.microsoft.icon"));
725    mimeTypeMap->add(ASCIILiteral("application/ico"), ASCIILiteral("image/vnd.microsoft.icon"));
726    mimeTypeMap->add(ASCIILiteral("image/x-icon"), ASCIILiteral("image/vnd.microsoft.icon"));
727    mimeTypeMap->add(ASCIILiteral("audio/vnd.qcelp"), ASCIILiteral("audio/qcelp"));
728    mimeTypeMap->add(ASCIILiteral("audio/qcp"), ASCIILiteral("audio/qcelp"));
729    mimeTypeMap->add(ASCIILiteral("audio/vnd.qcp"), ASCIILiteral("audio/qcelp"));
730    mimeTypeMap->add(ASCIILiteral("audio/wav"), ASCIILiteral("audio/x-wav"));
731    mimeTypeMap->add(ASCIILiteral("audio/mid"), ASCIILiteral("audio/midi"));
732    mimeTypeMap->add(ASCIILiteral("audio/sp-midi"), ASCIILiteral("audio/midi"));
733    mimeTypeMap->add(ASCIILiteral("audio/x-mid"), ASCIILiteral("audio/midi"));
734    mimeTypeMap->add(ASCIILiteral("audio/x-midi"), ASCIILiteral("audio/midi"));
735    mimeTypeMap->add(ASCIILiteral("audio/x-mpeg"), ASCIILiteral("audio/mpeg"));
736    mimeTypeMap->add(ASCIILiteral("audio/mp3"), ASCIILiteral("audio/mpeg"));
737    mimeTypeMap->add(ASCIILiteral("audio/x-mp3"), ASCIILiteral("audio/mpeg"));
738    mimeTypeMap->add(ASCIILiteral("audio/mpeg3"), ASCIILiteral("audio/mpeg"));
739    mimeTypeMap->add(ASCIILiteral("audio/x-mpeg3"), ASCIILiteral("audio/mpeg"));
740    mimeTypeMap->add(ASCIILiteral("audio/mpg3"), ASCIILiteral("audio/mpeg"));
741    mimeTypeMap->add(ASCIILiteral("audio/mpg"), ASCIILiteral("audio/mpeg"));
742    mimeTypeMap->add(ASCIILiteral("audio/x-mpg"), ASCIILiteral("audio/mpeg"));
743    mimeTypeMap->add(ASCIILiteral("audio/m4a"), ASCIILiteral("audio/mp4"));
744    mimeTypeMap->add(ASCIILiteral("audio/x-m4a"), ASCIILiteral("audio/mp4"));
745    mimeTypeMap->add(ASCIILiteral("audio/x-mp4"), ASCIILiteral("audio/mp4"));
746    mimeTypeMap->add(ASCIILiteral("audio/x-aac"), ASCIILiteral("audio/aac"));
747    mimeTypeMap->add(ASCIILiteral("audio/x-amr"), ASCIILiteral("audio/amr"));
748    mimeTypeMap->add(ASCIILiteral("audio/mpegurl"), ASCIILiteral("audio/x-mpegurl"));
749    mimeTypeMap->add(ASCIILiteral("audio/flac"), ASCIILiteral("audio/x-flac"));
750    mimeTypeMap->add(ASCIILiteral("video/3gp"), ASCIILiteral("video/3gpp"));
751    mimeTypeMap->add(ASCIILiteral("video/avi"), ASCIILiteral("video/x-msvideo"));
752    mimeTypeMap->add(ASCIILiteral("video/x-m4v"), ASCIILiteral("video/mp4"));
753    mimeTypeMap->add(ASCIILiteral("video/x-quicktime"), ASCIILiteral("video/quicktime"));
754    mimeTypeMap->add(ASCIILiteral("application/java"), ASCIILiteral("application/java-archive"));
755    mimeTypeMap->add(ASCIILiteral("application/x-java-archive"), ASCIILiteral("application/java-archive"));
756    mimeTypeMap->add(ASCIILiteral("application/x-zip-compressed"), ASCIILiteral("application/zip"));
757    mimeTypeMap->add(ASCIILiteral("text/cache-manifest"), ASCIILiteral("text/plain"));
758
759    return *mimeTypeMap;
760}
761
762String MIMETypeRegistry::getNormalizedMIMEType(const String& mimeType)
763{
764    MIMETypeAssociationMap::const_iterator it = mimeTypeAssociationMap().find(mimeType);
765
766    if (it != mimeTypeAssociationMap().end())
767        return it->value;
768
769    return mimeType;
770}
771#endif
772
773} // namespace WebCore
774