• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <map>
6 #include <string>
7 
8 #include "net/base/mime_util.h"
9 #include "net/base/platform_mime_util.h"
10 
11 #include "base/hash_tables.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/string_split.h"
15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h"
17 
18 using std::string;
19 
20 namespace net {
21 
22 // Singleton utility class for mime types.
23 class MimeUtil : public PlatformMimeUtil {
24  public:
25   bool GetMimeTypeFromExtension(const FilePath::StringType& ext,
26                                 std::string* mime_type) const;
27 
28   bool GetMimeTypeFromFile(const FilePath& file_path,
29                            std::string* mime_type) const;
30 
31   bool IsSupportedImageMimeType(const char* mime_type) const;
32   bool IsSupportedMediaMimeType(const char* mime_type) const;
33   bool IsSupportedNonImageMimeType(const char* mime_type) const;
34   bool IsSupportedJavascriptMimeType(const char* mime_type) const;
35 
36   bool IsViewSourceMimeType(const char* mime_type) const;
37 
38   bool IsSupportedMimeType(const std::string& mime_type) const;
39 
40   bool MatchesMimeType(const std::string &mime_type_pattern,
41                        const std::string &mime_type) const;
42 
43   bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
44 
45   void ParseCodecString(const std::string& codecs,
46                         std::vector<std::string>* codecs_out,
47                         bool strip);
48 
49   bool IsStrictMediaMimeType(const std::string& mime_type) const;
50   bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
51       const std::vector<std::string>& codecs) const;
52 
53  private:
54   friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
MimeUtil()55   MimeUtil() {
56     InitializeMimeTypeMaps();
57   }
58 
59   // For faster lookup, keep hash sets.
60   void InitializeMimeTypeMaps();
61 
62   typedef base::hash_set<std::string> MimeMappings;
63   MimeMappings image_map_;
64   MimeMappings media_map_;
65   MimeMappings non_image_map_;
66   MimeMappings javascript_map_;
67   MimeMappings view_source_map_;
68   MimeMappings codecs_map_;
69 
70   typedef std::map<std::string, base::hash_set<std::string> > StrictMappings;
71   StrictMappings strict_format_map_;
72 };  // class MimeUtil
73 
74 static base::LazyInstance<MimeUtil> g_mime_util(base::LINKER_INITIALIZED);
75 
76 struct MimeInfo {
77   const char* mime_type;
78   const char* extensions;  // comma separated list
79 };
80 
81 static const MimeInfo primary_mappings[] = {
82   { "text/html", "html,htm" },
83   { "text/css", "css" },
84   { "text/xml", "xml" },
85   { "image/gif", "gif" },
86   { "image/jpeg", "jpeg,jpg" },
87   { "image/webp", "webp" },
88   { "image/png", "png" },
89   { "video/mp4", "mp4,m4v" },
90   { "audio/x-m4a", "m4a" },
91   { "audio/mp3", "mp3" },
92   { "video/ogg", "ogv,ogm" },
93   { "audio/ogg", "ogg,oga" },
94   { "video/webm", "webm" },
95   { "audio/webm", "webm" },
96   { "audio/wav", "wav" },
97   { "application/xhtml+xml", "xhtml,xht" },
98   { "application/x-chrome-extension", "crx" }
99 };
100 
101 static const MimeInfo secondary_mappings[] = {
102   { "application/octet-stream", "exe,com,bin" },
103   { "application/gzip", "gz" },
104   { "application/pdf", "pdf" },
105   { "application/postscript", "ps,eps,ai" },
106   { "application/x-javascript", "js" },
107   { "image/bmp", "bmp" },
108   { "image/x-icon", "ico" },
109   { "image/jpeg", "jfif,pjpeg,pjp" },
110   { "image/tiff", "tiff,tif" },
111   { "image/x-xbitmap", "xbm" },
112   { "image/svg+xml", "svg,svgz" },
113   { "message/rfc822", "eml" },
114   { "text/plain", "txt,text" },
115   { "text/html", "shtml,ehtml" },
116   { "application/rss+xml", "rss" },
117   { "application/rdf+xml", "rdf" },
118   { "text/xml", "xsl,xbl" },
119   { "application/vnd.mozilla.xul+xml", "xul" },
120   { "application/x-shockwave-flash", "swf,swl" }
121 };
122 
FindMimeType(const MimeInfo * mappings,size_t mappings_len,const char * ext)123 static const char* FindMimeType(const MimeInfo* mappings,
124                                 size_t mappings_len,
125                                 const char* ext) {
126   size_t ext_len = strlen(ext);
127 
128   for (size_t i = 0; i < mappings_len; ++i) {
129     const char* extensions = mappings[i].extensions;
130     for (;;) {
131       size_t end_pos = strcspn(extensions, ",");
132       if (end_pos == ext_len &&
133           base::strncasecmp(extensions, ext, ext_len) == 0)
134         return mappings[i].mime_type;
135       extensions += end_pos;
136       if (!*extensions)
137         break;
138       extensions += 1;  // skip over comma
139     }
140   }
141   return NULL;
142 }
143 
GetMimeTypeFromExtension(const FilePath::StringType & ext,string * result) const144 bool MimeUtil::GetMimeTypeFromExtension(const FilePath::StringType& ext,
145                                         string* result) const {
146   // Avoids crash when unable to handle a long file path. See crbug.com/48733.
147   const unsigned kMaxFilePathSize = 65536;
148   if (ext.length() > kMaxFilePathSize)
149     return false;
150 
151   // We implement the same algorithm as Mozilla for mapping a file extension to
152   // a mime type.  That is, we first check a hard-coded list (that cannot be
153   // overridden), and then if not found there, we defer to the system registry.
154   // Finally, we scan a secondary hard-coded list to catch types that we can
155   // deduce but that we also want to allow the OS to override.
156 
157 #if defined(OS_WIN)
158   string ext_narrow_str = WideToUTF8(ext);
159 #elif defined(OS_POSIX)
160   const string& ext_narrow_str = ext;
161 #endif
162   const char* mime_type;
163 
164   mime_type = FindMimeType(primary_mappings, arraysize(primary_mappings),
165                            ext_narrow_str.c_str());
166   if (mime_type) {
167     *result = mime_type;
168     return true;
169   }
170 
171   if (GetPlatformMimeTypeFromExtension(ext, result))
172     return true;
173 
174   mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
175                            ext_narrow_str.c_str());
176   if (mime_type) {
177     *result = mime_type;
178     return true;
179   }
180 
181   return false;
182 }
183 
GetMimeTypeFromFile(const FilePath & file_path,string * result) const184 bool MimeUtil::GetMimeTypeFromFile(const FilePath& file_path,
185                                    string* result) const {
186   FilePath::StringType file_name_str = file_path.Extension();
187   if (file_name_str.empty())
188     return false;
189   return GetMimeTypeFromExtension(file_name_str.substr(1), result);
190 }
191 
192 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
193 
194 static const char* const supported_image_types[] = {
195   "image/jpeg",
196   "image/pjpeg",
197   "image/jpg",
198   "image/webp",
199   "image/png",
200   "image/gif",
201   "image/bmp",
202   "image/x-icon",    // ico
203   "image/x-xbitmap"  // xbm
204 };
205 
206 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
207 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
208 static const char* const supported_media_types[] = {
209   // Ogg.
210   "video/ogg",
211   "audio/ogg",
212   "application/ogg",
213   "video/webm",
214   "audio/webm",
215   "audio/wav",
216   "audio/x-wav",
217 
218 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
219   // MPEG-4.
220   "video/mp4",
221   "video/x-m4v",
222   "audio/mp4",
223   "audio/x-m4a",
224 
225   // MP3.
226   "audio/mp3",
227   "audio/x-mp3",
228   "audio/mpeg",
229 #endif
230 };
231 
232 // List of supported codecs when passed in with <source type="...">.
233 //
234 // Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support
235 // for more information.
236 static const char* const supported_media_codecs[] = {
237 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
238   "avc1",
239   "mp4a",
240 #endif
241   "theora",
242   "vorbis",
243   "vp8",
244   "1"  // PCM for WAV.
245 };
246 
247 // Note: does not include javascript types list (see supported_javascript_types)
248 static const char* const supported_non_image_types[] = {
249   "text/cache-manifest",
250   "text/html",
251   "text/xml",
252   "text/xsl",
253   "text/plain",
254   // Many users complained about css files served for
255   // download instead of displaying in the browser:
256   // http://code.google.com/p/chromium/issues/detail?id=7192
257   // So, by including "text/css" into this list we choose Firefox
258   // behavior - css files will be displayed:
259   "text/css",
260   "text/vnd.chromium.ftp-dir",
261   "text/",
262   "image/svg+xml",  // SVG is text-based XML, even though it has an image/ type
263   "application/xml",
264   "application/xhtml+xml",
265   "application/rss+xml",
266   "application/atom+xml",
267   "application/json",
268   "application/x-x509-user-cert",
269   "multipart/x-mixed-replace"
270   // Note: ADDING a new type here will probably render it AS HTML. This can
271   // result in cross site scripting.
272 };
273 COMPILE_ASSERT(arraysize(supported_non_image_types) == 16,
274                supported_non_images_types_must_equal_16);
275 
276 //  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
277 //  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
278 // application/x-javascript, but WinIE 7 doesn't.
279 //  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
280 // text/livescript, but Mozilla 1.8 doesn't.
281 //  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
282 //  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
283 // whitespace-only string.
284 //  We want to accept all the values that either of these browsers accept, but
285 // not other values.
286 static const char* const supported_javascript_types[] = {
287   "text/javascript",
288   "text/ecmascript",
289   "application/javascript",
290   "application/ecmascript",
291   "application/x-javascript",
292   "text/javascript1.1",
293   "text/javascript1.2",
294   "text/javascript1.3",
295   "text/jscript",
296   "text/livescript"
297 };
298 
299 static const char* const view_source_types[] = {
300   "text/xml",
301   "text/xsl",
302   "application/xml",
303   "application/rss+xml",
304   "application/atom+xml",
305   "image/svg+xml"
306 };
307 
308 struct MediaFormatStrict {
309   const char* mime_type;
310   const char* codecs_list;
311 };
312 
313 static const MediaFormatStrict format_codec_mappings[] = {
314   { "video/webm", "vorbis,vp8,vp8.0" },
315   { "audio/webm", "vorbis" },
316   { "audio/wav", "1" }
317 };
318 
InitializeMimeTypeMaps()319 void MimeUtil::InitializeMimeTypeMaps() {
320   for (size_t i = 0; i < arraysize(supported_image_types); ++i)
321     image_map_.insert(supported_image_types[i]);
322 
323   // Initialize the supported non-image types.
324   for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
325     non_image_map_.insert(supported_non_image_types[i]);
326   for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
327     non_image_map_.insert(supported_javascript_types[i]);
328   for (size_t i = 0; i < arraysize(supported_media_types); ++i)
329     non_image_map_.insert(supported_media_types[i]);
330 
331   // Initialize the supported media types.
332   for (size_t i = 0; i < arraysize(supported_media_types); ++i)
333     media_map_.insert(supported_media_types[i]);
334 
335   for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
336     javascript_map_.insert(supported_javascript_types[i]);
337 
338   for (size_t i = 0; i < arraysize(view_source_types); ++i)
339     view_source_map_.insert(view_source_types[i]);
340 
341   for (size_t i = 0; i < arraysize(supported_media_codecs); ++i)
342     codecs_map_.insert(supported_media_codecs[i]);
343 
344   // Initialize the strict supported media types.
345   for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
346     std::vector<std::string> mime_type_codecs;
347     ParseCodecString(format_codec_mappings[i].codecs_list,
348                      &mime_type_codecs,
349                      false);
350 
351     MimeMappings codecs;
352     for (size_t j = 0; j < mime_type_codecs.size(); ++j)
353       codecs.insert(mime_type_codecs[j]);
354     strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
355   }
356 }
357 
IsSupportedImageMimeType(const char * mime_type) const358 bool MimeUtil::IsSupportedImageMimeType(const char* mime_type) const {
359   return image_map_.find(mime_type) != image_map_.end();
360 }
361 
IsSupportedMediaMimeType(const char * mime_type) const362 bool MimeUtil::IsSupportedMediaMimeType(const char* mime_type) const {
363   return media_map_.find(mime_type) != media_map_.end();
364 }
365 
IsSupportedNonImageMimeType(const char * mime_type) const366 bool MimeUtil::IsSupportedNonImageMimeType(const char* mime_type) const {
367   return non_image_map_.find(mime_type) != non_image_map_.end();
368 }
369 
IsSupportedJavascriptMimeType(const char * mime_type) const370 bool MimeUtil::IsSupportedJavascriptMimeType(const char* mime_type) const {
371   return javascript_map_.find(mime_type) != javascript_map_.end();
372 }
373 
IsViewSourceMimeType(const char * mime_type) const374 bool MimeUtil::IsViewSourceMimeType(const char* mime_type) const {
375   return view_source_map_.find(mime_type) != view_source_map_.end();
376 }
377 
378 // Mirrors WebViewImpl::CanShowMIMEType()
IsSupportedMimeType(const std::string & mime_type) const379 bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
380   return (mime_type.compare(0, 6, "image/") == 0 &&
381           IsSupportedImageMimeType(mime_type.c_str())) ||
382          IsSupportedNonImageMimeType(mime_type.c_str());
383 }
384 
MatchesMimeType(const std::string & mime_type_pattern,const std::string & mime_type) const385 bool MimeUtil::MatchesMimeType(const std::string &mime_type_pattern,
386                                const std::string &mime_type) const {
387   // verify caller is passing lowercase
388   DCHECK_EQ(StringToLowerASCII(mime_type_pattern), mime_type_pattern);
389   DCHECK_EQ(StringToLowerASCII(mime_type), mime_type);
390 
391   // This comparison handles absolute maching and also basic
392   // wildcards.  The plugin mime types could be:
393   //      application/x-foo
394   //      application/*
395   //      application/*+xml
396   //      *
397   if (mime_type_pattern.empty())
398     return false;
399 
400   const std::string::size_type star = mime_type_pattern.find('*');
401 
402   if (star == std::string::npos)
403     return mime_type_pattern == mime_type;
404 
405   // Test length to prevent overlap between |left| and |right|.
406   if (mime_type.length() < mime_type_pattern.length() - 1)
407     return false;
408 
409   const std::string left(mime_type_pattern.substr(0, star));
410   const std::string right(mime_type_pattern.substr(star + 1));
411 
412   if (mime_type.find(left) != 0)
413     return false;
414 
415   if (!right.empty() &&
416       mime_type.rfind(right) != mime_type.length() - right.length())
417     return false;
418 
419   return true;
420 }
421 
AreSupportedMediaCodecs(const std::vector<std::string> & codecs) const422 bool MimeUtil::AreSupportedMediaCodecs(
423     const std::vector<std::string>& codecs) const {
424   for (size_t i = 0; i < codecs.size(); ++i) {
425     if (codecs_map_.find(codecs[i]) == codecs_map_.end()) {
426       return false;
427     }
428   }
429   return true;
430 }
431 
ParseCodecString(const std::string & codecs,std::vector<std::string> * codecs_out,bool strip)432 void MimeUtil::ParseCodecString(const std::string& codecs,
433                                 std::vector<std::string>* codecs_out,
434                                 bool strip) {
435   std::string no_quote_codecs;
436   TrimString(codecs, "\"", &no_quote_codecs);
437   base::SplitString(no_quote_codecs, ',', codecs_out);
438 
439   if (!strip)
440     return;
441 
442   // Strip everything past the first '.'
443   for (std::vector<std::string>::iterator it = codecs_out->begin();
444        it != codecs_out->end();
445        ++it) {
446     size_t found = it->find_first_of('.');
447     if (found != std::string::npos)
448       it->resize(found);
449   }
450 }
451 
IsStrictMediaMimeType(const std::string & mime_type) const452 bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
453   if (strict_format_map_.find(mime_type) == strict_format_map_.end())
454     return false;
455   return true;
456 }
457 
IsSupportedStrictMediaMimeType(const std::string & mime_type,const std::vector<std::string> & codecs) const458 bool MimeUtil::IsSupportedStrictMediaMimeType(const std::string& mime_type,
459     const std::vector<std::string>& codecs) const {
460   StrictMappings::const_iterator it = strict_format_map_.find(mime_type);
461 
462   if (it == strict_format_map_.end())
463     return false;
464 
465   const MimeMappings strict_codecs_map = it->second;
466   for (size_t i = 0; i < codecs.size(); ++i) {
467     if (strict_codecs_map.find(codecs[i]) == strict_codecs_map.end()) {
468       return false;
469     }
470   }
471   return true;
472 }
473 
474 //----------------------------------------------------------------------------
475 // Wrappers for the singleton
476 //----------------------------------------------------------------------------
477 
GetMimeTypeFromExtension(const FilePath::StringType & ext,std::string * mime_type)478 bool GetMimeTypeFromExtension(const FilePath::StringType& ext,
479                               std::string* mime_type) {
480   return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
481 }
482 
GetMimeTypeFromFile(const FilePath & file_path,std::string * mime_type)483 bool GetMimeTypeFromFile(const FilePath& file_path, std::string* mime_type) {
484   return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
485 }
486 
GetPreferredExtensionForMimeType(const std::string & mime_type,FilePath::StringType * extension)487 bool GetPreferredExtensionForMimeType(const std::string& mime_type,
488                                       FilePath::StringType* extension) {
489   return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
490                                                             extension);
491 }
492 
IsSupportedImageMimeType(const char * mime_type)493 bool IsSupportedImageMimeType(const char* mime_type) {
494   return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
495 }
496 
IsSupportedMediaMimeType(const char * mime_type)497 bool IsSupportedMediaMimeType(const char* mime_type) {
498   return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
499 }
500 
IsSupportedNonImageMimeType(const char * mime_type)501 bool IsSupportedNonImageMimeType(const char* mime_type) {
502   return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
503 }
504 
IsSupportedJavascriptMimeType(const char * mime_type)505 bool IsSupportedJavascriptMimeType(const char* mime_type) {
506   return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
507 }
508 
IsViewSourceMimeType(const char * mime_type)509 bool IsViewSourceMimeType(const char* mime_type) {
510   return g_mime_util.Get().IsViewSourceMimeType(mime_type);
511 }
512 
IsSupportedMimeType(const std::string & mime_type)513 bool IsSupportedMimeType(const std::string& mime_type) {
514   return g_mime_util.Get().IsSupportedMimeType(mime_type);
515 }
516 
MatchesMimeType(const std::string & mime_type_pattern,const std::string & mime_type)517 bool MatchesMimeType(const std::string &mime_type_pattern,
518                      const std::string &mime_type) {
519   return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
520 }
521 
AreSupportedMediaCodecs(const std::vector<std::string> & codecs)522 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
523   return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
524 }
525 
IsStrictMediaMimeType(const std::string & mime_type)526 bool IsStrictMediaMimeType(const std::string& mime_type) {
527   return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
528 }
529 
IsSupportedStrictMediaMimeType(const std::string & mime_type,const std::vector<std::string> & codecs)530 bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
531                                     const std::vector<std::string>& codecs) {
532   return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
533 }
534 
ParseCodecString(const std::string & codecs,std::vector<std::string> * codecs_out,const bool strip)535 void ParseCodecString(const std::string& codecs,
536                       std::vector<std::string>* codecs_out,
537                       const bool strip) {
538   g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
539 }
540 
541 namespace {
542 
543 // From http://www.w3schools.com/media/media_mimeref.asp and
544 // http://plugindoc.mozdev.org/winmime.php
545 static const char* kStandardImageTypes[] = {
546   "image/bmp",
547   "image/cis-cod",
548   "image/gif",
549   "image/ief",
550   "image/jpeg",
551   "image/webp",
552   "image/pict",
553   "image/pipeg",
554   "image/png",
555   "image/svg+xml",
556   "image/tiff",
557   "image/x-cmu-raster",
558   "image/x-cmx",
559   "image/x-icon",
560   "image/x-portable-anymap",
561   "image/x-portable-bitmap",
562   "image/x-portable-graymap",
563   "image/x-portable-pixmap",
564   "image/x-rgb",
565   "image/x-xbitmap",
566   "image/x-xpixmap",
567   "image/x-xwindowdump"
568 };
569 static const char* kStandardAudioTypes[] = {
570   "audio/aac",
571   "audio/aiff",
572   "audio/amr",
573   "audio/basic",
574   "audio/midi",
575   "audio/mp3",
576   "audio/mp4",
577   "audio/mpeg",
578   "audio/mpeg3",
579   "audio/ogg",
580   "audio/vorbis",
581   "audio/wav",
582   "audio/webm",
583   "audio/x-m4a",
584   "audio/x-ms-wma",
585   "audio/vnd.rn-realaudio",
586   "audio/vnd.wave"
587 };
588 static const char* kStandardVideoTypes[] = {
589   "video/avi",
590   "video/divx",
591   "video/flc",
592   "video/mp4",
593   "video/mpeg",
594   "video/ogg",
595   "video/quicktime",
596   "video/sd-video",
597   "video/webm",
598   "video/x-dv",
599   "video/x-m4v",
600   "video/x-mpeg",
601   "video/x-ms-asf",
602   "video/x-ms-wmv"
603 };
604 
GetExtensionsFromHardCodedMappings(const MimeInfo * mappings,size_t mappings_len,const std::string & leading_mime_type,base::hash_set<FilePath::StringType> * extensions)605 void GetExtensionsFromHardCodedMappings(
606     const MimeInfo* mappings,
607     size_t mappings_len,
608     const std::string& leading_mime_type,
609     base::hash_set<FilePath::StringType>* extensions) {
610   FilePath::StringType extension;
611   for (size_t i = 0; i < mappings_len; ++i) {
612     if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
613       std::vector<string> this_extensions;
614       base::SplitStringUsingSubstr(mappings[i].extensions,
615                                    ",",
616                                    &this_extensions);
617       for (size_t j = 0; j < this_extensions.size(); ++j) {
618 #if defined(OS_WIN)
619         FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
620 #else
621         FilePath::StringType extension(this_extensions[j]);
622 #endif
623         extensions->insert(extension);
624       }
625     }
626   }
627 }
628 
GetExtensionsHelper(const char ** standard_types,size_t standard_types_len,const std::string & leading_mime_type,base::hash_set<FilePath::StringType> * extensions)629 void GetExtensionsHelper(
630     const char** standard_types,
631     size_t standard_types_len,
632     const std::string& leading_mime_type,
633     base::hash_set<FilePath::StringType>* extensions) {
634   FilePath::StringType extension;
635   for (size_t i = 0; i < standard_types_len; ++i) {
636     if (GetPreferredExtensionForMimeType(standard_types[i], &extension))
637       extensions->insert(extension);
638   }
639 
640   // Also look up the extensions from hard-coded mappings in case that some
641   // supported extensions are not registered in the system registry, like ogg.
642   GetExtensionsFromHardCodedMappings(primary_mappings,
643                                      arraysize(primary_mappings),
644                                      leading_mime_type,
645                                      extensions);
646 
647   GetExtensionsFromHardCodedMappings(secondary_mappings,
648                                      arraysize(secondary_mappings),
649                                      leading_mime_type,
650                                      extensions);
651 }
652 
653 // Note that the elements in the source set will be appended to the target
654 // vector.
655 template<class T>
HashSetToVector(base::hash_set<T> * source,std::vector<T> * target)656 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
657   size_t old_target_size = target->size();
658   target->resize(old_target_size + source->size());
659   size_t i = 0;
660   for (typename base::hash_set<T>::iterator iter = source->begin();
661        iter != source->end(); ++iter, ++i) {
662     target->at(old_target_size + i) = *iter;
663   }
664 }
665 }
666 
GetImageExtensions(std::vector<FilePath::StringType> * extensions)667 void GetImageExtensions(std::vector<FilePath::StringType>* extensions) {
668   base::hash_set<FilePath::StringType> unique_extensions;
669   GetExtensionsHelper(kStandardImageTypes,
670                       arraysize(kStandardImageTypes),
671                       "image/",
672                       &unique_extensions);
673   HashSetToVector(&unique_extensions, extensions);
674 }
675 
GetAudioExtensions(std::vector<FilePath::StringType> * extensions)676 void GetAudioExtensions(std::vector<FilePath::StringType>* extensions) {
677   base::hash_set<FilePath::StringType> unique_extensions;
678   GetExtensionsHelper(kStandardAudioTypes,
679                       arraysize(kStandardAudioTypes),
680                       "audio/",
681                       &unique_extensions);
682   HashSetToVector(&unique_extensions, extensions);
683 }
684 
GetVideoExtensions(std::vector<FilePath::StringType> * extensions)685 void GetVideoExtensions(std::vector<FilePath::StringType>* extensions) {
686   base::hash_set<FilePath::StringType> unique_extensions;
687   GetExtensionsHelper(kStandardVideoTypes,
688                       arraysize(kStandardVideoTypes),
689                       "video/",
690                       &unique_extensions);
691   HashSetToVector(&unique_extensions, extensions);
692 }
693 
GetExtensionsForMimeType(const std::string & mime_type,std::vector<FilePath::StringType> * extensions)694 void GetExtensionsForMimeType(const std::string& mime_type,
695                               std::vector<FilePath::StringType>* extensions) {
696   base::hash_set<FilePath::StringType> unique_extensions;
697   FilePath::StringType extension;
698   if (GetPreferredExtensionForMimeType(mime_type, &extension))
699     unique_extensions.insert(extension);
700 
701   // Also look up the extensions from hard-coded mappings in case that some
702   // supported extensions are not registered in the system registry, like ogg.
703   GetExtensionsFromHardCodedMappings(primary_mappings,
704                                      arraysize(primary_mappings),
705                                      mime_type,
706                                      &unique_extensions);
707 
708   GetExtensionsFromHardCodedMappings(secondary_mappings,
709                                      arraysize(secondary_mappings),
710                                      mime_type,
711                                      &unique_extensions);
712 
713   HashSetToVector(&unique_extensions, extensions);
714 }
715 
716 }  // namespace net
717