summaryrefslogtreecommitdiffstats
path: root/chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm
blob: b088286c38343448b2e27137da4c2bd22657bcb8 (plain)
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