Home | History | Annotate | Download | only in media_galleries
      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/utility/media_galleries/picasa_albums_indexer.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 #include <vector>
     10 
     11 #include "base/ini_parser.h"
     12 #include "base/logging.h"
     13 #include "base/strings/string_split.h"
     14 #include "base/strings/stringprintf.h"
     15 
     16 namespace picasa {
     17 
     18 namespace {
     19 
     20 const char kAlbumSectionHeader[] = ".album:";
     21 const char kAlbumsKey[] = "albums";
     22 const int kMaxDedupeNumber = 1000;  // Chosen arbitrarily.
     23 
     24 class PicasaINIParser : public base::INIParser {
     25  public:
     26   PicasaINIParser(
     27       const base::FilePath& folder_path, AlbumImagesMap* albums_images)
     28       : folder_path_(folder_path),
     29         albums_images_(albums_images) {
     30   }
     31   virtual ~PicasaINIParser() {}
     32 
     33  private:
     34   virtual void HandleTriplet(const std::string& section,
     35                              const std::string& key,
     36                              const std::string& value) OVERRIDE {
     37     if (key != kAlbumsKey)
     38       return;
     39 
     40     // [.album:*] sections ignored as we get that data from the PMP files.
     41     if (section.find(kAlbumSectionHeader) == 0)
     42       return;
     43 
     44     std::vector<std::string> containing_albums;
     45     base::SplitString(value, ',', &containing_albums);
     46     for (std::vector<std::string>::iterator it = containing_albums.begin();
     47          it != containing_albums.end(); ++it) {
     48       AlbumImagesMap::iterator album_map_it = albums_images_->find(*it);
     49 
     50       // Ignore entry if the album uid is not listed among in |album_uids|
     51       // in the constructor. Happens if the PMP and INI files are inconsistent.
     52       if (album_map_it == albums_images_->end())
     53         continue;
     54 
     55       base::FilePath filename = base::FilePath::FromUTF8Unsafe(section);
     56       AlbumImages& album_images = album_map_it->second;
     57 
     58       // If filename is first of its name in album, simply add.
     59       if (album_images.insert(
     60               std::make_pair(section, folder_path_.Append(filename))).second) {
     61         continue;
     62       }
     63 
     64       // Otherwise, de-dupe by appending a number starting at (1).
     65       for (int i = 1; i < kMaxDedupeNumber; ++i) {
     66         std::string deduped_filename =
     67             filename.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", i))
     68                 .AsUTF8Unsafe();
     69 
     70         // Attempt to add the de-duped name.
     71         if (album_images.insert(
     72                 std::make_pair(deduped_filename, folder_path_.Append(filename)))
     73                 .second) {
     74           break;
     75         }
     76       }
     77     }
     78   }
     79 
     80   const base::FilePath folder_path_;
     81   AlbumImagesMap* const albums_images_;
     82 };
     83 
     84 }  // namespace
     85 
     86 PicasaAlbumsIndexer::PicasaAlbumsIndexer(const AlbumUIDSet& album_uids) {
     87   // Create an entry in the map for the valid album uids.
     88   for (AlbumUIDSet::const_iterator it = album_uids.begin();
     89        it != album_uids.end(); ++it) {
     90     albums_images_[*it] = AlbumImages();
     91   }
     92 }
     93 
     94 PicasaAlbumsIndexer::~PicasaAlbumsIndexer() {}
     95 
     96 void PicasaAlbumsIndexer::ParseFolderINI(
     97     const std::vector<picasa::FolderINIContents>& folders_inis) {
     98   // Make a copy for sorting
     99   std::vector<picasa::FolderINIContents> folders_inis_sorted = folders_inis;
    100 
    101   // Sort here so image names are deduplicated in a stable ordering.
    102   std::sort(folders_inis_sorted.begin(), folders_inis_sorted.end());
    103 
    104   for (std::vector<picasa::FolderINIContents>::const_iterator it =
    105            folders_inis_sorted.begin();
    106        it != folders_inis_sorted.end();
    107        ++it) {
    108     PicasaINIParser parser(it->folder_path, &albums_images_);
    109     parser.Parse(it->ini_contents);
    110   }
    111 }
    112 
    113 }  // namespace picasa
    114