Bluetooth: fix header sentry comment style
[chromium-blink-merge.git] / base / mac / foundation_util.mm
blob71e8942f0e3e2c23c3195ce1d535057be62031bc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/mac/foundation_util.h"
7 #include <stdlib.h>
8 #include <string.h>
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/mac/bundle_locations.h"
13 #include "base/mac/mac_logging.h"
14 #include "base/strings/sys_string_conversions.h"
16 #if !defined(OS_IOS)
17 extern "C" {
18 CFTypeID SecACLGetTypeID();
19 CFTypeID SecTrustedApplicationGetTypeID();
20 }  // extern "C"
21 #endif
23 namespace base {
24 namespace mac {
26 static bool g_override_am_i_bundled = false;
27 static bool g_override_am_i_bundled_value = false;
29 // Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
30 static bool UncachedAmIBundled() {
31 #if defined(OS_IOS)
32   // All apps are bundled on iOS
33   return true;
34 #else
35   if (g_override_am_i_bundled)
36     return g_override_am_i_bundled_value;
38   ProcessSerialNumber psn = {0, kCurrentProcess};
40   FSRef fsref;
41   OSStatus pbErr;
42   if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) {
43     OSSTATUS_DLOG(ERROR, pbErr) << "GetProcessBundleLocation failed";
44     return false;
45   }
47   FSCatalogInfo info;
48   OSErr fsErr;
49   if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
50                                 NULL, NULL, NULL)) != noErr) {
51     OSSTATUS_DLOG(ERROR, fsErr) << "FSGetCatalogInfo failed";
52     return false;
53   }
55   return info.nodeFlags & kFSNodeIsDirectoryMask;
56 #endif
59 bool AmIBundled() {
60   // If the return value is not cached, this function will return different
61   // values depending on when it's called. This confuses some client code, see
62   // http://crbug.com/63183 .
63   static bool result = UncachedAmIBundled();
64   DCHECK_EQ(result, UncachedAmIBundled())
65       << "The return value of AmIBundled() changed. This will confuse tests. "
66       << "Call SetAmIBundled() override manually if your test binary "
67       << "delay-loads the framework.";
68   return result;
71 void SetOverrideAmIBundled(bool value) {
72 #if defined(OS_IOS)
73   // It doesn't make sense not to be bundled on iOS.
74   if (!value)
75     NOTREACHED();
76 #endif
77   g_override_am_i_bundled = true;
78   g_override_am_i_bundled_value = value;
81 bool IsBackgroundOnlyProcess() {
82   // This function really does want to examine NSBundle's idea of the main
83   // bundle dictionary.  It needs to look at the actual running .app's
84   // Info.plist to access its LSUIElement property.
85   NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
86   return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
89 FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
90   NSBundle* bundle = base::mac::FrameworkBundle();
91   NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
92                                             ofType:nil];
93   return NSStringToFilePath(resourcePath);
96 OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
97   OSType creator = kUnknownType;
98   CFBundleGetPackageInfo(bundle, NULL, &creator);
99   return creator;
102 OSType CreatorCodeForApplication() {
103   CFBundleRef bundle = CFBundleGetMainBundle();
104   if (!bundle)
105     return kUnknownType;
107   return CreatorCodeForCFBundleRef(bundle);
110 bool GetSearchPathDirectory(NSSearchPathDirectory directory,
111                             NSSearchPathDomainMask domain_mask,
112                             FilePath* result) {
113   DCHECK(result);
114   NSArray* dirs =
115       NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
116   if ([dirs count] < 1) {
117     return false;
118   }
119   *result = NSStringToFilePath([dirs objectAtIndex:0]);
120   return true;
123 bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
124   return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
127 bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
128   return GetSearchPathDirectory(directory, NSUserDomainMask, result);
131 FilePath GetUserLibraryPath() {
132   FilePath user_library_path;
133   if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
134     DLOG(WARNING) << "Could not get user library path";
135   }
136   return user_library_path;
139 // Takes a path to an (executable) binary and tries to provide the path to an
140 // application bundle containing it. It takes the outermost bundle that it can
141 // find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
142 //   |exec_name| - path to the binary
143 //   returns - path to the application bundle, or empty on error
144 FilePath GetAppBundlePath(const FilePath& exec_name) {
145   const char kExt[] = ".app";
146   const size_t kExtLength = arraysize(kExt) - 1;
148   // Split the path into components.
149   std::vector<std::string> components;
150   exec_name.GetComponents(&components);
152   // It's an error if we don't get any components.
153   if (!components.size())
154     return FilePath();
156   // Don't prepend '/' to the first component.
157   std::vector<std::string>::const_iterator it = components.begin();
158   std::string bundle_name = *it;
159   DCHECK_GT(it->length(), 0U);
160   // If the first component ends in ".app", we're already done.
161   if (it->length() > kExtLength &&
162       !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
163     return FilePath(bundle_name);
165   // The first component may be "/" or "//", etc. Only append '/' if it doesn't
166   // already end in '/'.
167   if (bundle_name[bundle_name.length() - 1] != '/')
168     bundle_name += '/';
170   // Go through the remaining components.
171   for (++it; it != components.end(); ++it) {
172     DCHECK_GT(it->length(), 0U);
174     bundle_name += *it;
176     // If the current component ends in ".app", we're done.
177     if (it->length() > kExtLength &&
178         !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
179       return FilePath(bundle_name);
181     // Separate this component from the next one.
182     bundle_name += '/';
183   }
185   return FilePath();
188 #define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \
189 std::string TypeNameForCFType(TypeCF##Ref) { \
190   return #TypeCF; \
193 TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray);
194 TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag);
195 TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean);
196 TYPE_NAME_FOR_CF_TYPE_DEFN(CFData);
197 TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate);
198 TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary);
199 TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull);
200 TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber);
201 TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet);
202 TYPE_NAME_FOR_CF_TYPE_DEFN(CFString);
203 TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL);
204 TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID);
206 TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor);
208 TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont);
209 TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun);
211 #undef TYPE_NAME_FOR_CF_TYPE_DEFN
213 void NSObjectRetain(void* obj) {
214   id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
215   [nsobj retain];
218 void NSObjectRelease(void* obj) {
219   id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
220   [nsobj release];
223 void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) {
224   // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease
225   // is a no-op.
226   //
227   // In the traditional GC-less environment, NSMakeCollectable is a no-op,
228   // and cf_object is autoreleased, balancing out the caller's ownership claim.
229   //
230   // NSMakeCollectable returns nil when used on a NULL object.
231   return [NSMakeCollectable(cf_object) autorelease];
234 static const char* base_bundle_id;
236 const char* BaseBundleID() {
237   if (base_bundle_id) {
238     return base_bundle_id;
239   }
241 #if defined(GOOGLE_CHROME_BUILD)
242   return "com.google.Chrome";
243 #else
244   return "org.chromium.Chromium";
245 #endif
248 void SetBaseBundleID(const char* new_base_bundle_id) {
249   if (new_base_bundle_id != base_bundle_id) {
250     free((void*)base_bundle_id);
251     base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL;
252   }
255 // Definitions for the corresponding CF_TO_NS_CAST_DECL macros in
256 // foundation_util.h.
257 #define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
259 TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
260   DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
261   TypeNS* ns_val = \
262       const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
263   return ns_val; \
264 } \
266 TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
267   TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
268   DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
269   return cf_val; \
272 #define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
273 CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
275 NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
276   DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
277   NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
278   return ns_val; \
279 } \
281 CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
282   CFMutable##name##Ref cf_val = \
283       reinterpret_cast<CFMutable##name##Ref>(ns_val); \
284   DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
285   return cf_val; \
288 CF_TO_NS_MUTABLE_CAST_DEFN(Array);
289 CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
290 CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
291 CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
292 CF_TO_NS_MUTABLE_CAST_DEFN(Data);
293 CF_TO_NS_CAST_DEFN(CFDate, NSDate);
294 CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
295 CF_TO_NS_CAST_DEFN(CFError, NSError);
296 CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
297 CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
298 CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
299 CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
300 CF_TO_NS_MUTABLE_CAST_DEFN(Set);
301 CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
302 CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
303 CF_TO_NS_MUTABLE_CAST_DEFN(String);
304 CF_TO_NS_CAST_DEFN(CFURL, NSURL);
306 #undef CF_TO_NS_CAST_DEFN
307 #undef CF_TO_NS_MUTABLE_CAST_DEFN
309 #define CF_CAST_DEFN(TypeCF) \
310 template<> TypeCF##Ref \
311 CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \
312   if (cf_val == NULL) { \
313     return NULL; \
314   } \
315   if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \
316     return (TypeCF##Ref)(cf_val); \
317   } \
318   return NULL; \
319 } \
321 template<> TypeCF##Ref \
322 CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
323   TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val); \
324   DCHECK(cf_val == NULL || rv); \
325   return rv; \
328 CF_CAST_DEFN(CFArray);
329 CF_CAST_DEFN(CFBag);
330 CF_CAST_DEFN(CFBoolean);
331 CF_CAST_DEFN(CFData);
332 CF_CAST_DEFN(CFDate);
333 CF_CAST_DEFN(CFDictionary);
334 CF_CAST_DEFN(CFNull);
335 CF_CAST_DEFN(CFNumber);
336 CF_CAST_DEFN(CFSet);
337 CF_CAST_DEFN(CFString);
338 CF_CAST_DEFN(CFURL);
339 CF_CAST_DEFN(CFUUID);
341 CF_CAST_DEFN(CGColor);
343 CF_CAST_DEFN(CTFont);
344 CF_CAST_DEFN(CTRun);
346 #if !defined(OS_IOS)
347 CF_CAST_DEFN(SecACL);
348 CF_CAST_DEFN(SecTrustedApplication);
349 #endif
351 #undef CF_CAST_DEFN
353 std::string GetValueFromDictionaryErrorMessage(
354     CFStringRef key, const std::string& expected_type, CFTypeRef value) {
355   ScopedCFTypeRef<CFStringRef> actual_type_ref(
356       CFCopyTypeIDDescription(CFGetTypeID(value)));
357   return "Expected value for key " +
358       base::SysCFStringRefToUTF8(key) +
359       " to be " +
360       expected_type +
361       " but it was " +
362       base::SysCFStringRefToUTF8(actual_type_ref) +
363       " instead";
366 NSString* FilePathToNSString(const FilePath& path) {
367   if (path.empty())
368     return nil;
369   return [NSString stringWithUTF8String:path.value().c_str()];
372 FilePath NSStringToFilePath(NSString* str) {
373   if (![str length])
374     return FilePath();
375   return FilePath([str fileSystemRepresentation]);
378 }  // namespace mac
379 }  // namespace base
381 std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
382   return o << base::SysCFStringRefToUTF8(string);
385 std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
386   base::mac::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
387   base::mac::ScopedCFTypeRef<CFDictionaryRef> user_info(
388       CFErrorCopyUserInfo(err));
389   CFStringRef errorDesc = NULL;
390   if (user_info.get()) {
391     errorDesc = reinterpret_cast<CFStringRef>(
392         CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
393   }
394   o << "Code: " << CFErrorGetCode(err)
395     << " Domain: " << CFErrorGetDomain(err)
396     << " Desc: " << desc.get();
397   if(errorDesc) {
398     o << "(" << errorDesc << ")";
399   }
400   return o;