1 // Copyright (c) 2012 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.
5 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
14 #include "base/strings/string_util.h"
15 #include "net/base/mime_util.h"
19 const base::FilePath::CharType* const kExtraSupportedImageExtensions[] = {
20 // RAW picture file types.
21 // Some of which are just image/tiff.
22 FILE_PATH_LITERAL("3fr"), // (Hasselblad)
23 FILE_PATH_LITERAL("arw"), // (Sony)
24 FILE_PATH_LITERAL("dcr"), // (Kodak)
25 FILE_PATH_LITERAL("dng"), // (Adobe, Leica, Ricoh, Samsung)
26 FILE_PATH_LITERAL("erf"), // (Epson)
27 FILE_PATH_LITERAL("k25"), // (Kodak)
28 FILE_PATH_LITERAL("kdc"), // (Kodak)
29 FILE_PATH_LITERAL("mef"), // (Mamiya)
30 FILE_PATH_LITERAL("mos"), // (Leaf)
31 FILE_PATH_LITERAL("nef"), // (Nikon)
32 FILE_PATH_LITERAL("pef"), // (Pentax)
33 FILE_PATH_LITERAL("sr2"), // (Sony)
34 FILE_PATH_LITERAL("srf"), // (Sony)
36 // More RAW picture file types.
37 FILE_PATH_LITERAL("cr2"), // (Canon - image/x-canon-cr2)
38 // Note, some .crw files are just TIFFs.
39 FILE_PATH_LITERAL("crw"), // (Canon - image/x-canon-crw)
40 FILE_PATH_LITERAL("mrw"), // (Minolta - image/x-minolta-mrw)
41 FILE_PATH_LITERAL("orf"), // (Olympus - image/x-olympus-orf)
42 FILE_PATH_LITERAL("raf"), // (Fuji)
43 FILE_PATH_LITERAL("rw2"), // (Panasonic - image/x-panasonic-raw)
44 FILE_PATH_LITERAL("x3f"), // (Sigma - image/x-x3f)
46 // There exists many file formats all with the .raw extension. For now, only
47 // the following types are supported:
48 // - TIFF files with .raw extension - image/tiff
49 // - Leica / Panasonic RAW files - image/x-panasonic-raw
50 // - Phase One RAW files - image/x-phaseone-raw
51 FILE_PATH_LITERAL("raw"),
54 const base::FilePath::CharType* const kExtraSupportedVideoExtensions[] = {
55 FILE_PATH_LITERAL("3gp"),
56 FILE_PATH_LITERAL("3gpp"),
57 FILE_PATH_LITERAL("avi"),
58 FILE_PATH_LITERAL("flv"),
59 FILE_PATH_LITERAL("mkv"),
60 FILE_PATH_LITERAL("mov"),
61 FILE_PATH_LITERAL("mpeg"),
62 FILE_PATH_LITERAL("mpeg4"),
63 FILE_PATH_LITERAL("mpegps"),
64 FILE_PATH_LITERAL("mpg"),
65 FILE_PATH_LITERAL("wmv"),
68 const base::FilePath::CharType* const kExtraSupportedAudioExtensions[] = {
69 // Many of these file types are audio files in the same containers that the
70 // MIME sniffer already detects as video/subtype.
71 FILE_PATH_LITERAL("aac"), // audio/mpeg
72 FILE_PATH_LITERAL("alac"), // video/mp4
73 FILE_PATH_LITERAL("flac"), // audio/x-flac
74 FILE_PATH_LITERAL("m4b"), // video/mp4
75 FILE_PATH_LITERAL("m4p"), // video/mp4
76 FILE_PATH_LITERAL("wma"), // video/x-ms-asf
79 bool IsUnsupportedExtension(const base::FilePath::StringType& extension) {
80 std::string mime_type;
81 return !net::GetMimeTypeFromExtension(extension, &mime_type) ||
82 !net::IsSupportedMimeType(mime_type);
85 std::vector<base::FilePath::StringType> GetMediaExtensionList(
86 const std::string& mime_type) {
87 std::vector<base::FilePath::StringType> extensions;
88 net::GetExtensionsForMimeType(mime_type, &extensions);
89 std::vector<base::FilePath::StringType>::iterator new_end =
90 std::remove_if(extensions.begin(),
92 &IsUnsupportedExtension);
93 extensions.erase(new_end, extensions.end());
100 bool MediaPathFilter::ShouldSkip(const base::FilePath& path) {
101 const base::FilePath::StringType base_name = path.BaseName().value();
102 if (base_name.empty())
105 // Dot files (aka hidden files)
106 if (base_name[0] == '.')
110 if (base_name == FILE_PATH_LITERAL("__MACOSX"))
114 DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
115 if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
116 ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
119 // Windows always creates a recycle bin folder in the attached device to store
120 // all the deleted contents. On non-windows operating systems, there is no way
121 // to get the hidden attribute of windows recycle bin folders that are present
122 // on the attached device. Therefore, compare the file path name to the
123 // recycle bin name and exclude those folders. For more details, please refer
124 // to http://support.microsoft.com/kb/171694.
125 const char win_98_recycle_bin_name[] = "RECYCLED";
126 const char win_xp_recycle_bin_name[] = "RECYCLER";
127 const char win_vista_recycle_bin_name[] = "$Recycle.bin";
128 if ((base::strncasecmp(base_name.c_str(),
129 win_98_recycle_bin_name,
130 strlen(win_98_recycle_bin_name)) == 0) ||
131 (base::strncasecmp(base_name.c_str(),
132 win_xp_recycle_bin_name,
133 strlen(win_xp_recycle_bin_name)) == 0) ||
134 (base::strncasecmp(base_name.c_str(),
135 win_vista_recycle_bin_name,
136 strlen(win_vista_recycle_bin_name)) == 0))
138 #endif // defined(OS_WIN)
142 MediaPathFilter::MediaPathFilter()
143 : initialized_(false) {
144 sequence_checker_.DetachFromSequence();
147 MediaPathFilter::~MediaPathFilter() {
150 bool MediaPathFilter::Match(const base::FilePath& path) {
151 return GetType(path) != MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN;
154 MediaGalleryScanFileType MediaPathFilter::GetType(const base::FilePath& path) {
156 MediaFileExtensionMap::const_iterator it =
157 media_file_extensions_map_.find(StringToLowerASCII(path.Extension()));
158 if (it == media_file_extensions_map_.end())
159 return MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN;
160 return static_cast<MediaGalleryScanFileType>(it->second);
163 void MediaPathFilter::EnsureInitialized() {
164 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
168 // This may require I/O when it calls net::GetExtensionsForMimeType(), so
169 // doing this in the ctor and removing |initialized_| would result in a
170 // ThreadRestrictions failure.
171 AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("image/*"),
172 MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE);
173 AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("audio/*"),
174 MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO);
175 AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("video/*"),
176 MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO);
177 AddAdditionalExtensionsToMediaFileExtensionMap(
178 kExtraSupportedImageExtensions,
179 arraysize(kExtraSupportedImageExtensions),
180 MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE);
181 AddAdditionalExtensionsToMediaFileExtensionMap(
182 kExtraSupportedAudioExtensions,
183 arraysize(kExtraSupportedAudioExtensions),
184 MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO);
185 AddAdditionalExtensionsToMediaFileExtensionMap(
186 kExtraSupportedVideoExtensions,
187 arraysize(kExtraSupportedVideoExtensions),
188 MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO);
193 void MediaPathFilter::AddExtensionsToMediaFileExtensionMap(
194 const MediaFileExtensionList& extensions_list,
195 MediaGalleryScanFileType type) {
196 for (size_t i = 0; i < extensions_list.size(); ++i)
197 AddExtensionToMediaFileExtensionMap(extensions_list[i].c_str(), type);
200 void MediaPathFilter::AddAdditionalExtensionsToMediaFileExtensionMap(
201 const base::FilePath::CharType* const* extensions_list,
202 size_t extensions_list_size,
203 MediaGalleryScanFileType type) {
204 for (size_t i = 0; i < extensions_list_size; ++i)
205 AddExtensionToMediaFileExtensionMap(extensions_list[i], type);
208 void MediaPathFilter::AddExtensionToMediaFileExtensionMap(
209 const base::FilePath::CharType* extension,
210 MediaGalleryScanFileType type) {
211 base::FilePath::StringType extension_with_sep =
212 base::FilePath::kExtensionSeparator +
213 base::FilePath::StringType(extension);
214 media_file_extensions_map_[extension_with_sep] |= type;