- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / picasa_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/picasa_file_util.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/basictypes.h"
11 #include "base/bind_helpers.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
17 #include "chrome/browser/media_galleries/fileapi/picasa_data_provider.h"
18 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
19 #include "chrome/common/media_galleries/picasa_types.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "webkit/browser/fileapi/file_system_operation_context.h"
22 #include "webkit/browser/fileapi/file_system_url.h"
23 #include "webkit/browser/fileapi/native_file_util.h"
24 #include "webkit/common/fileapi/file_system_util.h"
25
26 using base::FilePath;
27 using fileapi::DirectoryEntry;
28 using fileapi::FileSystemOperationContext;
29 using fileapi::FileSystemURL;
30
31 namespace picasa {
32
33 namespace {
34
35 base::PlatformFileError FindAlbumInfo(const std::string& key,
36                                       const AlbumMap* map,
37                                       AlbumInfo* album_info) {
38   if (!map)
39     return base::PLATFORM_FILE_ERROR_FAILED;
40
41   AlbumMap::const_iterator it = map->find(key);
42
43   if (it == map->end())
44     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
45
46   if (album_info != NULL)
47     *album_info = it->second;
48
49   return base::PLATFORM_FILE_OK;
50 }
51
52 PicasaDataProvider::DataType GetDataTypeForURL(
53     const fileapi::FileSystemURL& url) {
54   std::vector<std::string> components;
55   fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
56
57   if (components.size() >= 2 && components[0] == kPicasaDirAlbums)
58     return PicasaDataProvider::ALBUMS_IMAGES_DATA;
59
60   return PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA;
61 }
62
63 }  // namespace
64
65 const char kPicasaDirAlbums[]  = "albums";
66 const char kPicasaDirFolders[] = "folders";
67
68 PicasaFileUtil::PicasaFileUtil(MediaPathFilter* media_path_filter)
69     : NativeMediaFileUtil(media_path_filter),
70       weak_factory_(this) {
71 }
72
73 PicasaFileUtil::~PicasaFileUtil() {}
74
75 void PicasaFileUtil::GetFileInfoOnTaskRunnerThread(
76     scoped_ptr<fileapi::FileSystemOperationContext> context,
77     const fileapi::FileSystemURL& url,
78     const GetFileInfoCallback& callback) {
79   GetDataProvider()->RefreshData(
80       GetDataTypeForURL(url),
81       base::Bind(&PicasaFileUtil::GetFileInfoWithFreshDataProvider,
82                  weak_factory_.GetWeakPtr(),
83                  base::Passed(&context),
84                  url,
85                  callback));
86 }
87
88 void PicasaFileUtil::ReadDirectoryOnTaskRunnerThread(
89     scoped_ptr<fileapi::FileSystemOperationContext> context,
90     const fileapi::FileSystemURL& url,
91     const ReadDirectoryCallback& callback) {
92   GetDataProvider()->RefreshData(
93       GetDataTypeForURL(url),
94       base::Bind(&PicasaFileUtil::ReadDirectoryWithFreshDataProvider,
95                  weak_factory_.GetWeakPtr(),
96                  base::Passed(&context),
97                  url,
98                  callback));
99 }
100
101 base::PlatformFileError PicasaFileUtil::GetFileInfoSync(
102     FileSystemOperationContext* context, const FileSystemURL& url,
103     base::PlatformFileInfo* file_info, base::FilePath* platform_path) {
104   DCHECK(context);
105   DCHECK(file_info);
106
107   if (platform_path)
108     *platform_path = base::FilePath();
109
110   std::vector<std::string> components;
111   fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
112
113   switch (components.size()) {
114     case 0:
115       // Root directory.
116       file_info->is_directory = true;
117       return base::PLATFORM_FILE_OK;
118     case 1:
119       if (components[0] == kPicasaDirAlbums ||
120           components[0] == kPicasaDirFolders) {
121         file_info->is_directory = true;
122         return base::PLATFORM_FILE_OK;
123       }
124
125       break;
126     case 2:
127       if (components[0] == kPicasaDirAlbums) {
128         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
129         base::PlatformFileError error =
130             FindAlbumInfo(components[1], album_map.get(), NULL);
131         if (error != base::PLATFORM_FILE_OK)
132           return error;
133
134         file_info->is_directory = true;
135         return base::PLATFORM_FILE_OK;
136       }
137
138       if (components[0] == kPicasaDirFolders) {
139         return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
140                                                     platform_path);
141       }
142       break;
143     case 3:
144       // NativeMediaFileUtil::GetInfo calls into virtual function
145       // PicasaFileUtil::GetLocalFilePath, and that will handle both
146       // album contents and folder contents.
147       base::PlatformFileError result = NativeMediaFileUtil::GetFileInfoSync(
148           context, url, file_info, platform_path);
149
150       DCHECK(components[0] == kPicasaDirAlbums ||
151              components[0] == kPicasaDirFolders ||
152              result == base::PLATFORM_FILE_ERROR_NOT_FOUND);
153
154       return result;
155   }
156
157   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
158 }
159
160 base::PlatformFileError PicasaFileUtil::ReadDirectorySync(
161     fileapi::FileSystemOperationContext* context,
162     const fileapi::FileSystemURL& url,
163     EntryList* file_list) {
164   DCHECK(context);
165   DCHECK(file_list);
166   DCHECK(file_list->empty());
167
168   base::PlatformFileInfo file_info;
169   base::FilePath platform_directory_path;
170   base::PlatformFileError error = GetFileInfoSync(
171       context, url, &file_info, &platform_directory_path);
172
173   if (error != base::PLATFORM_FILE_OK)
174     return error;
175
176   if (!file_info.is_directory)
177     return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
178
179   std::vector<std::string> components;
180   fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
181
182   switch (components.size()) {
183     case 0: {
184       // Root directory.
185       file_list->push_back(
186           DirectoryEntry(kPicasaDirAlbums, DirectoryEntry::DIRECTORY, 0,
187                          base::Time()));
188       file_list->push_back(
189           DirectoryEntry(kPicasaDirFolders, DirectoryEntry::DIRECTORY, 0,
190                          base::Time()));
191       break;
192     }
193     case 1:
194       if (components[0] == kPicasaDirAlbums) {
195         scoped_ptr<AlbumMap> albums = GetDataProvider()->GetAlbums();
196         if (!albums)
197           return base::PLATFORM_FILE_ERROR_NOT_FOUND;
198
199         for (AlbumMap::const_iterator it = albums->begin();
200              it != albums->end(); ++it) {
201           file_list->push_back(
202               DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
203                              it->second.timestamp));
204         }
205       } else if (components[0] == kPicasaDirFolders) {
206         scoped_ptr<AlbumMap> folders = GetDataProvider()->GetFolders();
207         if (!folders)
208           return base::PLATFORM_FILE_ERROR_NOT_FOUND;
209
210         for (AlbumMap::const_iterator it = folders->begin();
211              it != folders->end(); ++it) {
212           file_list->push_back(
213               DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
214                              it->second.timestamp));
215         }
216       }
217       break;
218     case 2:
219       if (components[0] == kPicasaDirAlbums) {
220         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
221         AlbumInfo album_info;
222         base::PlatformFileError error =
223             FindAlbumInfo(components[1], album_map.get(), &album_info);
224         if (error != base::PLATFORM_FILE_OK)
225           return error;
226
227         scoped_ptr<AlbumImages> album_images =
228             GetDataProvider()->FindAlbumImages(album_info.uid, &error);
229         if (error != base::PLATFORM_FILE_OK)
230           return error;
231
232         for (AlbumImages::const_iterator it = album_images->begin();
233              it != album_images->end();
234              ++it) {
235           fileapi::DirectoryEntry entry;
236           base::PlatformFileInfo info;
237
238           // Simply skip files that we can't get info on.
239           if (fileapi::NativeFileUtil::GetFileInfo(it->second, &info) !=
240               base::PLATFORM_FILE_OK) {
241             continue;
242           }
243
244           file_list->push_back(DirectoryEntry(
245               it->first, DirectoryEntry::FILE, info.size, info.last_modified));
246         }
247       }
248
249       if (components[0] == kPicasaDirFolders) {
250         EntryList super_list;
251         base::PlatformFileError error =
252             NativeMediaFileUtil::ReadDirectorySync(context, url, &super_list);
253         if (error != base::PLATFORM_FILE_OK)
254           return error;
255
256         for (EntryList::const_iterator it = super_list.begin();
257              it != super_list.end(); ++it) {
258           if (!it->is_directory)
259             file_list->push_back(*it);
260         }
261       }
262
263       break;
264   }
265
266   return base::PLATFORM_FILE_OK;
267 }
268
269 base::PlatformFileError PicasaFileUtil::GetLocalFilePath(
270     FileSystemOperationContext* context, const FileSystemURL& url,
271     base::FilePath* local_file_path) {
272   DCHECK(local_file_path);
273   DCHECK(url.is_valid());
274   std::vector<std::string> components;
275   fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
276
277   switch (components.size()) {
278     case 2:
279       if (components[0] == kPicasaDirFolders) {
280         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetFolders();
281         AlbumInfo album_info;
282         base::PlatformFileError error =
283             FindAlbumInfo(components[1], album_map.get(), &album_info);
284         if (error != base::PLATFORM_FILE_OK)
285           return error;
286
287         *local_file_path = album_info.path;
288         return base::PLATFORM_FILE_OK;
289       }
290       break;
291     case 3:
292       if (components[0] == kPicasaDirAlbums) {
293         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
294         AlbumInfo album_info;
295         base::PlatformFileError error =
296             FindAlbumInfo(components[1], album_map.get(), &album_info);
297         if (error != base::PLATFORM_FILE_OK)
298           return error;
299
300         scoped_ptr<AlbumImages> album_images =
301             GetDataProvider()->FindAlbumImages(album_info.uid, &error);
302         if (error != base::PLATFORM_FILE_OK)
303           return error;
304
305         AlbumImages::const_iterator it = album_images->find(components[2]);
306         if (it == album_images->end())
307           return base::PLATFORM_FILE_ERROR_NOT_FOUND;
308
309         *local_file_path = it->second;
310         return base::PLATFORM_FILE_OK;
311       }
312
313       if (components[0] == kPicasaDirFolders) {
314         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetFolders();
315         AlbumInfo album_info;
316         base::PlatformFileError error =
317             FindAlbumInfo(components[1], album_map.get(), &album_info);
318         if (error != base::PLATFORM_FILE_OK)
319           return error;
320
321         // Not part of this class's mandate to check that it actually exists.
322         *local_file_path = album_info.path.Append(url.path().BaseName());
323         return base::PLATFORM_FILE_OK;
324       }
325
326       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
327       break;
328   }
329
330   // All other cases don't have a local path. The valid cases should be
331   // intercepted by GetFileInfo()/CreateFileEnumerator(). Invalid cases
332   // return a NOT_FOUND error.
333   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
334 }
335
336 void PicasaFileUtil::GetFileInfoWithFreshDataProvider(
337     scoped_ptr<fileapi::FileSystemOperationContext> context,
338     const fileapi::FileSystemURL& url,
339     const GetFileInfoCallback& callback,
340     bool success) {
341   if (!success) {
342     content::BrowserThread::PostTask(
343         content::BrowserThread::IO,
344         FROM_HERE,
345         base::Bind(
346             callback, base::PLATFORM_FILE_ERROR_IO, base::PlatformFileInfo()));
347     return;
348   }
349   NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
350       context.Pass(), url, callback);
351 }
352
353 void PicasaFileUtil::ReadDirectoryWithFreshDataProvider(
354     scoped_ptr<fileapi::FileSystemOperationContext> context,
355     const fileapi::FileSystemURL& url,
356     const ReadDirectoryCallback& callback,
357     bool success) {
358   if (!success) {
359     content::BrowserThread::PostTask(
360         content::BrowserThread::IO,
361         FROM_HERE,
362         base::Bind(callback, base::PLATFORM_FILE_ERROR_IO, EntryList(), false));
363     return;
364   }
365   NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
366       context.Pass(), url, callback);
367 }
368
369 PicasaDataProvider* PicasaFileUtil::GetDataProvider() {
370   return ImportedMediaGalleryRegistry::PicasaDataProvider();
371 }
372
373 }  // namespace picasa