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::PlatformFileError
MakeDirectoryFileInfo(
33 base::PlatformFileInfo
* file_info
) {
34 base::PlatformFileInfo result
;
35 result
.is_directory
= true;
37 return base::PLATFORM_FILE_OK
;
41 bool ContainsElement(const std::vector
<T
>& collection
, const T
& key
) {
42 typename
std::vector
<T
>::const_iterator it
= collection
.begin();
43 while (it
!= collection
.end()) {
53 const char kIPhotoAlbumsDir
[] = "Albums";
54 const char kIPhotoOriginalsDir
[] = "Originals";
56 IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter
* media_path_filter
)
57 : NativeMediaFileUtil(media_path_filter
),
59 imported_registry_(NULL
) {
62 IPhotoFileUtil::~IPhotoFileUtil() {
65 void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
66 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
67 const fileapi::FileSystemURL
& url
,
68 const GetFileInfoCallback
& callback
) {
69 GetDataProvider()->RefreshData(
70 base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider
,
71 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
75 void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
76 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
77 const fileapi::FileSystemURL
& url
,
78 const ReadDirectoryCallback
& callback
) {
79 GetDataProvider()->RefreshData(
80 base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider
,
81 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
85 void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
86 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
87 const fileapi::FileSystemURL
& url
,
88 const CreateSnapshotFileCallback
& callback
) {
89 GetDataProvider()->RefreshData(
90 base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider
,
91 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
95 void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
96 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
97 const fileapi::FileSystemURL
& url
,
98 const GetFileInfoCallback
& callback
,
101 if (!callback
.is_null()) {
102 content::BrowserThread::PostTask(
103 content::BrowserThread::IO
,
105 base::Bind(callback
, base::PLATFORM_FILE_ERROR_IO
,
106 base::PlatformFileInfo()));
110 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context
.Pass(), url
,
114 void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider(
115 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
116 const fileapi::FileSystemURL
& url
,
117 const ReadDirectoryCallback
& callback
,
120 if (!callback
.is_null()) {
121 content::BrowserThread::PostTask(
122 content::BrowserThread::IO
,
124 base::Bind(callback
, base::PLATFORM_FILE_ERROR_IO
, EntryList(),
129 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context
.Pass(), url
,
133 void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider(
134 scoped_ptr
<fileapi::FileSystemOperationContext
> context
,
135 const fileapi::FileSystemURL
& url
,
136 const CreateSnapshotFileCallback
& callback
,
139 if (!callback
.is_null()) {
140 base::PlatformFileInfo file_info
;
141 base::FilePath platform_path
;
142 scoped_refptr
<webkit_blob::ShareableFileReference
> file_ref
;
143 content::BrowserThread::PostTask(
144 content::BrowserThread::IO
,
146 base::Bind(callback
, base::PLATFORM_FILE_ERROR_IO
, file_info
,
147 platform_path
, file_ref
));
151 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context
.Pass(), url
,
155 // Begin actual implementation.
157 base::PlatformFileError
IPhotoFileUtil::GetFileInfoSync(
158 fileapi::FileSystemOperationContext
* context
,
159 const fileapi::FileSystemURL
& url
,
160 base::PlatformFileInfo
* file_info
,
161 base::FilePath
* platform_path
) {
162 std::vector
<std::string
> components
;
163 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
165 if (components
.size() == 0) {
166 return MakeDirectoryFileInfo(file_info
);
169 // The 'Albums' directory.
170 if (components
[0] == kIPhotoAlbumsDir
) {
171 if (components
.size() == 1) {
172 return MakeDirectoryFileInfo(file_info
);
173 } else if (components
.size() == 2) {
174 std::vector
<std::string
> albums
=
175 GetDataProvider()->GetAlbumNames();
176 if (ContainsElement(albums
, components
[1]))
177 return MakeDirectoryFileInfo(file_info
);
178 } else if (components
.size() == 3) {
179 if (components
[2] == kIPhotoOriginalsDir
) {
180 if (GetDataProvider()->HasOriginals(components
[1]))
181 return MakeDirectoryFileInfo(file_info
);
183 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
186 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
187 components
[1], components
[2]);
188 if (!location
.empty()) {
189 return NativeMediaFileUtil::GetFileInfoSync(
190 context
, url
, file_info
, platform_path
);
192 } else if (components
.size() == 4 &&
193 GetDataProvider()->HasOriginals(components
[1]) &&
194 components
[2] == kIPhotoOriginalsDir
) {
195 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
196 components
[1], components
[3]);
197 if (!location
.empty()) {
198 return NativeMediaFileUtil::GetFileInfoSync(
199 context
, url
, file_info
, platform_path
);
204 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
207 base::PlatformFileError
IPhotoFileUtil::ReadDirectorySync(
208 fileapi::FileSystemOperationContext
* context
,
209 const fileapi::FileSystemURL
& url
,
210 EntryList
* file_list
) {
211 DCHECK(file_list
->empty());
212 std::vector
<std::string
> components
;
213 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
215 // Root directory. Child is the /Albums dir.
216 if (components
.size() == 0) {
217 file_list
->push_back(DirectoryEntry(kIPhotoAlbumsDir
,
218 DirectoryEntry::DIRECTORY
,
220 return base::PLATFORM_FILE_OK
;
223 if (components
[0] == kIPhotoAlbumsDir
) {
224 if (components
.size() == 1) {
225 // Albums dir contains all album names.
226 std::vector
<std::string
> albums
=
227 GetDataProvider()->GetAlbumNames();
228 for (std::vector
<std::string
>::const_iterator it
= albums
.begin();
229 it
!= albums
.end(); it
++) {
230 file_list
->push_back(DirectoryEntry(*it
, DirectoryEntry::DIRECTORY
,
233 return base::PLATFORM_FILE_OK
;
234 } else if (components
.size() == 2) {
235 std::vector
<std::string
> albums
=
236 GetDataProvider()->GetAlbumNames();
237 if (!ContainsElement(albums
, components
[1]))
238 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
240 // Album dirs contain all photos in them.
241 if (GetDataProvider()->HasOriginals(components
[1])) {
242 file_list
->push_back(DirectoryEntry(kIPhotoOriginalsDir
,
243 DirectoryEntry::DIRECTORY
,
246 std::map
<std::string
, base::FilePath
> locations
=
247 GetDataProvider()->GetAlbumContents(components
[1]);
248 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
250 it
!= locations
.end(); it
++) {
251 base::File::Info info
;
252 if (!base::GetFileInfo(it
->second
, &info
))
253 return base::PLATFORM_FILE_ERROR_IO
;
254 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
255 info
.size
, info
.last_modified
));
257 return base::PLATFORM_FILE_OK
;
258 } else if (components
.size() == 3 &&
259 components
[2] == kIPhotoOriginalsDir
&&
260 GetDataProvider()->HasOriginals(components
[1])) {
261 std::map
<std::string
, base::FilePath
> originals
=
262 GetDataProvider()->GetOriginals(components
[1]);
263 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
265 it
!= originals
.end(); it
++) {
266 base::File::Info info
;
267 if (!base::GetFileInfo(it
->second
, &info
))
268 return base::PLATFORM_FILE_ERROR_IO
;
269 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
270 info
.size
, info
.last_modified
));
272 return base::PLATFORM_FILE_OK
;
276 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
279 base::PlatformFileError
IPhotoFileUtil::DeleteDirectorySync(
280 fileapi::FileSystemOperationContext
* context
,
281 const fileapi::FileSystemURL
& url
) {
282 return base::PLATFORM_FILE_ERROR_SECURITY
;
285 base::PlatformFileError
IPhotoFileUtil::DeleteFileSync(
286 fileapi::FileSystemOperationContext
* context
,
287 const fileapi::FileSystemURL
& url
) {
288 return base::PLATFORM_FILE_ERROR_SECURITY
;
292 base::PlatformFileError
IPhotoFileUtil::GetLocalFilePath(
293 fileapi::FileSystemOperationContext
* context
,
294 const fileapi::FileSystemURL
& url
,
295 base::FilePath
* local_file_path
) {
296 std::vector
<std::string
> components
;
297 fileapi::VirtualPath::GetComponentsUTF8Unsafe(url
.path(), &components
);
299 if (components
.size() == 3 && components
[0] == kIPhotoAlbumsDir
) {
300 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
301 components
[1], components
[2]);
302 if (!location
.empty()) {
303 *local_file_path
= location
;
304 return base::PLATFORM_FILE_OK
;
308 if (components
.size() == 4 && components
[0] == kIPhotoAlbumsDir
&&
309 GetDataProvider()->HasOriginals(components
[1]) &&
310 components
[2] == kIPhotoOriginalsDir
) {
311 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
312 components
[1], components
[3]);
313 if (!location
.empty()) {
314 *local_file_path
= location
;
315 return base::PLATFORM_FILE_OK
;
319 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
322 IPhotoDataProvider
* IPhotoFileUtil::GetDataProvider() {
323 if (!imported_registry_
)
324 imported_registry_
= ImportedMediaGalleryRegistry::GetInstance();
325 return imported_registry_
->IPhotoDataProvider();
328 } // namespace iphoto