/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ /***************************************************************************** * * $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtStr.cpp * ***/ #include "../Pch.h" #pragma hdrstop /***************************************************************************** * * Private data * ***/ // These random values were generated by the radioactive decay based // random number generator at www.fourmilab.ch static dword s_hashValue[] = { 0xc30d2a72, 0x15efaec1, 0xd250c7d9, 0xaf3c60a8, 0x9608ae8f, 0x452c0e11, 0xb6840ffd, 0x3e36c913, 0x2864eace, 0x9b0a17d6, 0x108da74b, 0xf2c479c1, 0x8b4dd597, 0x97199bc0, 0x621f0cce, 0x1658553e, }; /**************************************************************************** * * Internal functions * ***/ //=========================================================================== template static chartype * IStrDup (const chartype str[]) { unsigned chars = IStrLen(str) + 1; chartype * buffer = (chartype *)ALLOC(chars * sizeof(chartype)); IStrCopy(buffer, str, chars); return buffer; } //=========================================================================== template static chartype * IStrDupLen (const chartype str[], unsigned chars) { unsigned len = IStrLen(str) + 1; if (len > chars) len = chars; chartype * buffer = (chartype *)ALLOC(len * sizeof(chartype)); IStrCopy(buffer, str, len); return buffer; } //=========================================================================== template static chartype * IStrChr (chartype * str, findchartype ch, unsigned chars) { for (; chars--; ++str) if (*str == ch) return str; else if (!*str) break; return nil; } //=========================================================================== template static chartype * IStrChrR (chartype * str, findchartype ch) { chartype * start = str; for (; *str; ++str) NULL_STMT; while (str-- > start) if (*str == ch) return str; return NULL; } //=========================================================================== static inline bool ICharUnicodeToUtf8 (char ** dest, const wchar * source[], unsigned destChars) { unsigned ch = *(*source)++; bool result = false; if (ch < 0x80) { if (destChars >= 1) { *(*dest)++ = (char)ch; result = true; } } else if (ch < 0x800) { if (destChars >= 2) { *(*dest)++ = (char)(0xc0 | (ch >> 6)); *(*dest)++ = (char)(0x80 | (ch & 0x3f)); result = true; } } else { if (destChars >= 3) { *(*dest)++ = (char)(0xe0 | (ch >> 12)); *(*dest)++ = (char)(0x80 | ((ch >> 6) & 0x3f)); *(*dest)++ = (char)(0x80 | (ch & 0x3f)); result = true; } } return result; } //=========================================================================== static inline void ICharUtf8ToUnicode (wchar ** dest, const char * source[]) { unsigned result, remaining; if ((**source & 0xf0) == 0xe0) { result = *(*source)++ & 0x0f; remaining = 2; } else if ((**source & 0xe0) == 0xc0) { result = *(*source)++ & 0x1f; remaining = 1; } else if ((**source & 0x80) == 0x00) { result = *(*source)++; remaining = 0; } else { // unsupported code sequence (>0xffff) ++(*source); return; } for (; remaining-- && *source; ++*source) if ((**source & 0xc0) == 0x80) result = (result << 6) | (**source & 0x3f); *(*dest)++ = (wchar)result; } //=========================================================================== template static unsigned IStrPrintfValidate (chartype * dest, unsigned count, int result) { if (!count) return 0; ASSERT(result <= (int)count); if ((result < 0) || (result == (int)count)) { dest[count - 1] = 0; return count - 1; } else return (unsigned)result; } //=========================================================================== template static int IStrCmp (const chartype str1[], const chartype str2[], unsigned chars) { for (; chars--; ++str1, ++str2) { if (*str1 != *str2) return (*str1 > *str2) ? 1 : -1; if (!*str1) return 0; } return 0; } //=========================================================================== template static int IStrCmpI (const chartype str1[], const chartype str2[], unsigned chars) { while (chars--) { chartype ch1 = CharLowerFast(*str1++); chartype ch2 = CharLowerFast(*str2++); if (ch1 != ch2) return (ch1 > ch2) ? 1 : -1; if (!ch1) return 0; } return 0; } //=========================================================================== template static void IStrCopy (chartype * dest, const chartype source[], unsigned chars) { while ((chars > 1) && ((*dest = *source++) != 0)) { --chars; ++dest; } if (chars) *dest = 0; } //=========================================================================== // returns StrLen(dest) template static unsigned IStrCopyLen (chartype * dest, const chartype source[], unsigned chars) { chartype * const start = dest; while ((chars > 1) && ((*dest = *source++) != 0)) { --chars; ++dest; } if (chars) *dest = 0; return dest - start; } //=========================================================================== template static void IStrPack (chartype * dest, const chartype source[], unsigned chars) { while ((chars > 1) && *dest) { --chars; ++dest; } while ((chars > 1) && ((*dest = *source++) != 0)) { --chars; ++dest; } if (chars) *dest = 0; } //=========================================================================== template static chartype * IStrStr (chartype source[], const chartype match[]) { if (!*match) return source; for (chartype * curr = source; *curr; ++curr) { chartype * s1 = curr; const chartype * s2 = match; while (*s1 && *s2 && *s1 == *s2) s1++, s2++; if (!*s2) return curr; } return nil; } //=========================================================================== template static chartype * IStrStrI (chartype source[], const chartype match[]) { if (!*match) return source; for (chartype * curr = source; *curr; ++curr) { chartype * s1 = curr; const chartype * s2 = match; while (*s1 && *s2 && (CharLowerFast(*s1) == CharLowerFast(*s2))) s1++, s2++; if (!*s2) return curr; } return nil; } //=========================================================================== template static unsigned IStrLen (const chartype str[]) { unsigned chars = 0; for (; *str++; ++chars) NULL_STMT; return chars; } //=========================================================================== template static void IStrLower (chartype * dest, unsigned chars) { while ((chars > 1) && ((*dest = CharLowerFast(*dest)) != 0)) { --chars; ++dest; } } //=========================================================================== template static void IStrLower (chartype * dest, const chartype source[], unsigned chars) { while ((chars > 1) && ((*dest = CharLowerFast(*source)) != 0)) { --chars; ++dest; ++source; } if (chars) *dest = 0; } //=========================================================================== template static dword IStrHash (const chartype str[], unsigned chars) { dword temp0 = 0xE2C15C9D; dword temp1 = 0x2170A28A; dword result = 0x325D1EAE; for (unsigned ch; chars-- && ((ch = (unsigned)*str) != 0); ++str) { temp0 = (temp0 << 3) ^ ch; temp1 += s_hashValue[temp0 & 0x0F]; result ^= temp0 + temp1; } return result; } //=========================================================================== template static dword IStrHashI (const chartype str[], unsigned chars) { dword temp0 = 0xE2C15C9D; dword temp1 = 0x2170A28A; dword result = 0x325D1EAE; for (unsigned ch; chars-- && ((ch = (unsigned)*str) != 0); ++str) { if ((ch >= 'a') && (ch <= 'z')) ch = ch + 'A' - 'a'; temp0 = (temp0 << 3) ^ ch; temp1 += s_hashValue[temp0 & 0x0F]; result ^= temp0 + temp1; } return result; } //=========================================================================== template static bool IStrTokenize (const chartype * source[], chartype * dest, unsigned chars, const chartype whitespace[], unsigned maxWhitespaceSkipCount) { // Skip past leading whitespace bool inQuotes = false; unsigned whitespaceSkipped = 0; while (**source && IStrChr(whitespace, **source, (unsigned)-1) && whitespaceSkipped < maxWhitespaceSkipCount) { inQuotes = (**source == '\"'); ++*source; ++whitespaceSkipped; if (inQuotes) break; } // Copy the token unsigned offset = 0; while (**source && ((inQuotes && (**source != '\"')) || !IStrChr(whitespace, **source, (unsigned)-1))) { if (offset + 1 < chars) dest[offset++] = **source; ++*source; } // Skip past the terminating quote if (inQuotes && (**source == '\"')) ++*source; // Null terminate the destination buffer if (chars) { ASSERT(offset < chars); dest[offset] = 0; } // Upon return, 'source' is guaranteed to point to the first character // following the returned token (and following any closing quotes) return (offset || inQuotes); } //=========================================================================== template static bool IStrTokenize (const chartype * source[], ARRAY(chartype) * destArray, const chartype whitespace[], unsigned maxWhitespaceSkipCount) { // Verify that the destination array is empty ASSERT(!destArray->Count()); // Skip past leading whitespace bool inQuotes = false; unsigned whitespaceSkipped = 0; while (**source && IStrChr(whitespace, **source, (unsigned)-1) && whitespaceSkipped < maxWhitespaceSkipCount) { inQuotes = (**source == '\"'); ++*source; ++whitespaceSkipped; if (inQuotes) break; } // Copy the token bool added = false; while (**source && ((inQuotes && (**source != '\"')) || !IStrChr(whitespace, **source, (unsigned)-1))) { destArray->Add(**source); added = true; ++*source; } // Skip past the terminating quote if (inQuotes && (**source == '\"')) ++*source; // Null terminate the destination array destArray->Add(0); // Upon return, 'source' is guaranteed to point to the first character // following the returned token (and following any closing quotes) return (added || inQuotes); } /**************************************************************************** * * Exported functions * ***/ //=========================================================================== char * StrDup (const char str[]) { return IStrDup(str); } //=========================================================================== wchar * StrDup (const wchar str[]) { return IStrDup(str); } //=========================================================================== char * StrDupLen (const char str[], unsigned chars) { return IStrDupLen(str, chars); } //=========================================================================== wchar * StrDupLen (const wchar str[], unsigned chars) { return IStrDupLen(str, chars); } //============================================================================ wchar * StrDupToUnicode (const char str[]) { unsigned bytes = StrBytes(str) * sizeof(wchar); wchar * dst = (wchar*)ALLOC(bytes); StrToUnicode(dst, str, bytes / sizeof(wchar)); return dst; } //============================================================================ char * StrDupToAnsi (const wchar str[]) { unsigned bytes = StrBytes(str) / sizeof(wchar); char * dst = (char*)ALLOC(bytes); StrToAnsi(dst, str, bytes); return dst; } //=========================================================================== unsigned StrBytes (const char str[]) { // includes space for terminator return (IStrLen(str) + 1) * sizeof(str[0]); } //=========================================================================== unsigned StrBytes (const wchar str[]) { // includes space for terminator return (IStrLen(str) + 1) * sizeof(str[0]); } //=========================================================================== char * StrChr (char * str, char ch, unsigned chars) { return IStrChr(str, ch, chars); } //=========================================================================== wchar * StrChr (wchar * str, wchar ch, unsigned chars) { return IStrChr(str, ch, chars); } //=========================================================================== const char * StrChr (const char str[], char ch, unsigned chars) { return IStrChr(str, ch, chars); } //=========================================================================== const wchar * StrChr (const wchar str[], wchar ch, unsigned chars) { return IStrChr(str, ch, chars); } //=========================================================================== char * StrChrR (char * str, char ch) { return IStrChrR(str, ch); } //=========================================================================== wchar * StrChrR (wchar * str, wchar ch) { return IStrChrR(str, ch); } //=========================================================================== const char * StrChrR (const char str[], char ch) { return IStrChrR(str, ch); } //=========================================================================== const wchar * StrChrR (const wchar str[], wchar ch) { return IStrChrR(str, ch); } //=========================================================================== unsigned StrPrintf (char * dest, unsigned count, const char format[], ...) { va_list argList; va_start(argList, format); int result = _vsnprintf((char *)dest, count, (const char *)format, argList); va_end(argList); return IStrPrintfValidate(dest, count, result); } //=========================================================================== unsigned StrPrintf (wchar * dest, unsigned count, const wchar format[], ...) { va_list argList; va_start(argList, format); int result = _vsnwprintf(dest, count, format, argList); va_end(argList); return IStrPrintfValidate(dest, count, result); } //=========================================================================== unsigned StrPrintfV (char * dest, unsigned count, const char format[], va_list args) { int result = _vsnprintf(dest, count, format, args); return IStrPrintfValidate(dest, count, result); } //=========================================================================== unsigned StrPrintfV (wchar * dest, unsigned count, const wchar format[], va_list args) { int result = _vsnwprintf(dest, count, format, args); return IStrPrintfValidate(dest, count, result); } //=========================================================================== int StrCmp (const char str1[], const char str2[], unsigned chars) { return IStrCmp(str1, str2, chars); } //=========================================================================== int StrCmp (const wchar str1[], const wchar str2[], unsigned chars) { return IStrCmp(str1, str2, chars); } //=========================================================================== int StrCmpI (const char str1[], const char str2[], unsigned chars) { return IStrCmpI(str1, str2, chars); } //=========================================================================== int StrCmpI (const wchar str1[], const wchar str2[], unsigned chars) { return IStrCmpI(str1, str2, chars); } //=========================================================================== void StrCopy (char * dest, const char source[], unsigned chars) { IStrCopy(dest, source, chars); } //=========================================================================== void StrCopy (wchar * dest, const wchar source[], unsigned chars) { IStrCopy(dest, source, chars); } //=========================================================================== unsigned StrCopyLen (char * dest, const char source[], unsigned chars) { return IStrCopyLen(dest, source, chars); } //=========================================================================== unsigned StrCopyLen (wchar * dest, const wchar source[], unsigned chars) { return IStrCopyLen(dest, source, chars); } //=========================================================================== void StrPack (char * dest, const char source[], unsigned chars) { IStrPack(dest, source, chars); } //=========================================================================== void StrPack (wchar * dest, const wchar source[], unsigned chars) { IStrPack(dest, source, chars); } //=========================================================================== char * StrStr (char * source, const char match[]) { return IStrStr(source, match); } //=========================================================================== const char * StrStr (const char source[], const char match[]) { return IStrStr(source, match); } //=========================================================================== wchar * StrStr (wchar * source, const wchar match[]) { return IStrStr(source, match); } //=========================================================================== const wchar * StrStr (const wchar source[], const wchar match[]) { return IStrStr(source, match); } //=========================================================================== char * StrStrI (char * source, const char match[]) { return IStrStrI(source, match); } //=========================================================================== const char * StrStrI (const char source[], const char match[]) { return IStrStrI(source, match); } //=========================================================================== wchar * StrStrI (wchar * source, const wchar match[]) { return IStrStrI(source, match); } //=========================================================================== const wchar * StrStrI (const wchar source[], const wchar match[]) { return IStrStrI(source, match); } //=========================================================================== unsigned StrLen (const char str[]) { return IStrLen(str); } //=========================================================================== unsigned StrLen (const wchar str[]) { return IStrLen(str); } //=========================================================================== unsigned StrUnicodeToUtf8 (char * dest, const wchar source[], unsigned destChars) { char * destCurr = dest; char * destTerm = dest + destChars; while (*source && (destCurr + 1 < destTerm)) if (!ICharUnicodeToUtf8(&destCurr, &source, destTerm - destCurr - 1)) break; if (destCurr < destTerm) *destCurr = 0; return destCurr - dest; // dest chars not including null terminator } //=========================================================================== unsigned StrUtf8ToUnicode (wchar * dest, const char source[], unsigned destChars) { wchar * destCurr = dest; wchar * destTerm = dest + destChars; while (*source && (destCurr + 1 < destTerm)) ICharUtf8ToUnicode(&destCurr, &source); if (destCurr < destTerm) *destCurr = 0; return destCurr - dest; // dest chars not including null terminator } //============================================================================ float StrToFloat (const char source[], const char ** endptr) { return (float) strtod(source, const_cast(endptr)); } //=========================================================================== float StrToFloat (const wchar source[], const wchar ** endptr) { return (float) wcstod(source, const_cast(endptr)); } //=========================================================================== int StrToInt (const char source[], const char ** endptr) { return strtol(source, const_cast(endptr), 0); } //=========================================================================== int StrToInt (const wchar source[], const wchar ** endptr) { return wcstol(source, const_cast(endptr), 0); } //=========================================================================== unsigned StrToUnsigned (char source[], char ** endptr, int radix) { return strtoul(source, const_cast(endptr), radix); } //=========================================================================== unsigned StrToUnsigned (wchar source[], wchar ** endptr, int radix) { return wcstoul(source, const_cast(endptr), radix); } //=========================================================================== unsigned StrToUnsigned (const char source[], const char ** endptr, int radix) { return strtoul(source, const_cast(endptr), radix); } //=========================================================================== unsigned StrToUnsigned (const wchar source[], const wchar ** endptr, int radix) { return wcstoul(source, const_cast(endptr), radix); } //=========================================================================== void StrLower (char * dest, unsigned chars) { IStrLower(dest, chars); } //=========================================================================== void StrLower (wchar * dest, unsigned chars) { IStrLower(dest, chars); } //=========================================================================== void StrLower (char * dest, const char source[], unsigned chars) { IStrLower(dest, source, chars); } //=========================================================================== void StrLower (wchar * dest, const wchar source[], unsigned chars) { IStrLower(dest, source, chars); } //============================================================================ dword StrHash (const char str[], unsigned chars) { return IStrHash(str, chars); } //=========================================================================== dword StrHash (const wchar str[], unsigned chars) { return IStrHash(str, chars); } //=========================================================================== dword StrHashI (const char str[], unsigned chars) { return IStrHashI(str, chars); } //=========================================================================== dword StrHashI (const wchar str[], unsigned chars) { return IStrHashI(str, chars); } //=========================================================================== bool StrTokenize (const char * source[], char * dest, unsigned chars, const char whitespace[], unsigned maxWhitespaceSkipCount) { return IStrTokenize(source, dest, chars, whitespace, maxWhitespaceSkipCount); } //=========================================================================== bool StrTokenize (const wchar * source[], wchar * dest, unsigned chars, const wchar whitespace[], unsigned maxWhitespaceSkipCount) { return IStrTokenize(source, dest, chars, whitespace, maxWhitespaceSkipCount); } //=========================================================================== bool StrTokenize (const char * source[], ARRAY(char) * destArray, const char whitespace[], unsigned maxWhitespaceSkipCount) { return IStrTokenize(source, destArray, whitespace, maxWhitespaceSkipCount); } //=========================================================================== bool StrTokenize (const wchar * source[], ARRAY(wchar) * destArray, const wchar whitespace[], unsigned maxWhitespaceSkipCount) { return IStrTokenize(source, destArray, whitespace, maxWhitespaceSkipCount); }