Home | History | Annotate | Download | only in fileapi
      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