CFLite/CFTest/SuperString.cpp
Jump to navigation
Jump to search
/*
* SuperString.cpp
* CFTest
*
* Created by David M. Cotter on 6/25/08.
* Copyright 2008 David M. Cotter. All rights reserved.
*
*/
#include "stdafx.h"
#ifndef KJAMS
#include "SuperString.h"
#else
#include "CApp.h"
#include "CPreferences.h"
#include "StringUtils.h"
#include "MessageAlert.h"
#endif
void CCFLog::operator()(CFTypeRef valRef) {
#if 1
SuperString valStr; valStr.Set_CFType(valRef);
FILE *log_fileP = stdout;
if (i_crB) {
valStr.append("\n");
}
#if defined(__WIN32__)
#ifdef __MWERKS__
// console app
static HANDLE consoleH = NULL;
if (!consoleH) {
consoleH = GetStdHandle(STD_OUTPUT_HANDLE);
}
unsigned long outL;
WriteConsoleW(consoleH, valStr.w_str(), valStr.uni().i_lengthL, &outL, NULL);
log_fileP = NULL;
#else
// GUI APP
static FILE *s_logP = NULL;
if (s_logP == NULL) {
(void)fopen_s(&s_logP, "log.txt", "a");
}
log_fileP = s_logP;
#endif
#endif
if (log_fileP) {
#ifdef KJAMS
Log(valStr.utf8Z(), false);
#else
fprintf(log_fileP, "%s", valStr.utf8Z());
fflush(log_fileP);
#endif
}
#else
fflush(stdout);
CFShow(valRef);
if (i_crB) {
printf("\n");
}
fflush(stdout);
#endif
}
void CCFLog::operator()(CFStringRef keyRef, CFTypeRef valRef) {
SuperString keyStr(keyRef);
keyStr.append(": ");
{
bool wasB = i_crB;
i_crB = false;
operator()(keyStr.ref());
i_crB = wasB;
}
operator()(valRef);
}
#ifndef KJAMS
void LogErr(const char *utf8Z, OSStatus err, bool crB, bool unixB)
{
if (err) { // && gApp->Logging()) {
SuperString keyStr(uc(utf8Z));
SuperString valStr((long)err);
CCFLog logger(crB);
logger(keyStr.ref(), valStr.ref());
}
}
#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);
}
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(""));
}
CFStringEncoding s_file_encoding = kCFStringEncodingInvalidId;
void SetDefaultEncoding(CFStringEncoding encoding)
{
s_file_encoding = encoding;
}
static CFStringEncoding ValidateEncoding(CFStringEncoding encoding = kCFStringEncodingInvalidId)
{
if (encoding == kCFStringEncodingInvalidId) {
encoding = s_file_encoding;
CF_ASSERT(encoding != kCFStringEncodingInvalidId);
}
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;
}
char *OSTypeToChar(OSType osType, char *bufZ)
{
osType = CFSwapInt32HostToBig(osType);
*((OSType *)bufZ) = osType;
bufZ[4] = 0;
return bufZ;
}
SuperString OSTypeToString(OSType osType)
{
SuperString str;
if (osType == -1) {
str.Set("-");
} else {
char bufAC[5];
str.Set(OSTypeToChar(osType, bufAC));
}
return str;
}
OSType CharToOSType(const char *bufZ)
{
OSType osType;
short lenL = strlen(bufZ);
osType = *((OSType *)(&bufZ[lenL - 4]));
osType = CFSwapInt32BigToHost(osType);
return osType;
}
// 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) */
};
#endif
#endif
#ifdef KJAMS
ushort GetSystemVers(void);
#define diacritic_insensitiveB (gApp && gApp->i_prefs && gApp->i_prefs->i_pref.diacritic_insensitive_searchB)
#else
bool g_pref_diacritic_insensitive_searchB = true;
#define diacritic_insensitiveB g_pref_diacritic_insensitive_searchB
#ifdef _ROSE_
unsigned short GetSystemVers(void);
#else
static unsigned short GetSystemVers(void) {
return 0x1050; // fake it to be OS 10.5
}
#endif
#endif
static CFOptionFlags GetFlags_NormalizeStrings(
SuperString& str1,
SuperString& str2,
CFOptionFlags optionFlags = 0
| kCFCompareNonliteral
| kCFCompareLocalized)
{
if (diacritic_insensitiveB) {
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;
}
#ifndef KJAMS
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;
}
#endif
bool SuperString::Split(const char *splitZ, SuperString *rhsP0, bool from_endB)
{
bool splitB;
if (from_endB) {
splitB = strrstr(utf8Z(), splitZ) != NULL;
} else {
splitB = strstr(utf8Z(), splitZ) != NULL;
}
if (splitB) {
UCharVec bufAC;
bufAC.assign(utf8().begin(), utf8().end());
bufAC.push_back(0);
UTF8Char *chZ;
if (from_endB) {
chZ = (UTF8Char *)strrstr((char *)&bufAC[0], (char *)splitZ);
} else {
chZ = (UTF8Char *)strstr((char *)&bufAC[0], (char *)splitZ);
}
SuperString temp(chZ + strlen(splitZ));
*chZ = 0;
Set(&bufAC[0]);
if (rhsP0) {
rhsP0->Set(temp);
}
}
return splitB;
}
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, CFStringEncoding encoding)
{
UCharVec charVec;
charVec.assign(&strZ[1], &strZ[strZ[0] + 1]);
charVec.push_back(0);
Set(&charVec[0], encoding);
}
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: <%s>, Value: <%s>");
logStr.ssprintf(NULL, descIDStr.utf8Z(), descStr.utf8Z());
Set(logStr);
}
}
#ifndef KJAMS
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;
}
#endif
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;
}
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;
}