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