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"
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"
27 using storage::DirectoryEntry
;
28 using storage::FileSystemOperationContext
;
29 using storage::FileSystemURL
;
35 base::File::Error
FindAlbumInfo(const std::string
& key
,
37 AlbumInfo
* album_info
) {
39 return base::File::FILE_ERROR_FAILED
;
41 AlbumMap::const_iterator it
= map
->find(key
);
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
);
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
;
78 const char kPicasaDirAlbums
[] = "albums";
79 const char kPicasaDirFolders
[] = "folders";
81 PicasaFileUtil::PicasaFileUtil(MediaPathFilter
* media_path_filter
)
82 : NativeMediaFileUtil(media_path_filter
),
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.
96 GetFileInfoWithFreshDataProvider(context
.Pass(), url
, callback
, false);
98 data_provider
->RefreshData(
99 GetDataTypeForURL(url
),
100 base::Bind(&PicasaFileUtil::GetFileInfoWithFreshDataProvider
,
101 weak_factory_
.GetWeakPtr(),
102 base::Passed(&context
),
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);
118 data_provider
->RefreshData(
119 GetDataTypeForURL(url
),
120 base::Bind(&PicasaFileUtil::ReadDirectoryWithFreshDataProvider
,
121 weak_factory_
.GetWeakPtr(),
122 base::Passed(&context
),
128 base::File::Error
PicasaFileUtil::GetFileInfoSync(
129 FileSystemOperationContext
* context
, const FileSystemURL
& url
,
130 base::File::Info
* file_info
, base::FilePath
* platform_path
) {
135 *platform_path
= base::FilePath();
137 std::vector
<std::string
> components
= GetVirtualPathComponents(url
);
139 switch (components
.size()) {
142 file_info
->is_directory
= true;
143 return base::File::FILE_OK
;
145 if (components
[0] == kPicasaDirAlbums
||
146 components
[0] == kPicasaDirFolders
) {
147 file_info
->is_directory
= true;
148 return base::File::FILE_OK
;
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
)
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
,
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
);
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
) {
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
)
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()) {
209 file_list
->push_back(
210 DirectoryEntry(kPicasaDirAlbums
, DirectoryEntry::DIRECTORY
, 0,
212 file_list
->push_back(
213 DirectoryEntry(kPicasaDirFolders
, DirectoryEntry::DIRECTORY
, 0,
218 if (components
[0] == kPicasaDirAlbums
) {
219 scoped_ptr
<AlbumMap
> albums
= GetDataProvider()->GetAlbums();
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();
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
));
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
)
251 scoped_ptr
<AlbumImages
> album_images
=
252 GetDataProvider()->FindAlbumImages(album_info
.uid
, &error
);
253 if (error
!= base::File::FILE_OK
)
256 for (AlbumImages::const_iterator it
= album_images
->begin();
257 it
!= album_images
->end();
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
) {
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
)
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
);
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()) {
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
)
322 *local_file_path
= album_info
.path
;
323 return base::File::FILE_OK
;
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
)
335 scoped_ptr
<AlbumImages
> album_images
=
336 GetDataProvider()->FindAlbumImages(album_info
.uid
, &error
);
337 if (error
!= base::File::FILE_OK
)
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
)
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
;
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
,
377 content::BrowserThread::PostTask(
378 content::BrowserThread::IO
,
380 base::Bind(callback
, base::File::FILE_ERROR_IO
, base::File::Info()));
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
,
393 content::BrowserThread::PostTask(
394 content::BrowserThread::IO
,
396 base::Bind(callback
, base::File::FILE_ERROR_IO
, EntryList(), false));
399 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
400 context
.Pass(), url
, callback
);
403 PicasaDataProvider
* PicasaFileUtil::GetDataProvider() {
404 return ImportedMediaGalleryRegistry::PicasaDataProvider();
407 } // namespace picasa