1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
// 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/iapps_finder_impl.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
#import "base/mac/foundation_util.h"
#import "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "base/time/time.h"
#include "components/policy/core/common/preferences_mac.h"
#include "components/storage_monitor/storage_info.h"
#include "content/public/browser/browser_thread.h"
using base::mac::CFCast;
using base::mac::CFToNSCast;
using base::mac::NSToCFCast;
namespace iapps {
namespace {
typedef base::Callback<base::FilePath(NSString*)> PListPathExtractor;
static MacPreferences* g_test_mac_preferences = NULL;
void FindMostRecentDatabase(
base::scoped_nsobject<NSString> recent_databases_key,
const PListPathExtractor& path_extractor,
const IAppsFinderCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
scoped_ptr<MacPreferences> real_preferences;
MacPreferences* prefs = g_test_mac_preferences;
if (!prefs) {
real_preferences.reset(new MacPreferences());
prefs = real_preferences.get();
}
CFStringRef iapp_id = CFSTR("com.apple.iApps");
base::scoped_nsobject<NSArray> plist(CFToNSCast(CFCast<CFArrayRef>(
prefs->CopyAppValue(NSToCFCast(recent_databases_key.get()), iapp_id))));
if (!plist) {
callback.Run(std::string());
return;
}
// Find the most recently used database from the list of database paths. Most
// of the time |plist| has a size of 1.
base::Time most_recent_db_time;
base::FilePath most_recent_db_path;
for (NSString* path_ns in plist.get()) {
base::FilePath db_path = path_extractor.Run(path_ns);
if (db_path.empty())
continue;
base::File::Info file_info;
if (!base::GetFileInfo(db_path, &file_info))
continue;
// In case of two databases with the same modified time, tie breaker goes
// to the first one on the list.
if (file_info.last_modified <= most_recent_db_time)
continue;
most_recent_db_time = file_info.last_modified;
most_recent_db_path = db_path;
}
callback.Run(most_recent_db_path.value());
}
base::FilePath ExtractIPhotoPath(NSString* path_ns) {
NSURL* url = [NSURL URLWithString:path_ns];
if (![url isFileURL])
return base::FilePath();
NSString* expanded_path_ns = [url path];
return base::mac::NSStringToFilePath(expanded_path_ns);
}
base::FilePath ExtractITunesPath(NSString* path_ns) {
NSString* expanded_path_ns = [path_ns stringByExpandingTildeInPath];
return base::mac::NSStringToFilePath(expanded_path_ns);
};
} // namespace
NSString* const kIPhotoRecentDatabasesKey = @"iPhotoRecentDatabases";
NSString* const kITunesRecentDatabasePathsKey = @"iTunesRecentDatabasePaths";
void FindIPhotoLibrary(const IAppsFinderCallback& callback) {
FindIAppsOnFileThread(
storage_monitor::StorageInfo::IPHOTO,
base::Bind(&FindMostRecentDatabase,
base::scoped_nsobject<NSString>(kIPhotoRecentDatabasesKey),
base::Bind(&ExtractIPhotoPath)),
callback);
}
void FindITunesLibrary(const IAppsFinderCallback& callback) {
FindIAppsOnFileThread(
storage_monitor::StorageInfo::ITUNES,
base::Bind(&FindMostRecentDatabase,
base::scoped_nsobject<NSString>(kITunesRecentDatabasePathsKey),
base::Bind(&ExtractITunesPath)),
callback);
}
void SetMacPreferencesForTesting(MacPreferences* preferences) {
g_test_mac_preferences = preferences;
}
NSArray* NSArrayFromFilePath(const base::FilePath& path) {
NSString* url =
[[NSURL fileURLWithPath:base::SysUTF8ToNSString(path.value())]
absoluteString];
return [NSArray arrayWithObject:url];
}
} // namespace iapps
|