diff options
author | kushi.p@gmail.com <kushi.p@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-19 00:36:56 +0000 |
---|---|---|
committer | kushi.p@gmail.com <kushi.p@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-19 00:36:56 +0000 |
commit | 28f5649780a53eb29f76565fe64a726a4123ac77 (patch) | |
tree | 4c0280ef2cf799d692aabb9610d2562e1f4dcd93 /base/mac | |
parent | 69a57e0d5d571cc8222b01a508841c6b7f10f680 (diff) | |
download | chromium_src-28f5649780a53eb29f76565fe64a726a4123ac77.zip chromium_src-28f5649780a53eb29f76565fe64a726a4123ac77.tar.gz chromium_src-28f5649780a53eb29f76565fe64a726a4123ac77.tar.bz2 |
Create a CFCast<>() method for casting a basic CFTypeRef to a more specific CF type
BUG=86004
Review URL: http://codereview.chromium.org/8108003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106186 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/mac')
-rw-r--r-- | base/mac/foundation_util.h | 33 | ||||
-rw-r--r-- | base/mac/foundation_util.mm | 34 | ||||
-rw-r--r-- | base/mac/foundation_util_unittest.mm | 161 |
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)); +} |