Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / picasa_file_util.cc
blob65a2c3cff6d1a92894bd7d03b3a59f26930bd683
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/picasa_file_util.h"
7 #include <string>
8 #include <vector>
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 "storage/browser/fileapi/file_system_operation_context.h"
22 #include "storage/browser/fileapi/file_system_url.h"
23 #include "storage/browser/fileapi/native_file_util.h"
24 #include "storage/common/fileapi/file_system_util.h"
26 using base::FilePath;
27 using storage::DirectoryEntry;
28 using storage::FileSystemOperationContext;
29 using storage::FileSystemURL;
31 namespace picasa {
33 namespace {
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;
41 AlbumMap::const_iterator it = map->find(key);
43 if (it == map->end())
44 return base::File::FILE_ERROR_NOT_FOUND;
46 if (album_info != NULL)
47 *album_info = it->second;
49 return base::File::FILE_OK;
52 std::vector<std::string> GetVirtualPathComponents(
53 const storage::FileSystemURL& url) {
54 ImportedMediaGalleryRegistry* imported_registry =
55 ImportedMediaGalleryRegistry::GetInstance();
56 base::FilePath root = imported_registry->ImportedRoot().AppendASCII("picasa");
58 DCHECK(root.IsParent(url.path()) || root == url.path());
59 base::FilePath virtual_path;
60 root.AppendRelativePath(url.path(), &virtual_path);
62 std::vector<std::string> result;
63 storage::VirtualPath::GetComponentsUTF8Unsafe(virtual_path, &result);
64 return result;
67 PicasaDataProvider::DataType GetDataTypeForURL(
68 const storage::FileSystemURL& url) {
69 std::vector<std::string> components = GetVirtualPathComponents(url);
70 if (components.size() >= 2 && components[0] == kPicasaDirAlbums)
71 return PicasaDataProvider::ALBUMS_IMAGES_DATA;
73 return PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA;
76 } // namespace
78 const char kPicasaDirAlbums[] = "albums";
79 const char kPicasaDirFolders[] = "folders";
81 PicasaFileUtil::PicasaFileUtil(MediaPathFilter* media_path_filter)
82 : NativeMediaFileUtil(media_path_filter),
83 weak_factory_(this) {
86 PicasaFileUtil::~PicasaFileUtil() {}
88 void PicasaFileUtil::GetFileInfoOnTaskRunnerThread(
89 scoped_ptr<storage::FileSystemOperationContext> context,
90 const storage::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));
108 void PicasaFileUtil::ReadDirectoryOnTaskRunnerThread(
109 scoped_ptr<storage::FileSystemOperationContext> context,
110 const storage::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));
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);
134 if (platform_path)
135 *platform_path = base::FilePath();
137 std::vector<std::string> components = GetVirtualPathComponents(url);
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;
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;
160 file_info->is_directory = true;
161 return base::File::FILE_OK;
164 if (components[0] == kPicasaDirFolders) {
165 return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
166 platform_path);
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);
176 DCHECK(components[0] == kPicasaDirAlbums ||
177 components[0] == kPicasaDirFolders ||
178 result == base::File::FILE_ERROR_NOT_FOUND);
180 return result;
183 return base::File::FILE_ERROR_NOT_FOUND;
186 base::File::Error PicasaFileUtil::ReadDirectorySync(
187 storage::FileSystemOperationContext* context,
188 const storage::FileSystemURL& url,
189 EntryList* file_list) {
190 DCHECK(context);
191 DCHECK(file_list);
192 DCHECK(file_list->empty());
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);
199 if (error != base::File::FILE_OK)
200 return error;
202 if (!file_info.is_directory)
203 return base::File::FILE_ERROR_NOT_A_DIRECTORY;
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;
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;
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));
229 } else if (components[0] == kPicasaDirFolders) {
230 scoped_ptr<AlbumMap> folders = GetDataProvider()->GetFolders();
231 if (!folders)
232 return base::File::FILE_ERROR_NOT_FOUND;
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));
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;
251 scoped_ptr<AlbumImages> album_images =
252 GetDataProvider()->FindAlbumImages(album_info.uid, &error);
253 if (error != base::File::FILE_OK)
254 return error;
256 for (AlbumImages::const_iterator it = album_images->begin();
257 it != album_images->end();
258 ++it) {
259 storage::DirectoryEntry entry;
260 base::File::Info info;
262 // Simply skip files that we can't get info on.
263 if (storage::NativeFileUtil::GetFileInfo(it->second, &info) !=
264 base::File::FILE_OK) {
265 continue;
268 file_list->push_back(DirectoryEntry(
269 it->first, DirectoryEntry::FILE, info.size, info.last_modified));
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;
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);
287 break;
290 return base::File::FILE_OK;
293 base::File::Error PicasaFileUtil::DeleteDirectorySync(
294 storage::FileSystemOperationContext* context,
295 const storage::FileSystemURL& url) {
296 return base::File::FILE_ERROR_SECURITY;
299 base::File::Error PicasaFileUtil::DeleteFileSync(
300 storage::FileSystemOperationContext* context,
301 const storage::FileSystemURL& url) {
302 return base::File::FILE_ERROR_SECURITY;
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);
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;
322 *local_file_path = album_info.path;
323 return base::File::FILE_OK;
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;
335 scoped_ptr<AlbumImages> album_images =
336 GetDataProvider()->FindAlbumImages(album_info.uid, &error);
337 if (error != base::File::FILE_OK)
338 return error;
340 AlbumImages::const_iterator it = album_images->find(components[2]);
341 if (it == album_images->end())
342 return base::File::FILE_ERROR_NOT_FOUND;
344 *local_file_path = it->second;
345 return base::File::FILE_OK;
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;
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;
361 return base::File::FILE_ERROR_NOT_FOUND;
362 break;
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;
371 void PicasaFileUtil::GetFileInfoWithFreshDataProvider(
372 scoped_ptr<storage::FileSystemOperationContext> context,
373 const storage::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;
383 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
384 context.Pass(), url, callback);
387 void PicasaFileUtil::ReadDirectoryWithFreshDataProvider(
388 scoped_ptr<storage::FileSystemOperationContext> context,
389 const storage::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;
399 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
400 context.Pass(), url, callback);
403 PicasaDataProvider* PicasaFileUtil::GetDataProvider() {
404 return ImportedMediaGalleryRegistry::PicasaDataProvider();
407 } // namespace picasa