Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / iphoto_file_util.cc
blob317d19fe98bca6ceed33e9db984ab251488fd999
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/iphoto_file_util.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/bind_helpers.h"
12 #include "base/files/file_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/media_galleries/fileapi/iphoto_data_provider.h"
16 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
17 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "storage/browser/blob/shareable_file_reference.h"
20 #include "storage/browser/fileapi/file_system_operation_context.h"
21 #include "storage/browser/fileapi/file_system_url.h"
22 #include "storage/browser/fileapi/native_file_util.h"
23 #include "storage/common/fileapi/directory_entry.h"
24 #include "storage/common/fileapi/file_system_util.h"
26 using storage::DirectoryEntry;
28 namespace iphoto {
30 namespace {
32 base::File::Error MakeDirectoryFileInfo(base::File::Info* file_info) {
33 base::File::Info result;
34 result.is_directory = true;
35 *file_info = result;
36 return base::File::FILE_OK;
39 template <typename T>
40 bool ContainsElement(const std::vector<T>& collection, const T& key) {
41 typename std::vector<T>::const_iterator it = collection.begin();
42 while (it != collection.end()) {
43 if (*it == key)
44 return true;
45 it++;
47 return false;
50 std::vector<std::string> GetVirtualPathComponents(
51 const storage::FileSystemURL& url) {
52 ImportedMediaGalleryRegistry* imported_registry =
53 ImportedMediaGalleryRegistry::GetInstance();
54 base::FilePath root = imported_registry->ImportedRoot().AppendASCII("iphoto");
56 DCHECK(root.IsParent(url.path()) || root == url.path());
57 base::FilePath virtual_path;
58 root.AppendRelativePath(url.path(), &virtual_path);
60 std::vector<std::string> result;
61 storage::VirtualPath::GetComponentsUTF8Unsafe(virtual_path, &result);
62 return result;
65 } // namespace
67 const char kIPhotoAlbumsDir[] = "Albums";
68 const char kIPhotoOriginalsDir[] = "Originals";
70 IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter* media_path_filter)
71 : NativeMediaFileUtil(media_path_filter),
72 imported_registry_(NULL),
73 weak_factory_(this) {
76 IPhotoFileUtil::~IPhotoFileUtil() {
79 void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
80 scoped_ptr<storage::FileSystemOperationContext> context,
81 const storage::FileSystemURL& url,
82 const GetFileInfoCallback& callback) {
83 IPhotoDataProvider* data_provider = GetDataProvider();
84 // |data_provider| may be NULL if the file system was revoked before this
85 // operation had a chance to run.
86 if (!data_provider) {
87 GetFileInfoWithFreshDataProvider(context.Pass(), url, callback, false);
88 } else {
89 data_provider->RefreshData(
90 base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider,
91 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
92 callback));
96 void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
97 scoped_ptr<storage::FileSystemOperationContext> context,
98 const storage::FileSystemURL& url,
99 const ReadDirectoryCallback& callback) {
100 IPhotoDataProvider* data_provider = GetDataProvider();
101 // |data_provider| may be NULL if the file system was revoked before this
102 // operation had a chance to run.
103 if (!data_provider) {
104 ReadDirectoryWithFreshDataProvider(context.Pass(), url, callback, false);
105 } else {
106 data_provider->RefreshData(
107 base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider,
108 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
109 callback));
113 void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
114 scoped_ptr<storage::FileSystemOperationContext> context,
115 const storage::FileSystemURL& url,
116 const CreateSnapshotFileCallback& callback) {
117 IPhotoDataProvider* data_provider = GetDataProvider();
118 // |data_provider| may be NULL if the file system was revoked before this
119 // operation had a chance to run.
120 if (!data_provider) {
121 CreateSnapshotFileWithFreshDataProvider(context.Pass(), url, callback,
122 false);
123 } else {
124 data_provider->RefreshData(
125 base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider,
126 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
127 callback));
131 void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
132 scoped_ptr<storage::FileSystemOperationContext> context,
133 const storage::FileSystemURL& url,
134 const GetFileInfoCallback& callback,
135 bool valid_parse) {
136 if (!valid_parse) {
137 if (!callback.is_null()) {
138 content::BrowserThread::PostTask(
139 content::BrowserThread::IO,
140 FROM_HERE,
141 base::Bind(callback, base::File::FILE_ERROR_IO, base::File::Info()));
143 return;
145 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
146 callback);
149 void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider(
150 scoped_ptr<storage::FileSystemOperationContext> context,
151 const storage::FileSystemURL& url,
152 const ReadDirectoryCallback& callback,
153 bool valid_parse) {
154 if (!valid_parse) {
155 if (!callback.is_null()) {
156 content::BrowserThread::PostTask(
157 content::BrowserThread::IO,
158 FROM_HERE,
159 base::Bind(callback, base::File::FILE_ERROR_IO, EntryList(), false));
161 return;
163 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
164 callback);
167 void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider(
168 scoped_ptr<storage::FileSystemOperationContext> context,
169 const storage::FileSystemURL& url,
170 const CreateSnapshotFileCallback& callback,
171 bool valid_parse) {
172 if (!valid_parse) {
173 if (!callback.is_null()) {
174 base::File::Info file_info;
175 base::FilePath platform_path;
176 scoped_refptr<storage::ShareableFileReference> file_ref;
177 content::BrowserThread::PostTask(
178 content::BrowserThread::IO,
179 FROM_HERE,
180 base::Bind(callback, base::File::FILE_ERROR_IO, file_info,
181 platform_path, file_ref));
183 return;
185 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url,
186 callback);
189 // Begin actual implementation.
191 base::File::Error IPhotoFileUtil::GetFileInfoSync(
192 storage::FileSystemOperationContext* context,
193 const storage::FileSystemURL& url,
194 base::File::Info* file_info,
195 base::FilePath* platform_path) {
196 std::vector<std::string> components = GetVirtualPathComponents(url);
198 if (components.size() == 0) {
199 return MakeDirectoryFileInfo(file_info);
202 // The 'Albums' directory.
203 if (components[0] == kIPhotoAlbumsDir) {
204 if (components.size() == 1) {
205 return MakeDirectoryFileInfo(file_info);
206 } else if (components.size() == 2) {
207 std::vector<std::string> albums =
208 GetDataProvider()->GetAlbumNames();
209 if (ContainsElement(albums, components[1]))
210 return MakeDirectoryFileInfo(file_info);
211 } else if (components.size() == 3) {
212 if (components[2] == kIPhotoOriginalsDir) {
213 if (GetDataProvider()->HasOriginals(components[1]))
214 return MakeDirectoryFileInfo(file_info);
215 else
216 return base::File::FILE_ERROR_NOT_FOUND;
219 base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum(
220 components[1], components[2]);
221 if (!location.empty()) {
222 return NativeMediaFileUtil::GetFileInfoSync(
223 context, url, file_info, platform_path);
225 } else if (components.size() == 4 &&
226 GetDataProvider()->HasOriginals(components[1]) &&
227 components[2] == kIPhotoOriginalsDir) {
228 base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation(
229 components[1], components[3]);
230 if (!location.empty()) {
231 return NativeMediaFileUtil::GetFileInfoSync(
232 context, url, file_info, platform_path);
237 return base::File::FILE_ERROR_NOT_FOUND;
240 base::File::Error IPhotoFileUtil::ReadDirectorySync(
241 storage::FileSystemOperationContext* context,
242 const storage::FileSystemURL& url,
243 EntryList* file_list) {
244 DCHECK(file_list->empty());
245 std::vector<std::string> components = GetVirtualPathComponents(url);
247 // Root directory. Child is the /Albums dir.
248 if (components.size() == 0) {
249 file_list->push_back(DirectoryEntry(kIPhotoAlbumsDir,
250 DirectoryEntry::DIRECTORY,
251 0, base::Time()));
252 return base::File::FILE_OK;
255 if (components[0] == kIPhotoAlbumsDir) {
256 if (components.size() == 1) {
257 // Albums dir contains all album names.
258 std::vector<std::string> albums =
259 GetDataProvider()->GetAlbumNames();
260 for (std::vector<std::string>::const_iterator it = albums.begin();
261 it != albums.end(); it++) {
262 file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
263 0, base::Time()));
265 return base::File::FILE_OK;
266 } else if (components.size() == 2) {
267 std::vector<std::string> albums =
268 GetDataProvider()->GetAlbumNames();
269 if (!ContainsElement(albums, components[1]))
270 return base::File::FILE_ERROR_NOT_FOUND;
272 // Album dirs contain all photos in them.
273 if (GetDataProvider()->HasOriginals(components[1])) {
274 file_list->push_back(DirectoryEntry(kIPhotoOriginalsDir,
275 DirectoryEntry::DIRECTORY,
276 0, base::Time()));
278 std::map<std::string, base::FilePath> locations =
279 GetDataProvider()->GetAlbumContents(components[1]);
280 for (std::map<std::string, base::FilePath>::const_iterator it =
281 locations.begin();
282 it != locations.end(); it++) {
283 base::File::Info info;
284 if (!base::GetFileInfo(it->second, &info))
285 return base::File::FILE_ERROR_IO;
286 file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
287 info.size, info.last_modified));
289 return base::File::FILE_OK;
290 } else if (components.size() == 3 &&
291 components[2] == kIPhotoOriginalsDir &&
292 GetDataProvider()->HasOriginals(components[1])) {
293 std::map<std::string, base::FilePath> originals =
294 GetDataProvider()->GetOriginals(components[1]);
295 for (std::map<std::string, base::FilePath>::const_iterator it =
296 originals.begin();
297 it != originals.end(); it++) {
298 base::File::Info info;
299 if (!base::GetFileInfo(it->second, &info))
300 return base::File::FILE_ERROR_IO;
301 file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
302 info.size, info.last_modified));
304 return base::File::FILE_OK;
308 return base::File::FILE_ERROR_NOT_FOUND;
311 base::File::Error IPhotoFileUtil::DeleteDirectorySync(
312 storage::FileSystemOperationContext* context,
313 const storage::FileSystemURL& url) {
314 return base::File::FILE_ERROR_SECURITY;
317 base::File::Error IPhotoFileUtil::DeleteFileSync(
318 storage::FileSystemOperationContext* context,
319 const storage::FileSystemURL& url) {
320 return base::File::FILE_ERROR_SECURITY;
323 base::File::Error IPhotoFileUtil::GetLocalFilePath(
324 storage::FileSystemOperationContext* context,
325 const storage::FileSystemURL& url,
326 base::FilePath* local_file_path) {
327 std::vector<std::string> components = GetVirtualPathComponents(url);
329 if (components.size() == 3 && components[0] == kIPhotoAlbumsDir) {
330 base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum(
331 components[1], components[2]);
332 if (!location.empty()) {
333 *local_file_path = location;
334 return base::File::FILE_OK;
338 if (components.size() == 4 && components[0] == kIPhotoAlbumsDir &&
339 GetDataProvider()->HasOriginals(components[1]) &&
340 components[2] == kIPhotoOriginalsDir) {
341 base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation(
342 components[1], components[3]);
343 if (!location.empty()) {
344 *local_file_path = location;
345 return base::File::FILE_OK;
349 return base::File::FILE_ERROR_NOT_FOUND;
352 IPhotoDataProvider* IPhotoFileUtil::GetDataProvider() {
353 if (!imported_registry_)
354 imported_registry_ = ImportedMediaGalleryRegistry::GetInstance();
355 return imported_registry_->IPhotoDataProvider();
358 } // namespace iphoto