Files

262 lines
8.4 KiB
C++

// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_APPLECRYPTO_CF_CFHELPER_H
#define OPENVPN_APPLECRYPTO_CF_CFHELPER_H
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/apple/cf/cf.hpp>
// These methods build on the Wrapper classes for Apple Core Foundation objects
// defined in cf.hpp. They add additional convenience methods, such as dictionary
// lookup.
namespace openvpn {
namespace CF {
// essentially a vector of void *, used as source for array and dictionary constructors
typedef BufferAllocatedType<CFTypeRef, thread_unsafe_refcount> SrcList;
inline Array array(const SrcList& values)
{
return array((const void **)values.c_data(), values.size());
}
inline Dict dict(const SrcList& keys, const SrcList& values)
{
return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size()));
}
inline CFTypeRef mutable_dict_new()
{
return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
inline CFTypeRef mutable_array_new()
{
return CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
}
// Lookup or create (if absent) an item in a mutable dictionary.
// Return the item, which will be owned by base.
template <typename KEY>
inline CFTypeRef dict_get_create(CFMutableDictionaryRef base,
const KEY& key,
CFTypeRef (*create_method)())
{
if (base)
{
String keystr = string(key);
CFTypeRef ret = CFDictionaryGetValue(base, keystr()); // try lookup first
if (!ret)
{
// doesn't exist, must create
ret = (*create_method)();
CFDictionaryAddValue(base, keystr(), ret);
CFRelease(ret); // because ret is now owned by base
}
return ret;
}
return nullptr;
}
// lookup a dict in another dict (base) and return or create if absent
template <typename KEY>
inline MutableDict dict_get_create_dict(MutableDict& base, const KEY& key)
{
String keystr = string(key);
return mutable_dict_cast(dict_get_create(base(), keystr(), mutable_dict_new));
}
// lookup an array in a dict (base) and return or create if absent
template <typename KEY>
inline MutableArray dict_get_create_array(MutableDict& base, const KEY& key)
{
String keystr = string(key);
return mutable_array_cast(dict_get_create(base(), keystr(), mutable_array_new));
}
// lookup an object in a dictionary (DICT should be a Dict or a MutableDict)
template <typename DICT, typename KEY>
inline CFTypeRef dict_get_obj(const DICT& dict, const KEY& key)
{
return dict_index(dict, key);
}
// lookup a string in a dictionary (DICT should be a Dict or a MutableDict)
template <typename DICT, typename KEY>
inline std::string dict_get_str(const DICT& dict, const KEY& key)
{
return cppstring(string_cast(dict_index(dict, key)));
}
// lookup a string in a dictionary (DICT should be a Dict or a MutableDict)
template <typename DICT, typename KEY>
inline std::string dict_get_str(const DICT& dict, const KEY& key, const std::string& default_value)
{
String str(string_cast(dict_index(dict, key)));
if (str.defined())
return cppstring(str());
else
return default_value;
}
// lookup an integer in a dictionary (DICT should be a Dict or a MutableDict)
template <typename DICT, typename KEY>
inline int dict_get_int(const DICT& dict, const KEY& key, const int default_value)
{
int ret;
Number num = number_cast(dict_index(dict, key));
if (num.defined() && CFNumberGetValue(num(), kCFNumberIntType, &ret))
return ret;
else
return default_value;
}
// lookup a boolean in a dictionary (DICT should be a Dict or a MutableDict)
template <typename DICT, typename KEY>
inline bool dict_get_bool(const DICT& dict, const KEY& key, const bool default_value)
{
Bool b = bool_cast(dict_index(dict, key));
if (b.defined())
{
if (b() == kCFBooleanTrue)
return true;
else if (b() == kCFBooleanFalse)
return false;
}
return default_value;
}
// like CFDictionarySetValue, but no-op if any args are NULL
inline void dictionarySetValue(CFMutableDictionaryRef theDict, const void *key, const void *value)
{
if (theDict && key && value)
CFDictionarySetValue(theDict, key, value);
}
// like CFArrayAppendValue, but no-op if any args are NULL
inline void arrayAppendValue(CFMutableArrayRef theArray, const void *value)
{
if (theArray && value)
CFArrayAppendValue(theArray, value);
}
// set a CFTypeRef in a mutable dictionary
template <typename KEY>
inline void dict_set_obj(MutableDict& dict, const KEY& key, CFTypeRef value)
{
String keystr = string(key);
dictionarySetValue(dict(), keystr(), value);
}
// set a string in a mutable dictionary
template <typename KEY, typename VALUE>
inline void dict_set_str(MutableDict& dict, const KEY& key, const VALUE& value)
{
String keystr = string(key);
String valstr = string(value);
dictionarySetValue(dict(), keystr(), valstr());
}
// set a number in a mutable dictionary
template <typename KEY>
inline void dict_set_int(MutableDict& dict, const KEY& key, int value)
{
String keystr = string(key);
Number num = number_from_int(value);
dictionarySetValue(dict(), keystr(), num());
}
template <typename KEY>
inline void dict_set_int32(MutableDict& dict, const KEY& key, SInt32 value)
{
String keystr = string(key);
Number num = number_from_int32(value);
dictionarySetValue(dict(), keystr(), num());
}
template <typename KEY>
inline void dict_set_long_long(MutableDict& dict, const KEY& key, long long value)
{
String keystr = string(key);
Number num = number_from_long_long(value);
dictionarySetValue(dict(), keystr(), num());
}
template <typename KEY>
inline void dict_set_index(MutableDict& dict, const KEY& key, CFIndex value)
{
String keystr = string(key);
Number num = number_from_index(value);
dictionarySetValue((CFMutableDictionaryRef)dict(), keystr(), num());
}
// set a boolean in a mutable dictionary
template <typename KEY>
inline void dict_set_bool(MutableDict& dict, const KEY& key, bool value)
{
String keystr = string(key);
CFBooleanRef boolref = value ? kCFBooleanTrue : kCFBooleanFalse;
dictionarySetValue(dict(), keystr(), boolref);
}
// append string to a mutable array
template <typename VALUE>
inline void array_append_str(MutableArray& array, const VALUE& value)
{
String valstr = string(value);
arrayAppendValue(array(), valstr());
}
// append a number to a mutable array
inline void array_append_int(MutableArray& array, int value)
{
Number num = number_from_int(value);
arrayAppendValue(array(), num());
}
inline void array_append_int32(MutableArray& array, SInt32 value)
{
Number num = number_from_int32(value);
arrayAppendValue(array(), num());
}
inline void array_append_long_long(MutableArray& array, long long value)
{
Number num = number_from_long_long(value);
arrayAppendValue(array(), num());
}
inline void array_append_index(MutableArray& array, CFIndex value)
{
Number num = number_from_index(value);
arrayAppendValue(array(), num());
}
}
}
#endif