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; }