Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: base/mac/foundation_util.mm

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/mac/foundation_util.h ('k') | base/mac/foundation_util_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "base/mac/foundation_util.h"
6
7 #include <stdlib.h>
8 #include <string.h>
9
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"
15
16 #if !defined(OS_IOS)
17 extern "C" {
18 CFTypeID SecACLGetTypeID();
19 CFTypeID SecTrustedApplicationGetTypeID();
20 Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj);
21 } // extern "C"
22 #endif
23
24 namespace base {
25 namespace mac {
26
27 namespace {
28
29 bool g_cached_am_i_bundled_called = false;
30 bool g_cached_am_i_bundled_value = false;
31 bool g_override_am_i_bundled = false;
32 bool g_override_am_i_bundled_value = false;
33
34 bool UncachedAmIBundled() {
35 #if defined(OS_IOS)
36 // All apps are bundled on iOS.
37 return true;
38 #else
39 if (g_override_am_i_bundled)
40 return g_override_am_i_bundled_value;
41
42 // Yes, this is cheap.
43 return [[base::mac::OuterBundle() bundlePath] hasSuffix:@".app"];
44 #endif
45 }
46
47 } // namespace
48
49 bool AmIBundled() {
50 // If the return value is not cached, this function will return different
51 // values depending on when it's called. This confuses some client code, see
52 // http://crbug.com/63183 .
53 if (!g_cached_am_i_bundled_called) {
54 g_cached_am_i_bundled_called = true;
55 g_cached_am_i_bundled_value = UncachedAmIBundled();
56 }
57 DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled())
58 << "The return value of AmIBundled() changed. This will confuse tests. "
59 << "Call SetAmIBundled() override manually if your test binary "
60 << "delay-loads the framework.";
61 return g_cached_am_i_bundled_value;
62 }
63
64 void SetOverrideAmIBundled(bool value) {
65 #if defined(OS_IOS)
66 // It doesn't make sense not to be bundled on iOS.
67 if (!value)
68 NOTREACHED();
69 #endif
70 g_override_am_i_bundled = true;
71 g_override_am_i_bundled_value = value;
72 }
73
74 BASE_EXPORT void ClearAmIBundledCache() {
75 g_cached_am_i_bundled_called = false;
76 }
77
78 bool IsBackgroundOnlyProcess() {
79 // This function really does want to examine NSBundle's idea of the main
80 // bundle dictionary. It needs to look at the actual running .app's
81 // Info.plist to access its LSUIElement property.
82 NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
83 return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
84 }
85
86 FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
87 NSBundle* bundle = base::mac::FrameworkBundle();
88 NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
89 ofType:nil];
90 return NSStringToFilePath(resourcePath);
91 }
92
93 OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
94 OSType creator = kUnknownType;
95 CFBundleGetPackageInfo(bundle, NULL, &creator);
96 return creator;
97 }
98
99 OSType CreatorCodeForApplication() {
100 CFBundleRef bundle = CFBundleGetMainBundle();
101 if (!bundle)
102 return kUnknownType;
103
104 return CreatorCodeForCFBundleRef(bundle);
105 }
106
107 bool GetSearchPathDirectory(NSSearchPathDirectory directory,
108 NSSearchPathDomainMask domain_mask,
109 FilePath* result) {
110 DCHECK(result);
111 NSArray* dirs =
112 NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
113 if ([dirs count] < 1) {
114 return false;
115 }
116 *result = NSStringToFilePath([dirs objectAtIndex:0]);
117 return true;
118 }
119
120 bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
121 return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
122 }
123
124 bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
125 return GetSearchPathDirectory(directory, NSUserDomainMask, result);
126 }
127
128 FilePath GetUserLibraryPath() {
129 FilePath user_library_path;
130 if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
131 DLOG(WARNING) << "Could not get user library path";
132 }
133 return user_library_path;
134 }
135
136 // Takes a path to an (executable) binary and tries to provide the path to an
137 // application bundle containing it. It takes the outermost bundle that it can
138 // find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
139 // |exec_name| - path to the binary
140 // returns - path to the application bundle, or empty on error
141 FilePath GetAppBundlePath(const FilePath& exec_name) {
142 const char kExt[] = ".app";
143 const size_t kExtLength = arraysize(kExt) - 1;
144
145 // Split the path into components.
146 std::vector<std::string> components;
147 exec_name.GetComponents(&components);
148
149 // It's an error if we don't get any components.
150 if (!components.size())
151 return FilePath();
152
153 // Don't prepend '/' to the first component.
154 std::vector<std::string>::const_iterator it = components.begin();
155 std::string bundle_name = *it;
156 DCHECK_GT(it->length(), 0U);
157 // If the first component ends in ".app", we're already done.
158 if (it->length() > kExtLength &&
159 !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
160 return FilePath(bundle_name);
161
162 // The first component may be "/" or "//", etc. Only append '/' if it doesn't
163 // already end in '/'.
164 if (bundle_name[bundle_name.length() - 1] != '/')
165 bundle_name += '/';
166
167 // Go through the remaining components.
168 for (++it; it != components.end(); ++it) {
169 DCHECK_GT(it->length(), 0U);
170
171 bundle_name += *it;
172
173 // If the current component ends in ".app", we're done.
174 if (it->length() > kExtLength &&
175 !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
176 return FilePath(bundle_name);
177
178 // Separate this component from the next one.
179 bundle_name += '/';
180 }
181
182 return FilePath();
183 }
184
185 #define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \
186 std::string TypeNameForCFType(TypeCF##Ref) { \
187 return #TypeCF; \
188 }
189
190 TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray);
191 TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag);
192 TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean);
193 TYPE_NAME_FOR_CF_TYPE_DEFN(CFData);
194 TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate);
195 TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary);
196 TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull);
197 TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber);
198 TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet);
199 TYPE_NAME_FOR_CF_TYPE_DEFN(CFString);
200 TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL);
201 TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID);
202
203 TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor);
204
205 TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont);
206 TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun);
207
208 #undef TYPE_NAME_FOR_CF_TYPE_DEFN
209
210 void NSObjectRetain(void* obj) {
211 id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
212 [nsobj retain];
213 }
214
215 void NSObjectRelease(void* obj) {
216 id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
217 [nsobj release];
218 }
219
220 void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) {
221 // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease
222 // is a no-op.
223 //
224 // In the traditional GC-less environment, NSMakeCollectable is a no-op,
225 // and cf_object is autoreleased, balancing out the caller's ownership claim.
226 //
227 // NSMakeCollectable returns nil when used on a NULL object.
228 return [NSMakeCollectable(cf_object) autorelease];
229 }
230
231 static const char* base_bundle_id;
232
233 const char* BaseBundleID() {
234 if (base_bundle_id) {
235 return base_bundle_id;
236 }
237
238 #if defined(GOOGLE_CHROME_BUILD)
239 return "com.google.Chrome";
240 #else
241 return "org.chromium.Chromium";
242 #endif
243 }
244
245 void SetBaseBundleID(const char* new_base_bundle_id) {
246 if (new_base_bundle_id != base_bundle_id) {
247 free((void*)base_bundle_id);
248 base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL;
249 }
250 }
251
252 // Definitions for the corresponding CF_TO_NS_CAST_DECL macros in
253 // foundation_util.h.
254 #define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
255 \
256 TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
257 DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
258 TypeNS* ns_val = \
259 const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
260 return ns_val; \
261 } \
262 \
263 TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
264 TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
265 DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
266 return cf_val; \
267 }
268
269 #define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
270 CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
271 \
272 NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
273 DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
274 NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
275 return ns_val; \
276 } \
277 \
278 CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
279 CFMutable##name##Ref cf_val = \
280 reinterpret_cast<CFMutable##name##Ref>(ns_val); \
281 DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
282 return cf_val; \
283 }
284
285 CF_TO_NS_MUTABLE_CAST_DEFN(Array);
286 CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
287 CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
288 CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
289 CF_TO_NS_MUTABLE_CAST_DEFN(Data);
290 CF_TO_NS_CAST_DEFN(CFDate, NSDate);
291 CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
292 CF_TO_NS_CAST_DEFN(CFError, NSError);
293 CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
294 CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
295 CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
296 CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
297 CF_TO_NS_MUTABLE_CAST_DEFN(Set);
298 CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
299 CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
300 CF_TO_NS_MUTABLE_CAST_DEFN(String);
301 CF_TO_NS_CAST_DEFN(CFURL, NSURL);
302
303 #if defined(OS_IOS)
304 CF_TO_NS_CAST_DEFN(CTFont, UIFont);
305 #else
306 // The NSFont/CTFont toll-free bridging is broken when it comes to type
307 // checking, so do some special-casing.
308 // http://www.openradar.me/15341349 rdar://15341349
309 NSFont* CFToNSCast(CTFontRef cf_val) {
310 NSFont* ns_val =
311 const_cast<NSFont*>(reinterpret_cast<const NSFont*>(cf_val));
312 DCHECK(!cf_val ||
313 CTFontGetTypeID() == CFGetTypeID(cf_val) ||
314 (_CFIsObjC(CTFontGetTypeID(), cf_val) &&
315 [ns_val isKindOfClass:NSClassFromString(@"NSFont")]));
316 return ns_val;
317 }
318
319 CTFontRef NSToCFCast(NSFont* ns_val) {
320 CTFontRef cf_val = reinterpret_cast<CTFontRef>(ns_val);
321 DCHECK(!cf_val ||
322 CTFontGetTypeID() == CFGetTypeID(cf_val) ||
323 [ns_val isKindOfClass:NSClassFromString(@"NSFont")]);
324 return cf_val;
325 }
326 #endif
327
328 #undef CF_TO_NS_CAST_DEFN
329 #undef CF_TO_NS_MUTABLE_CAST_DEFN
330
331 #define CF_CAST_DEFN(TypeCF) \
332 template<> TypeCF##Ref \
333 CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \
334 if (cf_val == NULL) { \
335 return NULL; \
336 } \
337 if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \
338 return (TypeCF##Ref)(cf_val); \
339 } \
340 return NULL; \
341 } \
342 \
343 template<> TypeCF##Ref \
344 CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
345 TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val); \
346 DCHECK(cf_val == NULL || rv); \
347 return rv; \
348 }
349
350 CF_CAST_DEFN(CFArray);
351 CF_CAST_DEFN(CFBag);
352 CF_CAST_DEFN(CFBoolean);
353 CF_CAST_DEFN(CFData);
354 CF_CAST_DEFN(CFDate);
355 CF_CAST_DEFN(CFDictionary);
356 CF_CAST_DEFN(CFNull);
357 CF_CAST_DEFN(CFNumber);
358 CF_CAST_DEFN(CFSet);
359 CF_CAST_DEFN(CFString);
360 CF_CAST_DEFN(CFURL);
361 CF_CAST_DEFN(CFUUID);
362
363 CF_CAST_DEFN(CGColor);
364
365 CF_CAST_DEFN(CTFontDescriptor);
366 CF_CAST_DEFN(CTRun);
367
368 #if defined(OS_IOS)
369 CF_CAST_DEFN(CTFont);
370 #else
371 // The NSFont/CTFont toll-free bridging is broken when it comes to type
372 // checking, so do some special-casing.
373 // http://www.openradar.me/15341349 rdar://15341349
374 template<> CTFontRef
375 CFCast<CTFontRef>(const CFTypeRef& cf_val) {
376 if (cf_val == NULL) {
377 return NULL;
378 }
379 if (CFGetTypeID(cf_val) == CTFontGetTypeID()) {
380 return (CTFontRef)(cf_val);
381 }
382
383 if (!_CFIsObjC(CTFontGetTypeID(), cf_val))
384 return NULL;
385
386 id<NSObject> ns_val = reinterpret_cast<id>(const_cast<void*>(cf_val));
387 if ([ns_val isKindOfClass:NSClassFromString(@"NSFont")]) {
388 return (CTFontRef)(cf_val);
389 }
390 return NULL;
391 }
392
393 template<> CTFontRef
394 CFCastStrict<CTFontRef>(const CFTypeRef& cf_val) {
395 CTFontRef rv = CFCast<CTFontRef>(cf_val);
396 DCHECK(cf_val == NULL || rv);
397 return rv;
398 }
399 #endif
400
401 #if !defined(OS_IOS)
402 CF_CAST_DEFN(SecACL);
403 CF_CAST_DEFN(SecTrustedApplication);
404 #endif
405
406 #undef CF_CAST_DEFN
407
408 std::string GetValueFromDictionaryErrorMessage(
409 CFStringRef key, const std::string& expected_type, CFTypeRef value) {
410 ScopedCFTypeRef<CFStringRef> actual_type_ref(
411 CFCopyTypeIDDescription(CFGetTypeID(value)));
412 return "Expected value for key " +
413 base::SysCFStringRefToUTF8(key) +
414 " to be " +
415 expected_type +
416 " but it was " +
417 base::SysCFStringRefToUTF8(actual_type_ref) +
418 " instead";
419 }
420
421 NSString* FilePathToNSString(const FilePath& path) {
422 if (path.empty())
423 return nil;
424 return [NSString stringWithUTF8String:path.value().c_str()];
425 }
426
427 FilePath NSStringToFilePath(NSString* str) {
428 if (![str length])
429 return FilePath();
430 return FilePath([str fileSystemRepresentation]);
431 }
432
433 } // namespace mac
434 } // namespace base
435
436 std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
437 return o << base::SysCFStringRefToUTF8(string);
438 }
439
440 std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
441 base::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
442 base::ScopedCFTypeRef<CFDictionaryRef> user_info(CFErrorCopyUserInfo(err));
443 CFStringRef errorDesc = NULL;
444 if (user_info.get()) {
445 errorDesc = reinterpret_cast<CFStringRef>(
446 CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
447 }
448 o << "Code: " << CFErrorGetCode(err)
449 << " Domain: " << CFErrorGetDomain(err)
450 << " Desc: " << desc.get();
451 if(errorDesc) {
452 o << "(" << errorDesc << ")";
453 }
454 return o;
455 }
OLDNEW
« no previous file with comments | « base/mac/foundation_util.h ('k') | base/mac/foundation_util_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698