CFLite/CFTest/SuperString.h
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