diff options
Diffstat (limited to 'base/mac')
-rw-r--r-- | base/mac/foundation_util.h | 54 | ||||
-rw-r--r-- | base/mac/foundation_util.mm | 51 | ||||
-rw-r--r-- | base/mac/foundation_util_unittest.mm | 44 |
3 files changed, 134 insertions, 15 deletions
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h index f7821de..a36ad75 100644 --- a/base/mac/foundation_util.h +++ b/base/mac/foundation_util.h @@ -13,6 +13,7 @@ #include "base/base_export.h" #include "base/logging.h" +#include "base/mac/scoped_cftyperef.h" #if defined(__OBJC__) #import <Foundation/Foundation.h> @@ -96,8 +97,32 @@ BASE_EXPORT FilePath GetUserLibraryPath(); // returns - path to the application bundle, or empty on error BASE_EXPORT FilePath GetAppBundlePath(const FilePath& exec_name); +#define TYPE_NAME_FOR_CF_TYPE_DECL(TypeCF) \ +std::string TypeNameForCFType(TypeCF##Ref); + +TYPE_NAME_FOR_CF_TYPE_DECL(CFArray); +TYPE_NAME_FOR_CF_TYPE_DECL(CFBag); +TYPE_NAME_FOR_CF_TYPE_DECL(CFBoolean); +TYPE_NAME_FOR_CF_TYPE_DECL(CFData); +TYPE_NAME_FOR_CF_TYPE_DECL(CFDate); +TYPE_NAME_FOR_CF_TYPE_DECL(CFDictionary); +TYPE_NAME_FOR_CF_TYPE_DECL(CFNull); +TYPE_NAME_FOR_CF_TYPE_DECL(CFNumber); +TYPE_NAME_FOR_CF_TYPE_DECL(CFSet); +TYPE_NAME_FOR_CF_TYPE_DECL(CFString); + +#undef TYPE_NAME_FOR_CF_TYPE_DECL + +// Helper function for GetValueFromDictionary to create the error message +// that appears when a type mismatch is encountered. +std::string GetValueFromDictionaryErrorMessage( + CFStringRef key, const std::string& expected_type, CFTypeRef value); + // Utility function to pull out a value from a dictionary, check its type, and // return it. Returns NULL if the key is not present or of the wrong type. +// This is now deprecated in favor of the two-argument form below. +// TODO(kushi.p): Remove this function once all cases of it have been +// replaced with the two-argument form below. See: crbug.com/104200. BASE_EXPORT CFTypeRef GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key, CFTypeID expected_type); @@ -198,6 +223,10 @@ CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream); CF_TO_NS_MUTABLE_CAST_DECL(String); CF_TO_NS_CAST_DECL(CFURL, NSURL); +#undef CF_TO_NS_CAST_DECL +#undef CF_TO_NS_MUTABLE_CAST_DECL +#undef OBJC_CPP_CLASS_DECL + namespace base { namespace mac { @@ -218,10 +247,10 @@ namespace mac { // base::mac::GetValueFromDictionary(some_dict, // CFSTR("a_key"), // CFStringGetTypeID())); -BASE_EXPORT template<class T> +BASE_EXPORT template<typename T> T CFCast(const CFTypeRef& cf_val); -BASE_EXPORT template<class T> +BASE_EXPORT template<typename T> T CFCastStrict(const CFTypeRef& cf_val); #if defined(__OBJC__) @@ -248,7 +277,7 @@ T CFCastStrict(const CFTypeRef& cf_val); // // NSString* str = base::mac::ObjCCastStrict<NSString>( // [ns_arr_of_ns_strs objectAtIndex:0]); -BASE_EXPORT template<class T> +BASE_EXPORT template<typename T> T* ObjCCast(id objc_val) { if ([objc_val isKindOfClass:[T class]]) { return reinterpret_cast<T*>(objc_val); @@ -256,7 +285,7 @@ T* ObjCCast(id objc_val) { return nil; } -BASE_EXPORT template<class T> +BASE_EXPORT template<typename T> T* ObjCCastStrict(id objc_val) { T* rv = ObjCCast<T>(objc_val); DCHECK(objc_val == nil || rv); @@ -265,6 +294,23 @@ T* ObjCCastStrict(id objc_val) { #endif // defined(__OBJC__) +// Utility function to pull out a value from a dictionary, check its type, and +// return it. Returns NULL if the key is not present or of the wrong type. +BASE_EXPORT template<typename T> +T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) { + CFTypeRef value = CFDictionaryGetValue(dict, key); + T value_specific = CFCast<T>(value); + + if (value && !value_specific) { + std::string expected_type = TypeNameForCFType(value_specific); + DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key, + expected_type, + value); + } + + return value_specific; +} + } // namespace mac } // namespace base diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm index 8a4ce47..44b81d3 100644 --- a/base/mac/foundation_util.mm +++ b/base/mac/foundation_util.mm @@ -9,7 +9,6 @@ #include "base/file_path.h" #include "base/logging.h" -#include "base/mac/scoped_cftyperef.h" #include "base/sys_string_conversions.h" namespace base { @@ -200,6 +199,37 @@ FilePath GetAppBundlePath(const FilePath& exec_name) { return FilePath(); } +#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \ +std::string TypeNameForCFType(TypeCF##Ref) { \ + return #TypeCF; \ +} + +TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFData); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet); +TYPE_NAME_FOR_CF_TYPE_DEFN(CFString); + +#undef TYPE_NAME_FOR_CF_TYPE_DEFN + +std::string GetValueFromDictionaryErrorMessage( + CFStringRef key, const std::string& expected_type, CFTypeRef value) { + ScopedCFTypeRef<CFStringRef> actual_type_ref( + CFCopyTypeIDDescription(CFGetTypeID(value))); + return "Expected value for key " + + base::SysCFStringRefToUTF8(key) + + " to be " + + expected_type + + " but it was " + + base::SysCFStringRefToUTF8(actual_type_ref) + + " instead"; +} + CFTypeRef GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key, CFTypeID expected_type) { @@ -208,17 +238,11 @@ CFTypeRef GetValueFromDictionary(CFDictionaryRef dict, return value; if (CFGetTypeID(value) != expected_type) { - ScopedCFTypeRef<CFStringRef> expected_type_ref( + std::string expected_type_name = base::SysCFStringRefToUTF8( CFCopyTypeIDDescription(expected_type)); - ScopedCFTypeRef<CFStringRef> actual_type_ref( - CFCopyTypeIDDescription(CFGetTypeID(value))); - DLOG(WARNING) << "Expected value for key " - << base::SysCFStringRefToUTF8(key) - << " to be " - << base::SysCFStringRefToUTF8(expected_type_ref) - << " but it was " - << base::SysCFStringRefToUTF8(actual_type_ref) - << " instead"; + DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key, + expected_type_name, + value); return NULL; } @@ -318,6 +342,9 @@ CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream); CF_TO_NS_MUTABLE_CAST_DEFN(String); CF_TO_NS_CAST_DEFN(CFURL, NSURL); +#undef CF_TO_NS_CAST_DEFN +#undef CF_TO_NS_MUTABLE_CAST_DEFN + #define CF_CAST_DEFN(TypeCF) \ template<> TypeCF##Ref \ CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \ @@ -348,6 +375,8 @@ CF_CAST_DEFN(CFNumber); CF_CAST_DEFN(CFSet); CF_CAST_DEFN(CFString); +#undef CF_CAST_DEFN + } // namespace mac } // namespace base diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm index 9c5daac..7405691 100644 --- a/base/mac/foundation_util_unittest.mm +++ b/base/mac/foundation_util_unittest.mm @@ -4,6 +4,7 @@ #include "base/mac/foundation_util.h" +#include "base/basictypes.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsautorelease_pool.h" #include "testing/gtest/include/gtest/gtest.h" @@ -275,3 +276,46 @@ TEST(FoundationUtilTest, ObjCCast) { EXPECT_FALSE(base::mac::ObjCCastStrict<NSSet>(nil)); EXPECT_FALSE(base::mac::ObjCCastStrict<NSString>(nil)); } + +TEST(FoundationUtilTest, GetValueFromDictionary) { + int one = 1, two = 2, three = 3; + + base::mac::ScopedCFTypeRef<CFNumberRef> cf_one( + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one)); + base::mac::ScopedCFTypeRef<CFNumberRef> cf_two( + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two)); + base::mac::ScopedCFTypeRef<CFNumberRef> cf_three( + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three)); + + CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") }; + CFNumberRef values[] = { cf_one, cf_two, cf_three }; + + COMPILE_ASSERT(arraysize(keys) == arraysize(values), + keys_and_values_arraysizes_are_different); + + base::mac::ScopedCFTypeRef<CFDictionaryRef> test_dict( + CFDictionaryCreate(kCFAllocatorDefault, + reinterpret_cast<const void**>(keys), + reinterpret_cast<const void**>(values), + arraysize(values), + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + // base::mac::GetValueFromDictionary<>(_, _) should produce the correct + // expected output. + EXPECT_EQ(values[0], + base::mac::GetValueFromDictionary<CFNumberRef>(test_dict, + CFSTR("one"))); + EXPECT_EQ(values[1], + base::mac::GetValueFromDictionary<CFNumberRef>(test_dict, + CFSTR("two"))); + EXPECT_EQ(values[2], + base::mac::GetValueFromDictionary<CFNumberRef>(test_dict, + CFSTR("three"))); + + // Bad input should produce bad output. + EXPECT_FALSE(base::mac::GetValueFromDictionary<CFNumberRef>(test_dict, + CFSTR("four"))); + EXPECT_FALSE(base::mac::GetValueFromDictionary<CFStringRef>(test_dict, + CFSTR("one"))); +} |