CFLite/CFTest/SuperString.cpp

From kJams Wiki
Revision as of 07:22, 29 June 2008 by Dave (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
/*
 *  SuperString.cpp
 *  CFTest
 *
 *  Created by David M. Cotter on 6/25/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "SuperString.h"

char*	strrstr(const char* stringZ, const char* findZ)
{
	bool	firstB = true, doneB = false;
	char	*nextZ;
	
	do {
		if (firstB) {
			nextZ = strstr(stringZ, findZ);
		} else {
			nextZ = strstr(&stringZ[1], findZ);
		}
		
		doneB = nextZ == NULL;
		
		if (!doneB) {
			stringZ = nextZ;
		} else if (firstB) {
			stringZ = NULL;
		}
		
		firstB = false;		
	} while (!doneB);
	
	return const_cast<char *>(stringZ);
}

static const char *		CopyLongToC(long valL)
{
	static	char	s_bufAC[256];
	
	sprintf(s_bufAC, "%d", valL);
	return s_bufAC;
}

float			CStringToFloat(const char *numF)
{
	float	valF = 0;
	
	sscanf(numF, "%f", &valF);
	return valF;
}

class Asciify {
public: void operator()(char &ch) {
	if (ch < 32 || ch > 126) ch = '?';
}
};

/********************************************************/
bool		CFStringIsEmpty(CFStringRef nameRef)
{
	return nameRef == NULL || CFStringEqual(nameRef, CFSTR(""));
}

static CFStringEncoding	ValidateEncoding(CFStringEncoding encoding = kCFStringEncodingInvalidId)
{
	if (encoding == kCFStringEncodingInvalidId) {
		encoding = kSourceFileEncoding;
	}
	
	return encoding;
}

CFStringRef		CFStringCreateWithC(
									const char *		bufZ, 
									CFStringEncoding	encoding)
{
	if (bufZ) {
		encoding = ValidateEncoding(encoding);
		
		CFStringRef		cf = NULL;
		
		cf = CFStringCreateWithCString(kCFAllocatorDefault, bufZ, encoding);
		if (!cf) cf = CFStringCreateWithCString(kCFAllocatorDefault, bufZ, kCFStringEncodingWindowsLatin1);
		if (!cf) cf = CFStringCreateWithCString(kCFAllocatorDefault, bufZ, kCFStringEncodingISOLatin1);
		if (!cf) cf = CFStringCreateWithCString(kCFAllocatorDefault, bufZ, kCFStringEncodingMacRoman);
		
		CF_ASSERT(cf);
		if (!cf) return NULL;
		
		return (CFStringRef)CFRetainDebug(cf, false);
	} else {
		return (CFStringRef)CFRetainDebug(CFSTR(""));
	}
}

CFStringRef		CFStringCreateWithCu(
									 const UTF8Char *	bufZ, 
									 CFStringEncoding	encoding)
{
	return CFStringCreateWithC((const char *)bufZ, encoding);
}

static	inline CFRange		CFStrGetRange(CFStringRef ref)
{
	return CFRangeMake(0, CFStringGetLength(ref));
}

ustring		&CopyCFStringToUString(CFStringRef str, ustring &result, CFStringEncoding encoding, bool externalB)
{
	result.clear();
	
	if (str) {
		#define						kBufSize		256
		UTF8Char					utf8Buf[kBufSize];
		CFRange						cfRange = CFStrGetRange(str);
		CFIndex						resultSize;
		CFIndex						numChars;
		
		encoding = ValidateEncoding(encoding);
		
		while (cfRange.length > 0) {
			
			numChars = CFStringGetBytes(
										str, cfRange, encoding, '?', externalB, 
										&utf8Buf[0], kBufSize, &resultSize);
			
			if (numChars == 0) break;   // Failed to convert anything...
			
			result.append(&utf8Buf[0], &utf8Buf[resultSize]);
			
			cfRange.location	+= numChars;
			cfRange.length		-= numChars;
		}
	}
	
	return result;
}

std::string		&CopyCFStringToStd(
								   CFStringRef			str, 
								   std::string			&stdstr, 
								   CFStringEncoding	encoding)
{
	stdstr.clear();
	
	encoding = ValidateEncoding(encoding);
	
	if (str) {
		const char	*charZ = CFStringGetCStringPtr(str, encoding);
		
		if (charZ) {
			stdstr = charZ;
		} else {
			ustring		ustr;
			
			CopyCFStringToUString(str, ustr, encoding);
			stdstr.append(ustr.begin(), ustr.end());
		}
	}
	
	return stdstr;
}

//	you should provide this function.  stubbed out here because my CF doesn't have it
#define		CFStringTransform(a, b, c, d)	true

SuperString&		SuperString::Normalize()
{
	ScCFReleaser<CFMutableStringRef>	str1;

	str1.Set(CFStringCreateMutableCopy(kCFAllocatorDefault, 0, ref()));
	
	CFStringNormalize(str1, kCFStringNormalizationFormD);
		
	CFRange		range = CFStrGetRange(str1);
	
	if (CFStringTransform(str1, &range, kCFStringTransformStripCombiningMarks, false)) {
		Set(str1);
	}

//	void CFStringFold(CFMutableStringRef theString, CFOptionFlags theFlags, CFLocaleRef theLocale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;

	return *this;
}

	
void		CFStrReplaceWith(CFMutableStringRef stringRef, CFStringRef replaceStr, CFStringRef withStr)
{
	ScCFReleaser<CFArrayRef>	arrayRef;
	
	arrayRef.Set(CFStringCreateArrayWithFindResults(
													NULL, stringRef, replaceStr, CFStrGetRange(stringRef), kCFCompareCaseInsensitive));
	
	if (arrayRef.Get()) {
		CFRange			*rangeRef;
		
		loop_reverse (CFArrayGetCount(arrayRef)) {
			rangeRef = (CFRange *)CFArrayGetValueAtIndex(arrayRef, _indexS);
			CFStringReplace(stringRef, *rangeRef, withStr);
		}
	}
}

bool	g_pref_diacritic_insensitive_searchB = true;

static CFOptionFlags		GetFlags_NormalizeStrings(
	SuperString&	str1, 
	SuperString&	str2, 
	CFOptionFlags	optionFlags = 0
		| kCFCompareNonliteral 
		| kCFCompareLocalized)
{
	if (g_pref_diacritic_insensitive_searchB) {
		static	bool	s_diacritic_compare_inittedB = false;
		static	bool	s_has_diacritic_insensitive_compareB;
		
		if (!s_diacritic_compare_inittedB) {
		
			#if defined(__WIN32__)
				SuperString		str_e("e");
				UInt32			e_grave(CFSwapInt32HostToBig(0xC3A90000));
				SuperString		str_e_grave((UInt8*)&e_grave);
				
				s_has_diacritic_insensitive_compareB = ::CFStringCompare(
					str_e.ref(), str_e_grave.ref(), (CFOptionFlags)kCFCompareDiacriticInsensitive)
					== kCFCompareEqualTo;
			#else
				s_has_diacritic_insensitive_compareB = true;	//	GetSystemVers() >= 0x1050;
			#endif
			
			s_diacritic_compare_inittedB = true;
		}
		
		if (s_has_diacritic_insensitive_compareB) {
			optionFlags |= (CFOptionFlags)(0
				| kCFCompareDiacriticInsensitive
				| kCFCompareWidthInsensitive);
		} else {
			str1.Normalize();
			str2.Normalize();
		}
	}
	
	return optionFlags;
}

bool					CFStringContains(CFStringRef inRef, CFStringRef findRef, bool case_sensitiveB)
{
	if (inRef == NULL || findRef == NULL) {
		return false;
	}
	
	SuperString		str1(inRef), str2(findRef);
	CFOptionFlags	optionFlags = case_sensitiveB ? kCFCompareCaseInsensitive : 0;
	
	optionFlags = GetFlags_NormalizeStrings(str1, str2, optionFlags);
	
	return !!CFStringFindWithOptions(str1.ref(), str2.ref(), CFStrGetRange(str1.ref()), optionFlags, NULL);
}

CFComparisonResult		CFStringCompare(CFStringRef ref1, CFStringRef ref2, bool case_sensitiveB)
{
	CFComparisonResult		compareResult = kCFCompareEqualTo;
	
	if (ref1 == NULL || ref2 == NULL) {
		
		if (ref1 == NULL ^ ref2 == NULL) {
			if (ref1) {
				compareResult = kCFCompareLessThan;
			} else {
				compareResult = kCFCompareGreaterThan;
			}
		}
	} else {
		SuperString		str1(ref1), str2(ref2);
		CFOptionFlags	optionFlags = case_sensitiveB ? 0 : kCFCompareCaseInsensitive;
		
		optionFlags = GetFlags_NormalizeStrings(str1, str2, optionFlags);
		compareResult = ::CFStringCompare(str1.ref(), str2.ref(), optionFlags);
	}
	
	return compareResult;
}

bool		CFStringEqual(CFStringRef str1, CFStringRef str2, bool case_sensitiveB)
{
	return CFStringCompare(str1, str2, case_sensitiveB) == kCFCompareEqualTo;
}

bool		CFStringLess(CFStringRef lhs, CFStringRef rhs, bool case_sensitiveB)
{
	bool	lessB = CFStringCompare(lhs, rhs, case_sensitiveB) == kCFCompareLessThan;
	
	return lessB;
}

SuperString		operator+(const SuperString &lhs, SuperString rhs)
{
	SuperString		str(lhs);
	
	str.append(rhs);
	return str;
}

static  void		mt_vsnprintf(char *destZ, size_t sizeL, const char *formatZ, va_list &args)
{
	vsnprintf(destZ, sizeL - 1, formatZ, args);
	destZ[sizeL - 1] = 0;
}

SuperString&	SuperString::ssprintf(const char *formatZ0, ...)
{
	CharVec		buf(2048);
	va_list		args;
	
	CF_ASSERT(utf8().size() < 1024);
	va_start(args, formatZ0);
	mt_vsnprintf(&buf[0], buf.size(), formatZ0 ? formatZ0 : utf8Z(), args);
	va_end(args);
	
	Set(uc(&buf[0]));
	return *this;
}

void	SuperString::Set_CFType(CFTypeRef cfType)
{
	CFTypeID						cfTypeID(CFGetTypeID(cfType));
	
	if (cfTypeID == CFStringGetTypeID()) {
		Set((CFStringRef)cfType);
	} else {
		ScCFReleaser<CFStringRef>		descIDRef(CFCopyTypeIDDescription(cfTypeID));
		ScCFReleaser<CFStringRef>		descRef(CFCopyDescription(cfType));
		SuperString						descIDStr(descIDRef.Get()), descStr(descRef.Get());
		SuperString						logStr("Type: " kLeftQuote "%s" kRightQuote ", Value: " kLeftQuote "%s" kRightQuote);
		
		logStr.ssprintf(NULL, descIDStr.utf8Z(), descStr.utf8Z());
		Set(logStr);
	}
}

int		AssertAlert(const char *msgZ, const char *fileZ, long lineL, bool noThrowB)
{
	SuperString		formatStr("$$$ Assert Fail: %s, in file: '%s' at line %ld");
	
	formatStr.ssprintf(NULL, msgZ, fileZ, lineL);
	CFLog()(formatStr.ref());
	return 1;
}

bool	Read_PList(const CFURLRef &url, CFDictionaryRef *plistP)
{
	bool						successB = false;
	ScCFReleaser<CFDataRef>     xmlData;
	
	*plistP = NULL;
	
	if (CFURLCreateDataAndPropertiesFromResource(
		kCFAllocatorDefault, url, xmlData.AddressOf(), NULL, NULL, NULL)
	) {
		//Log("created xml from file");
		
		*plistP = (CFDictionaryRef)CFPropertyListCreateFromXMLData(
			kCFAllocatorDefault,
			xmlData,
			kCFPropertyListImmutable,
			NULL);
		
		successB = *plistP != NULL;
		
		if (successB) {
			//	Log("created plist from xml");
		} else {
			printf("FAILED converting xml to plist");
		}
	} else {
		printf("FAILED creating xml from file");
	}
	
	return successB;
}

#define noErr	0

OSStatus		Write_PList(
	CFPropertyListRef	plist,
	CFURLRef			urlRef)
{
	OSStatus							err	= noErr;
	ScCFReleaser<CFDataRef>				xmlData;
	
	// Convert the property list into XML data.
	xmlData.Set(CFPropertyListCreateXMLData(kCFAllocatorDefault, plist));
	ETRL(xmlData.Get() == NULL, "creating xml data");
	
	if (!err) {
		(void)CFURLWriteDataAndPropertiesToResource (
			urlRef,		// URL to use
			xmlData,		// data to write
			NULL,   
			&err);
	}
	
	ETRL(err, "writing xml");
	
	return err;
}

void		LogErr(const char *utf8Z, OSStatus err, bool crB, bool unixB)
{
	if (err) {	//	&& gApp->Logging()) {
		SuperString		str(uc(utf8Z));
		
		str.append(": ");
		str.append((long)err);
		if (crB) {
			str.append("\n");
		}
		
		printf(str.consoleZ());
	}
}