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/iphoto_data_provider.h" 6 7 #include <map> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/location.h" 12 #include "base/logging.h" 13 #include "base/platform_file.h" 14 #include "base/stl_util.h" 15 #include "base/strings/string_number_conversions.h" 16 #include "base/threading/thread_restrictions.h" 17 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" 18 #include "chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h" 19 #include "content/public/browser/browser_thread.h" 20 21 namespace iphoto { 22 23 IPhotoDataProvider::IPhotoDataProvider(const base::FilePath& library_path) 24 : iapps::IAppsDataProvider(library_path), 25 weak_factory_(this) {} 26 27 IPhotoDataProvider::~IPhotoDataProvider() {} 28 29 void IPhotoDataProvider::DoParseLibrary( 30 const base::FilePath& library_path, 31 const ReadyCallback& ready_callback) { 32 xml_parser_ = new iapps::SafeIAppsLibraryParser; 33 xml_parser_->ParseIPhotoLibrary( 34 library_path, 35 base::Bind(&IPhotoDataProvider::OnLibraryParsed, 36 weak_factory_.GetWeakPtr(), 37 ready_callback)); 38 } 39 40 void IPhotoDataProvider::OnLibraryParsed(const ReadyCallback& ready_callback, 41 bool result, 42 const parser::Library& library) { 43 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread()); 44 set_valid(result); 45 if (valid()) 46 BuildIndices(library); 47 ready_callback.Run(valid()); 48 } 49 50 void IPhotoDataProvider::BuildIndices(const parser::Library& library) { 51 typedef base::hash_map<uint64, const base::FilePath*> IdIndex; 52 typedef base::hash_map<uint64, std::string> IdFileNameIndex; 53 54 IdIndex photo_id_index; 55 IdIndex originals_id_index; 56 for (std::set<parser::Photo>::const_iterator photo_it = 57 library.all_photos.begin(); 58 photo_it != library.all_photos.end(); photo_it++) { 59 photo_id_index[photo_it->id] = &(photo_it->location); 60 if (!photo_it->original_location.empty()) 61 originals_id_index[photo_it->id] = &(photo_it->original_location); 62 } 63 64 // Build up a set of IDs which have in-album duplicates. 65 // Those are the filenames we want to globally mangle. 66 std::set<uint64> dupe_ids; 67 for (parser::Albums::const_iterator album_it = library.albums.begin(); 68 album_it != library.albums.end(); album_it++) { 69 const parser::Album& album = album_it->second; 70 71 std::set<std::string> album_paths; 72 for (parser::Album::const_iterator id_it = album.begin(); 73 id_it != album.end(); id_it++) { 74 uint64 id = *id_it; 75 IdIndex::const_iterator photo_it = photo_id_index.find(id); 76 if (photo_it == photo_id_index.end()) 77 continue; 78 79 std::string filename = photo_it->second->BaseName().value(); 80 if (ContainsKey(album_paths, filename)) 81 dupe_ids.insert(id); 82 else 83 album_paths.insert(filename); 84 } 85 } 86 87 // Now build the directory index. 88 dir_index_.clear(); 89 originals_index_.clear(); 90 for (parser::Albums::const_iterator album_it = library.albums.begin(); 91 album_it != library.albums.end(); album_it++) { 92 std::string album_name = album_it->first; 93 const parser::Album& album = album_it->second; 94 95 for (parser::Album::const_iterator id_it = album.begin(); 96 id_it != album.end(); id_it++) { 97 uint64 id = *id_it; 98 IdIndex::const_iterator photo_it = photo_id_index.find(id); 99 if (photo_it == photo_id_index.end()) 100 continue; 101 base::FilePath path = *(photo_it->second); 102 103 std::string filename = path.BaseName().value(); 104 if (ContainsKey(dupe_ids, id)) { 105 filename = path.BaseName().InsertBeforeExtension( 106 "(" + base::Uint64ToString(id) + ")").value(); 107 } 108 109 dir_index_[album_name][filename] = path; 110 111 IdIndex::const_iterator original_it = originals_id_index.find(id); 112 if (original_it != originals_id_index.end()) 113 originals_index_[album_name][filename] = *(original_it->second); 114 } 115 } 116 } 117 118 std::vector<std::string> IPhotoDataProvider::GetAlbumNames() const { 119 std::vector<std::string> names; 120 121 for (DirIndex::const_iterator dir_it = dir_index_.begin(); 122 dir_it != dir_index_.end(); dir_it++) { 123 names.push_back(dir_it->first); 124 } 125 126 return names; 127 } 128 129 std::map<std::string, base::FilePath> IPhotoDataProvider::GetAlbumContents( 130 const std::string& album) const { 131 std::map<std::string, base::FilePath> locations; 132 DirIndex::const_iterator dir_it = dir_index_.find(album); 133 if (dir_it == dir_index_.end()) 134 return locations; 135 136 for (FileIndex::const_iterator file_it = dir_it->second.begin(); 137 file_it != dir_it->second.end(); file_it++) { 138 locations.insert(make_pair(file_it->first, file_it->second)); 139 } 140 141 return locations; 142 } 143 144 base::FilePath IPhotoDataProvider::GetPhotoLocationInAlbum( 145 const std::string& album, 146 const std::string& filename) const { 147 DirIndex::const_iterator dir_it = dir_index_.find(album); 148 if (dir_it == dir_index_.end()) 149 return base::FilePath(); 150 FileIndex::const_iterator file_it = dir_it->second.find(filename); 151 if (file_it == dir_it->second.end()) 152 return base::FilePath(); 153 return file_it->second; 154 } 155 156 bool IPhotoDataProvider::HasOriginals(const std::string& album) const { 157 DirIndex::const_iterator originals_it = originals_index_.find(album); 158 return originals_it != originals_index_.end(); 159 } 160 161 std::map<std::string, base::FilePath> IPhotoDataProvider::GetOriginals( 162 const std::string& album) const { 163 std::map<std::string, base::FilePath> locations; 164 DirIndex::const_iterator originals_it = originals_index_.find(album); 165 if (originals_it == originals_index_.end()) 166 return locations; 167 168 for (FileIndex::const_iterator file_it = originals_it->second.begin(); 169 file_it != originals_it->second.end(); file_it++) { 170 locations.insert(make_pair(file_it->first, file_it->second)); 171 } 172 173 return locations; 174 } 175 176 base::FilePath IPhotoDataProvider::GetOriginalPhotoLocation( 177 const std::string& album, 178 const std::string& filename) const { 179 DirIndex::const_iterator originals_it = originals_index_.find(album); 180 if (originals_it == originals_index_.end()) 181 return base::FilePath(); 182 FileIndex::const_iterator file_it = originals_it->second.find(filename); 183 if (file_it == originals_it->second.end()) 184 return base::FilePath(); 185 return file_it->second; 186 } 187 188 } // namespace iphoto 189