Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / itunes_file_util.cc
blobb8c45c88dda803862cb753ea9320b9c40f434d31
1 // Copyright 2013 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/itunes_file_util.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/bind_helpers.h"
12 #include "base/file_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
15 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
16 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "webkit/browser/fileapi/file_system_operation_context.h"
19 #include "webkit/browser/fileapi/file_system_url.h"
20 #include "webkit/browser/fileapi/native_file_util.h"
21 #include "webkit/common/blob/shareable_file_reference.h"
22 #include "webkit/common/fileapi/file_system_util.h"
24 using fileapi::DirectoryEntry;
26 namespace itunes {
28 namespace {
30 base::PlatformFileError MakeDirectoryFileInfo(
31 base::PlatformFileInfo* file_info) {
32 base::PlatformFileInfo result;
33 result.is_directory = true;
34 *file_info = result;
35 return base::PLATFORM_FILE_OK;
38 } // namespace
40 const char kITunesLibraryXML[] = "iTunes Music Library.xml";
41 const char kITunesMediaDir[] = "iTunes Media";
42 const char kITunesMusicDir[] = "Music";
43 const char kITunesAutoAddDir[] = "Automatically Add to iTunes";
45 ITunesFileUtil::ITunesFileUtil(MediaPathFilter* media_path_filter)
46 : NativeMediaFileUtil(media_path_filter),
47 weak_factory_(this),
48 imported_registry_(NULL) {
51 ITunesFileUtil::~ITunesFileUtil() {
54 void ITunesFileUtil::GetFileInfoOnTaskRunnerThread(
55 scoped_ptr<fileapi::FileSystemOperationContext> context,
56 const fileapi::FileSystemURL& url,
57 const GetFileInfoCallback& callback) {
58 GetDataProvider()->RefreshData(
59 base::Bind(&ITunesFileUtil::GetFileInfoWithFreshDataProvider,
60 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
61 callback));
64 void ITunesFileUtil::ReadDirectoryOnTaskRunnerThread(
65 scoped_ptr<fileapi::FileSystemOperationContext> context,
66 const fileapi::FileSystemURL& url,
67 const ReadDirectoryCallback& callback) {
68 GetDataProvider()->RefreshData(
69 base::Bind(&ITunesFileUtil::ReadDirectoryWithFreshDataProvider,
70 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
71 callback));
74 void ITunesFileUtil::CreateSnapshotFileOnTaskRunnerThread(
75 scoped_ptr<fileapi::FileSystemOperationContext> context,
76 const fileapi::FileSystemURL& url,
77 const CreateSnapshotFileCallback& callback) {
78 GetDataProvider()->RefreshData(
79 base::Bind(&ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider,
80 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
81 callback));
84 // Contents of the iTunes media gallery:
85 // / - root directory
86 // /iTunes Music Library.xml - library xml file
87 // /iTunes Media/Automatically Add to iTunes - auto-import directory
88 // /iTunes Media/Music/<Artist>/<Album>/<Track> - tracks
90 base::PlatformFileError ITunesFileUtil::GetFileInfoSync(
91 fileapi::FileSystemOperationContext* context,
92 const fileapi::FileSystemURL& url,
93 base::PlatformFileInfo* file_info,
94 base::FilePath* platform_path) {
95 std::vector<std::string> components;
96 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
98 if (components.size() == 0)
99 return MakeDirectoryFileInfo(file_info);
101 if (components.size() == 1 && components[0] == kITunesLibraryXML) {
102 // We can't just call NativeMediaFileUtil::GetFileInfoSync() here because it
103 // uses the MediaPathFilter. At this point, |library_path_| is known good
104 // because GetFileInfoWithFreshDataProvider() gates access to this method.
105 base::FilePath file_path = GetDataProvider()->library_path();
106 if (platform_path)
107 *platform_path = file_path;
108 return fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
111 if (components[0] != kITunesMediaDir)
112 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
114 if (components[1] == kITunesAutoAddDir) {
115 if (GetDataProvider()->auto_add_path().empty())
116 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
117 return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
118 platform_path);
121 if (components[1] == kITunesMusicDir) {
122 switch (components.size()) {
123 case 2:
124 return MakeDirectoryFileInfo(file_info);
126 case 3:
127 if (GetDataProvider()->KnownArtist(components[2]))
128 return MakeDirectoryFileInfo(file_info);
129 break;
131 case 4:
132 if (GetDataProvider()->KnownAlbum(components[2], components[3]))
133 return MakeDirectoryFileInfo(file_info);
134 break;
136 case 5: {
137 base::FilePath location =
138 GetDataProvider()->GetTrackLocation(components[2], components[3],
139 components[4]);
140 if (!location.empty()) {
141 return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
142 platform_path);
144 break;
149 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
152 base::PlatformFileError ITunesFileUtil::ReadDirectorySync(
153 fileapi::FileSystemOperationContext* context,
154 const fileapi::FileSystemURL& url,
155 EntryList* file_list) {
156 DCHECK(file_list->empty());
157 std::vector<std::string> components;
158 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
160 if (components.size() == 0) {
161 base::File::Info xml_info;
162 if (!base::GetFileInfo(GetDataProvider()->library_path(), &xml_info))
163 return base::PLATFORM_FILE_ERROR_IO;
164 file_list->push_back(DirectoryEntry(kITunesLibraryXML,
165 DirectoryEntry::FILE,
166 xml_info.size, xml_info.last_modified));
167 file_list->push_back(DirectoryEntry(kITunesMediaDir,
168 DirectoryEntry::DIRECTORY,
169 0, base::Time()));
170 return base::PLATFORM_FILE_OK;
173 if (components.size() == 1 && components[0] == kITunesLibraryXML)
174 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
176 if (components[0] != kITunesMediaDir || components.size() > 5)
177 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
179 if (components.size() == 1) {
180 if (!GetDataProvider()->auto_add_path().empty()) {
181 file_list->push_back(DirectoryEntry(kITunesAutoAddDir,
182 DirectoryEntry::DIRECTORY,
183 0, base::Time()));
185 file_list->push_back(DirectoryEntry(kITunesMusicDir,
186 DirectoryEntry::DIRECTORY,
187 0, base::Time()));
188 return base::PLATFORM_FILE_OK;
191 if (components[1] == kITunesAutoAddDir &&
192 !GetDataProvider()->auto_add_path().empty()) {
193 return NativeMediaFileUtil::ReadDirectorySync(context, url, file_list);
196 if (components[1] != kITunesMusicDir)
197 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
199 if (components.size() == 2) {
200 std::set<ITunesDataProvider::ArtistName> artists =
201 GetDataProvider()->GetArtistNames();
202 std::set<ITunesDataProvider::ArtistName>::const_iterator it;
203 for (it = artists.begin(); it != artists.end(); ++it)
204 file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
205 0, base::Time()));
206 return base::PLATFORM_FILE_OK;
209 if (components.size() == 3) {
210 std::set<ITunesDataProvider::AlbumName> albums =
211 GetDataProvider()->GetAlbumNames(components[2]);
212 if (albums.size() == 0)
213 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
214 std::set<ITunesDataProvider::AlbumName>::const_iterator it;
215 for (it = albums.begin(); it != albums.end(); ++it)
216 file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
217 0, base::Time()));
218 return base::PLATFORM_FILE_OK;
221 if (components.size() == 4) {
222 ITunesDataProvider::Album album =
223 GetDataProvider()->GetAlbum(components[2], components[3]);
224 if (album.size() == 0)
225 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
226 ITunesDataProvider::Album::const_iterator it;
227 for (it = album.begin(); it != album.end(); ++it) {
228 base::File::Info file_info;
229 if (media_path_filter()->Match(it->second) &&
230 base::GetFileInfo(it->second, &file_info)) {
231 file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
232 file_info.size,
233 file_info.last_modified));
236 return base::PLATFORM_FILE_OK;
239 // At this point, the only choice is one of two errors, but figuring out
240 // which one is required.
241 DCHECK_EQ(4UL, components.size());
242 base::FilePath location;
243 location = GetDataProvider()->GetTrackLocation(components[1], components[2],
244 components[3]);
245 if (!location.empty())
246 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
247 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
250 base::PlatformFileError ITunesFileUtil::DeleteDirectorySync(
251 fileapi::FileSystemOperationContext* context,
252 const fileapi::FileSystemURL& url) {
253 return base::PLATFORM_FILE_ERROR_SECURITY;
256 base::PlatformFileError ITunesFileUtil::DeleteFileSync(
257 fileapi::FileSystemOperationContext* context,
258 const fileapi::FileSystemURL& url) {
259 return base::PLATFORM_FILE_ERROR_SECURITY;
262 base::PlatformFileError ITunesFileUtil::CreateSnapshotFileSync(
263 fileapi::FileSystemOperationContext* context,
264 const fileapi::FileSystemURL& url,
265 base::PlatformFileInfo* file_info,
266 base::FilePath* platform_path,
267 scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
268 DCHECK(!url.path().IsAbsolute());
269 if (url.path() != base::FilePath().AppendASCII(kITunesLibraryXML)) {
270 return NativeMediaFileUtil::CreateSnapshotFileSync(context, url, file_info,
271 platform_path, file_ref);
274 // The following code is different than
275 // NativeMediaFileUtil::CreateSnapshotFileSync in that it knows that the
276 // library xml file is not a directory and it doesn't run mime sniffing on the
277 // file. The only way to get here is by way of
278 // CreateSnapshotFileWithFreshDataProvider() so the file has already been
279 // parsed and deemed valid.
280 *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
281 return GetFileInfoSync(context, url, file_info, platform_path);
284 base::PlatformFileError ITunesFileUtil::GetLocalFilePath(
285 fileapi::FileSystemOperationContext* context,
286 const fileapi::FileSystemURL& url,
287 base::FilePath* local_file_path) {
288 std::vector<std::string> components;
289 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
291 if (components.size() == 1 && components[0] == kITunesLibraryXML) {
292 *local_file_path = GetDataProvider()->library_path();
293 return base::PLATFORM_FILE_OK;
296 if (components.size() >= 2 && components[0] == kITunesMediaDir &&
297 components[1] == kITunesAutoAddDir) {
298 *local_file_path = GetDataProvider()->auto_add_path();
299 if (local_file_path->empty())
300 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
302 for (size_t i = 2; i < components.size(); ++i) {
303 *local_file_path = local_file_path->Append(
304 base::FilePath::FromUTF8Unsafe(components[i]));
306 return base::PLATFORM_FILE_OK;
309 // Should only get here for files, i.e. the xml file and tracks.
310 if (components[0] != kITunesMediaDir || components[1] != kITunesMusicDir||
311 components.size() != 5) {
312 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
315 *local_file_path = GetDataProvider()->GetTrackLocation(components[2],
316 components[3],
317 components[4]);
318 if (!local_file_path->empty())
319 return base::PLATFORM_FILE_OK;
321 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
324 void ITunesFileUtil::GetFileInfoWithFreshDataProvider(
325 scoped_ptr<fileapi::FileSystemOperationContext> context,
326 const fileapi::FileSystemURL& url,
327 const GetFileInfoCallback& callback,
328 bool valid_parse) {
329 if (!valid_parse) {
330 if (!callback.is_null()) {
331 content::BrowserThread::PostTask(
332 content::BrowserThread::IO,
333 FROM_HERE,
334 base::Bind(callback, base::PLATFORM_FILE_ERROR_IO,
335 base::PlatformFileInfo()));
337 return;
339 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
340 callback);
343 void ITunesFileUtil::ReadDirectoryWithFreshDataProvider(
344 scoped_ptr<fileapi::FileSystemOperationContext> context,
345 const fileapi::FileSystemURL& url,
346 const ReadDirectoryCallback& callback,
347 bool valid_parse) {
348 if (!valid_parse) {
349 if (!callback.is_null()) {
350 content::BrowserThread::PostTask(
351 content::BrowserThread::IO,
352 FROM_HERE,
353 base::Bind(callback, base::PLATFORM_FILE_ERROR_IO, EntryList(),
354 false));
356 return;
358 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
359 callback);
362 void ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider(
363 scoped_ptr<fileapi::FileSystemOperationContext> context,
364 const fileapi::FileSystemURL& url,
365 const CreateSnapshotFileCallback& callback,
366 bool valid_parse) {
367 if (!valid_parse) {
368 if (!callback.is_null()) {
369 base::PlatformFileInfo file_info;
370 base::FilePath platform_path;
371 scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
372 content::BrowserThread::PostTask(
373 content::BrowserThread::IO,
374 FROM_HERE,
375 base::Bind(callback, base::PLATFORM_FILE_ERROR_IO, file_info,
376 platform_path, file_ref));
378 return;
380 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url,
381 callback);
384 ITunesDataProvider* ITunesFileUtil::GetDataProvider() {
385 if (!imported_registry_)
386 imported_registry_ = ImportedMediaGalleryRegistry::GetInstance();
387 return imported_registry_->ITunesDataProvider();
390 } // namespace itunes