utilities.h   [plain text]


/*
 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
 * 
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */


/*
 * cssm utilities
 */
#ifndef _H_UTILITIES
#define _H_UTILITIES

#include <security_utilities/utility_config.h>
#include <security_utilities/errors.h>
#include <exception>
#include <new>
#include <string>
#include <string.h>

namespace Security
{

//
// Elementary debugging support.
// #include <debugging.h> for more debugging facilities.
//
#define IFDEBUG(it)		IFELSEDEBUG(it,)
#define IFNDEBUG(it)	IFELSEDEBUG(,it)

#if defined(NDEBUG)

# define safe_cast	static_cast
# define safer_cast	static_cast

# define IFELSEDEBUG(d,nd) nd

#else

template <class Derived, class Base>
inline Derived safer_cast(Base &base)
{
    return dynamic_cast<Derived>(base);
}

template <class Derived, class Base>
inline Derived safe_cast(Base *base)
{
    if (base == NULL)
        return NULL;	// okay to cast NULL to NULL
    Derived p = dynamic_cast<Derived>(base);
    assert(p);
    return p;
}

# define IFELSEDEBUG(d,nd) d

#endif //NDEBUG


//
// Place this into your class definition if you don't want it to be copyable
// or asignable. This will not prohibit allocation on the stack or in static
// memory, but it will make anything derived from it, and anything containing
// it, fixed-once-created. A proper object, I suppose.
//
#define NOCOPY(Type)	\
	private: Type(const Type &) DEPRECATED_IN_MAC_OS_X_VERSION_10_0_AND_LATER; \
	void operator = (const Type &) DEPRECATED_IN_MAC_OS_X_VERSION_10_0_AND_LATER;


//
// Helpers for memory pointer validation
//
#define MY_CSSM_ERRCODE_INVALID_POINTER 0x0004
template <class T>
inline T &Required(T *ptr, OSStatus err = MY_CSSM_ERRCODE_INVALID_POINTER)
{
    if (ptr == NULL)
        MacOSError::throwMe(err);
    return *ptr;
}

// specialization for void * (just check for non-null; don't return a void & :-)
inline void Required(void *ptr, OSStatus err = MY_CSSM_ERRCODE_INVALID_POINTER)
{
	if (ptr == NULL)
		MacOSError::throwMe(err);
}


//
// Tools to build POD wrapper classes
//
template <class Wrapper, class POD>
class PodWrapper : public POD {
public:
    // pure typecasts
    static Wrapper * &overlayVar(POD * &data)
    { return reinterpret_cast<Wrapper * &>(data); }
    static const Wrapper * &overlayVar(const POD * &data)
    { return reinterpret_cast<const Wrapper * &>(data); }
	
    static Wrapper *overlay(POD *data)
    { return static_cast<Wrapper *>(data); }
    static const Wrapper *overlay(const POD *data)
    { return static_cast<const Wrapper *>(data); }
    static Wrapper &overlay(POD &data)
    { return static_cast<Wrapper &>(data); }
    static const Wrapper &overlay(const POD &data)
    { return static_cast<const Wrapper &>(data); }

    // optional/required forms
    static Wrapper &required(POD *data)
    { return overlay(Required(data)); }
    static const Wrapper &required(const POD *data)
    { return overlay(Required(data)); }
    static Wrapper *optional(POD *data)
    { return overlay(data); }
    static const Wrapper *optional(const POD *data)
    { return overlay(data); }
    
    // general helpers for all PodWrappers
    void clearPod()
    { memset(static_cast<POD *>(this), 0, sizeof(POD)); }
	
