summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-17 21:58:33 +0000
committervandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-17 21:58:33 +0000
commitf8c6cc8048819b4921ea99a723205b0ece36f92f (patch)
tree7f30f28056c1341395c600c68b848fb2e49df3c3
parent140e5584aed841d830d3c3d21312602d82fcef4c (diff)
downloadchromium_src-f8c6cc8048819b4921ea99a723205b0ece36f92f.zip
chromium_src-f8c6cc8048819b4921ea99a723205b0ece36f92f.tar.gz
chromium_src-f8c6cc8048819b4921ea99a723205b0ece36f92f.tar.bz2
Find iTunes library on windows.
BUG=234837 Review URL: https://chromiumcodereview.appspot.com/14611014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@200897 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_finder_win.cc158
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc181
-rw-r--r--chrome/browser/storage_monitor/media_storage_util.cc3
-rw-r--r--chrome/browser/storage_monitor/storage_info.cc6
-rw-r--r--chrome/chrome_tests_unit.gypi1
5 files changed, 345 insertions, 4 deletions
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
index 9bd8210..68492f6 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
@@ -4,10 +4,155 @@
#include "chrome/browser/media_galleries/fileapi/itunes_finder_win.h"
+#include <string>
+
+#include "base/base64.h"
+#include "base/base_paths_win.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
namespace itunes {
+namespace {
+
+// Traverse |reader| looking for a node named |name| at the current depth
+// of |reader|.
+bool SeekToNodeAtCurrentDepth(XmlReader* reader, const std::string& name) {
+ int depth = reader->Depth();
+ do {
+ if (!reader->SkipToElement()) {
+ // SkipToElement returns false if the current node is an end element,
+ // try to advance to the next element and then try again.
+ if (!reader->Read() || !reader->SkipToElement())
+ return false;
+ }
+ DCHECK_EQ(depth, reader->Depth());
+ if (reader->NodeName() == name)
+ return true;
+ } while (reader->Next());
+
+ return false;
+}
+
+// Search within the dict for |key|.
+bool SeekInDict(XmlReader* reader, const std::string& key) {
+ DCHECK_EQ("dict", reader->NodeName());
+
+ int dict_content_depth = reader->Depth() + 1;
+ // Advance past the dict node and into the body of the dictionary.
+ if (!reader->Read())
+ return false;
+
+ while (reader->Depth() >= dict_content_depth) {
+ if (!SeekToNodeAtCurrentDepth(reader, "key"))
+ return false;
+ std::string found_key;
+ if (!reader->ReadElementContent(&found_key))
+ return false;
+ DCHECK_EQ(dict_content_depth, reader->Depth());
+ if (found_key == key)
+ return true;
+ }
+ return false;
+}
+
+// Read the iTunes preferences from |pref_file| and then try to extract the
+// library XML location from the XML file. Return it if found. The minimal
+// valid snippet of XML is:
+//
+// <plist>
+// <dict>
+// <key>User Preferences</key>
+// <dict>
+// <key>iTunes Library XML Location:1</key>
+// <data>Base64 encoded w string path</data>
+// </dict>
+// </dict>
+// </plist>
+//
+base::FilePath::StringType FindLibraryLocationInPrefXML(
+ const std::string& pref_file) {
+ XmlReader reader;
+ base::FilePath::StringType result;
+
+ if (!reader.LoadFile(pref_file))
+ return result;
+
+ // Find the plist node and then search within that tag.
+ if (!SeekToNodeAtCurrentDepth(&reader, "plist"))
+ return result;
+ if (!reader.Read())
+ return result;
+
+ if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
+ return result;
+
+ if (!SeekInDict(&reader, "User Preferences"))
+ return result;
+
+ if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
+ return result;
+
+ if (!SeekInDict(&reader, "iTunes Library XML Location:1"))
+ return result;
+
+ if (!SeekToNodeAtCurrentDepth(&reader, "data"))
+ return result;
+
+ std::string pref_value;
+ if (!reader.ReadElementContent(&pref_value))
+ return result;
+ // The data is a base64 encoded wchar_t*. Because Base64Decode uses
+ // std::strings, the result has to be casted to a wchar_t*.
+ std::string data;
+ if (!base::Base64Decode(CollapseWhitespaceASCII(pref_value, true), &data))
+ return result;
+ return base::FilePath::StringType(
+ reinterpret_cast<const wchar_t*>(data.data()), data.size()/2);
+}
+
+// Try to find the iTunes library XML by examining the iTunes preferences
+// file and return it if found.
+base::FilePath TryPreferencesFile() {
+ base::FilePath appdata_dir;
+ if (!PathService::Get(base::DIR_APP_DATA, &appdata_dir))
+ return base::FilePath();
+ base::FilePath pref_file = appdata_dir.AppendASCII("Apple Computer")
+ .AppendASCII("iTunes")
+ .AppendASCII("iTunesPrefs.xml");
+ if (!file_util::PathExists(pref_file))
+ return base::FilePath();
+
+ base::FilePath::StringType library_location =
+ FindLibraryLocationInPrefXML(pref_file.AsUTF8Unsafe());
+ base::FilePath library_file(library_location);
+ if (!file_util::PathExists(library_file))
+ return base::FilePath();
+ return library_file;
+}
+
+// Check the default location for the iTunes library XML file. Return the
+// location if found.
+base::FilePath TryDefaultLocation() {
+ base::FilePath music_dir;
+ if (!PathService::Get(chrome::DIR_USER_MUSIC, &music_dir))
+ return base::FilePath();
+ base::FilePath library_file =
+ music_dir.AppendASCII("iTunes").AppendASCII("iTunes Music Library.xml");
+
+ if (!file_util::PathExists(library_file))
+ return base::FilePath();
+ return library_file;
+}
+
+} // namespace
+
ITunesFinderWin::ITunesFinderWin(const ITunesFinderCallback& callback)
: ITunesFinder(callback) {
}
@@ -15,8 +160,17 @@ ITunesFinderWin::ITunesFinderWin(const ITunesFinderCallback& callback)
ITunesFinderWin::~ITunesFinderWin() {}
void ITunesFinderWin::FindITunesLibraryOnFileThread() {
- PostResultToUIThread(std::string());
- NOTIMPLEMENTED();
+ base::FilePath library_file = TryPreferencesFile();
+
+ if (library_file.empty())
+ library_file = TryDefaultLocation();
+
+ if (library_file.empty()) {
+ PostResultToUIThread(std::string());
+ return;
+ }
+
+ PostResultToUIThread(library_file.AsUTF8Unsafe());
}
} // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc
new file mode 100644
index 0000000..ed3fb39
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 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 "base/base64.h"
+#include "base/base_paths_win.h"
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/stringprintf.h"
+#include "base/test/scoped_path_override.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_finder.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_finder_win.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace itunes {
+
+namespace {
+
+std::string EncodePath(const base::FilePath& path) {
+ std::string input(reinterpret_cast<const char*>(path.value().data()),
+ path.value().size()*2);
+ std::string result;
+ base::Base64Encode(input, &result);
+ return result;
+}
+
+void TouchFile(const base::FilePath& file) {
+ ASSERT_EQ(1, file_util::WriteFile(file, " ", 1));
+}
+
+class ITunesFinderWinTest : public testing::Test {
+ public:
+ ITunesFinderWinTest()
+ : ui_thread_(content::BrowserThread::UI, &loop_),
+ file_thread_(content::BrowserThread::FILE, &loop_) {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(app_data_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(music_dir_.CreateUniqueTempDir());
+ app_data_dir_override_.reset(
+ new base::ScopedPathOverride(base::DIR_APP_DATA, app_data_dir()));
+ music_dir_override_.reset(
+ new base::ScopedPathOverride(chrome::DIR_USER_MUSIC, music_dir()));
+ }
+
+ const base::FilePath& app_data_dir() {
+ return app_data_dir_.path();
+ }
+
+ const base::FilePath& music_dir() {
+ return music_dir_.path();
+ }
+
+ void WritePrefFile(const std::string& data) {
+ base::FilePath pref_dir =
+ app_data_dir().AppendASCII("Apple Computer").AppendASCII("iTunes");
+ ASSERT_TRUE(file_util::CreateDirectory(pref_dir));
+ ASSERT_EQ(data.size(),
+ file_util::WriteFile(pref_dir.AppendASCII("iTunesPrefs.xml"),
+ data.data(), data.size()));
+ }
+
+ void TouchDefault() {
+ base::FilePath default_dir = music_dir().AppendASCII("iTunes");
+ ASSERT_TRUE(file_util::CreateDirectory(default_dir));
+ TouchFile(default_dir.AppendASCII("iTunes Music Library.xml"));
+ }
+
+ std::string TestFindITunesLibrary() {
+ std::string result;
+ ITunesFinder::FindITunesLibrary(
+ base::Bind(&ITunesFinderWinTest::FinderCallback,
+ base::Unretained(this), base::Unretained(&result)));
+ base::RunLoop().RunUntilIdle();
+ return result;
+ }
+
+ private:
+ void FinderCallback(std::string* result_holder, const std::string& result) {
+ *result_holder = result;
+ }
+
+ scoped_ptr<base::ScopedPathOverride> app_data_dir_override_;
+ scoped_ptr<base::ScopedPathOverride> music_dir_override_;
+ base::ScopedTempDir app_data_dir_;
+ base::ScopedTempDir music_dir_;
+
+ MessageLoop loop_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread file_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(ITunesFinderWinTest);
+};
+
+TEST_F(ITunesFinderWinTest, NotFound) {
+ std::string result = TestFindITunesLibrary();
+ EXPECT_TRUE(result.empty());
+}
+
+TEST_F(ITunesFinderWinTest, DefaultLocation) {
+ TouchDefault();
+ std::string result = TestFindITunesLibrary();
+ EXPECT_FALSE(result.empty());
+}
+
+TEST_F(ITunesFinderWinTest, CustomLocation) {
+ base::FilePath library_xml = music_dir().AppendASCII("library.xml");
+ TouchFile(library_xml);
+ std::string xml = base::StringPrintf(
+ "<plist>"
+ " <dict>"
+ " <key>User Preferences</key>"
+ " <dict>"
+ " <key>iTunes Library XML Location:1</key>"
+ " <data>%s</data>"
+ " </dict>"
+ " </dict>"
+ "</plist>", EncodePath(library_xml).c_str());
+ WritePrefFile(xml);
+ std::string result = TestFindITunesLibrary();
+ EXPECT_FALSE(result.empty());
+}
+
+TEST_F(ITunesFinderWinTest, BadCustomLocation) {
+ // Missing file.
+ base::FilePath library_xml = music_dir().AppendASCII("library.xml");
+ std::string xml = base::StringPrintf(
+ "<plist>"
+ " <dict>"
+ " <key>User Preferences</key>"
+ " <dict>"
+ " <key>iTunes Library XML Location:1</key>"
+ " <data>%s</data>"
+ " </dict>"
+ " </dict>"
+ "</plist>", EncodePath(library_xml).c_str());
+ WritePrefFile(xml);
+ std::string result = TestFindITunesLibrary();
+ EXPECT_TRUE(result.empty());
+ TouchFile(library_xml);
+
+ // User Preferences dictionary at the wrong level.
+ xml = base::StringPrintf(
+ "<plist>"
+ " <key>User Preferences</key>"
+ " <dict>"
+ " <key>iTunes Library XML Location:1</key>"
+ " <data>%s</data>"
+ " </dict>"
+ "</plist>", EncodePath(library_xml).c_str());
+ WritePrefFile(xml);
+ result = TestFindITunesLibrary();
+ EXPECT_TRUE(result.empty());
+
+ // Library location at the wrong scope.
+ xml = base::StringPrintf(
+ "<plist>"
+ " <dict>"
+ " <key>User Preferences</key>"
+ " <dict/>"
+ " <key>iTunes Library XML Location:1</key>"
+ " <data>%s</data>"
+ " </dict>"
+ "</plist>", EncodePath(library_xml).c_str());
+ WritePrefFile(xml);
+ result = TestFindITunesLibrary();
+ EXPECT_TRUE(result.empty());
+}
+
+} // namespace
+
+} // namespace itunes
diff --git a/chrome/browser/storage_monitor/media_storage_util.cc b/chrome/browser/storage_monitor/media_storage_util.cc
index 7efde88..7bb2203 100644
--- a/chrome/browser/storage_monitor/media_storage_util.cc
+++ b/chrome/browser/storage_monitor/media_storage_util.cc
@@ -84,7 +84,8 @@ void FilterAttachedDevicesOnFileThread(MediaStorageUtil::DeviceIdSet* devices) {
continue;
}
- if (type == StorageInfo::FIXED_MASS_STORAGE) {
+ if (type == StorageInfo::FIXED_MASS_STORAGE ||
+ type == StorageInfo::ITUNES) {
if (!file_util::PathExists(base::FilePath::FromUTF8Unsafe(unique_id)))
missing_devices.insert(*it);
continue;
diff --git a/chrome/browser/storage_monitor/storage_info.cc b/chrome/browser/storage_monitor/storage_info.cc
index 65d29f8..c28bb79 100644
--- a/chrome/browser/storage_monitor/storage_info.cc
+++ b/chrome/browser/storage_monitor/storage_info.cc
@@ -107,7 +107,11 @@ bool StorageInfo::IsMediaDevice(const std::string& device_id) {
// static
bool StorageInfo::IsRemovableDevice(const std::string& device_id) {
Type type;
- return CrackDeviceId(device_id, &type, NULL) && type != FIXED_MASS_STORAGE;
+ return CrackDeviceId(device_id, &type, NULL) &&
+ (type == REMOVABLE_MASS_STORAGE_WITH_DCIM ||
+ type == REMOVABLE_MASS_STORAGE_NO_DCIM ||
+ type == MTP_OR_PTP ||
+ type == MAC_IMAGE_CAPTURE);
}
// static
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 4ea34a2..ace1a9e 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -906,6 +906,7 @@
'browser/managed_mode/managed_mode_url_filter_unittest.cc',
'browser/managed_mode/managed_user_passphrase_unittest.cc',
'browser/managed_mode/managed_user_service_unittest.cc',
+ 'browser/media_galleries/fileapi/itunes_finder_win_unittest.cc',
'browser/media_galleries/fileapi/native_media_file_util_unittest.cc',
'browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc',
'browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc',