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