Upstream version 7.36.149.0
[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::File::Error FindAlbumInfo(const std::string& key,
36                                 const AlbumMap* map,
37                                 AlbumInfo* album_info) {
38   if (!map)
39     return base::File::FILE_ERROR_FAILED;
40
41   AlbumMap::const_iterator it = map->find(key);
42
43   if (it == map->end())
44     return base::File::FILE_ERROR_NOT_FOUND;
45
46   if (album_info != NULL)
47     *album_info = it->second;
48
49   return base::File::FILE_OK;
50 }
51
52 std::vector<std::string> GetVirtualPathComponents(
53     const fileapi::FileSystemURL& url) {
54   ImportedMediaGalleryRegistry* imported_registry =
55       ImportedMediaGalleryRegistry::GetInstance();
56   base::FilePath root = imported_registry->ImportedRoot().AppendASCII("picasa");
57
58   DCHECK(root.IsParent(url.path()) || root == url.path());
59   base::FilePath virtual_path;
60   root.AppendRelativePath(url.path(), &virtual_path);
61
62   std::vector<std::string> result;
63   fileapi::VirtualPath::GetComponentsUTF8Unsafe(virtual_path, &result);
64   return result;
65 }
66
67 PicasaDataProvider::DataType GetDataTypeForURL(
68     const fileapi::FileSystemURL& url) {
69   std::vector<std::string> components = GetVirtualPathComponents(url);
70   if (components.size() >= 2 && components[0] == kPicasaDirAlbums)
71     return PicasaDataProvider::ALBUMS_IMAGES_DATA;
72
73   return PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA;
74 }
75
76 }  // namespace
77
78 const char kPicasaDirAlbums[]  = "albums";
79 const char kPicasaDirFolders[] = "folders";
80
81 PicasaFileUtil::PicasaFileUtil(MediaPathFilter* media_path_filter)
82     : NativeMediaFileUtil(media_path_filter),
83       weak_factory_(this) {
84 }
85
86 PicasaFileUtil::~PicasaFileUtil() {}
87
88 void PicasaFileUtil::GetFileInfoOnTaskRunnerThread(
89     scoped_ptr<fileapi::FileSystemOperationContext> context,
90     const fileapi::FileSystemURL& url,
91     const GetFileInfoCallback& callback) {
92   PicasaDataProvider* data_provider = GetDataProvider();
93   // |data_provider| may be NULL if the file system was revoked before this
94   // operation had a chance to run.
95   if (!data_provider) {
96     GetFileInfoWithFreshDataProvider(context.Pass(), url, callback, false);
97   } else {
98     data_provider->RefreshData(
99         GetDataTypeForURL(url),
100         base::Bind(&PicasaFileUtil::GetFileInfoWithFreshDataProvider,
101                    weak_factory_.GetWeakPtr(),
102                    base::Passed(&context),
103                    url,
104                    callback));
105   }
106 }
107
108 void PicasaFileUtil::ReadDirectoryOnTaskRunnerThread(
109     scoped_ptr<fileapi::FileSystemOperationContext> context,
110     const fileapi::FileSystemURL& url,
111     const ReadDirectoryCallback& callback) {
112   PicasaDataProvider* data_provider = GetDataProvider();
113   // |data_provider| may be NULL if the file system was revoked before this
114   // operation had a chance to run.
115   if (!data_provider) {
116     ReadDirectoryWithFreshDataProvider(context.Pass(), url, callback, false);
117   } else {
118     data_provider->RefreshData(
119         GetDataTypeForURL(url),
120         base::Bind(&PicasaFileUtil::ReadDirectoryWithFreshDataProvider,
121                    weak_factory_.GetWeakPtr(),
122                    base::Passed(&context),
123                    url,
124                    callback));
125   }
126 }
127
128 base::File::Error PicasaFileUtil::GetFileInfoSync(
129     FileSystemOperationContext* context, const FileSystemURL& url,
130     base::File::Info* file_info, base::FilePath* platform_path) {
131   DCHECK(context);
132   DCHECK(file_info);
133
134   if (platform_path)
135     *platform_path = base::FilePath();
136
137   std::vector<std::string> components = GetVirtualPathComponents(url);
138
139   switch (components.size()) {
140     case 0:
141       // Root directory.
142       file_info->is_directory = true;
143       return base::File::FILE_OK;
144     case 1:
145       if (components[0] == kPicasaDirAlbums ||
146           components[0] == kPicasaDirFolders) {
147         file_info->is_directory = true;
148         return base::File::FILE_OK;
149       }
150
151       break;
152     case 2:
153       if (components[0] == kPicasaDirAlbums) {
154         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
155         base::File::Error error =
156             FindAlbumInfo(components[1], album_map.get(), NULL);
157         if (error != base::File::FILE_OK)
158           return error;
159
160         file_info->is_directory = true;
161         return base::File::FILE_OK;
162       }
163
164       if (components[0] == kPicasaDirFolders) {
165         return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
166                                                     platform_path);
167       }
168       break;
169     case 3:
170       // NativeMediaFileUtil::GetInfo calls into virtual function
171       // PicasaFileUtil::GetLocalFilePath, and that will handle both
172       // album contents and folder contents.
173       base::File::Error result = NativeMediaFileUtil::GetFileInfoSync(
174           context, url, file_info, platform_path);
175
176       DCHECK(components[0] == kPicasaDirAlbums ||
177              components[0] == kPicasaDirFolders ||
178              result == base::File::FILE_ERROR_NOT_FOUND);
179
180       return result;
181   }
182
183   return base::File::FILE_ERROR_NOT_FOUND;
184 }
185
186 base::File::Error PicasaFileUtil::ReadDirectorySync(
187     fileapi::FileSystemOperationContext* context,
188     const fileapi::FileSystemURL& url,
189     EntryList* file_list) {
190   DCHECK(context);
191   DCHECK(file_list);
192   DCHECK(file_list->empty());
193
194   base::File::Info file_info;
195   base::FilePath platform_directory_path;
196   base::File::Error error = GetFileInfoSync(
197       context, url, &file_info, &platform_directory_path);
198
199   if (error != base::File::FILE_OK)
200     return error;
201
202   if (!file_info.is_directory)
203     return base::File::FILE_ERROR_NOT_A_DIRECTORY;
204
205   std::vector<std::string> components = GetVirtualPathComponents(url);
206   switch (components.size()) {
207     case 0: {
208       // Root directory.
209       file_list->push_back(
210           DirectoryEntry(kPicasaDirAlbums, DirectoryEntry::DIRECTORY, 0,
211                          base::Time()));
212       file_list->push_back(
213           DirectoryEntry(kPicasaDirFolders, DirectoryEntry::DIRECTORY, 0,
214                          base::Time()));
215       break;
216     }
217     case 1:
218       if (components[0] == kPicasaDirAlbums) {
219         scoped_ptr<AlbumMap> albums = GetDataProvider()->GetAlbums();
220         if (!albums)
221           return base::File::FILE_ERROR_NOT_FOUND;
222
223         for (AlbumMap::const_iterator it = albums->begin();
224              it != albums->end(); ++it) {
225           file_list->push_back(
226               DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
227                              it->second.timestamp));
228         }
229       } else if (components[0] == kPicasaDirFolders) {
230         scoped_ptr<AlbumMap> folders = GetDataProvider()->GetFolders();
231         if (!folders)
232           return base::File::FILE_ERROR_NOT_FOUND;
233
234         for (AlbumMap::const_iterator it = folders->begin();
235              it != folders->end(); ++it) {
236           file_list->push_back(
237               DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
238                              it->second.timestamp));
239         }
240       }
241       break;
242     case 2:
243       if (components[0] == kPicasaDirAlbums) {
244         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
245         AlbumInfo album_info;
246         base::File::Error error =
247             FindAlbumInfo(components[1], album_map.get(), &album_info);
248         if (error != base::File::FILE_OK)
249           return error;
250
251         scoped_ptr<AlbumImages> album_images =
252             GetDataProvider()->FindAlbumImages(album_info.uid, &error);
253         if (error != base::File::FILE_OK)
254           return error;
255
256         for (AlbumImages::const_iterator it = album_images->begin();
257              it != album_images->end();
258              ++it) {
259           fileapi::DirectoryEntry entry;
260           base::File::Info info;
261
262           // Simply skip files that we can't get info on.
263           if (fileapi::NativeFileUtil::GetFileInfo(it->second, &info) !=
264               base::File::FILE_OK) {
265             continue;
266           }
267
268           file_list->push_back(DirectoryEntry(
269               it->first, DirectoryEntry::FILE, info.size, info.last_modified));
270         }
271       }
272
273       if (components[0] == kPicasaDirFolders) {
274         EntryList super_list;
275         base::File::Error error =
276             NativeMediaFileUtil::ReadDirectorySync(context, url, &super_list);
277         if (error != base::File::FILE_OK)
278           return error;
279
280         for (EntryList::const_iterator it = super_list.begin();
281              it != super_list.end(); ++it) {
282           if (!it->is_directory)
283             file_list->push_back(*it);
284         }
285       }
286
287       break;
288   }
289
290   return base::File::FILE_OK;
291 }
292
293 base::File::Error PicasaFileUtil::DeleteDirectorySync(
294     fileapi::FileSystemOperationContext* context,
295     const fileapi::FileSystemURL& url) {
296   return base::File::FILE_ERROR_SECURITY;
297 }
298
299 base::File::Error PicasaFileUtil::DeleteFileSync(
300     fileapi::FileSystemOperationContext* context,
301     const fileapi::FileSystemURL& url) {
302   return base::File::FILE_ERROR_SECURITY;
303 }
304
305 base::File::Error PicasaFileUtil::GetLocalFilePath(
306     FileSystemOperationContext* context, const FileSystemURL& url,
307     base::FilePath* local_file_path) {
308   DCHECK(local_file_path);
309   DCHECK(url.is_valid());
310   std::vector<std::string> components = GetVirtualPathComponents(url);
311
312   switch (components.size()) {
313     case 2:
314       if (components[0] == kPicasaDirFolders) {
315         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetFolders();
316         AlbumInfo album_info;
317         base::File::Error error =
318             FindAlbumInfo(components[1], album_map.get(), &album_info);
319         if (error != base::File::FILE_OK)
320           return error;
321
322         *local_file_path = album_info.path;
323         return base::File::FILE_OK;
324       }
325       break;
326     case 3:
327       if (components[0] == kPicasaDirAlbums) {
328         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetAlbums();
329         AlbumInfo album_info;
330         base::File::Error error =
331             FindAlbumInfo(components[1], album_map.get(), &album_info);
332         if (error != base::File::FILE_OK)
333           return error;
334
335         scoped_ptr<AlbumImages> album_images =
336             GetDataProvider()->FindAlbumImages(album_info.uid, &error);
337         if (error != base::File::FILE_OK)
338           return error;
339
340         AlbumImages::const_iterator it = album_images->find(components[2]);
341         if (it == album_images->end())
342           return base::File::FILE_ERROR_NOT_FOUND;
343
344         *local_file_path = it->second;
345         return base::File::FILE_OK;
346       }
347
348       if (components[0] == kPicasaDirFolders) {
349         scoped_ptr<AlbumMap> album_map = GetDataProvider()->GetFolders();
350         AlbumInfo album_info;
351         base::File::Error error =
352             FindAlbumInfo(components[1], album_map.get(), &album_info);
353         if (error != base::File::FILE_OK)
354           return error;
355
356         // Not part of this class's mandate to check that it actually exists.
357         *local_file_path = album_info.path.Append(url.path().BaseName());
358         return base::File::FILE_OK;
359       }
360
361       return base::File::FILE_ERROR_NOT_FOUND;
362       break;
363   }
364
365   // All other cases don't have a local path. The valid cases should be
366   // intercepted by GetFileInfo()/CreateFileEnumerator(). Invalid cases
367   // return a NOT_FOUND error.
368   return base::File::FILE_ERROR_NOT_FOUND;
369 }
370
371 void PicasaFileUtil::GetFileInfoWithFreshDataProvider(
372     scoped_ptr<fileapi::FileSystemOperationContext> context,
373     const fileapi::FileSystemURL& url,
374     const GetFileInfoCallback& callback,
375     bool success) {
376   if (!success) {
377     content::BrowserThread::PostTask(
378         content::BrowserThread::IO,
379         FROM_HERE,
380         base::Bind(callback, base::File::FILE_ERROR_IO, base::File::Info()));
381     return;
382   }
383   NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
384       context.Pass(), url, callback);
385 }
386
387 void PicasaFileUtil::ReadDirectoryWithFreshDataProvider(
388     scoped_ptr<fileapi::FileSystemOperationContext> context,
389     const fileapi::FileSystemURL& url,
390     const ReadDirectoryCallback& callback,
391     bool success) {
392   if (!success) {
393     content::BrowserThread::PostTask(
394         content::BrowserThread::IO,
395         FROM_HERE,
396         base::Bind(callback, base::File::FILE_ERROR_IO, EntryList(), false));
397     return;
398   }
399   NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
400       context.Pass(), url, callback);
401 }
402
403 PicasaDataProvider* PicasaFileUtil::GetDataProvider() {
404   return ImportedMediaGalleryRegistry::PicasaDataProvider();
405 }
406
407 }  // namespace picasa