CFLite/CFTest/SuperString.h

From kJams Wiki
Jump to navigation Jump to search
#ifndef _H_SuperString
#define _H_SuperString

#include <string>
#include <cctype>
#include <vector>
#include "string.h"
#include <stdarg.h>
#include <CoreFoundation/CoreFoundation.h>

#define	kCodePage_WindowsLatin1				1252
#define	kCFStringEncodingPercentEscapes		(0xfffffffeU)

#if !defined(KJAMS)
	#define		loop(_n)				for (long _indexS = 0, _maxS = (_n); _indexS < _maxS; _indexS++)
	#define		loop2(_n)				for (long _index2S = 0, _max2S = (_n); _index2S < _max2S; _index2S++)
	#define		loop_reverse(_n)		for (long _indexS = ((_n) - 1); _indexS >= 0; _indexS--)

	void		LogErr(const char *utf8Z, OSStatus err, bool crB = true, bool unixB = false);

	#define ERR_(_ERR, FUNC)	if (!_ERR) { _ERR = (FUNC); }
	#define ERR(FUNC)			ERR_(err, FUNC);
	#define	ERRL(FUNC, _str)	if (!err) { ERR(FUNC); if (err) { 	LogErr("### Error " _str, err); }}
	#define	ETRL(_exp, _str)	{ ERRL(_exp, _str); if (err) { return err;} }

	int		AssertAlert(const char *msgZ, const char *fileZ, long lineL, bool noThrowB);

	#define		CF_ASSERT(_foo)	if (!(_foo)) {					\
		AssertAlert(#_foo, __FILE__, (long)__LINE__, true);	}

	typedef std::basic_string<UTF8Char, std::char_traits<UTF8Char>, std::allocator<UTF8Char> > ustring;
	#define uc(_foo) (unsigned char *)(_foo)

	typedef std::vector<char>			CharVec;
	typedef std::vector<UTF8Char>		UCharVec;
	typedef std::vector<UTF16Char>		UTF16Vec;

	inline CFTypeRef	CFRetainDebug(CFTypeRef cf, bool do_itB = true) {
		return do_itB ? CFRetain(cf) : cf;
	}

	#define	CFReleaseDebug(_x)		CFRelease(_x)
	#define noErr	0

#else

	#include "Standard.h"
	
	#ifdef kDEBUG
		#define		TRACK_RETAINS	1
	#else
		#define		TRACK_RETAINS	0
	#endif

	#if TRACK_RETAINS
		class	ScTrackRetains {
			void	*i_dataP;
				
			public:
				ScTrackRetains();
				~ScTrackRetains();
		};
	#else
		class	ScTrackRetains {};
	#endif

	#if TRACK_RETAINS
		CFTypeRef	CFRetainDebug(CFTypeRef cf, bool do_itB = true);
		void		CFReleaseDebug(CFTypeRef cf);
	#else
		inline CFTypeRef	CFRetainDebug(CFTypeRef cf, bool do_itB = true) {
			return do_itB ? CFRetain(cf) : cf;
		}

		#define	CFReleaseDebug(_x)		CFRelease(_x)
	#endif

	#define	CF_ASSERT	ASSERT
#endif
	
#ifdef __WIN32__	
	typedef std::vector<wchar_t>	WCharVec;
#endif

/****************************************************************/
bool			Read_PList(const CFURLRef &url, CFDictionaryRef *plistP);
OSStatus		Write_PList(
	CFPropertyListRef	plist,
	CFURLRef			urlRef);

char *			CopyFloatToC(float valF, char *bufZ, short precisionS = 2);
float			CStringToFloat(const char *numF);
char*			strrstr(const char* stringZ, const char* findZ);
const char *	CopyLongToC(long valL);

bool				CFStringContains(CFStringRef inRef, CFStringRef findRef, bool case_sensitiveB = false);
CFComparisonResult	CFStringCompare(CFStringRef str1, CFStringRef str2, bool case_sensitiveB = false);
bool				CFStringEqual(CFStringRef str1, CFStringRef str2, bool case_sensitiveB = false);
bool				CFStringLess(CFStringRef lhs, CFStringRef rhs, bool case_sensitiveB = false);
bool				CFStringIsEmpty(CFStringRef nameRef);
void				SetDefaultEncoding(CFStringEncoding encoding);

ustring			&CopyCFStringToUString(
									   CFStringRef			str, 
									   ustring				&result, 
									   CFStringEncoding	encoding	= kCFStringEncodingUTF8, 
									   bool				externalB	= false);

CFStringRef		CFStringCreateWithC(
									const char *		bufZ, 
									CFStringEncoding	encoding = kCFStringEncodingInvalidId);

CFStringRef		CFStringCreateWithCu(
									 const UTF8Char *	bufZ, 
									 CFStringEncoding	encoding = kCFStringEncodingUTF8);

std::string		&CopyCFStringToStd(
								   CFStringRef			str, 
								   std::string			&stdstr, 
								   CFStringEncoding	encoding = kCFStringEncodingInvalidId);

void			CFStrReplaceWith(CFMutableStringRef stringRef, CFStringRef replaceStr, CFStringRef withStr);

extern	bool	g_pref_diacritic_insensitive_searchB;


/****************************************************************/
typedef struct {
	const char	*replaceZ;
	const char	*withZ;
} SuperStringReplaceRec;

template <typename T>
class	ScCFReleaser {
	T	i_typeRef;
	
public:
	ScCFReleaser(T typeRef = NULL) : i_typeRef(typeRef)	{}
	
	~ScCFReleaser() {
		if (i_typeRef) {
			CFReleaseDebug(i_typeRef);
			i_typeRef = NULL;
		}
	}
	
	T	Retain()	{	CFRetainDebug(i_typeRef);	return i_typeRef;	}
	T	Release()	{	CFReleaseDebug(i_typeRef);	return i_typeRef;	}
	
	T	Get()		{	return i_typeRef;	}
	T	Set(T typeRef)	{
		
		if (typeRef) {
			CFRetainDebug(typeRef);
		}
		
		if (i_typeRef) {
			CFReleaseDebug(i_typeRef);
		}
		
		i_typeRef = typeRef;
		return i_typeRef;
	}
	
	T*	AddressOf()	{	return &i_typeRef;	}
	
	operator T()	{	return i_typeRef;	}
	operator T*()	{	return AddressOf();	}
	
	T	operator =(T typeRef)	{	return Set(typeRef);	}
	
	T	transfer()	{
		T	ret = i_typeRef;
		
		i_typeRef = NULL;
		return ret;
	}
	
	T	adopt(T typeRef)	{
		Set(NULL);
		i_typeRef = typeRef;
		return i_typeRef;
	}
	
	void	LogCount(const char *nameZ) {	S_LogCount(i_typeRef, nameZ);	}
};


class	UniString {
	UTF16Char	i_nullChar;
	UTF16Vec	*i_charVecP;
	
	void		UpdateNamePointer() {
		if (i_charVecP) {
			i_charVecP->push_back(0);
			i_nameP = &(*i_charVecP)[0];
		} else {
			i_nameP = &i_nullChar;
		}
	}
	
public:
	void	Initialize(CFStringRef cf_name, bool forceBigEndianB = false) {
		if (cf_name && !CFStringIsEmpty(cf_name)) {
			ustring		utf16str;
			
			CopyCFStringToUString(cf_name, utf16str, forceBigEndianB ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16);
			
			//	divide by 2
			i_lengthL	= utf16str.size() >> 1;
			
			if (i_charVecP == NULL) {
				i_charVecP = new UTF16Vec();
			}
			
			UTF16Char	*utf16A = (UTF16Char *)utf16str.c_str();
			
			i_charVecP->assign(&utf16A[0], &utf16A[i_lengthL]);
			//			CFStringGetCharacters(cf_name, CFRangeMake(0, i_lengthL), &(*i_charVecP)[0]);
		} else {
			delete i_charVecP;
			i_charVecP = NULL;
			i_lengthL = 0;
		}
		
		UpdateNamePointer();
	}

	#if defined(__MWERKS__)
		typedef long	UniCharCount;
	#endif

	UniCharCount		i_lengthL;
	UniChar				*i_nameP;
	
	UniString(const UniString &uni)	: i_nameP(NULL), i_charVecP(NULL), i_nullChar(0) {
		i_lengthL	= uni.i_lengthL;
		
		if (i_lengthL) {
			i_charVecP = new UTF16Vec();
			i_charVecP->resize(i_lengthL);
			std::copy(&uni.i_nameP[0], &uni.i_nameP[i_lengthL], &(*i_charVecP)[0]);
		}
		
		UpdateNamePointer();
	}
	
	UniString(CFStringRef cf_name, bool forceBigEndianB = false) : i_nameP(NULL), i_charVecP(NULL), i_nullChar(0) {
		Initialize(cf_name, forceBigEndianB);
	}
	
	UniString(const char *nameZ = NULL) : i_nameP(NULL), i_charVecP(NULL), i_nullChar(0), i_lengthL(0) {
		if (nameZ) {
			ScCFReleaser<CFStringRef>	cf_name(CFStringCreateWithC(nameZ));
			
			Initialize(cf_name);
		}
	}
	
	~UniString() {
		delete i_charVecP;
	}
};

#if defined(__WIN32__)
	#ifndef __MACTYPES__
		typedef RECT	Rect;
		typedef UInt32	OSType;
	#endif
#endif

std::string		ULong_To_Hex(UInt32 valueL);
UInt32			Hex_To_ULong(const char *hexZ);
OSType			CharToOSType(const char *bufZ);

class SuperString {
	CFStringRef			i_ref;
	mutable std::string	*i_std;
	mutable UniString	*i_uni;
	mutable ustring		*i_utf8;
	mutable ustring		*i_pstr;
	
public:
	const	std::string	&std() const	{	Update_std();	return *i_std;	}
	const	CFStringRef	&ref() const	{	return i_ref;	}
	const	UniString	&uni(bool forceBigEndianB = false) const	{	Update_uni(forceBigEndianB);	return *i_uni;	}
	const	ustring		&utf8() const	{	Update_utf8();	return *i_utf8;	}
	const	char *		c_str() const  	{	return std().c_str();	}
	const	char *		utf8Z() const	{	return (const char *)utf8().c_str();	}
	ConstStr255Param	p_str() const	{	Update_pstr();	return i_pstr->c_str();	}

	#ifdef __WIN32__
		LPCWSTR		w_str() const		{	return (LPCWSTR)uni().i_nameP;	}
	#endif
	
	operator const UniString&() const	{	return uni();	}
	operator const std::string&() const	{	return std();	}
	//operator const ustring&() const		{	return utf8();	}	causes all sorts of ambiguities
	operator CFStringRef() const		{	return ref();	}
	operator const UInt8*() const		{	return utf8().c_str();	}

	/************************************/
	SuperString&	Truncate(bool activeB, const Rect& frameR);
	SuperString&	ssprintf(const char *formatZ0, ...);
	SuperString&	format(const char *formatZ0, ...);
	
private:
	void	SetNULL()
	{
		i_ref	= NULL;
		i_std	= NULL;
		i_uni	= NULL;
		i_utf8	= NULL;
		i_pstr	= NULL;
	}
	
public:
	#ifdef __WIN32__
	
	SuperString(const wchar_t *wcharZ);

	SuperString(const WCharVec& wcharVec) {
		SetNULL();
		Set(*(UTF16Vec *)&wcharVec);
	}

	#endif
	
	SuperString(const char *strZ = NULL, CFStringEncoding encoding = kCFStringEncodingInvalidId) {
		SetNULL();		
		Set(uc(strZ), encoding);
	}
	
	SuperString(const SuperString &sstr) {
		SetNULL();
		Set(sstr.ref());
	}
	
	#ifdef KJAMS
	SuperString(const CDHMSF msf, kTimeCodeType type = kTimeCode_NORMAL) {
		SetNULL();
		Set(msf, type);
	}

	SuperString(const HFSUniStr255 &str) {
		SetNULL();
		
		ScCFReleaser<CFStringRef>	myRef = CFStringCreateWithCharacters(
																		 kCFAllocatorDefault, 
																		 str.unicode,
																		 str.length);
		
		Set(myRef);
	}
	#endif

	SuperString(const UInt16* strZ) {
		SetNULL();
		
		ScCFReleaser<CFStringRef>	myRef = strZ 
			? CFStringCreateWithC((const char *)strZ, kCFStringEncodingUnicode) : 
			(CFStringRef)CFRetainDebug(CFSTR(""));

		Set(myRef);
	}
	
	SuperString(const UInt8 *strZ) {
		SetNULL();
		Set(strZ);
	}
	
	SuperString(long valL) {
		SetNULL();
		append(valL);
	}
	
	/*
	 dam!  this causes ambiguation
	 SuperString(double valF) {
	 SetNULL();
	 append((float)valF);
	 }
	 */
	
	SuperString(const ustring &str) {
		SetNULL();
		Set(str.c_str());
	}
	
	SuperString(const std::string &str) {
		SetNULL();
		Set(str.c_str());
	}
	
	SuperString(CFStringRef myRef, bool retainB = true) {
		SetNULL();
		Set(myRef, retainB);
	}
	
	void	Set_CFType(CFTypeRef cfType);
	
	/************************************/
	void	Set_p(ConstStr255Param strZ, CFStringEncoding encoding = kCFStringEncodingInvalidId);
	
	#if KJAMS
	void	Set(const CDHMSF msf, kTimeCodeType type = kTimeCode_NORMAL) {
		char	bufAC[256];
		
		Set(CopyMSFToC(msf, bufAC, type));
	}
	#endif

	void	Set(const char *strZ) {
		ScCFReleaser<CFStringRef>	myRef = CFStringCreateWithC(strZ);
		
		Set(myRef);
	}
	
	void	Set(const UInt8 *strZ, CFStringEncoding encoding = kCFStringEncodingUTF8) {
		ScCFReleaser<CFStringRef>	myRef;
		
		if (strZ) {
			if (encoding == kCFStringEncodingPercentEscapes) {
				Set(strZ, kCFStringEncodingASCII);
				
				UnEscape();
				return;
			} else {
				myRef.Set(CFStringCreateWithCu(strZ, encoding));
			}
		} else {
			myRef.Set((CFStringRef)CFRetainDebug(CFSTR("")));
		}
		
		Set(myRef);
	}
	
	void	Escape() {
		Set(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, ref(), NULL, NULL, kCFStringEncodingUTF8), false);
	}

	void	UnEscape() {
		Set(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, ref(), CFSTR("")));
	}
	
	void	Set(const ustring& utf8, CFStringEncoding encoding = kCFStringEncodingUTF8) {
		Set(utf8.c_str(), encoding);
	}
	
	void	Set(const UTF16Vec &vec) {
		ScCFReleaser<CFStringRef>	myRef = CFStringCreateWithCharacters(kCFAllocatorDefault, &vec[0], vec.size());
		
		Set(myRef);
	}
	
	void	assign(const UTF8Char *beginZ, const UTF8Char *endZ, CFStringEncoding encoding = kCFStringEncodingUTF8) {
		ustring		str(beginZ, endZ);
		
		Set(str, encoding);
	}
	
	void	Set(const SuperString &sstr) {
		if (&sstr != this) {
			Set(sstr.i_ref);
		}
	}
	
  	CFStringRef	Retain() const {	CFRetainDebug(i_ref);	return i_ref;	}
	
	void	Set(CFStringRef myRef, bool retainB = true) {
		
		if (i_ref) {
			CFReleaseDebug(i_ref);
		}
		
		if (myRef == NULL) {
			myRef = CFSTR("");
		}
		
		i_ref = myRef;
		
		if (retainB) {
			CFRetainDebug(i_ref);
		}
		
		delete i_uni;
		i_uni	= NULL;
		
		delete i_std;
		i_std	= NULL;
		
		delete i_utf8;
		i_utf8	= NULL;
		
		delete i_pstr;
		i_pstr = NULL;
	}
	
	/************************************/
	~SuperString() {
		Set((CFStringRef)NULL, false);
	}
	
	void	Release() {
		CFReleaseDebug(i_ref);
	}
	
	/************************************/
	void	Update_pstr() const {
		
		if (!i_pstr) {
			i_pstr = new ustring;
			i_pstr->push_back(0);
			Update_std();
			i_pstr->insert(i_pstr->end(), i_std->begin(), i_std->end());
			(*i_pstr)[0] = i_pstr->size() - 1;
			
			delete i_std;
			i_std	= NULL;
		}
	}
	
	void	Update_uni(bool forceBigEndianB) const {
		if (!i_uni) {
			i_uni = new UniString(i_ref, forceBigEndianB);
		}
	}
	
	void	Update_std() const {
		if (!i_std) {
			i_std = new std::string;
			CopyCFStringToStd(i_ref, *i_std);
		}
	}
	
	void	Update_utf8() const {
		if (!i_utf8) {
			i_utf8 = new ustring;
			CopyCFStringToUString(i_ref, *i_utf8);
		}
	}

	/************************************/
	void	clear()	{	Set((CFStringRef)NULL);	}
	
	bool				Contains(const SuperString& other) {
		return strstr(utf8Z(), other.utf8Z()) != NULL;
	}
	
	//	returns number of utf8 bytes (not characters) that match the start of the other string
	CFIndex				MatchStart(const SuperString& other, char delimiterCh = 0);
	
	SuperString&		ReplaceTable(SuperStringReplaceRec *recA, long sizeL);
	SuperString&		Replace(const SuperString& replaceStr, const SuperString& withStr) {
		ScCFReleaser<CFMutableStringRef>	newRef(CFStringCreateMutableCopy(NULL, 0, i_ref));
		
		CFStrReplaceWith(newRef, replaceStr.ref(), withStr.ref());
		Set(newRef);
		return *this;
	} 
	
	SuperString		&UnderScoresToSpaces() {
		return Replace("_", " ");
	}
	
	//	returns a new string, does not modify original
	SuperString			md5() const;
	
	SuperString&		Scramble();
	SuperString&		UnScramble();
	
	SuperString&		trim();

	#ifdef KJAMS
	void		MakeRecoverable(bool old_styleB = false) {
		ScCFReleaser<CFStringRef>		sc(CFStrCreateRecoverableName(i_ref, false));
		
		Set(sc);
	}
	
	SuperString&		Recover() {
		ScCFReleaser<CFStringRef>		sc(CFStrRecoverName(i_ref));
		
		Set(sc);
		return *this;
	}
	#endif
	
	CFDataRef		CopyDataRef() {
		return CFStringCreateExternalRepresentation(
			kCFAllocatorDefault, i_ref, kCFStringEncodingUTF8, 0);
	}
	
	void			Set(CFDataRef dataRef) {
		ScCFReleaser<CFStringRef>	myRef = CFStringCreateFromExternalRepresentation(
			kCFAllocatorDefault, dataRef, kCFStringEncodingUTF8);

		Set(myRef);
	}
	
	/*
	 ambiguous
	 
	 char			operator[](size_t indexS) {
	 char	ch = 0;
	 
	 if (utf8().size() > indexS) {
	 ch = utf8().c_str()[indexS];
	 }
	 
	 return ch;
	 }
	 */
	
	UTF8Char		GetIndChar(size_t indexL = 0) const {
		UTF8Char		ch = 0;
		
		if (indexL >= 0 && indexL < utf8().size()) {
			ch = utf8()[indexL];
		}
		
		return ch;
	}
	
	UTF8Char		GetIndCharR(long indexL = 0) const {
		return GetIndChar(utf8().size() - (indexL + 1));
	}
	
	SuperString&	ToUpper();
	SuperString&	ToLower();
	bool			IsAllCaps();
	SuperString&	Normalize();
	SuperString&	InterCaps(bool allow_line_breaksB = false, bool titleCaseB = true);
	
	#ifdef KJAMS
	SuperString&	RecoverCaps(bool titleCaseB = true) {
		Recover();
		InterCaps(false, titleCaseB);
		MakeRecoverable();
		return *this;
	}
	#endif
	
	SuperString&	operator =(const SuperString &other) {	Set(other);	return *this;	}
	SuperString&	operator =(const char *otherZ) {	Set(otherZ);	return *this;	}
	
	bool			operator<(CFStringRef other) const {
		return CFStringLess(i_ref, other);
	}
	
	bool			operator ==(CFStringRef other) {
		return CFStringEqual(i_ref, other);
	}
	
	bool			operator ==(CFStringRef other) const {
		return CFStringEqual(i_ref, other);
	}
	
	bool			operator !=(CFStringRef other)	{
		return ! operator==(other);
	}
	
	bool			operator ==(const SuperString &other) {
		return operator==(other.i_ref);
	}
	
	bool			operator ==(const SuperString &other) const {
		return operator==(other.i_ref);
	}
	
	bool			operator !=(const SuperString &other)	{
		return ! operator==(other.i_ref);
	}
	
	bool	IsNumeric() const;
	bool	empty() const		{	return CFStringIsEmpty(i_ref);	}
	long	value_long() const	{	return ::atoi(c_str());	}
	float	value_float() const	{	return CStringToFloat(c_str());	}
	UInt32	hex_to_ulong()		{	return Hex_To_ULong(c_str());	}
	
	SuperString		pop_front(size_t numL = 1)	{
		SuperString			str;
		
		if (utf8().size() <= numL) {
			str.Set(*this);
			clear();
		} else {
			UCharVec	bufAC(numL);
			
			std::copy(i_utf8->begin(), i_utf8->begin() + numL, &bufAC[0]);
			bufAC.push_back(0);
			
			str.Set(&bufAC[0]);
			Set(&(utf8().c_str())[numL]);
		}
		
		return str;
	}
	
	short	count_match(const char *matchZ) {
		short		countS = 0;
		const char	*chZ = (const char *)utf8().c_str();
		
		do {
			chZ = strstr(chZ, matchZ);
			if (chZ) {
				++countS;
				++chZ;
			}
		} while (chZ);
		
		return countS;
	}
	
	bool	rSplit(const char *splitZ, SuperString *lhsP0 = NULL, bool from_endB = false) {
		SuperString		rhs;
		bool			splitB = Split(splitZ, &rhs, from_endB);
		
		if (splitB) {
			if (lhsP0) {
				lhsP0->Set(*this);
			}
			
			Set(rhs);
		}
		
		return splitB;
	}
	
	bool	Split(const char *splitZ, SuperString *rhsP0 = NULL, bool from_endB = false);
	
	SuperString	&pop_back(UInt32 numCharsL = 1);
	
	OSType	&pop_ext(OSType *extP) const;
	
	OSType	get_ext() const {
		OSType		ext;
		
		pop_ext(&ext);
		return ext;
	}
	
	SuperString	&pop_ext(SuperString *extP0 = NULL) {
		ustring				ustr(utf8());
		const unsigned char	*dotP;
		
		dotP = uc(strrchr(utf8Z(), '.'));
		
		if (dotP) {
			if (extP0) {
				extP0->Set(dotP);
			}
			
			ustr.resize(ustr.size() - strlen((char *)dotP));
			
			Set(ustr);
		}
		
		return *this;
	}
	
	/******************************/
	SuperString		&resize(long num_utf8_charsL) {
		ustring		ustr(utf8());
		
		ustr.resize(num_utf8_charsL);
		Set(ustr);
		return *this;
	}
	
	SuperString		&append(const ustring &other) {
		Set(utf8() + other);
		return *this;
	}
	
	SuperString		&append(SuperString &other) {
		return append(other.utf8());
	}
	
	SuperString		&append(CFStringRef myRef) {
		return append(SuperString(myRef).utf8());
	}
	
	SuperString		&append(const char *other) {
		return append(SuperString(other).utf8());
	}
	
	SuperString		&append(long valueL)
	{
		char	bufAC[32];
		
		::sprintf(bufAC, "%ld", valueL);
		return append(bufAC);
		//		std::string		strStr;
		
		//		return append(NumToCString(valueL, strStr));
	}
	
	SuperString		&append(float valueF, short precS = 1)
	{
		char	bufAC[32];
		
		CopyFloatToC(valueF, bufAC, precS);
		return append(bufAC);
	}
	
	/****************************/
	SuperString		&prepend(const ustring &other) {
		Set(other + utf8());
		return *this;
	}
	
	SuperString		&prepend(SuperString &other) {
		return prepend(other.utf8());
	}
	
	SuperString		&prepend(const char *other) {
		return prepend(SuperString(other).utf8());
	}
	
	SuperString		&prepend(long valueL) {
		char	bufAC[32];
		
		::sprintf(bufAC, "%.2ld", valueL);
		return prepend(bufAC);
	}
	
	OSType			GetAsOSType() const	{	return CharToOSType(utf8Z());	}
	SuperString		&Ascii();
	SuperString		&Localize();
};

