blob: 317d19fe98bca6ceed33e9db984ab251488fd999 [file] [log] [blame]
// 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 <set>
#include <string>
#include <vector>
#include "base/bind_helpers.h"
#include "base/files/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 "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/fileapi/file_system_operation_context.h"
#include "storage/browser/fileapi/file_system_url.h"
#include "storage/browser/fileapi/native_file_util.h"
#include "storage/common/fileapi/directory_entry.h"
#include "storage/common/fileapi/file_system_util.h"
using storage::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 <typename T>
bool ContainsElement(const std::vector<T>& collection, const T& key) {
typename std::vector<T>::const_iterator it = collection.begin();
while (it != collection.end()) {
if (*it == key)
return true;
it++;
}
return false;
}
std::vector<std::string> GetVirtualPathComponents(
const storage::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<std::string> result;
storage::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),
imported_registry_(NULL),
weak_factory_(this) {
}
IPhotoFileUtil::~IPhotoFileUtil() {
}
void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
scoped_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
const GetFileInfoCallback& callback) {
IPhotoDataProvider* data_provider = GetDataProvider();
// |data_provider| may be NULL if the file system was revoked before this
// operation had a chance to run.
if (!data_provider) {
GetFileInfoWithFreshDataProvider(context.Pass(), url, callback, false);
} else {
data_provider->RefreshData(
base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider,
weak_factory_.GetWeakPtr(), base::Passed(&context), url,
callback));
}
}
void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
scoped_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
const ReadDirectoryCallback& callback) {
IPhotoDataProvider* data_provider = GetDataProvider();
// |data_provider| may be NULL if the file system was revoked before this
// operation had a chance to run.
if (!data_provider) {
ReadDirectoryWithFreshDataProvider(context.Pass(), url, callback, false);
} else {
data_provider->RefreshData(
base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider,
weak_factory_.GetWeakPtr(), base::Passed(&context), url,
callback));
}
}
void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
scoped_ptr<storage::FileSystemOperationContext> context,
const storage::FileSystemURL& url,
const CreateSnapshotFileCallback& callback) {
IPhotoDataProvider* data_provider = GetDataProvider();
// |data_provider| may be NULL if the file system was revoked before this
// operation had a chance to run.
if (!data_provider) {
CreateSnapshotFileWithFreshDataProvider(context.Pass(), url, callback,
false);
} else {
data_provider->RefreshData(
base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider,
weak_factory_.GetWeakPtr(), base::Passed(&context), url,
callback));
}
}
void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
scoped_ptr<storage::FileSystemOperationContext> context,
const storage::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<storage::FileSystemOperationContext> context,
const storage::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<storage::FileSystemOperationContext> context,
const storage::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<storage::ShareableFileReference> 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(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::File::Info* file_info,
base::FilePath* platform_path) {
std::vector<std::string> 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<std::string> 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(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
EntryList* file_list) {
DCHECK(file_list->empty());
std::vector<std::string> 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<std::string> albums =
GetDataProvider()->GetAlbumNames();
for (std::vector<std::string>::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<std::string> 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<std::string, base::FilePath> locations =
GetDataProvider()->GetAlbumContents(components[1]);
for (std::map<std::string, base::FilePath>::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<std::string, base::FilePath> originals =
GetDataProvider()->GetOriginals(components[1]);
for (std::map<std::string, base::FilePath>::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(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url) {
return base::File::FILE_ERROR_SECURITY;
}
base::File::Error IPhotoFileUtil::DeleteFileSync(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url) {
return base::File::FILE_ERROR_SECURITY;
}
base::File::Error IPhotoFileUtil::GetLocalFilePath(
storage::FileSystemOperationContext* context,
const storage::FileSystemURL& url,
base::FilePath* local_file_path) {
std::vector<std::string> 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