#include "core/stdafx.h" #include "tier1/strtools.h" FORCEINLINE unsigned char tolower_fast(unsigned char c) { if ((c >= 'A') && (c <= 'Z')) return c + ('a' - 'A'); return c; } //----------------------------------------------------------------------------- // Finds a string in another string with a case insensitive test //----------------------------------------------------------------------------- char const* V_stristr(char const* pStr, char const* pSearch) { AssertValidStringPtr(reinterpret_cast(pStr)); AssertValidStringPtr(reinterpret_cast(pSearch)); if (!pStr || !pSearch) return 0; char const* pLetter = pStr; // Check the entire string while (*pLetter != 0) { // Skip over non-matches if (tolower_fast((unsigned char)*pLetter) == tolower_fast((unsigned char)*pSearch)) { // Check for match char const* pMatch = pLetter + 1; char const* pTest = pSearch + 1; while (*pTest != 0) { // We've run off the end; don't bother. if (*pMatch == 0) return 0; if (tolower_fast((unsigned char)*pMatch) != tolower_fast((unsigned char)*pTest)) break; ++pMatch; ++pTest; } // Found a match! if (*pTest == 0) return pLetter; } ++pLetter; } return 0; } char* V_stristr(char* pStr, char const* pSearch) { AssertValidStringPtr(reinterpret_cast(pStr)); AssertValidStringPtr(reinterpret_cast(pSearch)); return (char*)V_stristr((char const*)pStr, pSearch); } //----------------------------------------------------------------------------- // Finds a string in another string with a case insensitive test w/ length validation //----------------------------------------------------------------------------- const char* V_strnistr(const char* pStr, const char* pSearch, int64_t n) { Assert(pStr); Assert(pSearch); if (!pStr || !pSearch) return 0; const char* pLetter = pStr; // Check the entire string while (*pLetter != 0) { if (n <= 0) return 0; // Skip over non-matches if (FastASCIIToLower(*pLetter) == FastASCIIToLower(*pSearch)) { int n1 = n - 1; // Check for match const char* pMatch = pLetter + 1; const char* pTest = pSearch + 1; while (*pTest != 0) { if (n1 <= 0) return 0; // We've run off the end; don't bother. if (*pMatch == 0) return 0; if (FastASCIIToLower(*pMatch) != FastASCIIToLower(*pTest)) break; ++pMatch; ++pTest; --n1; } // Found a match! if (*pTest == 0) return pLetter; } ++pLetter; --n; } return 0; } const char* V_strnchr(const char* pStr, char c, int64_t n) { const char* pLetter = pStr; const char* pLast = pStr + n; // Check the entire string while ((pLetter < pLast) && (*pLetter != 0)) { if (*pLetter == c) return pLetter; ++pLetter; } return NULL; } bool V_isspace(int c) { // The standard white-space characters are the following: space, tab, carriage-return, newline, vertical tab, and form-feed. In the C locale, V_isspace() returns true only for the standard white-space characters. //return c == ' ' || c == 9 /*horizontal tab*/ || c == '\r' || c == '\n' || c == 11 /*vertical tab*/ || c == '\f'; // codes of whitespace symbols: 9 HT, 10 \n, 11 VT, 12 form feed, 13 \r, 32 space // easy to understand version, validated: // return ((1 << (c-1)) & 0x80001F00) != 0 && ((c-1)&0xE0) == 0; // 5% faster on Core i7, 35% faster on Xbox360, no branches, validated: #ifdef _X360 return ((1 << (c - 1)) & 0x80001F00 & ~(-int((c - 1) & 0xE0))) != 0; #else // this is 11% faster on Core i7 than the previous, VC2005 compiler generates a seemingly unbalanced search tree that's faster switch (c) { case ' ': case 9: case '\r': case '\n': case 11: case '\f': return true; default: return false; } #endif } //----------------------------------------------------------------------------- // Purpose: Converts a UTF8 string into a unicode string //----------------------------------------------------------------------------- int V_UTF8ToUnicode(const char* pUTF8, wchar_t* pwchDest, int cubDestSizeInBytes) { Assert(cubDestSizeInBytes >= sizeof(*pwchDest)); pwchDest[0] = 0; if (!pUTF8) return 0; #ifdef _WIN32 int cchResult = MultiByteToWideChar(CP_UTF8, 0, pUTF8, -1, pwchDest, cubDestSizeInBytes / sizeof(wchar_t)); #elif POSIX int cchResult = mbstowcs(pwchDest, pUTF8, cubDestSizeInBytes / sizeof(wchar_t)); #endif pwchDest[(cubDestSizeInBytes / sizeof(wchar_t)) - 1] = 0; return cchResult; } //----------------------------------------------------------------------------- // Purpose: Converts a unicode string into a UTF8 (standard) string //----------------------------------------------------------------------------- int V_UnicodeToUTF8(const wchar_t* pUnicode, char* pUTF8, int cubDestSizeInBytes) { if (cubDestSizeInBytes > 0) pUTF8[0] = 0; #ifdef _WIN32 int cchResult = WideCharToMultiByte(CP_UTF8, 0, pUnicode, -1, pUTF8, cubDestSizeInBytes, NULL, NULL); #elif POSIX int cchResult = 0; if (pUnicode && pUTF8) cchResult = wcstombs(pUTF8, pUnicode, cubDestSizeInBytes); #endif if (cubDestSizeInBytes > 0) pUTF8[cubDestSizeInBytes - 1] = 0; return cchResult; } //----------------------------------------------------------------------------- // Purpose: Changes all '/' or '\' characters into separator // Input : *pName - // cSeparator - //----------------------------------------------------------------------------- void V_FixSlashes(char* pName, char cSeperator /* = CORRECT_PATH_SEPARATOR */) { while (*pName) { if (*pName == INCORRECT_PATH_SEPARATOR || *pName == CORRECT_PATH_SEPARATOR) { *pName = cSeperator; } pName++; } }