38ae639b92c30026bff59bffe3221fc57f7fbde8
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / iphoto_file_util.cc
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.
4
5 #include "chrome/browser/media_galleries/fileapi/iphoto_file_util.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind_helpers.h"
12 #include "base/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 "webkit/browser/fileapi/file_system_operation_context.h"
20 #include "webkit/browser/fileapi/file_system_url.h"
21 #include "webkit/browser/fileapi/native_file_util.h"
22 #include "webkit/common/blob/shareable_file_reference.h"
23 #include "webkit/common/fileapi/directory_entry.h"
24 #include "webkit/common/fileapi/file_system_util.h"
25
26 using fileapi::DirectoryEntry;
27
28 namespace iphoto {
29
30 namespace {
31
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;
37 }
38
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++;
46   }
47   return false;
48 }
49
50 std::vector<std::string> GetVirtualPathComponents(
51     const fileapi::FileSystemURL& url) {
52   ImportedMediaGalleryRegistry* imported_registry =
53       ImportedMediaGalleryRegistry::GetInstance();
54   base::FilePath root = imported_registry->ImportedRoot().AppendASCII("iphoto");
55
56   DCHECK(root.IsParent(url.path()) || root == url.path());
57   base::FilePath virtual_path;
58   root.AppendRelativePath(url.path(), &virtual_path);
59
60   std::vector<std::string> result;
61   fileapi::VirtualPath::GetComponentsUTF8Unsafe(virtual_path, &result);
62   return result;
63 }
64
65 }  // namespace
66
67 const char kIPhotoAlbumsDir[] = "Albums";
68 const char kIPhotoOriginalsDir[] = "Originals";
69
70 IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter* media_path_filter)
71     : NativeMediaFileUtil(media_path_filter),
72       weak_factory_(this),
73       imported_registry_(NULL) {
74 }
75
76 IPhotoFileUtil::~IPhotoFileUtil() {
77 }
78
79 void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
80     scoped_ptr<fileapi::FileSystemOperationContext> context,
81     const fileapi::FileSystemURL& url,
82     const GetFileInfoCallback& callback) {
83   GetDataProvider()->RefreshData(
84       base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider,
85                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
86                  callback));
87 }
88
89 void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
90     scoped_ptr<fileapi::FileSystemOperationContext> context,
91     const fileapi::FileSystemURL& url,
92     const ReadDirectoryCallback& callback) {
93   GetDataProvider()->RefreshData(
94       base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider,
95                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
96                  callback));
97 }
98
99 void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
100     scoped_ptr<fileapi::FileSystemOperationContext> context,
101     const fileapi::FileSystemURL& url,
102     const CreateSnapshotFileCallback& callback) {
103   GetDataProvider()->RefreshData(
104       base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider,
105                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
106                  callback));
107 }
108
109 void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
110     scoped_ptr<fileapi::FileSystemOperationContext> context,
111     const fileapi::FileSystemURL& url,
112     const GetFileInfoCallback& callback,
113     bool valid_parse) {
114   if (!valid_parse) {
115     if (!callback.is_null()) {
116       content::BrowserThread::PostTask(
117           content::BrowserThread::IO,
118           FROM_HERE,
119           base::Bind(callback, base::File::FILE_ERROR_IO, base::File::Info()));
120     }
121     return;
122   }
123   NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
124                                                      callback);
125 }
126
127 void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider(
128     scoped_ptr<fileapi::FileSystemOperationContext> context,
129     const fileapi::FileSystemURL& url,
130     const ReadDirectoryCallback& callback,
131     bool valid_parse) {
132   if (!valid_parse) {
133     if (!callback.is_null()) {
134       content::BrowserThread::PostTask(
135           content::BrowserThread::IO,
136           FROM_HERE,
137           base::Bind(callback, base::File::FILE_ERROR_IO, EntryList(), false));
138     }
139     return;
140   }
141   NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
142                                                        callback);
143 }
144
145 void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider(
146     scoped_ptr<fileapi::FileSystemOperationContext> context,
147     const fileapi::FileSystemURL& url,
148     const CreateSnapshotFileCallback& callback,
149     bool valid_parse) {
150   if (!valid_parse) {
151     if (!callback.is_null()) {
152       base::File::Info file_info;
153       base::FilePath platform_path;
154       scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
155       content::BrowserThread::PostTask(
156           content::BrowserThread::IO,
157           FROM_HERE,
158           base::Bind(callback, base::File::FILE_ERROR_IO, file_info,
159                      platform_path, file_ref));
160     }
161     return;
162   }
163   NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url,
164                                                             callback);
165 }
166
167 // Begin actual implementation.
168
169 base::File::Error IPhotoFileUtil::GetFileInfoSync(
170     fileapi::FileSystemOperationContext* context,
171     const fileapi::FileSystemURL& url,
172     base::File::Info* file_info,
173     base::FilePath* platform_path) {
174   std::vector<std::string> components = GetVirtualPathComponents(url);
175
176   if (components.size() == 0) {
177     return MakeDirectoryFileInfo(file_info);
178   }
179
180   // The 'Albums' directory.
181   if (components[0] == kIPhotoAlbumsDir) {
182     if (components.size() == 1) {
183       return MakeDirectoryFileInfo(file_info);
184     } else if (components.size() == 2) {
185       std::vector<std::string> albums =
186           GetDataProvider()->GetAlbumNames();
187       if (ContainsElement(albums, components[1]))
188         return MakeDirectoryFileInfo(file_info);
189     } else if (components.size() == 3) {
190       if (components[2] == kIPhotoOriginalsDir) {
191         if (GetDataProvider()->HasOriginals(components[1]))
192           return MakeDirectoryFileInfo(file_info);
193         else
194           return base::File::FILE_ERROR_NOT_FOUND;
195       }
196
197       base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum(
198           components[1], components[2]);
199       if (!location.empty()) {
200         return NativeMediaFileUtil::GetFileInfoSync(
201             context, url, file_info, platform_path);
202       }
203     } else if (components.size() == 4 &&
204                GetDataProvider()->HasOriginals(components[1]) &&
205                components[2] == kIPhotoOriginalsDir) {
206       base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation(
207           components[1], components[3]);
208       if (!location.empty()) {
209         return NativeMediaFileUtil::GetFileInfoSync(
210             context, url, file_info, platform_path);
211       }
212     }
213   }
214
215   return base::File::FILE_ERROR_NOT_FOUND;
216 }
217
218 base::File::Error IPhotoFileUtil::ReadDirectorySync(
219     fileapi::FileSystemOperationContext* context,
220     const fileapi::FileSystemURL& url,
221     EntryList* file_list) {
222   DCHECK(file_list->empty());
223   std::vector<std::string> components = GetVirtualPathComponents(url);
224
225   // Root directory. Child is the /Albums dir.
226   if (components.size() == 0) {
227     file_list->push_back(DirectoryEntry(kIPhotoAlbumsDir,
228                                         DirectoryEntry::DIRECTORY,
229                                         0, base::Time()));
230     return base::File::FILE_OK;
231   }
232
233   if (components[0] == kIPhotoAlbumsDir) {
234     if (components.size() == 1) {
235       // Albums dir contains all album names.
236       std::vector<std::string> albums =
237           GetDataProvider()->GetAlbumNames();
238       for (std::vector<std::string>::const_iterator it = albums.begin();
239            it != albums.end(); it++) {
240         file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
241                                             0, base::Time()));
242       }
243       return base::File::FILE_OK;
244     } else if (components.size() == 2) {
245       std::vector<std::string> albums =
246           GetDataProvider()->GetAlbumNames();
247       if (!ContainsElement(albums, components[1]))
248         return base::File::FILE_ERROR_NOT_FOUND;
249
250       // Album dirs contain all photos in them.
251       if (GetDataProvider()->HasOriginals(components[1])) {
252         file_list->push_back(DirectoryEntry(kIPhotoOriginalsDir,
253                                             DirectoryEntry::DIRECTORY,
254                                             0, base::Time()));
255       }
256       std::map<std::string, base::FilePath> locations =
257           GetDataProvider()->GetAlbumContents(components[1]);
258       for (std::map<std::string, base::FilePath>::const_iterator it =
259                locations.begin();
260            it != locations.end(); it++) {
261         base::File::Info info;
262         if (!base::GetFileInfo(it->second, &info))
263           return base::File::FILE_ERROR_IO;
264         file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
265                                             info.size, info.last_modified));
266       }
267       return base::File::FILE_OK;
268     } else if (components.size() == 3 &&
269                components[2] == kIPhotoOriginalsDir &&
270                GetDataProvider()->HasOriginals(components[1])) {
271       std::map<std::string, base::FilePath> originals =
272           GetDataProvider()->GetOriginals(components[1]);
273       for (std::map<std::string, base::FilePath>::const_iterator it =
274                originals.begin();
275            it != originals.end(); it++) {
276         base::File::Info info;
277         if (!base::GetFileInfo(it->second, &info))
278           return base::File::FILE_ERROR_IO;
279         file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
280                                             info.size, info.last_modified));
281       }
282       return base::File::FILE_OK;
283     }
284   }
285
286   return base::File::FILE_ERROR_NOT_FOUND;
287 }
288
289 base::File::Error IPhotoFileUtil::DeleteDirectorySync(
290     fileapi::FileSystemOperationContext* context,
291     const fileapi::FileSystemURL& url) {
292   return base::File::FILE_ERROR_SECURITY;
293 }
294
295 base::File::Error IPhotoFileUtil::DeleteFileSync(
296     fileapi::FileSystemOperationContext* context,
297     const fileapi::FileSystemURL& url) {
298   return base::File::FILE_ERROR_SECURITY;
299 }
300
301
302 base::File::Error IPhotoFileUtil::GetLocalFilePath(
303     fileapi::FileSystemOperationContext* context,
304     const fileapi::FileSystemURL& url,
305     base::FilePath* local_file_path) {
306   std::vector<std::string> components = GetVirtualPathComponents(url);
307
308   if (components.size() == 3 && components[0] == kIPhotoAlbumsDir) {
309     base::FilePath location = GetDataProvider()->GetPhotoLocationInAlbum(
310         components[1], components[2]);
311     if (!location.empty()) {
312       *local_file_path = location;
313       return base::File::FILE_OK;
314     }
315   }
316
317   if (components.size() == 4 && components[0] == kIPhotoAlbumsDir &&
318       GetDataProvider()->HasOriginals(components[1]) &&
319       components[2] == kIPhotoOriginalsDir) {
320     base::FilePath location = GetDataProvider()->GetOriginalPhotoLocation(
321         components[1], components[3]);
322     if (!location.empty()) {
323       *local_file_path = location;
324       return base::File::FILE_OK;
325     }
326   }
327
328   return base::File::FILE_ERROR_NOT_FOUND;
329 }
330
331 IPhotoDataProvider* IPhotoFileUtil::GetDataProvider() {
332   if (!imported_registry_)
333     imported_registry_ = ImportedMediaGalleryRegistry::GetInstance();
334   return imported_registry_->IPhotoDataProvider();
335 }
336
337 }  // namespace iphoto