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/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