xref: /aosp_15_r20/external/cronet/base/apple/foundation_util.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker// Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker// found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker#include "base/apple/foundation_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker#include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker#include <stdlib.h>
9*6777b538SAndroid Build Coastguard Worker#include <string.h>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker#include <vector>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker#include "base/apple/bundle_locations.h"
14*6777b538SAndroid Build Coastguard Worker#include "base/apple/osstatus_logging.h"
15*6777b538SAndroid Build Coastguard Worker#include "base/containers/adapters.h"
16*6777b538SAndroid Build Coastguard Worker#include "base/files/file_path.h"
17*6777b538SAndroid Build Coastguard Worker#include "base/logging.h"
18*6777b538SAndroid Build Coastguard Worker#include "base/notreached.h"
19*6777b538SAndroid Build Coastguard Worker#include "base/numerics/checked_math.h"
20*6777b538SAndroid Build Coastguard Worker#include "base/numerics/safe_conversions.h"
21*6777b538SAndroid Build Coastguard Worker#include "base/ranges/algorithm.h"
22*6777b538SAndroid Build Coastguard Worker#include "base/strings/string_util.h"
23*6777b538SAndroid Build Coastguard Worker#include "base/strings/sys_string_conversions.h"
24*6777b538SAndroid Build Coastguard Worker#include "build/branding_buildflags.h"
25*6777b538SAndroid Build Coastguard Worker#include "build/build_config.h"
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker#if !BUILDFLAG(IS_IOS)
28*6777b538SAndroid Build Coastguard Worker#import <AppKit/AppKit.h>
29*6777b538SAndroid Build Coastguard Worker#endif
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Workerextern "C" {
32*6777b538SAndroid Build Coastguard WorkerCFTypeID SecKeyGetTypeID();
33*6777b538SAndroid Build Coastguard Worker}  // extern "C"
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Workernamespace base::apple {
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Workernamespace {
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Workerbool g_cached_am_i_bundled_called = false;
40*6777b538SAndroid Build Coastguard Workerbool g_cached_am_i_bundled_value = false;
41*6777b538SAndroid Build Coastguard Workerbool g_override_am_i_bundled = false;
42*6777b538SAndroid Build Coastguard Workerbool g_override_am_i_bundled_value = false;
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Workerbool UncachedAmIBundled() {
45*6777b538SAndroid Build Coastguard Worker#if BUILDFLAG(IS_IOS)
46*6777b538SAndroid Build Coastguard Worker  // All apps are bundled on iOS.
47*6777b538SAndroid Build Coastguard Worker  return true;
48*6777b538SAndroid Build Coastguard Worker#else
49*6777b538SAndroid Build Coastguard Worker  if (g_override_am_i_bundled) {
50*6777b538SAndroid Build Coastguard Worker    return g_override_am_i_bundled_value;
51*6777b538SAndroid Build Coastguard Worker  }
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker  // Yes, this is cheap.
54*6777b538SAndroid Build Coastguard Worker  return [apple::OuterBundle().bundlePath hasSuffix:@".app"];
55*6777b538SAndroid Build Coastguard Worker#endif
56*6777b538SAndroid Build Coastguard Worker}
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker}  // namespace
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Workerbool AmIBundled() {
61*6777b538SAndroid Build Coastguard Worker  // If the return value is not cached, this function will return different
62*6777b538SAndroid Build Coastguard Worker  // values depending on when it's called. This confuses some client code, see
63*6777b538SAndroid Build Coastguard Worker  // http://crbug.com/63183 .
64*6777b538SAndroid Build Coastguard Worker  if (!g_cached_am_i_bundled_called) {
65*6777b538SAndroid Build Coastguard Worker    g_cached_am_i_bundled_called = true;
66*6777b538SAndroid Build Coastguard Worker    g_cached_am_i_bundled_value = UncachedAmIBundled();
67*6777b538SAndroid Build Coastguard Worker  }
68*6777b538SAndroid Build Coastguard Worker  DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled())
69*6777b538SAndroid Build Coastguard Worker      << "The return value of AmIBundled() changed. This will confuse tests. "
70*6777b538SAndroid Build Coastguard Worker      << "Call SetAmIBundled() override manually if your test binary "
71*6777b538SAndroid Build Coastguard Worker      << "delay-loads the framework.";
72*6777b538SAndroid Build Coastguard Worker  return g_cached_am_i_bundled_value;
73*6777b538SAndroid Build Coastguard Worker}
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Workervoid SetOverrideAmIBundled(bool value) {
76*6777b538SAndroid Build Coastguard Worker#if BUILDFLAG(IS_IOS)
77*6777b538SAndroid Build Coastguard Worker  // It doesn't make sense not to be bundled on iOS.
78*6777b538SAndroid Build Coastguard Worker  if (!value) {
79*6777b538SAndroid Build Coastguard Worker    NOTREACHED();
80*6777b538SAndroid Build Coastguard Worker  }
81*6777b538SAndroid Build Coastguard Worker#endif
82*6777b538SAndroid Build Coastguard Worker  g_override_am_i_bundled = true;
83*6777b538SAndroid Build Coastguard Worker  g_override_am_i_bundled_value = value;
84*6777b538SAndroid Build Coastguard Worker}
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard WorkerBASE_EXPORT void ClearAmIBundledCache() {
87*6777b538SAndroid Build Coastguard Worker  g_cached_am_i_bundled_called = false;
88*6777b538SAndroid Build Coastguard Worker}
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Workerbool IsBackgroundOnlyProcess() {
91*6777b538SAndroid Build Coastguard Worker  // This function really does want to examine NSBundle's idea of the main
92*6777b538SAndroid Build Coastguard Worker  // bundle dictionary.  It needs to look at the actual running .app's
93*6777b538SAndroid Build Coastguard Worker  // Info.plist to access its LSUIElement property.
94*6777b538SAndroid Build Coastguard Worker  @autoreleasepool {
95*6777b538SAndroid Build Coastguard Worker    NSDictionary* info_dictionary = [apple::MainBundle() infoDictionary];
96*6777b538SAndroid Build Coastguard Worker    return [info_dictionary[@"LSUIElement"] boolValue] != NO;
97*6777b538SAndroid Build Coastguard Worker  }
98*6777b538SAndroid Build Coastguard Worker}
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard WorkerFilePath PathForFrameworkBundleResource(const char* resource_name) {
101*6777b538SAndroid Build Coastguard Worker  NSBundle* bundle = apple::FrameworkBundle();
102*6777b538SAndroid Build Coastguard Worker  NSURL* resource_url = [bundle URLForResource:@(resource_name)
103*6777b538SAndroid Build Coastguard Worker                                 withExtension:nil];
104*6777b538SAndroid Build Coastguard Worker  return NSURLToFilePath(resource_url);
105*6777b538SAndroid Build Coastguard Worker}
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard WorkerOSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
108*6777b538SAndroid Build Coastguard Worker  OSType creator = kUnknownType;
109*6777b538SAndroid Build Coastguard Worker  CFBundleGetPackageInfo(bundle, /*packageType=*/nullptr, &creator);
110*6777b538SAndroid Build Coastguard Worker  return creator;
111*6777b538SAndroid Build Coastguard Worker}
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard WorkerOSType CreatorCodeForApplication() {
114*6777b538SAndroid Build Coastguard Worker  CFBundleRef bundle = CFBundleGetMainBundle();
115*6777b538SAndroid Build Coastguard Worker  if (!bundle) {
116*6777b538SAndroid Build Coastguard Worker    return kUnknownType;
117*6777b538SAndroid Build Coastguard Worker  }
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker  return CreatorCodeForCFBundleRef(bundle);
120*6777b538SAndroid Build Coastguard Worker}
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Workerbool GetSearchPathDirectory(NSSearchPathDirectory directory,
123*6777b538SAndroid Build Coastguard Worker                            NSSearchPathDomainMask domain_mask,
124*6777b538SAndroid Build Coastguard Worker                            FilePath* result) {
125*6777b538SAndroid Build Coastguard Worker  DCHECK(result);
126*6777b538SAndroid Build Coastguard Worker  NSArray<NSString*>* dirs =
127*6777b538SAndroid Build Coastguard Worker      NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
128*6777b538SAndroid Build Coastguard Worker  if (dirs.count < 1) {
129*6777b538SAndroid Build Coastguard Worker    return false;
130*6777b538SAndroid Build Coastguard Worker  }
131*6777b538SAndroid Build Coastguard Worker  *result = NSStringToFilePath(dirs[0]);
132*6777b538SAndroid Build Coastguard Worker  return true;
133*6777b538SAndroid Build Coastguard Worker}
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Workerbool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
136*6777b538SAndroid Build Coastguard Worker  return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
137*6777b538SAndroid Build Coastguard Worker}
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Workerbool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
140*6777b538SAndroid Build Coastguard Worker  return GetSearchPathDirectory(directory, NSUserDomainMask, result);
141*6777b538SAndroid Build Coastguard Worker}
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard WorkerFilePath GetUserLibraryPath() {
144*6777b538SAndroid Build Coastguard Worker  FilePath user_library_path;
145*6777b538SAndroid Build Coastguard Worker  if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
146*6777b538SAndroid Build Coastguard Worker    DLOG(WARNING) << "Could not get user library path";
147*6777b538SAndroid Build Coastguard Worker  }
148*6777b538SAndroid Build Coastguard Worker  return user_library_path;
149*6777b538SAndroid Build Coastguard Worker}
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard WorkerFilePath GetUserDocumentPath() {
152*6777b538SAndroid Build Coastguard Worker  FilePath user_document_path;
153*6777b538SAndroid Build Coastguard Worker  if (!GetUserDirectory(NSDocumentDirectory, &user_document_path)) {
154*6777b538SAndroid Build Coastguard Worker    DLOG(WARNING) << "Could not get user document path";
155*6777b538SAndroid Build Coastguard Worker  }
156*6777b538SAndroid Build Coastguard Worker  return user_document_path;
157*6777b538SAndroid Build Coastguard Worker}
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker// Takes a path to an (executable) binary and tries to provide the path to an
160*6777b538SAndroid Build Coastguard Worker// application bundle containing it. It takes the outermost bundle that it can
161*6777b538SAndroid Build Coastguard Worker// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
162*6777b538SAndroid Build Coastguard Worker//   |exec_name| - path to the binary
163*6777b538SAndroid Build Coastguard Worker//   returns - path to the application bundle, or empty on error
164*6777b538SAndroid Build Coastguard WorkerFilePath GetAppBundlePath(const FilePath& exec_name) {
165*6777b538SAndroid Build Coastguard Worker  const char kExt[] = ".app";
166*6777b538SAndroid Build Coastguard Worker  const size_t kExtLength = std::size(kExt) - 1;
167*6777b538SAndroid Build Coastguard Worker
168*6777b538SAndroid Build Coastguard Worker  // Split the path into components.
169*6777b538SAndroid Build Coastguard Worker  std::vector<std::string> components = exec_name.GetComponents();
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker  // It's an error if we don't get any components.
172*6777b538SAndroid Build Coastguard Worker  if (components.empty()) {
173*6777b538SAndroid Build Coastguard Worker    return FilePath();
174*6777b538SAndroid Build Coastguard Worker  }
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker  // Don't prepend '/' to the first component.
177*6777b538SAndroid Build Coastguard Worker  std::vector<std::string>::const_iterator it = components.begin();
178*6777b538SAndroid Build Coastguard Worker  std::string bundle_name = *it;
179*6777b538SAndroid Build Coastguard Worker  DCHECK_GT(it->length(), 0U);
180*6777b538SAndroid Build Coastguard Worker  // If the first component ends in ".app", we're already done.
181*6777b538SAndroid Build Coastguard Worker  if (it->length() > kExtLength &&
182*6777b538SAndroid Build Coastguard Worker      !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength)) {
183*6777b538SAndroid Build Coastguard Worker    return FilePath(bundle_name);
184*6777b538SAndroid Build Coastguard Worker  }
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker  // The first component may be "/" or "//", etc. Only append '/' if it doesn't
187*6777b538SAndroid Build Coastguard Worker  // already end in '/'.
188*6777b538SAndroid Build Coastguard Worker  if (bundle_name.back() != '/') {
189*6777b538SAndroid Build Coastguard Worker    bundle_name += '/';
190*6777b538SAndroid Build Coastguard Worker  }
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker  // Go through the remaining components.
193*6777b538SAndroid Build Coastguard Worker  for (++it; it != components.end(); ++it) {
194*6777b538SAndroid Build Coastguard Worker    DCHECK_GT(it->length(), 0U);
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker    bundle_name += *it;
197*6777b538SAndroid Build Coastguard Worker
198*6777b538SAndroid Build Coastguard Worker    // If the current component ends in ".app", we're done.
199*6777b538SAndroid Build Coastguard Worker    if (it->length() > kExtLength &&
200*6777b538SAndroid Build Coastguard Worker        !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength)) {
201*6777b538SAndroid Build Coastguard Worker      return FilePath(bundle_name);
202*6777b538SAndroid Build Coastguard Worker    }
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker    // Separate this component from the next one.
205*6777b538SAndroid Build Coastguard Worker    bundle_name += '/';
206*6777b538SAndroid Build Coastguard Worker  }
207*6777b538SAndroid Build Coastguard Worker
208*6777b538SAndroid Build Coastguard Worker  return FilePath();
209*6777b538SAndroid Build Coastguard Worker}
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker// Takes a path to an (executable) binary and tries to provide the path to an
212*6777b538SAndroid Build Coastguard Worker// application bundle containing it. It takes the innermost bundle that it can
213*6777b538SAndroid Build Coastguard Worker// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces
214*6777b538SAndroid Build Coastguard Worker// "/Foo/Bar.app/.../Baz.app").
215*6777b538SAndroid Build Coastguard Worker//   |exec_name| - path to the binary
216*6777b538SAndroid Build Coastguard Worker//   returns - path to the application bundle, or empty on error
217*6777b538SAndroid Build Coastguard WorkerFilePath GetInnermostAppBundlePath(const FilePath& exec_name) {
218*6777b538SAndroid Build Coastguard Worker  static constexpr char kExt[] = ".app";
219*6777b538SAndroid Build Coastguard Worker  static constexpr size_t kExtLength = std::size(kExt) - 1;
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker  // Split the path into components.
222*6777b538SAndroid Build Coastguard Worker  std::vector<std::string> components = exec_name.GetComponents();
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker  // It's an error if we don't get any components.
225*6777b538SAndroid Build Coastguard Worker  if (components.empty()) {
226*6777b538SAndroid Build Coastguard Worker    return FilePath();
227*6777b538SAndroid Build Coastguard Worker  }
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard Worker  auto app = ranges::find_if(
230*6777b538SAndroid Build Coastguard Worker      Reversed(components), [](const std::string& component) -> bool {
231*6777b538SAndroid Build Coastguard Worker        return component.size() > kExtLength && EndsWith(component, kExt);
232*6777b538SAndroid Build Coastguard Worker      });
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker  if (app == components.rend()) {
235*6777b538SAndroid Build Coastguard Worker    return FilePath();
236*6777b538SAndroid Build Coastguard Worker  }
237*6777b538SAndroid Build Coastguard Worker
238*6777b538SAndroid Build Coastguard Worker  // Remove all path components after the final ".app" extension.
239*6777b538SAndroid Build Coastguard Worker  components.erase(app.base(), components.end());
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker  std::string bundle_path;
242*6777b538SAndroid Build Coastguard Worker  for (const std::string& component : components) {
243*6777b538SAndroid Build Coastguard Worker    // Don't prepend a slash if this is the first component or if the
244*6777b538SAndroid Build Coastguard Worker    // previous component ended with a slash, which can happen when dealing
245*6777b538SAndroid Build Coastguard Worker    // with an absolute path.
246*6777b538SAndroid Build Coastguard Worker    if (!bundle_path.empty() && bundle_path.back() != '/') {
247*6777b538SAndroid Build Coastguard Worker      bundle_path += '/';
248*6777b538SAndroid Build Coastguard Worker    }
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker    bundle_path += component;
251*6777b538SAndroid Build Coastguard Worker  }
252*6777b538SAndroid Build Coastguard Worker
253*6777b538SAndroid Build Coastguard Worker  return FilePath(bundle_path);
254*6777b538SAndroid Build Coastguard Worker}
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF)     \
257*6777b538SAndroid Build Coastguard Worker  std::string TypeNameForCFType(TypeCF##Ref) { \
258*6777b538SAndroid Build Coastguard Worker    return #TypeCF;                            \
259*6777b538SAndroid Build Coastguard Worker  }
260*6777b538SAndroid Build Coastguard Worker
261*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFArray)
262*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFBag)
263*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean)
264*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFData)
265*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFDate)
266*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary)
267*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFNull)
268*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber)
269*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFSet)
270*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFString)
271*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFURL)
272*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID)
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CGColor)
275*6777b538SAndroid Build Coastguard Worker
276*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CTFont)
277*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(CTRun)
278*6777b538SAndroid Build Coastguard Worker
279*6777b538SAndroid Build Coastguard Worker#if !BUILDFLAG(IS_IOS)
280*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(SecAccessControl)
281*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(SecCertificate)
282*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(SecKey)
283*6777b538SAndroid Build Coastguard WorkerTYPE_NAME_FOR_CF_TYPE_DEFN(SecPolicy)
284*6777b538SAndroid Build Coastguard Worker#endif
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker#undef TYPE_NAME_FOR_CF_TYPE_DEFN
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Workerstatic const char* base_bundle_id;
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Workerconst char* BaseBundleID() {
291*6777b538SAndroid Build Coastguard Worker  if (base_bundle_id) {
292*6777b538SAndroid Build Coastguard Worker    return base_bundle_id;
293*6777b538SAndroid Build Coastguard Worker  }
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
296*6777b538SAndroid Build Coastguard Worker  return "com.google.Chrome";
297*6777b538SAndroid Build Coastguard Worker#else
298*6777b538SAndroid Build Coastguard Worker  return "org.chromium.Chromium";
299*6777b538SAndroid Build Coastguard Worker#endif
300*6777b538SAndroid Build Coastguard Worker}
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Workervoid SetBaseBundleID(const char* new_base_bundle_id) {
303*6777b538SAndroid Build Coastguard Worker  if (new_base_bundle_id != base_bundle_id) {
304*6777b538SAndroid Build Coastguard Worker    free((void*)base_bundle_id);
305*6777b538SAndroid Build Coastguard Worker    base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : nullptr;
306*6777b538SAndroid Build Coastguard Worker  }
307*6777b538SAndroid Build Coastguard Worker}
308*6777b538SAndroid Build Coastguard Worker
309*6777b538SAndroid Build Coastguard Worker#define CF_CAST_DEFN(TypeCF)                                       \
310*6777b538SAndroid Build Coastguard Worker  template <>                                                      \
311*6777b538SAndroid Build Coastguard Worker  TypeCF##Ref CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) {       \
312*6777b538SAndroid Build Coastguard Worker    if (cf_val == NULL) {                                          \
313*6777b538SAndroid Build Coastguard Worker      return NULL;                                                 \
314*6777b538SAndroid Build Coastguard Worker    }                                                              \
315*6777b538SAndroid Build Coastguard Worker    if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) {              \
316*6777b538SAndroid Build Coastguard Worker      return (TypeCF##Ref)(cf_val);                                \
317*6777b538SAndroid Build Coastguard Worker    }                                                              \
318*6777b538SAndroid Build Coastguard Worker    return NULL;                                                   \
319*6777b538SAndroid Build Coastguard Worker  }                                                                \
320*6777b538SAndroid Build Coastguard Worker                                                                   \
321*6777b538SAndroid Build Coastguard Worker  template <>                                                      \
322*6777b538SAndroid Build Coastguard Worker  TypeCF##Ref CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
323*6777b538SAndroid Build Coastguard Worker    TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val);                  \
324*6777b538SAndroid Build Coastguard Worker    DCHECK(cf_val == NULL || rv);                                  \
325*6777b538SAndroid Build Coastguard Worker    return rv;                                                     \
326*6777b538SAndroid Build Coastguard Worker  }
327*6777b538SAndroid Build Coastguard Worker
328*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFArray)
329*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFBag)
330*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFBoolean)
331*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFData)
332*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFDate)
333*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFDictionary)
334*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFNull)
335*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFNumber)
336*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFSet)
337*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFString)
338*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFURL)
339*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CFUUID)
340*6777b538SAndroid Build Coastguard Worker
341*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CGColor)
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CTFont)
344*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CTFontDescriptor)
345*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(CTRun)
346*6777b538SAndroid Build Coastguard Worker
347*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(SecCertificate)
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker#if !BUILDFLAG(IS_IOS)
350*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(SecAccessControl)
351*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(SecKey)
352*6777b538SAndroid Build Coastguard WorkerCF_CAST_DEFN(SecPolicy)
353*6777b538SAndroid Build Coastguard Worker#endif
354*6777b538SAndroid Build Coastguard Worker
355*6777b538SAndroid Build Coastguard Worker#undef CF_CAST_DEFN
356*6777b538SAndroid Build Coastguard Worker
357*6777b538SAndroid Build Coastguard Workerstd::string GetValueFromDictionaryErrorMessage(CFStringRef key,
358*6777b538SAndroid Build Coastguard Worker                                               const std::string& expected_type,
359*6777b538SAndroid Build Coastguard Worker                                               CFTypeRef value) {
360*6777b538SAndroid Build Coastguard Worker  ScopedCFTypeRef<CFStringRef> actual_type_ref(
361*6777b538SAndroid Build Coastguard Worker      CFCopyTypeIDDescription(CFGetTypeID(value)));
362*6777b538SAndroid Build Coastguard Worker  return "Expected value for key " + SysCFStringRefToUTF8(key) + " to be " +
363*6777b538SAndroid Build Coastguard Worker         expected_type + " but it was " +
364*6777b538SAndroid Build Coastguard Worker         SysCFStringRefToUTF8(actual_type_ref.get()) + " instead";
365*6777b538SAndroid Build Coastguard Worker}
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard WorkerNSURL* FilePathToNSURL(const FilePath& path) {
368*6777b538SAndroid Build Coastguard Worker  if (NSString* path_string = FilePathToNSString(path)) {
369*6777b538SAndroid Build Coastguard Worker    return [NSURL fileURLWithPath:path_string];
370*6777b538SAndroid Build Coastguard Worker  }
371*6777b538SAndroid Build Coastguard Worker  return nil;
372*6777b538SAndroid Build Coastguard Worker}
373*6777b538SAndroid Build Coastguard Worker
374*6777b538SAndroid Build Coastguard WorkerNSString* FilePathToNSString(const FilePath& path) {
375*6777b538SAndroid Build Coastguard Worker  if (path.empty()) {
376*6777b538SAndroid Build Coastguard Worker    return nil;
377*6777b538SAndroid Build Coastguard Worker  }
378*6777b538SAndroid Build Coastguard Worker  return @(path.value().c_str());  // @() does UTF8 conversion.
379*6777b538SAndroid Build Coastguard Worker}
380*6777b538SAndroid Build Coastguard Worker
381*6777b538SAndroid Build Coastguard WorkerFilePath NSStringToFilePath(NSString* str) {
382*6777b538SAndroid Build Coastguard Worker  if (!str.length) {
383*6777b538SAndroid Build Coastguard Worker    return FilePath();
384*6777b538SAndroid Build Coastguard Worker  }
385*6777b538SAndroid Build Coastguard Worker  return FilePath(str.fileSystemRepresentation);
386*6777b538SAndroid Build Coastguard Worker}
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard WorkerFilePath NSURLToFilePath(NSURL* url) {
389*6777b538SAndroid Build Coastguard Worker  if (!url.fileURL) {
390*6777b538SAndroid Build Coastguard Worker    return FilePath();
391*6777b538SAndroid Build Coastguard Worker  }
392*6777b538SAndroid Build Coastguard Worker  return NSStringToFilePath(url.path);
393*6777b538SAndroid Build Coastguard Worker}
394*6777b538SAndroid Build Coastguard Worker
395*6777b538SAndroid Build Coastguard WorkerScopedCFTypeRef<CFURLRef> FilePathToCFURL(const FilePath& path) {
396*6777b538SAndroid Build Coastguard Worker  DCHECK(!path.empty());
397*6777b538SAndroid Build Coastguard Worker
398*6777b538SAndroid Build Coastguard Worker  // The function's docs promise that it does not require an NSAutoreleasePool.
399*6777b538SAndroid Build Coastguard Worker  // A straightforward way to accomplish this is to use *Create* functions,
400*6777b538SAndroid Build Coastguard Worker  // combined with ScopedCFTypeRef.
401*6777b538SAndroid Build Coastguard Worker  const std::string& path_string = path.value();
402*6777b538SAndroid Build Coastguard Worker  ScopedCFTypeRef<CFStringRef> path_cfstring(CFStringCreateWithBytes(
403*6777b538SAndroid Build Coastguard Worker      kCFAllocatorDefault, reinterpret_cast<const UInt8*>(path_string.data()),
404*6777b538SAndroid Build Coastguard Worker      checked_cast<CFIndex>(path_string.length()), kCFStringEncodingUTF8,
405*6777b538SAndroid Build Coastguard Worker      /*isExternalRepresentation=*/FALSE));
406*6777b538SAndroid Build Coastguard Worker  if (!path_cfstring) {
407*6777b538SAndroid Build Coastguard Worker    return ScopedCFTypeRef<CFURLRef>();
408*6777b538SAndroid Build Coastguard Worker  }
409*6777b538SAndroid Build Coastguard Worker
410*6777b538SAndroid Build Coastguard Worker  return ScopedCFTypeRef<CFURLRef>(CFURLCreateWithFileSystemPath(
411*6777b538SAndroid Build Coastguard Worker      kCFAllocatorDefault, path_cfstring.get(), kCFURLPOSIXPathStyle,
412*6777b538SAndroid Build Coastguard Worker      /*isDirectory=*/FALSE));
413*6777b538SAndroid Build Coastguard Worker}
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Workerbool CFRangeToNSRange(CFRange range, NSRange* range_out) {
416*6777b538SAndroid Build Coastguard Worker  NSUInteger end;
417*6777b538SAndroid Build Coastguard Worker  if (IsValueInRangeForNumericType<NSUInteger>(range.location) &&
418*6777b538SAndroid Build Coastguard Worker      IsValueInRangeForNumericType<NSUInteger>(range.length) &&
419*6777b538SAndroid Build Coastguard Worker      CheckAdd(range.location, range.length).AssignIfValid(&end) &&
420*6777b538SAndroid Build Coastguard Worker      IsValueInRangeForNumericType<NSUInteger>(end)) {
421*6777b538SAndroid Build Coastguard Worker    *range_out = NSMakeRange(static_cast<NSUInteger>(range.location),
422*6777b538SAndroid Build Coastguard Worker                             static_cast<NSUInteger>(range.length));
423*6777b538SAndroid Build Coastguard Worker    return true;
424*6777b538SAndroid Build Coastguard Worker  }
425*6777b538SAndroid Build Coastguard Worker  return false;
426*6777b538SAndroid Build Coastguard Worker}
427*6777b538SAndroid Build Coastguard Worker
428*6777b538SAndroid Build Coastguard Worker}  // namespace base::apple
429*6777b538SAndroid Build Coastguard Worker
430*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, const CFStringRef string) {
431*6777b538SAndroid Build Coastguard Worker  return o << base::SysCFStringRefToUTF8(string);
432*6777b538SAndroid Build Coastguard Worker}
433*6777b538SAndroid Build Coastguard Worker
434*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
435*6777b538SAndroid Build Coastguard Worker  base::apple::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
436*6777b538SAndroid Build Coastguard Worker  base::apple::ScopedCFTypeRef<CFDictionaryRef> user_info(
437*6777b538SAndroid Build Coastguard Worker      CFErrorCopyUserInfo(err));
438*6777b538SAndroid Build Coastguard Worker  CFStringRef errorDesc = nullptr;
439*6777b538SAndroid Build Coastguard Worker  if (user_info.get()) {
440*6777b538SAndroid Build Coastguard Worker    errorDesc = reinterpret_cast<CFStringRef>(
441*6777b538SAndroid Build Coastguard Worker        CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
442*6777b538SAndroid Build Coastguard Worker  }
443*6777b538SAndroid Build Coastguard Worker  o << "Code: " << CFErrorGetCode(err) << " Domain: " << CFErrorGetDomain(err)
444*6777b538SAndroid Build Coastguard Worker    << " Desc: " << desc.get();
445*6777b538SAndroid Build Coastguard Worker  if (errorDesc) {
446*6777b538SAndroid Build Coastguard Worker    o << "(" << errorDesc << ")";
447*6777b538SAndroid Build Coastguard Worker  }
448*6777b538SAndroid Build Coastguard Worker  return o;
449*6777b538SAndroid Build Coastguard Worker}
450*6777b538SAndroid Build Coastguard Worker
451*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, CFRange range) {
452*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromRange(
453*6777b538SAndroid Build Coastguard Worker             NSMakeRange(static_cast<NSUInteger>(range.location),
454*6777b538SAndroid Build Coastguard Worker                         static_cast<NSUInteger>(range.length)));
455*6777b538SAndroid Build Coastguard Worker}
456*6777b538SAndroid Build Coastguard Worker
457*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, id obj) {
458*6777b538SAndroid Build Coastguard Worker  return obj ? o << [obj description].UTF8String : o << "(nil)";
459*6777b538SAndroid Build Coastguard Worker}
460*6777b538SAndroid Build Coastguard Worker
461*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, NSRange range) {
462*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromRange(range);
463*6777b538SAndroid Build Coastguard Worker}
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, SEL selector) {
466*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromSelector(selector);
467*6777b538SAndroid Build Coastguard Worker}
468*6777b538SAndroid Build Coastguard Worker
469*6777b538SAndroid Build Coastguard Worker#if !BUILDFLAG(IS_IOS)
470*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, NSPoint point) {
471*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromPoint(point);
472*6777b538SAndroid Build Coastguard Worker}
473*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, NSRect rect) {
474*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromRect(rect);
475*6777b538SAndroid Build Coastguard Worker}
476*6777b538SAndroid Build Coastguard Workerstd::ostream& operator<<(std::ostream& o, NSSize size) {
477*6777b538SAndroid Build Coastguard Worker  return o << NSStringFromSize(size);
478*6777b538SAndroid Build Coastguard Worker}
479*6777b538SAndroid Build Coastguard Worker#endif
480