• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_APPLE_FOUNDATION_UTIL_H_
6 #define BASE_APPLE_FOUNDATION_UTIL_H_
7 
8 #include <AvailabilityMacros.h>
9 #include <CoreFoundation/CoreFoundation.h>
10 #include <CoreText/CoreText.h>
11 #include <Security/Security.h>
12 
13 #include <string>
14 
15 #include "base/apple/scoped_cftyperef.h"
16 #include "base/base_export.h"
17 #include "base/compiler_specific.h"
18 #include "base/containers/span.h"
19 #include "base/logging.h"
20 #include "build/build_config.h"
21 
22 #if defined(__OBJC__)
23 #import <Foundation/Foundation.h>
24 @class NSFont;
25 @class UIFont;
26 #endif  // __OBJC__
27 
28 namespace base {
29 class FilePath;
30 }
31 
32 namespace base::apple {
33 
34 // Returns true if the application is running from a bundle
35 BASE_EXPORT bool AmIBundled();
36 BASE_EXPORT void SetOverrideAmIBundled(bool value);
37 
38 #if defined(UNIT_TEST)
39 // This is required because instantiating some tests requires checking the
40 // directory structure, which sets the AmIBundled cache state. Individual tests
41 // may or may not be bundled, and this would trip them up if the cache weren't
42 // cleared. This should not be called from individual tests, just from test
43 // instantiation code that gets a path from PathService.
44 BASE_EXPORT void ClearAmIBundledCache();
45 #endif
46 
47 // Returns true if this process is marked as a "Background only process".
48 BASE_EXPORT bool IsBackgroundOnlyProcess();
49 
50 // Returns the path to a resource within the framework bundle.
51 BASE_EXPORT FilePath PathForFrameworkBundleResource(const char* resource_name);
52 
53 // Returns the creator code associated with the CFBundleRef at bundle.
54 OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
55 
56 // Returns the creator code associated with this application, by calling
57 // CreatorCodeForCFBundleRef for the application's main bundle.  If this
58 // information cannot be determined, returns kUnknownType ('????').  This
59 // does not respect the override app bundle because it's based on CFBundle
60 // instead of NSBundle, and because callers probably don't want the override
61 // app bundle's creator code anyway.
62 BASE_EXPORT OSType CreatorCodeForApplication();
63 
64 #if defined(__OBJC__)
65 
66 // Searches for directories for the given key in only the given |domain_mask|.
67 // If found, fills result (which must always be non-NULL) with the
68 // first found directory and returns true.  Otherwise, returns false.
69 BASE_EXPORT bool GetSearchPathDirectory(NSSearchPathDirectory directory,
70                                         NSSearchPathDomainMask domain_mask,
71                                         FilePath* result);
72 
73 // Searches for directories for the given key in only the local domain.
74 // If found, fills result (which must always be non-NULL) with the
75 // first found directory and returns true.  Otherwise, returns false.
76 BASE_EXPORT bool GetLocalDirectory(NSSearchPathDirectory directory,
77                                    FilePath* result);
78 
79 // Searches for directories for the given key in only the user domain.
80 // If found, fills result (which must always be non-NULL) with the
81 // first found directory and returns true.  Otherwise, returns false.
82 BASE_EXPORT bool GetUserDirectory(NSSearchPathDirectory directory,
83                                   FilePath* result);
84 
85 #endif  // __OBJC__
86 
87 // Returns the ~/Library directory.
88 BASE_EXPORT FilePath GetUserLibraryPath();
89 
90 // Returns the ~/Documents directory.
91 BASE_EXPORT FilePath GetUserDocumentPath();
92 
93 // Takes a path to an (executable) binary and tries to provide the path to an
94 // application bundle containing it. It takes the outermost bundle that it can
95 // find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
96 //   |exec_name| - path to the binary
97 //   returns - path to the application bundle, or empty on error
98 BASE_EXPORT FilePath GetAppBundlePath(const FilePath& exec_name);
99 
100 // Takes a path to an (executable) binary and tries to provide the path to an
101 // application bundle containing it. It takes the innermost bundle that it can
102 // find (so for "/Foo/Bar.app/.../Baz.app/..." it produces
103 // "/Foo/Bar.app/.../Baz.app").
104 //   |exec_name| - path to the binary
105 //   returns - path to the application bundle, or empty on error
106 BASE_EXPORT FilePath GetInnermostAppBundlePath(const FilePath& exec_name);
107 
108 #define TYPE_NAME_FOR_CF_TYPE_DECL(TypeCF) \
109   BASE_EXPORT std::string TypeNameForCFType(TypeCF##Ref)
110 
111 TYPE_NAME_FOR_CF_TYPE_DECL(CFArray);
112 TYPE_NAME_FOR_CF_TYPE_DECL(CFBag);
113 TYPE_NAME_FOR_CF_TYPE_DECL(CFBoolean);
114 TYPE_NAME_FOR_CF_TYPE_DECL(CFData);
115 TYPE_NAME_FOR_CF_TYPE_DECL(CFDate);
116 TYPE_NAME_FOR_CF_TYPE_DECL(CFDictionary);
117 TYPE_NAME_FOR_CF_TYPE_DECL(CFNull);
118 TYPE_NAME_FOR_CF_TYPE_DECL(CFNumber);
119 TYPE_NAME_FOR_CF_TYPE_DECL(CFSet);
120 TYPE_NAME_FOR_CF_TYPE_DECL(CFString);
121 TYPE_NAME_FOR_CF_TYPE_DECL(CFURL);
122 TYPE_NAME_FOR_CF_TYPE_DECL(CFUUID);
123 
124 TYPE_NAME_FOR_CF_TYPE_DECL(CGColor);
125 
126 TYPE_NAME_FOR_CF_TYPE_DECL(CTFont);
127 TYPE_NAME_FOR_CF_TYPE_DECL(CTRun);
128 
129 TYPE_NAME_FOR_CF_TYPE_DECL(SecAccessControl);
130 TYPE_NAME_FOR_CF_TYPE_DECL(SecCertificate);
131 TYPE_NAME_FOR_CF_TYPE_DECL(SecKey);
132 TYPE_NAME_FOR_CF_TYPE_DECL(SecPolicy);
133 
134 #undef TYPE_NAME_FOR_CF_TYPE_DECL
135 
136 // Returns the base bundle ID, which can be set by SetBaseBundleID but
137 // defaults to a reasonable string. This never returns NULL. BaseBundleID
138 // returns a pointer to static storage that must not be freed.
139 BASE_EXPORT const char* BaseBundleID();
140 
141 // Sets the base bundle ID to override the default. The implementation will
142 // make its own copy of new_base_bundle_id.
143 BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id);
144 
145 // CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more specific
146 // CoreFoundation type. The compatibility of the passed object is found by
147 // comparing its opaque type against the requested type identifier. If the
148 // supplied object is not compatible with the requested return type, CFCast<>()
149 // returns null and CFCastStrict<>() will CHECK. Providing a null pointer to
150 // either variant results in null being returned without triggering any CHECK.
151 //
152 // Example usage:
153 // CFNumberRef some_number = base::apple::CFCast<CFNumberRef>(
154 //     CFArrayGetValueAtIndex(array, index));
155 //
156 // CFTypeRef hello = CFSTR("hello world");
157 // CFStringRef some_string = base::apple::CFCastStrict<CFStringRef>(hello);
158 
159 template <typename T>
160 T CFCast(const CFTypeRef& cf_val);
161 
162 template <typename T>
163 T CFCastStrict(const CFTypeRef& cf_val);
164 
165 #define CF_CAST_DECL(TypeCF)                                            \
166   template <>                                                           \
167   BASE_EXPORT TypeCF##Ref CFCast<TypeCF##Ref>(const CFTypeRef& cf_val); \
168                                                                         \
169   template <>                                                           \
170   BASE_EXPORT TypeCF##Ref CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val)
171 
172 CF_CAST_DECL(CFArray);
173 CF_CAST_DECL(CFBag);
174 CF_CAST_DECL(CFBoolean);
175 CF_CAST_DECL(CFData);
176 CF_CAST_DECL(CFDate);
177 CF_CAST_DECL(CFDictionary);
178 CF_CAST_DECL(CFNull);
179 CF_CAST_DECL(CFNumber);
180 CF_CAST_DECL(CFSet);
181 CF_CAST_DECL(CFString);
182 CF_CAST_DECL(CFURL);
183 CF_CAST_DECL(CFUUID);
184 
185 CF_CAST_DECL(CGColor);
186 
187 CF_CAST_DECL(CTFont);
188 CF_CAST_DECL(CTFontDescriptor);
189 CF_CAST_DECL(CTRun);
190 
191 CF_CAST_DECL(SecAccessControl);
192 CF_CAST_DECL(SecCertificate);
193 CF_CAST_DECL(SecKey);
194 CF_CAST_DECL(SecPolicy);
195 
196 #undef CF_CAST_DECL
197 
198 #if defined(__OBJC__)
199 
200 // ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more specific
201 // (NSObject-derived) type. The compatibility of the passed object is found by
202 // checking if it's a kind of the requested type identifier. If the supplied
203 // object is not compatible with the requested return type, ObjCCast<>() returns
204 // nil and ObjCCastStrict<>() will CHECK. Providing a nil pointer to either
205 // variant results in nil being returned without triggering any CHECK.
206 //
207 // The strict variant is useful when retrieving a value from a collection which
208 // only has values of a specific type, e.g. an NSArray of NSStrings. The
209 // non-strict variant is useful when retrieving values from data that you can't
210 // fully control. For example, a plist read from disk may be beyond your
211 // exclusive control, so you'd only want to check that the values you retrieve
212 // from it are of the expected types, but not crash if they're not.
213 //
214 // Example usage:
215 //   NSString* version = base::apple::ObjCCast<NSString>(
216 //       [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
217 //
218 //   // (If it's not possible to use an NSArray<NSString>.)
219 //   NSString* str = base::apple::ObjCCastStrict<NSString>(
220 //       [ns_arr_of_ns_strs objectAtIndex:0]);
221 template <typename T>
ObjCCast(id objc_val)222 T* ObjCCast(id objc_val) {
223   if ([objc_val isKindOfClass:[T class]]) {
224     return reinterpret_cast<T*>(objc_val);
225   }
226   return nil;
227 }
228 
229 template <typename T>
ObjCCastStrict(id objc_val)230 T* ObjCCastStrict(id objc_val) {
231   T* rv = ObjCCast<T>(objc_val);
232   CHECK(objc_val == nil || rv);
233   return rv;
234 }
235 
236 #endif  // defined(__OBJC__)
237 
238 // Helper function for GetValueFromDictionary to create the error message
239 // that appears when a type mismatch is encountered.
240 BASE_EXPORT std::string GetValueFromDictionaryErrorMessage(
241     CFStringRef key,
242     const std::string& expected_type,
243     CFTypeRef value);
244 
245 // Utility function to pull out a value from a dictionary, check its type, and
246 // return it. Returns NULL if the key is not present or of the wrong type.
247 template <typename T>
GetValueFromDictionary(CFDictionaryRef dict,CFStringRef key)248 T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) {
249   CFTypeRef value = CFDictionaryGetValue(dict, key);
250   T value_specific = CFCast<T>(value);
251 
252   if (value && !value_specific) {
253     std::string expected_type = TypeNameForCFType(value_specific);
254     DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key, expected_type,
255                                                         value);
256   }
257 
258   return value_specific;
259 }
260 
261 #if defined(__OBJC__)
262 
263 // Converts |path| to an autoreleased NSURL. Returns nil if |path| is empty.
264 BASE_EXPORT NSURL* FilePathToNSURL(const FilePath& path);
265 
266 // Converts |path| to an autoreleased NSString. Returns nil if |path| is empty.
267 BASE_EXPORT NSString* FilePathToNSString(const FilePath& path);
268 
269 // Converts |str| to a FilePath. Returns an empty path if |str| is nil.
270 BASE_EXPORT FilePath NSStringToFilePath(NSString* str);
271 
272 // Converts |url| to a FilePath. Returns an empty path if |url| is nil or if
273 // |url| is not of scheme "file".
274 BASE_EXPORT FilePath NSURLToFilePath(NSURL* url);
275 
276 #endif  // __OBJC__
277 
278 // CoreFoundation versions of the above calls. These only uses manually-owned
279 // resources, so they do not depend on an NSAutoreleasePool being set up on the
280 // current thread.
281 
282 // Converts |path| to a CFURLRef. Returns nil if |path| is empty.
283 BASE_EXPORT ScopedCFTypeRef<CFURLRef> FilePathToCFURL(const FilePath& path);
284 
285 // Converts |path| to a CFStringRef. Returns nil if |path| is empty.
286 BASE_EXPORT ScopedCFTypeRef<CFStringRef> FilePathToCFString(
287     const FilePath& path);
288 
289 // Converts |str| to a FilePath. Returns an empty path if |str| is nil.
290 BASE_EXPORT FilePath CFStringToFilePath(CFStringRef str);
291 
292 // Converts |url| to a FilePath. Returns an empty path if |url| is nil or if
293 // |url| is not of scheme "file".
294 BASE_EXPORT FilePath CFURLToFilePath(CFURLRef url);
295 
296 #if defined(__OBJC__)
297 // Converts |range| to an NSRange, returning the new range in |range_out|.
298 // Returns true if conversion was successful, false if the values of |range|
299 // could not be converted to NSUIntegers.
300 [[nodiscard]] BASE_EXPORT bool CFRangeToNSRange(CFRange range,
301                                                 NSRange* range_out);
302 
303 // Returns an immutable `base::span<const uint8_t>` pointing to the memory owned
304 // by `data`. Returns an empty span if `data` is nil or empty.
305 //
306 // The resulting span will be valid until the top-most autorelease pool is
307 // popped. Ensure that the span does not outlive that autorelease pool.
NSDataToSpan(NSData * data)308 inline span<const uint8_t> NSDataToSpan(NSData* data) {
309   // SAFETY: `NSData` guarantees that `bytes` is exactly `length` in size.
310   return UNSAFE_BUFFERS(
311       span(static_cast<const uint8_t*>(data.bytes), size_t{data.length}));
312 }
313 
314 // Returns a mutable `base::span<uint8_t>` pointing to the memory owned by
315 // `data`. Returns an empty span if `data` is nil or empty.
316 //
317 // The resulting span will be valid until the top-most autorelease pool is
318 // popped. Ensure that the span does not outlive that autorelease pool.
NSMutableDataToSpan(NSMutableData * data)319 inline span<uint8_t> NSMutableDataToSpan(NSMutableData* data) {
320   // SAFETY: `NSMutableData` guarantees that `mutableBytes` is exactly `length`
321   // in size.
322   return UNSAFE_BUFFERS(
323       span(static_cast<uint8_t*>(data.mutableBytes), size_t{data.length}));
324 }
325 
326 #endif  // defined(__OBJC__)
327 
328 // Returns an immutable `base::span<const uint8_t>` pointing to the memory
329 // owned by `data`. `data` must outlive the returned span.
330 // Returns an empty span if `data` is null or empty.
331 BASE_EXPORT span<const uint8_t> CFDataToSpan(CFDataRef data);
332 
333 // Returns a mutable `base::span<uint8_t>` pointing to the memory
334 // owned by `data`. `data` must outlive the returned span.
335 // Returns an empty span if `data` is null or empty.
336 BASE_EXPORT span<uint8_t> CFMutableDataToSpan(CFMutableDataRef data);
337 
338 }  // namespace base::apple
339 
340 // Stream operations for CFTypes. They can be used with Objective-C types as
341 // well by using the casting methods in base/apple/bridging.h.
342 //
343 // For example: LOG(INFO) << base::apple::NSToCFPtrCast(@"foo");
344 //
345 // operator<<() can not be overloaded for Objective-C types as the compiler
346 // cannot distinguish between overloads for id with overloads for void*.
347 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
348                                             const CFErrorRef err);
349 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
350                                             const CFStringRef str);
351 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, CFRange);
352 
353 #if defined(__OBJC__)
354 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, id);
355 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, NSRange);
356 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, SEL);
357 
358 #if BUILDFLAG(IS_MAC)
359 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, NSPoint);
360 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, NSRect);
361 BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, NSSize);
362 #endif  // IS_MAC
363 
364 #endif  // __OBJC__
365 
366 #endif  // BASE_APPLE_FOUNDATION_UTIL_H_
367