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