SuperString		operator+(const SuperString &lhs, SuperString rhs);

char			*OSTypeToChar(OSType osType, char *bufZ);
SuperString		OSTypeToString(OSType osType);

/*****************************************************/
//	dictionary, array, xml iterators
class	CDictionaryIterator {
	CFDictionaryRef		i_dict;
	
	static	void 	CB_S_Operator(const void *key, const void *value, void *context) {
		CDictionaryIterator		*thiz = (CDictionaryIterator *)context;
		
		thiz->operator()((CFStringRef)key, value);
	}
	
public:
	CDictionaryIterator(CFDictionaryRef dict) : i_dict(dict) { }
	
	void	for_each() {
		CFDictionaryApplyFunction(i_dict, CB_S_Operator, this);
	}
	
	virtual void	operator()(CFStringRef key, const void *value) {
		
	}
};

template <class Function>
class CDict_ForEach : public CDictionaryIterator {
	Function		i_f;
	
public: CDict_ForEach(CFDictionaryRef dict, Function f) : CDictionaryIterator(dict), i_f(f) { }
	
	void	operator()(CFStringRef keyRef, const void *valRef) {
		i_f(keyRef, valRef);
	}
};

template <class Function>
inline	void	dict_for_each(CFDictionaryRef dict, Function f)
{
	if (dict) {
		CDict_ForEach<Function>		cdict(dict, f);
		
		cdict.for_each();
	}
}

