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