summaryrefslogtreecommitdiffstats
path: root/base/mac
diff options
context:
space:
mode:
Diffstat (limited to 'base/mac')
-rw-r--r--base/mac/foundation_util.h33
-rw-r--r--base/mac/foundation_util.mm34
-rw-r--r--base/mac/foundation_util_unittest.mm161
3 files changed, 224 insertions, 4 deletions
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
index 2e7757e..4c4abc6 100644
--- a/base/mac/foundation_util.h
+++ b/base/mac/foundation_util.h
@@ -164,7 +164,7 @@ namespace mac { \
BASE_EXPORT TypeNS* CFToNSCast(TypeCF##Ref cf_val); \
BASE_EXPORT TypeCF##Ref NSToCFCast(TypeNS* ns_val); \
} \
-} \
+}
#define CF_TO_NS_MUTABLE_CAST_DECL(name) \
CF_TO_NS_CAST_DECL(CF##name, NS##name) \
@@ -175,7 +175,7 @@ namespace mac { \
BASE_EXPORT NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val); \
BASE_EXPORT CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val); \
} \
-} \
+}
// List of toll-free bridged types taken from:
// http://www.cocoadev.com/index.pl?TollFreeBridged
@@ -198,6 +198,35 @@ CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream);
CF_TO_NS_MUTABLE_CAST_DECL(String);
CF_TO_NS_CAST_DECL(CFURL, NSURL);
+namespace base {
+namespace mac {
+
+// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more
+// specific CoreFoundation type. The compatibility of the passed
+// object is found by comparing its opaque type against the
+// requested type identifier. If the supplied object is not
+// compatible with the requested return type, CFCast<>() returns
+// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer
+// to either variant results in NULL being returned without
+// triggering any DCHECK.
+//
+// Example usage:
+// CFNumberRef some_number = base::mac::CFCast<CFNumberRef>(
+// CFArrayGetValueAtIndex(array, index));
+//
+// CFStringRef some_string = base::mac::CFCastStrict<CFStringRef>(
+// base::mac::GetValueFromDictionary(some_dict,
+// CFSTR("a_key"),
+// CFStringGetTypeID()));
+BASE_EXPORT template<class T>
+T CFCast(const CFTypeRef& cf_val);
+
+BASE_EXPORT template<class T>
+T CFCastStrict(const CFTypeRef& cf_val);
+
+} // namespace mac
+} // namespace base
+
// Stream operations for CFTypes. They can be used with NSTypes as well
// by using the NSToCFCast methods above.
// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo");
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index cb5746a..37b001b 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -282,7 +282,7 @@ TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
-} \
+}
#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
@@ -298,7 +298,7 @@ CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
reinterpret_cast<CFMutable##name##Ref>(ns_val); \
DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
-} \
+}
CF_TO_NS_MUTABLE_CAST_DEFN(Array);
CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
@@ -318,6 +318,36 @@ CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
CF_TO_NS_MUTABLE_CAST_DEFN(String);
CF_TO_NS_CAST_DEFN(CFURL, NSURL);
+#define CF_CAST_DEFN(TypeCF) \
+template<> TypeCF##Ref \
+CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+ if (cf_val == NULL) { \
+ return NULL; \
+ } \
+ if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \
+ return reinterpret_cast<TypeCF##Ref>(cf_val); \
+ } \
+ return NULL; \
+} \
+\
+template<> TypeCF##Ref \
+CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+ TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val); \
+ DCHECK(cf_val == NULL || rv); \
+ return rv; \
+}
+
+CF_CAST_DEFN(CFArray);
+CF_CAST_DEFN(CFBag);
+CF_CAST_DEFN(CFBoolean);
+CF_CAST_DEFN(CFData);
+CF_CAST_DEFN(CFDate);
+CF_CAST_DEFN(CFDictionary);
+CF_CAST_DEFN(CFNull);
+CF_CAST_DEFN(CFNumber);
+CF_CAST_DEFN(CFSet);
+CF_CAST_DEFN(CFString);
+
} // namespace mac
} // namespace base
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm
new file mode 100644
index 0000000..cfd4fc6
--- /dev/null
+++ b/base/mac/foundation_util_unittest.mm
@@ -0,0 +1,161 @@
+// Copyright (c) 2011 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 "base/mac/foundation_util.h"
+
+#include "base/mac/scoped_cftyperef.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(FoundationUtilTest, CFCast) {
+ // Build out the CF types to be tested as empty containers.
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_array(
+ CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_array_mutable(
+ CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_bag(
+ CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
+ CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks));
+ CFTypeRef test_bool = kCFBooleanTrue;
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_data(
+ CFDataCreate(NULL, NULL, 0));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_data_mutable(
+ CFDataCreateMutable(NULL, 0));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_date(
+ CFDateCreate(NULL, 0));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_dict(
+ CFDictionaryCreate(NULL, NULL, NULL, 0,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
+ CFDictionaryCreateMutable(NULL, 0,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ int int_val = 256;
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_number(
+ CFNumberCreate(NULL, kCFNumberIntType, &int_val));
+ CFTypeRef test_null = kCFNull;
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_set(
+ CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_set_mutable(
+ CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_str(
+ CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII,
+ false));
+ CFTypeRef test_str_const = CFSTR("hello");
+ base::mac::ScopedCFTypeRef<CFTypeRef> test_str_mutable(
+ CFStringCreateMutable(NULL, 0));
+
+ // Make sure the allocations of CF types are good.
+ EXPECT_TRUE(test_array);
+ EXPECT_TRUE(test_array_mutable);
+ EXPECT_TRUE(test_bag);
+ EXPECT_TRUE(test_bag_mutable);
+ EXPECT_TRUE(test_bool);
+ EXPECT_TRUE(test_data);
+ EXPECT_TRUE(test_data_mutable);
+ EXPECT_TRUE(test_date);
+ EXPECT_TRUE(test_dict);
+ EXPECT_TRUE(test_dict_mutable);
+ EXPECT_TRUE(test_number);
+ EXPECT_TRUE(test_null);
+ EXPECT_TRUE(test_set);
+ EXPECT_TRUE(test_set_mutable);
+ EXPECT_TRUE(test_str);
+ EXPECT_TRUE(test_str_const);
+ EXPECT_TRUE(test_str_mutable);
+
+ // Casting the CFTypeRef objects correctly provides the same pointer.
+ EXPECT_EQ(test_array, base::mac::CFCast<CFArrayRef>(test_array));
+ EXPECT_EQ(test_array_mutable,
+ base::mac::CFCast<CFArrayRef>(test_array_mutable));
+ EXPECT_EQ(test_bag, base::mac::CFCast<CFBagRef>(test_bag));
+ EXPECT_EQ(test_bag_mutable,
+ base::mac::CFCast<CFBagRef>(test_bag_mutable));
+ EXPECT_EQ(test_bool, base::mac::CFCast<CFBooleanRef>(test_bool));
+ EXPECT_EQ(test_data, base::mac::CFCast<CFDataRef>(test_data));
+ EXPECT_EQ(test_data_mutable,
+ base::mac::CFCast<CFDataRef>(test_data_mutable));
+ EXPECT_EQ(test_date, base::mac::CFCast<CFDateRef>(test_date));
+ EXPECT_EQ(test_dict, base::mac::CFCast<CFDictionaryRef>(test_dict));
+ EXPECT_EQ(test_dict_mutable,
+ base::mac::CFCast<CFDictionaryRef>(test_dict_mutable));
+ EXPECT_EQ(test_number, base::mac::CFCast<CFNumberRef>(test_number));
+ EXPECT_EQ(test_null, base::mac::CFCast<CFNullRef>(test_null));
+ EXPECT_EQ(test_set, base::mac::CFCast<CFSetRef>(test_set));
+ EXPECT_EQ(test_set_mutable, base::mac::CFCast<CFSetRef>(test_set_mutable));
+ EXPECT_EQ(test_str, base::mac::CFCast<CFStringRef>(test_str));
+ EXPECT_EQ(test_str_const, base::mac::CFCast<CFStringRef>(test_str_const));
+ EXPECT_EQ(test_str_mutable,
+ base::mac::CFCast<CFStringRef>(test_str_mutable));
+
+ // When given an incorrect CF cast, provide NULL.
+ EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_array));
+ EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_array_mutable));
+ EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_bag));
+ EXPECT_FALSE(base::mac::CFCast<CFSetRef>(test_bag_mutable));
+ EXPECT_FALSE(base::mac::CFCast<CFSetRef>(test_bool));
+ EXPECT_FALSE(base::mac::CFCast<CFNullRef>(test_data));
+ EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(test_data_mutable));
+ EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(test_date));
+ EXPECT_FALSE(base::mac::CFCast<CFNumberRef>(test_dict));
+ EXPECT_FALSE(base::mac::CFCast<CFDateRef>(test_dict_mutable));
+ EXPECT_FALSE(base::mac::CFCast<CFDataRef>(test_number));
+ EXPECT_FALSE(base::mac::CFCast<CFDataRef>(test_null));
+ EXPECT_FALSE(base::mac::CFCast<CFBooleanRef>(test_set));
+ EXPECT_FALSE(base::mac::CFCast<CFBagRef>(test_set_mutable));
+ EXPECT_FALSE(base::mac::CFCast<CFBagRef>(test_str));
+ EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(test_str_const));
+ EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(test_str_mutable));
+
+ // Giving a NULL provides a NULL.
+ EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFBagRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFBooleanRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFDataRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFDateRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFNullRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFNumberRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFSetRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCast<CFStringRef>(NULL));
+
+ // CFCastStrict: correct cast results in correct pointer being returned.
+ EXPECT_EQ(test_array, base::mac::CFCastStrict<CFArrayRef>(test_array));
+ EXPECT_EQ(test_array_mutable,
+ base::mac::CFCastStrict<CFArrayRef>(test_array_mutable));
+ EXPECT_EQ(test_bag, base::mac::CFCastStrict<CFBagRef>(test_bag));
+ EXPECT_EQ(test_bag_mutable,
+ base::mac::CFCastStrict<CFBagRef>(test_bag_mutable));
+ EXPECT_EQ(test_bool, base::mac::CFCastStrict<CFBooleanRef>(test_bool));
+ EXPECT_EQ(test_data, base::mac::CFCastStrict<CFDataRef>(test_data));
+ EXPECT_EQ(test_data_mutable,
+ base::mac::CFCastStrict<CFDataRef>(test_data_mutable));
+ EXPECT_EQ(test_date, base::mac::CFCastStrict<CFDateRef>(test_date));
+ EXPECT_EQ(test_dict, base::mac::CFCastStrict<CFDictionaryRef>(test_dict));
+ EXPECT_EQ(test_dict_mutable,
+ base::mac::CFCastStrict<CFDictionaryRef>(test_dict_mutable));
+ EXPECT_EQ(test_number, base::mac::CFCastStrict<CFNumberRef>(test_number));
+ EXPECT_EQ(test_null, base::mac::CFCastStrict<CFNullRef>(test_null));
+ EXPECT_EQ(test_set, base::mac::CFCastStrict<CFSetRef>(test_set));
+ EXPECT_EQ(test_set_mutable,
+ base::mac::CFCastStrict<CFSetRef>(test_set_mutable));
+ EXPECT_EQ(test_str, base::mac::CFCastStrict<CFStringRef>(test_str));
+ EXPECT_EQ(test_str_const,
+ base::mac::CFCastStrict<CFStringRef>(test_str_const));
+ EXPECT_EQ(test_str_mutable,
+ base::mac::CFCastStrict<CFStringRef>(test_str_mutable));
+
+ // CFCastStrict: Giving a NULL provides a NULL.
+ EXPECT_FALSE(base::mac::CFCastStrict<CFArrayRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFBagRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFBooleanRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFDataRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFDateRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFDictionaryRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFNullRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFNumberRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFSetRef>(NULL));
+ EXPECT_FALSE(base::mac::CFCastStrict<CFStringRef>(NULL));
+}