#define		CFArrayApplyFunctionToAll(_array, _cb, _data) \
	CFArrayApplyFunction((CFArrayRef)_array, CFRangeMake(0, CFArrayGetCount((CFArrayRef)_array)), _cb, _data)

class	CArrayIterator {
	CFArrayRef		i_array;
	
	static	void 	CB_S_Operator(const void *value, void *context) {
		CArrayIterator		*thiz = (CArrayIterator *)context;
		
		thiz->operator()(value);
	}
	
	public:
	CArrayIterator(CFArrayRef array) : i_array(array) { }
	
	void	for_each() {
		CFArrayApplyFunctionToAll(i_array, CB_S_Operator, this);
	}
	
	virtual void	operator()(const void *value) { }
};

template <class Function>
class CArray_ForEach : public CArrayIterator {
	Function		i_f;
	
	public: CArray_ForEach(CFArrayRef dict, Function f) : CArrayIterator(dict), i_f(f) { }
	
	void	operator()(CFTypeRef valRef) {
		i_f(valRef);
	}
};

template <class Function>
inline	void	array_for_each(CFArrayRef array, Function f)
{
	if (array) {
		CArray_ForEach<Function>		carray(array, f);
		
		carray.for_each();
	}
}

template <class Function>
void		xml_for_each(CFXMLTreeRef xmlTree, Function f, short levelS = 0)
{
	CFXMLNodeRef    xmlNode;
	long			sizeL = CFTreeGetChildCount(xmlTree);
	
	loop (sizeL) {
		CFTreeRef	xmlTreeNode = CFTreeGetChildAtIndex(xmlTree, _indexS);
		xmlNode = CFXMLTreeGetNode(xmlTreeNode);
		f(xmlNode, levelS);
		xml_for_each(xmlTreeNode, f, levelS + 1);
	}
}

/*****************************************************/
//	logging
class CCFLog {
	bool	i_crB;
	
	public: 
	CCFLog(bool crB = false) : i_crB(crB) { }
	
	void operator()(CFTypeRef valRef);
	void operator()(CFStringRef keyRef, CFTypeRef valRef);
};

#endif