NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / itunes_file_util.cc
blob07371f542a75980ed155b6857a25c20966730bb2
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::File::Error MakeDirectoryFileInfo(base::File::Info* file_info) {
31 base::File::Info result;
32 result.is_directory = true;
33 *file_info = result;
34 return base::File::FILE_OK;
37 } // namespace
39 const char kITunesLibraryXML[] = "iTunes Music Library.xml";
40 const char kITunesMediaDir[] = "iTunes Media";
41 const char kITunesMusicDir[] = "Music";
42 const char kITunesAutoAddDir[] = "Automatically Add to iTunes";
44 ITunesFileUtil::ITunesFileUtil(MediaPathFilter* media_path_filter)
45 : NativeMediaFileUtil(media_path_filter),
46 weak_factory_(this),
47 imported_registry_(NULL) {
50 ITunesFileUtil::~ITunesFileUtil() {
53 void ITunesFileUtil::GetFileInfoOnTaskRunnerThread(
54 scoped_ptr<fileapi::FileSystemOperationContext> context,
55 const fileapi::FileSystemURL& url,
56 const GetFileInfoCallback& callback) {
57 GetDataProvider()->RefreshData(
58 base::Bind(&ITunesFileUtil::GetFileInfoWithFreshDataProvider,
59 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
60 callback));
63 void ITunesFileUtil::ReadDirectoryOnTaskRunnerThread(
64 scoped_ptr<fileapi::FileSystemOperationContext> context,
65 const fileapi::FileSystemURL& url,
66 const ReadDirectoryCallback& callback) {
67 GetDataProvider()->RefreshData(
68 base::Bind(&ITunesFileUtil::ReadDirectoryWithFreshDataProvider,
69 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
70 callback));
73 void ITunesFileUtil::CreateSnapshotFileOnTaskRunnerThread(
74 scoped_ptr<fileapi::FileSystemOperationContext> context,
75 const fileapi::FileSystemURL& url,
76 const CreateSnapshotFileCallback& callback) {
77 GetDataProvider()->RefreshData(
78 base::Bind(&ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider,
79 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
80 callback));
83 // Contents of the iTunes media gallery:
84 // / - root directory
85 // /iTunes Music Library.xml - library xml file
86 // /iTunes Media/Automatically Add to iTunes - auto-import directory
87 // /iTunes Media/Music/<Artist>/<Album>/<Track> - tracks
89 base::File::Error ITunesFileUtil::GetFileInfoSync(
90 fileapi::FileSystemOperationContext* context,
91 const fileapi::FileSystemURL& url,
92 base::File::Info* file_info,
93 base::FilePath* platform_path) {
94 std::vector<std::string> components;
95 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
97 if (components.size() == 0)
98 return MakeDirectoryFileInfo(file_info);
100 if (components.size() == 1 && components[0] == kITunesLibraryXML) {
101 // We can't just call NativeMediaFileUtil::GetFileInfoSync() here because it
102 // uses the MediaPathFilter. At this point, |library_path_| is known good
103 // because GetFileInfoWithFreshDataProvider() gates access to this method.
104 base::FilePath file_path = GetDataProvider()->library_path();
105 if (platform_path)
106 *platform_path = file_path;
107 return fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
110 if (components[0] != kITunesMediaDir)
111 return base::File::FILE_ERROR_NOT_FOUND;
113 if (components[1] == kITunesAutoAddDir) {
114 if (GetDataProvider()->auto_add_path().empty())
115 return base::File::FILE_ERROR_NOT_FOUND;
116 return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
117 platform_path);
120 if (components[1] == kITunesMusicDir) {
121 switch (components.size()) {
122 case 2:
123 return MakeDirectoryFileInfo(file_info);
125 case 3:
126 if (GetDataProvider()->KnownArtist(components[2]))
127 return MakeDirectoryFileInfo(file_info);
128 break;
130 case 4:
131 if (GetDataProvider()->KnownAlbum(components[2], components[3]))
132 return MakeDirectoryFileInfo(file_info);
133 break;
135 case 5: {
136 base::FilePath location =
137 GetDataProvider()->GetTrackLocation(components[2], components[3],
138 components[4]);
139 if (!location.empty()) {
140 return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
141 platform_path);
143 break;
148 return base::File::FILE_ERROR_NOT_FOUND;
151 base::File::Error ITunesFileUtil::ReadDirectorySync(
152 fileapi::FileSystemOperationContext* context,
153 const fileapi::FileSystemURL& url,
154 EntryList* file_list) {
155 DCHECK(file_list->empty());
156 std::vector<std::string> components;
157 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
159 if (components.size() == 0) {
160 base::File::Info xml_info;
161 if (!base::GetFileInfo(GetDataProvider()->library_path(), &xml_info))
162 return base::File::FILE_ERROR_IO;
163 file_list->push_back(DirectoryEntry(kITunesLibraryXML,
164 DirectoryEntry::FILE,
165 xml_info.size, xml_info.last_modified));
166 file_list->push_back(DirectoryEntry(kITunesMediaDir,
167 DirectoryEntry::DIRECTORY,
168 0, base::Time()));
169 return base::File::FILE_OK;
172 if (components.size() == 1 && components[0] == kITunesLibraryXML)
173 return base::File::FILE_ERROR_NOT_A_DIRECTORY;
175 if (components[0] != kITunesMediaDir || components.size() > 5)
176 return base::File::FILE_ERROR_NOT_FOUND;
178 if (components.size() == 1) {
179 if (!GetDataProvider()->auto_add_path().empty()) {
180 file_list->push_back(DirectoryEntry(kITunesAutoAddDir,
181 DirectoryEntry::DIRECTORY,
182 0, base::Time()));
184 file_list->push_back(DirectoryEntry(kITunesMusicDir,
185 DirectoryEntry::DIRECTORY,
186 0, base::Time()));
187 return base::File::FILE_OK;
190 if (components[1] == kITunesAutoAddDir &&
191 !GetDataProvider()->auto_add_path().empty()) {
192 return NativeMediaFileUtil::ReadDirectorySync(context, url, file_list);
195 if (components[1] != kITunesMusicDir)
196 return base::File::FILE_ERROR_NOT_FOUND;
198 if (components.size() == 2) {
199 std::set<ITunesDataProvider::ArtistName> artists =
200 GetDataProvider()->GetArtistNames();
201 std::set<ITunesDataProvider::ArtistName>::const_iterator it;
202 for (it = artists.begin(); it != artists.end(); ++it)
203 file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
204 0, base::Time()));
205 return base::File::FILE_OK;
208 if (components.size() == 3) {
209 std::set<ITunesDataProvider::AlbumName> albums =
210 GetDataProvider()->GetAlbumNames(components[2]);
211 if (albums.size() == 0)
212 return base::File::FILE_ERROR_NOT_FOUND;
213 std::set<ITunesDataProvider::AlbumName>::const_iterator it;
214 for (it = albums.begin(); it != albums.end(); ++it)
215 file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
216 0, base::Time()));
217 return base::File::FILE_OK;
220 if (components.size() == 4) {
221 ITunesDataProvider::Album album =
222 GetDataProvider()->GetAlbum(components[2], components[3]);
223 if (album.size() == 0)
224 return base::File::FILE_ERROR_NOT_FOUND;
225 ITunesDataProvider::Album::const_iterator it;
226 for (it = album.begin(); it != album.end(); ++it) {
227 base::File::Info file_info;
228 if (media_path_filter()->Match(it->second) &&
229 base::GetFileInfo(it->second, &file_info)) {
230 file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
231 file_info.size,
232 file_info.last_modified));
235 return base::File::FILE_OK;
238 // At this point, the only choice is one of two errors, but figuring out
239 // which one is required.
240 DCHECK_EQ(4UL, components.size());
241 base::FilePath location;
242 location = GetDataProvider()->GetTrackLocation(components[1], components[2],
243 components[3]);
244 if (!location.empty())
245 return base::File::FILE_ERROR_NOT_A_DIRECTORY;
246 return base::File::FILE_ERROR_NOT_FOUND;
249 base::File::Error ITunesFileUtil::DeleteDirectorySync(
250 fileapi::FileSystemOperationContext* context,
251 const fileapi::FileSystemURL& url) {
252 return base::File::FILE_ERROR_SECURITY;
255 base::File::Error ITunesFileUtil::DeleteFileSync(
256 fileapi::FileSystemOperationContext* context,
257 const fileapi::FileSystemURL& url) {
258 return base::File::FILE_ERROR_SECURITY;
261 base::File::Error ITunesFileUtil::CreateSnapshotFileSync(
262 fileapi::FileSystemOperationContext* context,
263 const fileapi::FileSystemURL& url,
264 base::File::Info* file_info,
265 base::FilePath* platform_path,
266 scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
267 DCHECK(!url.path().IsAbsolute());
268 if (url.path() != base::FilePath().AppendASCII(kITunesLibraryXML)) {
269 return NativeMediaFileUtil::CreateSnapshotFileSync(context, url, file_info,
270 platform_path, file_ref);
273 // The following code is different than
274 // NativeMediaFileUtil::CreateSnapshotFileSync in that it knows that the
275 // library xml file is not a directory and it doesn't run mime sniffing on the
276 // file. The only way to get here is by way of
277 // CreateSnapshotFileWithFreshDataProvider() so the file has already been
278 // parsed and deemed valid.
279 *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
280 return GetFileInfoSync(context, url, file_info, platform_path);
283 base::File::Error ITunesFileUtil::GetLocalFilePath(
284 fileapi::FileSystemOperationContext* context,
285 const fileapi::FileSystemURL& url,
286 base::FilePath* local_file_path) {
287 std::vector<std::string> components;
288 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
290 if (components.size() == 1 && components[0] == kITunesLibraryXML) {
291 *local_file_path = GetDataProvider()->library_path();
292 return base::File::FILE_OK;
295 if (components.size() >= 2 && components[0] == kITunesMediaDir &&
296 components[1] == kITunesAutoAddDir) {
297 *local_file_path = GetDataProvider()->auto_add_path();
298 if (local_file_path->empty())
299 return base::File::FILE_ERROR_NOT_FOUND;
301 for (size_t i = 2; i < components.size(); ++i) {
302 *local_file_path = local_file_path->Append(
303 base::FilePath::FromUTF8Unsafe(components[i]));
305 return base::File::FILE_OK;
308 // Should only get here for files, i.e. the xml file and tracks.
309 if (components[0] != kITunesMediaDir || components[1] != kITunesMusicDir||
310 components.size() != 5) {
311 return base::File::FILE_ERROR_NOT_FOUND;
314 *local_file_path = GetDataProvider()->GetTrackLocation(components[2],
315 components[3],
316 components[4]);
317 if (!local_file_path->empty())
318 return base::File::FILE_OK;
320 return base::File::FILE_ERROR_NOT_FOUND;
323 void ITunesFileUtil::GetFileInfoWithFreshDataProvider(
324 scoped_ptr<fileapi::FileSystemOperationContext> context,
325 const fileapi::FileSystemURL& url,
326 const GetFileInfoCallback& callback,
327 bool valid_parse) {
328 if (!valid_parse) {
329 if (!callback.is_null()) {
330 content::BrowserThread::PostTask(
331 content::BrowserThread::IO,
332 FROM_HERE,
333 base::Bind(callback, base::File::FILE_ERROR_IO,
334 base::File::Info()));
336 return;
338 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
339 callback);
342 void ITunesFileUtil::ReadDirectoryWithFreshDataProvider(
343 scoped_ptr<fileapi::FileSystemOperationContext> context,
344 const fileapi::FileSystemURL& url,
345 const ReadDirectoryCallback& callback,
346 bool valid_parse) {
347 if (!valid_parse) {
348 if (!callback.is_null()) {
349 content::BrowserThread::PostTask(
350 content::BrowserThread::IO,
351 FROM_HERE,
352 base::Bind(callback, base::File::FILE_ERROR_IO, EntryList(), false));
354 return;
356 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
357 callback);
360 void ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider(
361 scoped_ptr<fileapi::FileSystemOperationContext> context,
362 const fileapi::FileSystemURL& url,
363 const CreateSnapshotFileCallback& callback,
364 bool valid_parse) {
365 if (!valid_parse) {
366 if (!callback.is_null()) {
367 base::File::Info file_info;
368 base::FilePath platform_path;
369 scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
370 content::BrowserThread::PostTask(
371 content::BrowserThread::IO,
372 FROM_HERE,
373 base::Bind(callback, base::File::FILE_ERROR_IO, file_info,
374 platform_path, file_ref));
376 return;
378 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url,
379 callback);
382 ITunesDataProvider* ITunesFileUtil::GetDataProvider() {
383 if (!imported_registry_)
384 imported_registry_ = ImportedMediaGalleryRegistry::GetInstance();
385 return imported_registry_->ITunesDataProvider();
388 } // namespace itunes