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/iphoto_file_util.h"
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"
26 using fileapi::DirectoryEntry
;
32 base::File::Error
MakeDirectoryFileInfo(base::File::Info
* file_info
) {
33 base::File::Info result
;
34 result
.is_directory
= true;
36 return base::File::FILE_OK
;
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()) {
52 const char kIPhotoAlbumsDir
[] = "Albums";
53 const char kIPhotoOriginalsDir
[] = "Originals";
55 IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter
* media_path_filter
)
56 : NativeMediaFileUtil(media_path_filter
),
58 imported_registry_(NULL
) {
61 IPhotoFileUtil::~IPhotoFileUtil() {
64 void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
65 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
66 const fileapi::FileSystemURL
& url
,
67 const GetFileInfoCallback
& callback
) {
68 GetDataProvider()->RefreshData(
69 base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider
,
70 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
74 void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
75 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
76 const fileapi::FileSystemURL
& url
,
77 const ReadDirectoryCallback
& callback
) {
78 GetDataProvider()->RefreshData(
79 base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider
,
80 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
84 void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
85 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
86 const fileapi::FileSystemURL
& url
,
87 const CreateSnapshotFileCallback
& callback
) {
88 GetDataProvider()->RefreshData(
89 base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider
,
90 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
94 void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
95 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
96 const fileapi::FileSystemURL
& url
,
97 const GetFileInfoCallback
& callback
,
100 if (!callback
.is_null()) {
101 content::BrowserThread::PostTask(
102 content::BrowserThread::IO
,
104 base::Bind(callback
, base::File::FILE_ERROR_IO
, base::File::Info()));
108 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context
.Pass(), url
,
112 void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider(
113 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
114 const fileapi::FileSystemURL
& url
,
115 const ReadDirectoryCallback
& callback
,
118 if (!callback
.is_null()) {
119 content::BrowserThread::PostTask(
120 content::BrowserThread::IO
,
122 base::Bind(callback
, base::File::FILE_ERROR_IO
, EntryList(), false));
126 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context
.Pass(), url
,
130 void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider(
131 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
132 const fileapi::FileSystemURL
& url
,
133 const CreateSnapshotFileCallback
& callback
,
136 if (!callback
.is_null()) {
137 base::File::Info file_info
;
138 base::FilePath platform_path
;
139 scoped_refptr
<webkit_blob::ShareableFileReference
> file_ref
;
140 content::BrowserThread::PostTask(
141 content::BrowserThread::IO
,
143 base::Bind(callback
, base::File::FILE_ERROR_IO
, file_info
,
144 platform_path
, file_ref
));
148 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context
.Pass(), url
,
152 // Begin actual implementation.
154 base::File::Error
IPhotoFileUtil::GetFileInfoSync(
155 fileapi::FileSystemOperationContext
* context
,
156 const fileapi::FileSystemURL
& url
,
157 base::File::Info
* file_info
,
158 base::FilePath
* platform_path
) {
159 std::vector
<std::string
> components
;
160 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
162 if (components
.size() == 0) {
163 return MakeDirectoryFileInfo(file_info
);
166 // The 'Albums' directory.
167 if (components
[0] == kIPhotoAlbumsDir
) {
168 if (components
.size() == 1) {
169 return MakeDirectoryFileInfo(file_info
);
170 } else if (components
.size() == 2) {
171 std::vector
<std::string
> albums
=
172 GetDataProvider()->GetAlbumNames();
173 if (ContainsElement(albums
, components
[1]))
174 return MakeDirectoryFileInfo(file_info
);
175 } else if (components
.size() == 3) {
176 if (components
[2] == kIPhotoOriginalsDir
) {
177 if (GetDataProvider()->HasOriginals(components
[1]))
178 return MakeDirectoryFileInfo(file_info
);
180 return base::File::FILE_ERROR_NOT_FOUND
;
183 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
184 components
[1], components
[2]);
185 if (!location
.empty()) {
186 return NativeMediaFileUtil::GetFileInfoSync(
187 context
, url
, file_info
, platform_path
);
189 } else if (components
.size() == 4 &&
190 GetDataProvider()->HasOriginals(components
[1]) &&
191 components
[2] == kIPhotoOriginalsDir
) {
192 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
193 components
[1], components
[3]);
194 if (!location
.empty()) {
195 return NativeMediaFileUtil::GetFileInfoSync(
196 context
, url
, file_info
, platform_path
);
201 return base::File::FILE_ERROR_NOT_FOUND
;
204 base::File::Error
IPhotoFileUtil::ReadDirectorySync(
205 fileapi::FileSystemOperationContext
* context
,
206 const fileapi::FileSystemURL
& url
,
207 EntryList
* file_list
) {
208 DCHECK(file_list
->empty());
209 std::vector
<std::string
> components
;
210 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
212 // Root directory. Child is the /Albums dir.
213 if (components
.size() == 0) {
214 file_list
->push_back(DirectoryEntry(kIPhotoAlbumsDir
,
215 DirectoryEntry::DIRECTORY
,
217 return base::File::FILE_OK
;
220 if (components
[0] == kIPhotoAlbumsDir
) {
221 if (components
.size() == 1) {
222 // Albums dir contains all album names.
223 std::vector
<std::string
> albums
=
224 GetDataProvider()->GetAlbumNames();
225 for (std::vector
<std::string
>::const_iterator it
= albums
.begin();
226 it
!= albums
.end(); it
++) {
227 file_list
->push_back(DirectoryEntry(*it
, DirectoryEntry::DIRECTORY
,
230 return base::File::FILE_OK
;
231 } else if (components
.size() == 2) {
232 std::vector
<std::string
> albums
=
233 GetDataProvider()->GetAlbumNames();
234 if (!ContainsElement(albums
, components
[1]))
235 return base::File::FILE_ERROR_NOT_FOUND
;
237 // Album dirs contain all photos in them.
238 if (GetDataProvider()->HasOriginals(components
[1])) {
239 file_list
->push_back(DirectoryEntry(kIPhotoOriginalsDir
,
240 DirectoryEntry::DIRECTORY
,
243 std::map
<std::string
, base::FilePath
> locations
=
244 GetDataProvider()->GetAlbumContents(components
[1]);
245 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
247 it
!= locations
.end(); it
++) {
248 base::File::Info info
;
249 if (!base::GetFileInfo(it
->second
, &info
))
250 return base::File::FILE_ERROR_IO
;
251 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
252 info
.size
, info
.last_modified
));
254 return base::File::FILE_OK
;
255 } else if (components
.size() == 3 &&
256 components
[2] == kIPhotoOriginalsDir
&&
257 GetDataProvider()->HasOriginals(components
[1])) {
258 std::map
<std::string
, base::FilePath
> originals
=
259 GetDataProvider()->GetOriginals(components
[1]);
260 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
262 it
!= originals
.end(); it
++) {
263 base::File::Info info
;
264 if (!base::GetFileInfo(it
->second
, &info
))
265 return base::File::FILE_ERROR_IO
;
266 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
267 info
.size
, info
.last_modified
));
269 return base::File::FILE_OK
;
273 return base::File::FILE_ERROR_NOT_FOUND
;
276 base::File::Error
IPhotoFileUtil::DeleteDirectorySync(
277 fileapi::FileSystemOperationContext
* context
,
278 const fileapi::FileSystemURL
& url
) {
279 return base::File::FILE_ERROR_SECURITY
;
282 base::File::Error
IPhotoFileUtil::DeleteFileSync(
283 fileapi::FileSystemOperationContext
* context
,
284 const fileapi::FileSystemURL
& url
) {
285 return base::File::FILE_ERROR_SECURITY
;
289 base::File::Error
IPhotoFileUtil::GetLocalFilePath(
290 fileapi::FileSystemOperationContext
* context
,
291 const fileapi::FileSystemURL
& url
,
292 base::FilePath
* local_file_path
) {
293 std::vector
<std::string
> components
;
294 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
296 if (components
.size() == 3 && components
[0] == kIPhotoAlbumsDir
) {
297 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
298 components
[1], components
[2]);
299 if (!location
.empty()) {
300 *local_file_path
= location
;
301 return base::File::FILE_OK
;
305 if (components
.size() == 4 && components
[0] == kIPhotoAlbumsDir
&&
306 GetDataProvider()->HasOriginals(components
[1]) &&
307 components
[2] == kIPhotoOriginalsDir
) {
308 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
309 components
[1], components
[3]);
310 if (!location
.empty()) {
311 *local_file_path
= location
;
312 return base::File::FILE_OK
;
316 return base::File::FILE_ERROR_NOT_FOUND
;
319 IPhotoDataProvider
* IPhotoFileUtil::GetDataProvider() {
320 if (!imported_registry_
)
321 imported_registry_
= ImportedMediaGalleryRegistry::GetInstance();
322 return imported_registry_
->IPhotoDataProvider();
325 } // namespace iphoto