/*
* SuperString.cpp
* CFTest
*
* Created by David M. Cotter on 6/25/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
//#include "stdafx.h"
#include "SuperString.h"
void CCFLog::operator()(CFTypeRef valRef) {
#if 1
SuperString valStr; valStr.Set_CFType(valRef);
FILE *log_fileP = stdout;
#if defined(__WIN32__)
#ifndef __MWERKS__ // NOT using Metrowerks?
// GUI APP
static FILE *s_logP = NULL;
if (s_logP == NULL) {
#if defined(__MWERKS__) // using Metrowerks?
s_logP = fopen("log.txt", "a");
#else
(void)fopen_s(&s_logP, "log.txt", "a");
#endif
}
log_fileP = s_logP;
#endif
#endif
fprintf(log_fileP, "%s%s", valStr.consoleZ(), i_crB ? "\n" : "");
fflush(log_fileP);
#else
fflush(stdout);
CFShow(valRef);
if (i_crB) {
printf("\n");
}
fflush(stdout);
#endif
}
char* strrstr(const char* stringZ, const char* findZ)
{
bool firstB = true, doneB = false;
const 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);
}
}
}
#ifndef __WIN32__
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
enum {
kCFCompareDiacriticInsensitive = 128, /* If specified, ignores diacritics (o-umlaut == o) */
kCFCompareWidthInsensitive = 256, /* If specified, ignores width differences ('a' == UFF41) */
kCFCompareForcedOrdering = 512 /* If specified, comparisons are forced to return either kCFCompareLessThan or kCFCompareGreaterThan if the strings are equivalent but not strictly equal, for stability when sorting (e.g. "aaa" > "AAA" with kCFCompareCaseInsensitive specified) */
};
ushort GetSystemVers(void);
#else
ushort GetSystemVers(void) {
return 0x1050; // fake it to be OS 10.5
}
#endif
#endif
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 = 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;
}
SuperString & SuperString::pop_back(UInt32 numCharsL)
{
ustring ustr(utf8());
if (!ustr.empty()) {
ustr.resize(ustr.size() - numCharsL);
Set(ustr.c_str());
}
return *this;
}
#ifdef __WIN32__
#if defined(__MWERKS__)
class CIsZero {
public: bool operator()(const wchar_t& ch) {
return ch == 0;
}
};
static size_t wcslen(const wchar_t *wcharZ)
{
const wchar_t* it(std::find_if(&wcharZ[0], &wcharZ[512], CIsZero()));
return std::distance(&wcharZ[0], it);
}
#endif
SuperString::SuperString(const wchar_t *wcharZ)
{
UTF16Vec vec((UTF16Char *)&wcharZ[0], (UTF16Char *)&wcharZ[wcslen(wcharZ)]);
SetNULL();
Set(vec);
}
#endif
void SuperString::Set_p(ConstStr255Param strZ)
{
CharVec charVec;
charVec.assign(&strZ[1], &strZ[strZ[0] + 1]);
charVec.push_back(0);
Set(&charVec[0]);
}
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\n");
formatStr.ssprintf(NULL, msgZ, fileZ, lineL);
CCFLog()(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 {
CCFLog()("FAILED converting xml to plist\n");
}
} else {
CCFLog()("FAILED creating xml from file\n");
}
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);
CCFLog(crB)(str.ref());
}
}