// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/media_galleries/fileapi/iphoto_file_util.h" #include #include #include #include "base/bind_helpers.h" #include "base/file_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media_galleries/fileapi/iphoto_data_provider.h" #include "chrome/browser/media_galleries/fileapi/media_path_filter.h" #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" #include "content/public/browser/browser_thread.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/native_file_util.h" #include "webkit/common/blob/shareable_file_reference.h" #include "webkit/common/fileapi/directory_entry.h" #include "webkit/common/fileapi/file_system_util.h" using fileapi::DirectoryEntry; namespace iphoto { namespace { base::File::Error MakeDirectoryFileInfo(base::File::Info* file_info) { base::File::Info result; result.is_directory = true; *file_info = result; return base::File::FILE_OK; } template bool ContainsElement(const std::vector& collection, const T& key) { typename std::vector::const_iterator it = collection.begin(); while (it != collection.end()) { if (*it == key) return true; it++; } return false; } std::vector GetVirtualPathComponents( const fileapi::FileSystemURL& url) { ImportedMediaGalleryRegistry* imported_registry = ImportedMediaGalleryRegistry::GetInstance(); base::FilePath root = imported_registry->ImportedRoot().AppendASCII("iphoto"); DCHECK(root.IsParent(url.path()) || root == url.path()); base::FilePath virtual_path; root.AppendRelativePath(url.path(), &virtual_path); std::vector result; fileapi::VirtualPath::GetComponentsUTF8Unsafe(virtual_path, &result); return result; } } // namespace const char kIPhotoAlbumsDir[] = "Albums"; const char kIPhotoOriginalsDir[] = "Originals"; IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter* media_path_filter) : NativeMediaFileUtil(media_path_filter), weak_factory_(this), imported_registry_(NULL) { } IPhotoFileUtil::~IPhotoFileUtil() { } void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread( scoped_ptr context, const fileapi::FileSystemURL& url, const GetFileInfoCallback& callback) { GetDataProvider()->RefreshData( base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider, weak_factory_.GetWeakPtr(), base::Passed(&context), url, callback)); } void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread( scoped_ptr context, const fileapi::FileSystemURL& url, const ReadDirectoryCallback& callback) { GetDataProvider()->RefreshData( base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider, weak_factory_.GetWeakPtr(), base::Passed(&context), url, callback)); } void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread( scoped_ptr context, const fileapi::FileSystemURL& url, const CreateSnapshotFileCallback& callback) { GetDataProvider()->RefreshData( base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider, weak_factory_.GetWeakPtr(), base::Passed(&context), url, callback)); } void IPhotoFileUtil::GetFileInfoWithFreshDataProvider( scoped_ptr context, const fileapi::FileSystemURL& url, const GetFileInfoCallback& callback, bool valid_parse) { if (!valid_parse) { if (!callback.is_null()) { content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_IO, base::File::Info())); } return; } NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url, callback); } void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider( scoped_ptr context, const fileapi::FileSystemURL& url, const ReadDirectoryCallback& callback, bool valid_parse) { if (!valid_parse) { if (!callback.is_null()) { content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_IO, EntryList(), false)); } return; } NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url, callback); } void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider( scoped_ptr context, const fileapi::FileSystemURL& url, const CreateSnapshotFileCallback& callback, bool valid_parse) { if (!valid_parse) { if (!callback.is_null()) { base::File::Info file_info; base::FilePath platform_path; scoped_refptr file_ref; content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_IO, file_info, platform_path, file_ref)); } return; } NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url, callback); } // Begin actual implementation. base::File::Error IPhotoFileUtil::GetFileInfoSync( fileapi::FileSystemOperationContext* context, const fileapi::FileSystemURL& url, base::File::Info* file_info, base::FilePath* platform_path) { std::vector components = GetVirtualPathComponents(url); if (components.size() == 0) { return MakeDirectoryFileInfo(file_info); } // The 'Albums' directory. if (components[0] == kIPhotoAlbumsDir) { if (components.size() == 1) { return MakeDirectoryFileInfo(file_info); } else if (components.size() == 2) { std::vector albums = GetDataProvider()->GetAlbumNames(); if (ContainsElement(albums, components[1])) return MakeDirectoryFileInfo(file_info); } else if (components.size() == 3) { if (components[2] == kIPhotoOriginalsDir) { if (GetDataProvider()->HasOriginals(components[1])) return MakeDirectoryFileInfo(file_info); else return base::File::FILE_ERROR_NOT_FOUND; } base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum( components[1], components[2]); if (!location.empty()) { return NativeMediaFileUtil::GetFileInfoSync( context, url, file_info, platform_path); } } else if (components.size() == 4 && GetDataProvider()->HasOriginals(components[1]) && components[2] == kIPhotoOriginalsDir) { base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation( components[1], components[3]); if (!location.empty()) { return NativeMediaFileUtil::GetFileInfoSync( context, url, file_info, platform_path); } } } return base::File::FILE_ERROR_NOT_FOUND; } base::File::Error IPhotoFileUtil::ReadDirectorySync( fileapi::FileSystemOperationContext* context, const fileapi::FileSystemURL& url, EntryList* file_list) { DCHECK(file_list->empty()); std::vector components = GetVirtualPathComponents(url); // Root directory. Child is the /Albums dir. if (components.size() == 0) { file_list->push_back(DirectoryEntry(kIPhotoAlbumsDir, DirectoryEntry::DIRECTORY, 0, base::Time())); return base::File::FILE_OK; } if (components[0] == kIPhotoAlbumsDir) { if (components.size() == 1) { // Albums dir contains all album names. std::vector albums = GetDataProvider()->GetAlbumNames(); for (std::vector::const_iterator it = albums.begin(); it != albums.end(); it++) { file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY, 0, base::Time())); } return base::File::FILE_OK; } else if (components.size() == 2) { std::vector albums = GetDataProvider()->GetAlbumNames(); if (!ContainsElement(albums, components[1])) return base::File::FILE_ERROR_NOT_FOUND; // Album dirs contain all photos in them. if (GetDataProvider()->HasOriginals(components[1])) { file_list->push_back(DirectoryEntry(kIPhotoOriginalsDir, DirectoryEntry::DIRECTORY, 0, base::Time())); } std::map locations = GetDataProvider()->GetAlbumContents(components[1]); for (std::map::const_iterator it = locations.begin(); it != locations.end(); it++) { base::File::Info info; if (!base::GetFileInfo(it->second, &info)) return base::File::FILE_ERROR_IO; file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE, info.size, info.last_modified)); } return base::File::FILE_OK; } else if (components.size() == 3 && components[2] == kIPhotoOriginalsDir && GetDataProvider()->HasOriginals(components[1])) { std::map originals = GetDataProvider()->GetOriginals(components[1]); for (std::map::const_iterator it = originals.begin(); it != originals.end(); it++) { base::File::Info info; if (!base::GetFileInfo(it->second, &info)) return base::File::FILE_ERROR_IO; file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE, info.size, info.last_modified)); } return base::File::FILE_OK; } } return base::File::FILE_ERROR_NOT_FOUND; } base::File::Error IPhotoFileUtil::DeleteDirectorySync( fileapi::FileSystemOperationContext* context, const fileapi::FileSystemURL& url) { return base::File::FILE_ERROR_SECURITY; } base::File::Error IPhotoFileUtil::DeleteFileSync( fileapi::FileSystemOperationContext* context, const fileapi::FileSystemURL& url) { return base::File::FILE_ERROR_SECURITY; } base::File::Error IPhotoFileUtil::GetLocalFilePath( fileapi::FileSystemOperationContext* context, const fileapi::FileSystemURL& url, base::FilePath* local_file_path) { std::vector components = GetVirtualPathComponents(url); if (components.size() == 3 && components[0] == kIPhotoAlbumsDir) { base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum( components[1], components[2]); if (!location.empty()) { *local_file_path = location; return base::File::FILE_OK; } } if (components.size() == 4 && components[0] == kIPhotoAlbumsDir && GetDataProvider()->HasOriginals(components[1]) && components[2] == kIPhotoOriginalsDir) { base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation( components[1], components[3]); if (!location.empty()) { *local_file_path = location; return base::File::FILE_OK; } } return base::File::FILE_ERROR_NOT_FOUND; } IPhotoDataProvider* IPhotoFileUtil::GetDataProvider() { if (!imported_registry_) imported_registry_ = ImportedMediaGalleryRegistry::GetInstance(); return imported_registry_->IPhotoDataProvider(); } } // namespace iphoto