/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code 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. IceTech Source Code 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 IceTech Source Code. If not, see . In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #ifndef __STR_H__ #define __STR_H__ /* =============================================================================== Character string =============================================================================== */ #ifdef QUAKE4 #ifdef _XENON class __declspec(align(16)) idVec4; #else class idVec4; #endif #else class idVec4; #endif #ifndef FILE_HASH_SIZE #define FILE_HASH_SIZE 1024 #endif // color escape character const int C_COLOR_ESCAPE = '^'; const int C_COLOR_DEFAULT = '0'; const int C_COLOR_RED = '1'; const int C_COLOR_GREEN = '2'; const int C_COLOR_YELLOW = '3'; const int C_COLOR_BLUE = '4'; const int C_COLOR_CYAN = '5'; const int C_COLOR_MAGENTA = '6'; const int C_COLOR_WHITE = '7'; const int C_COLOR_GRAY = '8'; const int C_COLOR_BLACK = '9'; #ifdef QUAKE4 const int C_COLOR_CONSOLE = ':'; #endif // color escape string #define S_COLOR_DEFAULT "^0" #define S_COLOR_RED "^1" #define S_COLOR_GREEN "^2" #define S_COLOR_YELLOW "^3" #define S_COLOR_BLUE "^4" #define S_COLOR_CYAN "^5" #define S_COLOR_MAGENTA "^6" #define S_COLOR_WHITE "^7" #define S_COLOR_GRAY "^8" #define S_COLOR_BLACK "^9" #ifdef QUAKE4 #define S_COLOR_CONSOLE "^:" #define S_COLOR_MARINE "^c683" #define S_COLOR_STROGG "^c950" #define S_COLOR_ALERT "^c920" #define I_VOICE_ENABLED "^ivce" #define I_VOICE_DISABLED "^ivcd" #define I_FRIEND_ENABLED "^ifde" #define I_FRIEND_DISABLED "^ifdd" #define I_FLAG_MARINE "^iflm" #define I_FLAG_STROGG "^ifls" #define I_READY "^iyrd" #define I_NOT_READY "^inrd" #define I_SERVER_DEDICATED "^ids0" #define I_SERVER_DEDICATED_PB "^idsp" #define I_SERVER_LOCKED "^isl0" #define I_SERVER_FAVORITE "^isf0" const int VA_BUF_LEN = 16384; const int VA_NUM_BUFS = 8; #endif // make idStr a multiple of 16 bytes long // don't make too large to keep memory requirements to a minimum const int STR_ALLOC_BASE = 20; const int STR_ALLOC_GRAN = 32; typedef enum { MEASURE_SIZE = 0, MEASURE_BANDWIDTH } Measure_t; #ifdef QUAKE4 // Raven string escape codes #define S_ESCAPE_UNKNOWN BIT(0) #define S_ESCAPE_COLOR BIT(1) #define S_ESCAPE_COLORINDEX BIT(2) #define S_ESCAPE_ICON BIT(3) #define S_ESCAPE_COMMAND BIT(4) #define S_ESCAPE_ALL ( S_ESCAPE_COLOR | S_ESCAPE_COLORINDEX | S_ESCAPE_ICON | S_ESCAPE_COMMAND ) #endif class idStr { public: idStr(void); idStr(const idStr& text); idStr(const idStr& text, int start, int end); idStr(const char* text); idStr(const char* text, int start, int end); explicit idStr(const bool b); explicit idStr(const char c); explicit idStr(const int i); explicit idStr(const unsigned u); explicit idStr(const float f); ~idStr(void); size_t Size(void) const; const char* c_str(void) const; operator const char* (void) const; operator const char* (void); char operator[](int index) const; char& operator[](int index); void operator=(const idStr& text); void operator=(const char* text); friend idStr operator+(const idStr& a, const idStr& b); friend idStr operator+(const idStr& a, const char* b); friend idStr operator+(const char* a, const idStr& b); friend idStr operator+(const idStr& a, const float b); friend idStr operator+(const idStr& a, const int b); friend idStr operator+(const idStr& a, const unsigned b); friend idStr operator+(const idStr& a, const bool b); friend idStr operator+(const idStr& a, const char b); idStr& operator+=(const idStr& a); idStr& operator+=(const char* a); idStr& operator+=(const float a); idStr& operator+=(const char a); idStr& operator+=(const int a); idStr& operator+=(const unsigned a); idStr& operator+=(const bool a); // case sensitive compare friend bool operator==(const idStr& a, const idStr& b); friend bool operator==(const idStr& a, const char* b); friend bool operator==(const char* a, const idStr& b); // case sensitive compare friend bool operator!=(const idStr& a, const idStr& b); friend bool operator!=(const idStr& a, const char* b); friend bool operator!=(const char* a, const idStr& b); // case sensitive compare int Cmp(const char* text) const; int Cmpn(const char* text, int n) const; int CmpPrefix(const char* text) const; // case insensitive compare int Icmp(const char* text) const; int Icmpn(const char* text, int n) const; int IcmpPrefix(const char* text) const; // case insensitive compare ignoring color int IcmpNoColor(const char* text) const; #ifdef QUAKE4 int IcmpNoEscape(const char* text) const; #endif // compares paths and makes sure folders come first int IcmpPath(const char* text) const; int IcmpnPath(const char* text, int n) const; int IcmpPrefixPath(const char* text) const; int Length(void) const; int Allocated(void) const; void Empty(void); bool IsEmpty(void) const; void Clear(void); void Append(const char a); void Append(const idStr& text); void Append(const char* text); void Append(const char* text, int len); void Insert(const char a, int index); void Insert(const char* text, int index); void ToLower(void); void ToUpper(void); bool IsNumeric(void) const; bool IsColor(void) const; bool HasLower(void) const; bool HasUpper(void) const; int LengthWithoutColors(void) const; idStr& RemoveColors(void); #ifdef QUAKE4 int IsEscape(int* type = NULL) const; int LengthWithoutEscapes(void) const; idStr& RemoveEscapes(int escapes = S_ESCAPE_ALL); #endif void CapLength(int); void Fill(const char ch, int newlen); int Find(const char c, int start = 0, int end = -1) const; int Find(const char* text, bool casesensitive = true, int start = 0, int end = -1) const; bool Filter(const char* filter, bool casesensitive = true) const; int Last(const char c) const; // return the index to the last occurance of 'c', returns -1 if not found const char* Left(int len, idStr& result) const; // store the leftmost 'len' characters in the result const char* Right(int len, idStr& result) const; // store the rightmost 'len' characters in the result const char* Mid(int start, int len, idStr& result) const; // store 'len' characters starting at 'start' in result idStr Left(int len) const; // return the leftmost 'len' characters idStr Right(int len) const; // return the rightmost 'len' characters idStr Mid(int start, int len) const; // return 'len' characters starting at 'start' void StripLeading(const char c); // strip char from front as many times as the char occurs void StripLeading(const char* string); // strip string from front as many times as the string occurs bool StripLeadingOnce(const char* string); // strip string from front just once if it occurs void StripTrailing(const char c); // strip char from end as many times as the char occurs void StripTrailing(const char* string); // strip string from end as many times as the string occurs bool StripTrailingOnce(const char* string); // strip string from end just once if it occurs void Strip(const char c); // strip char from front and end as many times as the char occurs void Strip(const char* string); // strip string from front and end as many times as the string occurs void StripTrailingWhitespace(void); // strip trailing white space characters #ifdef QUAKE4 void StripUntil(const char c); // strip until this character is reached or there is no string left #endif idStr& StripQuotes(void); // strip quotes around string #ifdef QUAKE4 int Replace(const char* old, const char* nw); #else void Replace(const char* old, const char* nw); #endif // file name methods int FileNameHash(void) const; // hash key for the filename (skips extension) idStr& BackSlashesToSlashes(void); // convert slashes #ifdef QUAKE4 idStr& SlashesToBackSlashes(void); // convert slashes bool HasChar(const char check); bool HasChars(const char* check); idStr& ReplaceChar(const char from, const char to); idStr& ReplaceChars(const char* from, const char to); #endif idStr& SetFileExtension(const char* extension); // set the given file extension idStr& StripFileExtension(void); // remove any file extension idStr& StripAbsoluteFileExtension(void); // remove any file extension looking from front (useful if there are multiple .'s) idStr& DefaultFileExtension(const char* extension); // if there's no file extension use the default idStr& DefaultPath(const char* basepath); // if there's no path use the default void AppendPath(const char* text); // append a partial path idStr& StripFilename(void); // remove the filename from a path idStr& StripPath(void); // remove the path from the filename void ExtractFilePath(idStr& dest) const; // copy the file path to another string void ExtractFileName(idStr& dest) const; // copy the filename to another string void ExtractFileBase(idStr& dest) const; // copy the filename minus the extension to another string void ExtractFileExtension(idStr& dest) const; // copy the file extension to another string bool CheckExtension(const char* ext); #ifdef QUAKE4 void ScrubFileName(void); // Turns a bad file name into a good one or your money back void MakeNameCanonical(void); void EnsurePrintable(void); void Split(idList& list, const char delimiter = ',', const char groupDelimiter = '\''); #endif // char * methods to replace library functions static int Length(const char* s); static char* ToLower(char* s); static char* ToUpper(char* s); static bool IsNumeric(const char* s); static bool IsColor(const char* s); static bool HasLower(const char* s); static bool HasUpper(const char* s); static int LengthWithoutColors(const char* s); static char* RemoveColors(char* s); #ifdef QUAKE4 static int IsEscape(const char* s, int* type = NULL); static int LengthWithoutEscapes(const char* s); static char* RemoveEscapes(char* s, int escapes = S_ESCAPE_ALL); #endif static int Cmp(const char* s1, const char* s2); static int Cmpn(const char* s1, const char* s2, int n); static int Icmp(const char* s1, const char* s2); static int Icmpn(const char* s1, const char* s2, int n); static int IcmpNoColor(const char* s1, const char* s2); #ifdef QUAKE4 static int IcmpNoEscape(const char* s1, const char* s2); #endif static int IcmpPath(const char* s1, const char* s2); // compares paths and makes sure folders come first static int IcmpnPath(const char* s1, const char* s2, int n); // compares paths and makes sure folders come first static void Append(char* dest, int size, const char* src); static void Copynz(char* dest, const char* src, int destsize); static int snPrintf(char* dest, int size, const char* fmt, ...) id_attribute((format(printf, 3, 4))); static int vsnPrintf(char* dest, int size, const char* fmt, va_list argptr); static int FindChar(const char* str, const char c, int start = 0, int end = -1); static int FindText(const char* str, const char* text, bool casesensitive = true, int start = 0, int end = -1); static bool Filter(const char* filter, const char* name, bool casesensitive); static void StripMediaName(const char* name, idStr& mediaName); static bool CheckExtension(const char* name, const char* ext); static const char* FloatArrayToString(const float* array, const int length, const int precision); // hash keys static int Hash(const char* string); static int Hash(const char* string, int length); static int IHash(const char* string); // case insensitive static int IHash(const char* string, int length); // case insensitive // character methods #ifdef QUAKE4 static char ToLower(byte c); static char ToUpper(byte c); static bool CharIsPrintable(byte c); static bool CharIsLower(byte c); static bool CharIsUpper(byte c); static bool CharIsAlpha(byte c); static bool CharIsNumeric(byte c); static bool CharIsNewLine(byte c); static bool CharIsTab(byte c); #else static char ToLower(char c); static char ToUpper(char c); static bool CharIsPrintable(int c); static bool CharIsLower(int c); static bool CharIsUpper(int c); static bool CharIsAlpha(int c); static bool CharIsNumeric(int c); static bool CharIsNewLine(char c); static bool CharIsTab(char c); #endif static int ColorIndex(int c); static idVec4& ColorForIndex(int i); friend int sprintf(idStr& dest, const char* fmt, ...); friend int vsprintf(idStr& dest, const char* fmt, va_list ap); void ReAllocate(int amount, bool keepold); // reallocate string data buffer void FreeData(void); // free allocated string memory // format value in the given measurement with the best unit, returns the best unit int BestUnit(const char* format, float value, Measure_t measure); // format value in the requested unit and measurement void SetUnit(const char* format, float value, int unit, Measure_t measure); static void InitMemory(void); static void ShutdownMemory(void); static void PurgeMemory(void); static void ShowMemoryUsage_f(const idCmdArgs& args); int DynamicMemoryUsed() const; static idStr FormatNumber(int number); #ifdef QUAKE4 static void Split(const char* source, idList& list, const char delimiter = ',', const char groupDelimiter = '\''); idStr GetLastColorCode(void) const; #endif protected: int len; char* data; int alloced; char baseBuffer[STR_ALLOC_BASE]; void Init(void); // initialize string using base buffer void EnsureAlloced(int amount, bool keepold = true); // ensure string data buffer is large anough #ifdef QUAKE4 public: static const bool printableCharacter[256]; static const char upperCaseCharacter[256]; static const char lowerCaseCharacter[256]; #endif }; char* va(const char* fmt, ...) id_attribute((format(printf, 1, 2))); #ifdef QUAKE4 char* fe(int errorId); #endif ID_INLINE void idStr::EnsureAlloced(int amount, bool keepold) { if (amount > alloced) { ReAllocate(amount, keepold); } } ID_INLINE void idStr::Init(void) { len = 0; alloced = STR_ALLOC_BASE; data = baseBuffer; data[0] = '\0'; #if defined( ID_DEBUG_UNINITIALIZED_MEMORY ) || ( defined( QUAKE4 ) && defined( ID_DEBUG_MEMORY ) ) memset(baseBuffer, 0, sizeof(baseBuffer)); #endif } ID_INLINE idStr::idStr(void) { Init(); } ID_INLINE idStr::idStr(const idStr& text) { int l; Init(); l = text.Length(); EnsureAlloced(l + 1); strcpy(data, text.data); len = l; } ID_INLINE idStr::idStr(const idStr& text, int start, int end) { int i; int l; Init(); if (end > text.Length()) { end = text.Length(); } if (start > text.Length()) { start = text.Length(); } else if (start < 0) { start = 0; } l = end - start; if (l < 0) { l = 0; } EnsureAlloced(l + 1); for (i = 0; i < l; i++) { data[i] = text[start + i]; } data[l] = '\0'; len = l; } ID_INLINE idStr::idStr(const char* text) { int l; Init(); if (text) { l = strlen(text); EnsureAlloced(l + 1); strcpy(data, text); len = l; } } ID_INLINE idStr::idStr(const char* text, int start, int end) { int i; int l = strlen(text); Init(); if (end > l) { end = l; } if (start > l) { start = l; } else if (start < 0) { start = 0; } l = end - start; if (l < 0) { l = 0; } EnsureAlloced(l + 1); for (i = 0; i < l; i++) { data[i] = text[start + i]; } data[l] = '\0'; len = l; } ID_INLINE idStr::idStr(const bool b) { Init(); EnsureAlloced(2); data[0] = b ? '1' : '0'; data[1] = '\0'; len = 1; } ID_INLINE idStr::idStr(const char c) { Init(); EnsureAlloced(2); data[0] = c; data[1] = '\0'; len = 1; } ID_INLINE idStr::idStr(const int i) { char text[64]; int l; Init(); l = sprintf(text, "%d", i); EnsureAlloced(l + 1); strcpy(data, text); len = l; } ID_INLINE idStr::idStr(const unsigned u) { char text[64]; int l; Init(); l = sprintf(text, "%u", u); EnsureAlloced(l + 1); strcpy(data, text); len = l; } ID_INLINE idStr::idStr(const float f) { char text[64]; int l; Init(); l = idStr::snPrintf(text, sizeof(text), "%f", f); while (l > 0 && text[l - 1] == '0') text[--l] = '\0'; while (l > 0 && text[l - 1] == '.') text[--l] = '\0'; EnsureAlloced(l + 1); strcpy(data, text); len = l; } ID_INLINE idStr::~idStr(void) { FreeData(); } ID_INLINE size_t idStr::Size(void) const { return sizeof(*this) + Allocated(); } ID_INLINE const char* idStr::c_str(void) const { return data; } ID_INLINE idStr::operator const char* (void) { return c_str(); } ID_INLINE idStr::operator const char* (void) const { return c_str(); } ID_INLINE char idStr::operator[](int index) const { assert((index >= 0) && (index <= len)); return data[index]; } ID_INLINE char& idStr::operator[](int index) { assert((index >= 0) && (index <= len)); return data[index]; } ID_INLINE void idStr::operator=(const idStr& text) { int l; l = text.Length(); EnsureAlloced(l + 1, false); memcpy(data, text.data, l); data[l] = '\0'; len = l; } ID_INLINE idStr operator+(const idStr& a, const idStr& b) { idStr result(a); result.Append(b); return result; } ID_INLINE idStr operator+(const idStr& a, const char* b) { idStr result(a); result.Append(b); return result; } ID_INLINE idStr operator+(const char* a, const idStr& b) { idStr result(a); result.Append(b); return result; } ID_INLINE idStr operator+(const idStr& a, const bool b) { idStr result(a); result.Append(b ? "true" : "false"); return result; } ID_INLINE idStr operator+(const idStr& a, const char b) { idStr result(a); result.Append(b); return result; } ID_INLINE idStr operator+(const idStr& a, const float b) { char text[64]; idStr result(a); sprintf(text, "%f", b); result.Append(text); return result; } ID_INLINE idStr operator+(const idStr& a, const int b) { char text[64]; idStr result(a); sprintf(text, "%d", b); result.Append(text); return result; } ID_INLINE idStr operator+(const idStr& a, const unsigned b) { char text[64]; idStr result(a); sprintf(text, "%u", b); result.Append(text); return result; } ID_INLINE idStr& idStr::operator+=(const float a) { char text[64]; sprintf(text, "%f", a); Append(text); return *this; } ID_INLINE idStr& idStr::operator+=(const int a) { char text[64]; sprintf(text, "%d", a); Append(text); return *this; } ID_INLINE idStr& idStr::operator+=(const unsigned a) { char text[64]; sprintf(text, "%u", a); Append(text); return *this; } ID_INLINE idStr& idStr::operator+=(const idStr& a) { Append(a); return *this; } ID_INLINE idStr& idStr::operator+=(const char* a) { Append(a); return *this; } ID_INLINE idStr& idStr::operator+=(const char a) { Append(a); return *this; } ID_INLINE idStr& idStr::operator+=(const bool a) { Append(a ? "true" : "false"); return *this; } ID_INLINE bool operator==(const idStr& a, const idStr& b) { return (!idStr::Cmp(a.data, b.data)); } ID_INLINE bool operator==(const idStr& a, const char* b) { assert(b); return (!idStr::Cmp(a.data, b)); } ID_INLINE bool operator==(const char* a, const idStr& b) { assert(a); return (!idStr::Cmp(a, b.data)); } ID_INLINE bool operator!=(const idStr& a, const idStr& b) { return !(a == b); } ID_INLINE bool operator!=(const idStr& a, const char* b) { return !(a == b); } ID_INLINE bool operator!=(const char* a, const idStr& b) { return !(a == b); } ID_INLINE int idStr::Cmp(const char* text) const { assert(text); return idStr::Cmp(data, text); } ID_INLINE int idStr::Cmpn(const char* text, int n) const { assert(text); return idStr::Cmpn(data, text, n); } ID_INLINE int idStr::CmpPrefix(const char* text) const { assert(text); return idStr::Cmpn(data, text, strlen(text)); } ID_INLINE int idStr::Icmp(const char* text) const { assert(text); return idStr::Icmp(data, text); } ID_INLINE int idStr::Icmpn(const char* text, int n) const { assert(text); return idStr::Icmpn(data, text, n); } ID_INLINE int idStr::IcmpPrefix(const char* text) const { assert(text); return idStr::Icmpn(data, text, strlen(text)); } ID_INLINE int idStr::IcmpNoColor(const char* text) const { assert(text); return idStr::IcmpNoColor(data, text); } #ifdef QUAKE4 ID_INLINE int idStr::IcmpNoEscape(const char* text) const { assert(text); return idStr::IcmpNoEscape(data, text); } #endif ID_INLINE int idStr::IcmpPath(const char* text) const { assert(text); return idStr::IcmpPath(data, text); } ID_INLINE int idStr::IcmpnPath(const char* text, int n) const { assert(text); return idStr::IcmpnPath(data, text, n); } ID_INLINE int idStr::IcmpPrefixPath(const char* text) const { assert(text); return idStr::IcmpnPath(data, text, strlen(text)); } ID_INLINE int idStr::Length(void) const { return len; } ID_INLINE int idStr::Allocated(void) const { if (data != baseBuffer) { return alloced; } else { return 0; } } ID_INLINE void idStr::Empty(void) { EnsureAlloced(1); data[0] = '\0'; len = 0; } ID_INLINE bool idStr::IsEmpty(void) const { return (idStr::Cmp(data, "") == 0); } ID_INLINE void idStr::Clear(void) { FreeData(); Init(); } ID_INLINE void idStr::Append(const char a) { EnsureAlloced(len + 2); data[len] = a; len++; data[len] = '\0'; } ID_INLINE void idStr::Append(const idStr& text) { int newLen; int i; newLen = len + text.Length(); EnsureAlloced(newLen + 1); for (i = 0; i < text.len; i++) { data[len + i] = text[i]; } len = newLen; data[len] = '\0'; } ID_INLINE void idStr::Append(const char* text) { int newLen; int i; if (text) { newLen = len + strlen(text); EnsureAlloced(newLen + 1); for (i = 0; text[i]; i++) { data[len + i] = text[i]; } len = newLen; data[len] = '\0'; } } ID_INLINE void idStr::Append(const char* text, int l) { int newLen; int i; if (text && l) { newLen = len + l; EnsureAlloced(newLen + 1); for (i = 0; text[i] && i < l; i++) { data[len + i] = text[i]; } len = newLen; data[len] = '\0'; } } ID_INLINE void idStr::Insert(const char a, int index) { int i, l; if (index < 0) { index = 0; } else if (index > len) { index = len; } l = 1; EnsureAlloced(len + l + 1); for (i = len; i >= index; i--) { data[i + l] = data[i]; } data[index] = a; len++; } ID_INLINE void idStr::Insert(const char* text, int index) { int i, l; if (index < 0) { index = 0; } else if (index > len) { index = len; } l = strlen(text); EnsureAlloced(len + l + 1); for (i = len; i >= index; i--) { data[i + l] = data[i]; } for (i = 0; i < l; i++) { data[index + i] = text[i]; } len += l; } ID_INLINE void idStr::ToLower(void) { for (int i = 0; data[i]; i++) { #ifdef QUAKE4 data[i] = ToLower((byte)data[i]); #else if (CharIsUpper(data[i])) { data[i] += ('a' - 'A'); } #endif } } ID_INLINE void idStr::ToUpper(void) { for (int i = 0; data[i]; i++) { #ifdef QUAKE4 data[i] = ToUpper((byte)data[i]); #else if (CharIsLower(data[i])) { data[i] -= ('a' - 'A'); } #endif } } ID_INLINE bool idStr::IsNumeric(void) const { return idStr::IsNumeric(data); } ID_INLINE bool idStr::IsColor(void) const { return idStr::IsColor(data); } ID_INLINE bool idStr::HasLower(void) const { return idStr::HasLower(data); } ID_INLINE bool idStr::HasUpper(void) const { return idStr::HasUpper(data); } ID_INLINE idStr& idStr::RemoveColors(void) { idStr::RemoveColors(data); len = Length(data); return *this; } ID_INLINE int idStr::LengthWithoutColors(void) const { return idStr::LengthWithoutColors(data); } #ifdef QUAKE4 ID_INLINE int idStr::IsEscape(int* type) const { return idStr::IsEscape(data, type); } ID_INLINE idStr& idStr::RemoveEscapes(int escapes) { idStr::RemoveEscapes(data, escapes); len = Length(data); return *this; } ID_INLINE int idStr::LengthWithoutEscapes(void) const { return idStr::LengthWithoutEscapes(data); } #endif ID_INLINE void idStr::CapLength(int newlen) { if (len <= newlen) { return; } data[newlen] = 0; len = newlen; } ID_INLINE void idStr::Fill(const char ch, int newlen) { EnsureAlloced(newlen + 1); len = newlen; memset(data, ch, len); data[len] = 0; } ID_INLINE int idStr::Find(const char c, int start, int end) const { if (end == -1) { end = len; } return idStr::FindChar(data, c, start, end); } ID_INLINE int idStr::Find(const char* text, bool casesensitive, int start, int end) const { if (end == -1) { end = len; } return idStr::FindText(data, text, casesensitive, start, end); } ID_INLINE bool idStr::Filter(const char* filter, bool casesensitive) const { return idStr::Filter(filter, data, casesensitive); } ID_INLINE const char* idStr::Left(int len, idStr& result) const { return Mid(0, len, result); } ID_INLINE const char* idStr::Right(int len, idStr& result) const { if (len >= Length()) { result = *this; return result; } return Mid(Length() - len, len, result); } ID_INLINE idStr idStr::Left(int len) const { return Mid(0, len); } ID_INLINE idStr idStr::Right(int len) const { if (len >= Length()) { return *this; } return Mid(Length() - len, len); } ID_INLINE void idStr::Strip(const char c) { StripLeading(c); StripTrailing(c); } ID_INLINE void idStr::Strip(const char* string) { StripLeading(string); StripTrailing(string); } ID_INLINE bool idStr::CheckExtension(const char* ext) { return idStr::CheckExtension(data, ext); } ID_INLINE int idStr::Length(const char* s) { int i; for (i = 0; s[i]; i++) {} return i; } ID_INLINE char* idStr::ToLower(char* s) { for (int i = 0; s[i]; i++) { #ifdef QUAKE4 s[i] = ToLower((byte)s[i]); #else if (CharIsUpper(s[i])) { s[i] += ('a' - 'A'); } #endif } return s; } ID_INLINE char* idStr::ToUpper(char* s) { for (int i = 0; s[i]; i++) { #ifdef QUAKE4 s[i] = ToUpper((byte)s[i]); #else if (CharIsLower(s[i])) { s[i] -= ('a' - 'A'); } #endif } return s; } ID_INLINE int idStr::Hash(const char* string) { int i, hash = 0; for (i = 0; *string != '\0'; i++) { hash += (*string++) * (i + 119); } return hash; } ID_INLINE int idStr::Hash(const char* string, int length) { int i, hash = 0; for (i = 0; i < length; i++) { hash += (*string++) * (i + 119); } return hash; } ID_INLINE int idStr::IHash(const char* string) { int i, hash = 0; for (i = 0; *string != '\0'; i++) { hash += ToLower(*string++) * (i + 119); } return hash; } ID_INLINE int idStr::IHash(const char* string, int length) { int i, hash = 0; for (i = 0; i < length; i++) { hash += ToLower(*string++) * (i + 119); } return hash; } ID_INLINE bool idStr::IsColor(const char* s) { return (s[0] == C_COLOR_ESCAPE && s[1] != '\0' && s[1] != ' '); } #ifdef QUAKE4 ID_INLINE char idStr::ToLower(byte c) { if (lowerCaseCharacter[c]) { return lowerCaseCharacter[c]; } return c; } ID_INLINE char idStr::ToUpper(byte c) { if (upperCaseCharacter[c]) { return upperCaseCharacter[c]; } return c; } ID_INLINE bool idStr::CharIsPrintable(byte c) { return printableCharacter[c]; } ID_INLINE bool idStr::CharIsLower(byte c) { return !!lowerCaseCharacter[c] && (lowerCaseCharacter[c] == c); } ID_INLINE bool idStr::CharIsUpper(byte c) { return !!upperCaseCharacter[c] && (upperCaseCharacter[c] == c); } ID_INLINE bool idStr::CharIsAlpha(byte c) { return !!upperCaseCharacter[c]; } ID_INLINE bool idStr::CharIsNumeric(byte c) { return (c <= '9' && c >= '0'); } ID_INLINE bool idStr::CharIsNewLine(byte c) { return (c == '\n' || c == '\r' || c == '\v'); } ID_INLINE bool idStr::CharIsTab(byte c) { return (c == '\t'); } #else ID_INLINE char idStr::ToLower(char c) { if (c <= 'Z' && c >= 'A') { return (c + ('a' - 'A')); } return c; } ID_INLINE char idStr::ToUpper(char c) { if (c >= 'a' && c <= 'z') { return (c - ('a' - 'A')); } return c; } ID_INLINE bool idStr::CharIsPrintable(int c) { return (c >= 0x20 && c <= 0x7E) || (c >= 0xA1 && c <= 0xFF); } ID_INLINE bool idStr::CharIsLower(int c) { return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF); } ID_INLINE bool idStr::CharIsUpper(int c) { return (c <= 'Z' && c >= 'A') || (c >= 0xC0 && c <= 0xDF); } ID_INLINE bool idStr::CharIsAlpha(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xFF)); } ID_INLINE bool idStr::CharIsNumeric(int c) { return (c <= '9' && c >= '0'); } ID_INLINE bool idStr::CharIsNewLine(char c) { return (c == '\n' || c == '\r' || c == '\v'); } ID_INLINE bool idStr::CharIsTab(char c) { return (c == '\t'); } #endif ID_INLINE int idStr::ColorIndex(int c) { return (c & 15); } ID_INLINE int idStr::DynamicMemoryUsed() const { return (data == baseBuffer) ? 0 : alloced; } #endif /* !__STR_H__ */