	void assignPod(const POD &source)
	{ static_cast<POD &>(*this) = source; }
};


//
// Template builder support
//
template <class T>
struct Nonconst {
	typedef T Type;
};

template <class U>
struct Nonconst<const U> {
	typedef U Type;
};

template <class U>
struct Nonconst<const U *> {
	typedef U *Type;
};

// cast away pointed-to constness
template <class T>
typename Nonconst<T>::Type unconst_cast(T obj)
{
	return const_cast<typename Nonconst<T>::Type>(obj);
}

template <class T>
typename Nonconst<T>::Type &unconst_ref_cast(T &obj)
{
	return const_cast<typename Nonconst<T>::Type &>(obj);
}


// Help with container of something->pointer cleanup
template <class In>
static inline void for_each_delete(In first, In last)
{
    while (first != last)
        delete *(first++);
}

// Help with map of something->pointer cleanup
template <class In>
static inline void for_each_map_delete(In first, In last)
{
    while (first != last)
        delete (first++)->second;
}

// versions of copy that project to pair elements
template <class InIterator, class OutIterator>
inline OutIterator copy_first(InIterator first, InIterator last, OutIterator out)
{
	while (first != last)
		*out++ = (first++)->first;
	return out;
}

template <class InIterator, class OutIterator>
inline OutIterator copy_second(InIterator first, InIterator last, OutIterator out)
{
	while (first != last)
		*out++ = (first++)->second;
	return out;
}


// simple safe re-entry blocker
class RecursionBlock {
public:
	RecursionBlock() : mActive(false) { }
	~RecursionBlock() { assert(!mActive); }

public:
	class Once {
	public:
		Once(RecursionBlock &rb) : block(rb), mActive(false) { }
		~Once() { block.mActive &= !mActive; }
		bool operator () ()
		{ if (block.mActive) return true; mActive = block.mActive = true; return false; }
		
		RecursionBlock &block;
	
	private:
		bool mActive;
	};
	friend class Once;
	
private:
	bool mActive;
};

// Quick and dirty template for a (temporary) array of something
// Usage example auto_array<UInt32> anArray(20);
template <class T>
class auto_array
{
public:
	auto_array() : mArray(NULL) {}
	auto_array(size_t inSize) : mArray(new T[inSize]) {}
	~auto_array() { if (mArray) delete[] mArray; }
    T &operator[](size_t inIndex) { return mArray[inIndex]; }
	void allocate(size_t inSize) { if (mArray) delete[] mArray; mArray = new T[inSize]; }
	T *get() { return mArray; }
	T *release() { T *anArray = mArray; mArray = NULL; return anArray; }
private:
	T *mArray;
};

// Template for a vector-like class that takes a c-array as it's
// underlying storage without making a copy.
template <class _Tp>
class constVector
{
    NOCOPY(constVector<_Tp>)
public:
    typedef _Tp value_type;
    typedef const value_type* const_pointer;
    typedef const value_type* const_iterator;
    typedef const value_type& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
public:
    const_iterator begin() const { return _M_start; }
    const_iterator end() const { return _M_finish; }

    const_reverse_iterator rbegin() const
    { return const_reverse_iterator(end()); }
    const_reverse_iterator rend() const
    { return const_reverse_iterator(begin()); }

    size_type size() const
    { return size_type(end() - begin()); }
    bool empty() const
    { return begin() == end(); }

    const_reference operator[](size_type __n) const { return *(begin() + __n); }

    // "at" will eventually have range checking, once we have the
    // infrastructure to be able to throw stl range errors.
    const_reference at(size_type n) const { return (*this)[n]; }

    constVector(size_type __n, const _Tp* __value)
    : _M_start(__value), _M_finish(__value + __n)
    {}
	
	constVector() : _M_start(NULL), _M_finish(NULL) {}
	
	void overlay(size_type __n, const _Tp* __value) {
		_M_start = __value;
		_M_finish = __value + __n;
	}

    const_reference front() const { return *begin(); }
    const_reference back() const { return *(end() - 1); }
private:
    const _Tp *_M_start;
    const _Tp *_M_finish;
};

char *cached_realpath(const char * file_name, char * resolved_name);

} // end namespace Security


#endif //_H_UTILITIES