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