diff options
10 files changed, 293 insertions, 24 deletions
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h index 51eff72..5f34d8a 100644 --- a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h +++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h @@ -19,11 +19,8 @@ namespace picasa { -struct AlbumInfo; class SafePicasaAlbumTableReader; -typedef std::map<std::string, AlbumInfo> AlbumMap; - // Created and owned by ImportedMediaGalleryRegistryTaskRunnerValues class PicasaDataProvider { public: diff --git a/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.cc b/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.cc new file mode 100644 index 0000000..57ea926 --- /dev/null +++ b/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.cc @@ -0,0 +1,141 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.h" + +#include "base/file_util.h" +#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" +#include "chrome/common/chrome_utility_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/utility_process_host.h" + +using chrome::MediaFileSystemBackend; +using content::BrowserThread; +using content::UtilityProcessHost; + +namespace picasa { + +namespace { + +// Picasa INI files are named "picasa.ini" on Picasa for Windows before version +// 71.18. Later versions and Picasa for Mac uses ".picasa.ini". +// See: https://support.google.com/picasa/answer/11257?hl=en +const char kPicasaINIFilename[] = ".picasa.ini"; +const char kPicasaINIFilenameLegacy[] = "picasa.ini"; + +// Arbitrarily chosen to be a decent size but not block thread too much. +const int kPicasaINIReadBatchSize = 10; + +} // namespace + +SafePicasaAlbumsIndexer::SafePicasaAlbumsIndexer( + const AlbumMap& albums, + const AlbumMap& folders, + const DoneCallback& callback) + : callback_(callback), + parser_state_(INITIAL_STATE) { + DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread()); + DCHECK(!callback_.is_null()); + + folders_inis_.reserve(folders.size()); + + for (AlbumMap::const_iterator it = albums.begin(); it != albums.end(); ++it) + album_uids_.insert(it->second.uid); + + for (AlbumMap::const_iterator it = folders.begin(); it != folders.end(); ++it) + folders_queue_.push(it->second.path); +} + +void SafePicasaAlbumsIndexer::Start() { + DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread()); + + ProcessFoldersBatch(); +} + +SafePicasaAlbumsIndexer::~SafePicasaAlbumsIndexer() { +} + +void SafePicasaAlbumsIndexer::ProcessFoldersBatch() { + DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread()); + + for (int i = 0; i < kPicasaINIReadBatchSize && !folders_queue_.empty(); ++i) { + base::FilePath folder_path = folders_queue_.front(); + folders_queue_.pop(); + + folders_inis_.push_back(FolderINIContents()); + + bool ini_read = + file_util::ReadFileToString( + folder_path.AppendASCII(kPicasaINIFilename), + &folders_inis_.back().ini_contents) || + file_util::ReadFileToString( + folder_path.AppendASCII(kPicasaINIFilenameLegacy), + &folders_inis_.back().ini_contents); + + // See kPicasaINIFilename declaration for details. + if (ini_read) + folders_inis_.back().folder_path = folder_path; + else + folders_inis_.pop_back(); + } + + // If queue of folders to process not empty, post self onto task runner again. + if (!folders_queue_.empty()) { + MediaFileSystemBackend::MediaTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SafePicasaAlbumsIndexer::ProcessFoldersBatch, this)); + } else { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&SafePicasaAlbumsIndexer::StartWorkOnIOThread, this)); + } +} + +void SafePicasaAlbumsIndexer::StartWorkOnIOThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK_EQ(INITIAL_STATE, parser_state_); + + UtilityProcessHost* host = + UtilityProcessHost::Create(this, base::MessageLoopProxy::current()); + host->EnableZygote(); + host->Send(new ChromeUtilityMsg_IndexPicasaAlbumsContents(album_uids_, + folders_inis_)); + parser_state_ = STARTED_PARSING_STATE; +} + +void SafePicasaAlbumsIndexer::OnIndexPicasaAlbumsContentsFinished( + const AlbumImagesMap& albums_images) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (parser_state_ != STARTED_PARSING_STATE) + return; + + MediaFileSystemBackend::MediaTaskRunner()->PostTask( + FROM_HERE, + base::Bind(callback_, true, albums_images)); + parser_state_ = FINISHED_PARSING_STATE; +} + +void SafePicasaAlbumsIndexer::OnProcessCrashed(int exit_code) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + MediaFileSystemBackend::MediaTaskRunner()->PostTask( + FROM_HERE, + base::Bind(callback_, false, AlbumImagesMap())); +} + +bool SafePicasaAlbumsIndexer::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(SafePicasaAlbumsIndexer, message) + IPC_MESSAGE_HANDLER( + ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished, + OnIndexPicasaAlbumsContentsFinished) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +} // namespace picasa diff --git a/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.h b/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.h new file mode 100644 index 0000000..983652c --- /dev/null +++ b/chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.h @@ -0,0 +1,88 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_PICASA_ALBUMS_INDEXER_H_ +#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_PICASA_ALBUMS_INDEXER_H_ + +#include <queue> +#include <vector> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "chrome/common/media_galleries/picasa_types.h" +#include "content/public/browser/utility_process_host_client.h" + +namespace base { +class FilePath; +} + +namespace IPC { +class Message; +} + +namespace picasa { + +// SafePicasaAlbumsIndexer indexes the contents of Picasa Albums by parsing the +// INI files found in Folders. The SafePicasaAlbumsIndexer object is ref-counted +// and kept alive after Start() is called until the ParserCallback is called. +// The ParserCallback is guaranteed to be called eventually either when the +// utility process replies or when it dies. +class SafePicasaAlbumsIndexer : public content::UtilityProcessHostClient { + public: + typedef base::Callback<void(bool /* success */, + const picasa::AlbumImagesMap&)> DoneCallback; + + SafePicasaAlbumsIndexer(const AlbumMap& albums, + const AlbumMap& folders, + const DoneCallback& callback); + + void Start(); + + private: + enum ParserState { + INITIAL_STATE, + STARTED_PARSING_STATE, + FINISHED_PARSING_STATE, + }; + + // Private because content::UtilityProcessHostClient is ref-counted. + virtual ~SafePicasaAlbumsIndexer(); + + // Processes a batch of folders. Reposts itself until done, then starts IPC. + void ProcessFoldersBatch(); + + // Launches the utility process. Must run on the IO thread. + void StartWorkOnIOThread(); + + // Notification from the utility process when it finshes indexing all the + // album contents. On error will return an empty map. + // Runs on the IO thread. + void OnIndexPicasaAlbumsContentsFinished(const AlbumImagesMap& albums_images); + + // UtilityProcessHostClient implementation. + // Runs on the IO thread. + virtual void OnProcessCrashed(int exit_code) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + AlbumUIDSet album_uids_; + + // List of folders that still need their INI files read. + std::queue<base::FilePath> folders_queue_; + + std::vector<picasa::FolderINIContents> folders_inis_; + + // Only accessed on the Media Task Runner. + const DoneCallback callback_; + + // Verifies the messages from the utility process came at the right time. + // Initialized on the Media Task Runner, but only accessed on the IO thread. + ParserState parser_state_; + + DISALLOW_COPY_AND_ASSIGN(SafePicasaAlbumsIndexer); +}; + +} // namespace picasa + +#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_PICASA_ALBUMS_INDEXER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b901144..a55106d 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2456,6 +2456,8 @@ 'browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h', 'browser/media_galleries/fileapi/safe_picasa_album_table_reader.cc', 'browser/media_galleries/fileapi/safe_picasa_album_table_reader.h', + 'browser/media_galleries/fileapi/safe_picasa_albums_indexer.cc', + 'browser/media_galleries/fileapi/safe_picasa_albums_indexer.h', ], }], ['enable_extensions==1', { diff --git a/chrome/common/chrome_utility_messages.h b/chrome/common/chrome_utility_messages.h index 19eed81..f48b136 100644 --- a/chrome/common/chrome_utility_messages.h +++ b/chrome/common/chrome_utility_messages.h @@ -88,6 +88,11 @@ IPC_STRUCT_TRAITS_BEGIN(picasa::AlbumTableFilesForTransit) IPC_STRUCT_TRAITS_MEMBER(uid_file) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(picasa::FolderINIContents) + IPC_STRUCT_TRAITS_MEMBER(folder_path) + IPC_STRUCT_TRAITS_MEMBER(ini_contents) +IPC_STRUCT_TRAITS_END() + //------------------------------------------------------------------------------ // Utility process messages: // These are messages from the browser to the utility process. @@ -176,6 +181,12 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParseITunesLibraryXmlFile, // listing of the user's Picasa albums and folders, along with metadata. IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParsePicasaPMPDatabase, picasa::AlbumTableFilesForTransit /* album_table_files */) + +// Tells the utility process to index the Picasa user-created Album contents +// by parsing all the INI files in Picasa Folders. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_IndexPicasaAlbumsContents, + picasa::AlbumUIDSet /* album_uids */, + std::vector<picasa::FolderINIContents> /* folders_inis */) #endif // defined(OS_WIN) || defined(OS_MACOSX) //------------------------------------------------------------------------------ @@ -295,4 +306,9 @@ IPC_MESSAGE_CONTROL3(ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished, bool /* parse_success */, std::vector<picasa::AlbumInfo> /* albums */, std::vector<picasa::AlbumInfo> /* folders */) + +// Reply after indexing the Picasa user-created Album contents by parsing all +// the INI files in Picasa Folders. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished, + picasa::AlbumImagesMap /* albums_images */) #endif // defined(OS_WIN) || defined(OS_MACOSX) diff --git a/chrome/common/media_galleries/picasa_types.h b/chrome/common/media_galleries/picasa_types.h index 58dcf32..e807bc1 100644 --- a/chrome/common/media_galleries/picasa_types.h +++ b/chrome/common/media_galleries/picasa_types.h @@ -5,6 +5,8 @@ #ifndef CHROME_COMMON_MEDIA_GALLERIES_PICASA_TYPES_H_ #define CHROME_COMMON_MEDIA_GALLERIES_PICASA_TYPES_H_ +#include <map> +#include <set> #include <string> #include "base/files/file_path.h" @@ -13,6 +15,13 @@ namespace picasa { +struct AlbumInfo; + +typedef std::set<base::FilePath> AlbumImages; +typedef std::set<std::string> AlbumUIDSet; +typedef std::map<std::string, AlbumImages> AlbumImagesMap; +typedef std::map<std::string, AlbumInfo> AlbumMap; + const char kPicasaAlbumTableName[] = "albumdata"; struct AlbumInfo { @@ -56,6 +65,11 @@ struct AlbumTableFilesForTransit { IPC::PlatformFileForTransit uid_file; }; +struct FolderINIContents { + base::FilePath folder_path; + std::string ini_contents; +}; + void CloseAlbumTableFiles(AlbumTableFiles* table_files); } // namespace picasa diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index b5db0fd..66303fa 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc @@ -43,9 +43,9 @@ #endif // defined(OS_WIN) #if defined(OS_WIN) || defined(OS_MACOSX) -#include "chrome/common/media_galleries/picasa_types.h" #include "chrome/utility/itunes_library_parser.h" #include "chrome/utility/media_galleries/picasa_album_table_reader.h" +#include "chrome/utility/media_galleries/picasa_albums_indexer.h" #endif // defined(OS_WIN) || defined(OS_MACOSX) #if defined(ENABLE_PRINTING) @@ -562,6 +562,21 @@ void ChromeContentUtilityClient::OnParsePicasaPMPDatabase( reader.folders())); ReleaseProcessIfNeeded(); } + +void OnIndexPicasaAlbumsContents( + const picasa::AlbumUIDSet& album_uids, + const std::vector<picasa::FolderINIContents>& folders_inis) { + picasa::PicasaAlbumsIndexer indexer(album_uids); + for (std::vector<picasa::FolderINIContents>::const_iterator it = + folders_inis.begin(); + it != folders_inis.end(); ++it) { + indexer.ParseFolderINI(it->folder_path, it->ini_contents); + } + + Send(new ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished( + indexer.albums_images())); + ReleaseProcessIfNeeded(); +} #endif // defined(OS_WIN) || defined(OS_MACOSX) } // namespace chrome diff --git a/chrome/utility/chrome_content_utility_client.h b/chrome/utility/chrome_content_utility_client.h index c155cf5..419c155 100644 --- a/chrome/utility/chrome_content_utility_client.h +++ b/chrome/utility/chrome_content_utility_client.h @@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_vector.h" #include "base/platform_file.h" +#include "chrome/common/media_galleries/picasa_types.h" #include "content/public/utility/content_utility_client.h" #include "ipc/ipc_platform_file.h" #include "printing/pdf_render_settings.h" @@ -21,10 +22,6 @@ namespace gfx { class Rect; } -namespace picasa { -struct AlbumTableFilesForTransit; -} - namespace printing { struct PageRange; } @@ -91,11 +88,15 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient { #endif // defined(OS_WIN) #if defined(OS_WIN) || defined(OS_MACOSX) + void OnParseITunesLibraryXmlFile( + IPC::PlatformFileForTransit itunes_library_file); + void OnParsePicasaPMPDatabase( const picasa::AlbumTableFilesForTransit& album_table_files); - void OnParseITunesLibraryXmlFile( - IPC::PlatformFileForTransit itunes_library_file); + void OnIndexPicasaAlbumsContents( + const picasa::AlbumUIDSet& album_uids, + const std::vector<picasa::FolderINIContents>& folders_inis); #endif // defined(OS_WIN) || defined(OS_MACOSX) typedef ScopedVector<UtilityMessageHandler> Handlers; diff --git a/chrome/utility/media_galleries/picasa_albums_indexer.cc b/chrome/utility/media_galleries/picasa_albums_indexer.cc index a512e4e..87c7a47 100644 --- a/chrome/utility/media_galleries/picasa_albums_indexer.cc +++ b/chrome/utility/media_galleries/picasa_albums_indexer.cc @@ -43,7 +43,7 @@ class PicasaINIParser : public base::INIParser { it != containing_albums.end(); ++it) { AlbumImagesMap::iterator album_map_it = albums_images_->find(*it); - // Ignore entry if the album UUID is not listed among in |album_uuids| + // Ignore entry if the album uid is not listed among in |album_uids| // in the constructor. Happens if the PMP and INI files are inconsistent. if (album_map_it == albums_images_->end()) continue; @@ -59,11 +59,10 @@ class PicasaINIParser : public base::INIParser { } // namespace -PicasaAlbumsIndexer::PicasaAlbumsIndexer( - const AlbumUUIDSet& album_uuids) { - // Create an entry in the map for the valid album uuids. - for (AlbumUUIDSet::const_iterator it = album_uuids.begin(); - it != album_uuids.end(); ++it) { +PicasaAlbumsIndexer::PicasaAlbumsIndexer(const AlbumUIDSet& album_uids) { + // Create an entry in the map for the valid album uids. + for (AlbumUIDSet::const_iterator it = album_uids.begin(); + it != album_uids.end(); ++it) { albums_images_[*it] = AlbumImages(); } } diff --git a/chrome/utility/media_galleries/picasa_albums_indexer.h b/chrome/utility/media_galleries/picasa_albums_indexer.h index 6bf9993..9cb180f 100644 --- a/chrome/utility/media_galleries/picasa_albums_indexer.h +++ b/chrome/utility/media_galleries/picasa_albums_indexer.h @@ -10,16 +10,12 @@ #include <string> #include "base/files/file_path.h" +#include "chrome/common/media_galleries/picasa_types.h" namespace picasa { -// Defined outside of class because used by IPC messages. -typedef std::set<base::FilePath> AlbumImages; -typedef std::set<std::string> AlbumUUIDSet; -typedef std::map<std::string, AlbumImages> AlbumImagesMap; - // Parses a series of INI files and builds up the set of files contained within -// the albums passed in through |album_uuids|. +// the albums passed in through |album_uids|. // // Each INI file only describes the images contained within a single directory. // To build the contents of all the albums, we read in all the INI files @@ -28,7 +24,7 @@ typedef std::map<std::string, AlbumImages> AlbumImagesMap; // The INI albums also contain ".album*" sections describing the albums that // have pictures in the same directory as the INI. However, we use the PMP // database as the authoritative source on Album metadata, so we ignore those -// sections. The PMP derived |album_uuids| are passed in by the constructor. +// sections. The PMP derived |album_uids| are passed in by the constructor. // // Example INI File: // @@ -48,7 +44,7 @@ typedef std::map<std::string, AlbumImages> AlbumImagesMap; // albums=18cb2df48aaa98e1c276b45cfcd81c95 class PicasaAlbumsIndexer { public: - explicit PicasaAlbumsIndexer(const AlbumUUIDSet& album_uuids); + explicit PicasaAlbumsIndexer(const AlbumUIDSet& album_uids); ~PicasaAlbumsIndexer(); // This method should be called once for each Folder in the PMP database. |