#pragma once #include // std::min /****************************************************************************/ // SCString class SCString { friend class c_Graph; private: //On 64-bit build size is 24 bytes char* m_String; int m_OwnString; int m_IsModified; const char* m_DefaultString; #ifndef _WIN64 char Reserve[60]; #endif public: SCString(); SCString(int DummyValue); // this is needed by the c_ArrayWrapper class SCString(const SCString& Str);//Copy constructor SCString(const char* SourceString); SCString(const char* SourceString, int Length); SCString(const char ch); ~SCString(); void Initialize(); void Clear(); bool operator == (const SCString& Rhs) const; bool operator == (const char* Rhs) const; bool operator != (const SCString& Rhs) const; bool operator != (const char* Rhs) const; bool operator < (const SCString& Rhs) const; bool operator < (const char* Rhs) const; SCString& operator = (const SCString& Rhs); SCString& operator = (const char* String); SCString& operator += (const SCString& Rhs); SCString operator + (const SCString& Rhs) const; operator const char* () const; SCString& Format(const char* String, ...); SCString& AppendFormat(const char* String, ...); int Compare(const char* StringToCompare, int NumChars = 0) const; int CompareNoCase(const char* StringToCompare, int NumChars = 0) const; int CompareNoCase(const SCString& StringToCompare, int NumChars = 0) const; int IsModified() const; int IsEmpty() const; const char* GetChars() const; int GetLength() const; int IndexOf(char Delimiter, int StartIndex = 0) const; int LastIndexOf(char SearchCharacter, int StartIndex) const; SCString GetSubString(int SubstringLength, int StartIndex = 0) const; void ParseLines(std::vector &Lines); void ParseLineItemsAsFloats(std::vector &FloatValues); int Tokenize(const char* Delim, std::vector& Tokens); SCString& Append(const SCString& Rhs); SCString Left(int Count) const; SCString Right(int Count) const; private: // The maximum allowed length of a string is the maximum value that // can be stored in an int, -1 so that the buffer size which has to // include the null terminating character can also be stored in an // int. static const int MAX_LENGTH = INT_MAX - 1; private: static int TerminatedStringLength(const char* String); static char* StringNew(const int NumBytes); static void StringDelete(char* String); SCString& Copy(const char* String, int StringLength); void InternalAppendFormat ( const char* String , const va_list& ArgumentList ); // For Sierra Chart internal use only void InternalSetStatic(const char* String); }; /*==========================================================================*/ inline SCString::SCString() { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString = 0; m_IsModified = 0; } /*============================================================================ This constructor is needed by the c_ArrayWrapper class. ----------------------------------------------------------------------------*/ inline SCString::SCString(int DummyValue) { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString= 0; m_IsModified= 0; } /*==========================================================================*/ inline SCString::SCString(const SCString& Str) { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString = 0; m_IsModified = Str.m_IsModified; const int StringLength = TerminatedStringLength(Str.m_String); if (StringLength != 0) { const int BufferSize = StringLength + 1; m_String = StringNew(BufferSize); if (m_String != NULL) { #if __STDC_WANT_SECURE_LIB__ strcpy_s(m_String, BufferSize, Str.m_String); #else strcpy(m_String, Str.m_String); #endif m_OwnString = 1; } else { m_String = (char*)m_DefaultString; //NULL } } else { m_String = (char*)m_DefaultString; //NULL } } /*==========================================================================*/ inline SCString::SCString(const char* SourceString) { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString= 0; m_IsModified= 0; const int StringLength = TerminatedStringLength(SourceString); if (StringLength != 0) { const int BufferSize = StringLength + 1; m_String = StringNew(BufferSize); if (m_String != NULL) { #if __STDC_WANT_SECURE_LIB__ strncpy_s(m_String, BufferSize, SourceString, StringLength); #else strncpy(m_String, SourceString, StringLength); #endif m_OwnString = 1; m_IsModified = 1; } else { m_String = (char*)m_DefaultString; //NULL } } else m_String = (char*)m_DefaultString; //NULL } /*==========================================================================*/ inline SCString::SCString(const char* SourceString, int Length) { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString= 0; m_IsModified= 0; int StringLength = 0; if (SourceString != NULL) { if (Length >= 0) { // Note: if `min` is defined as a macro, that prevents us from // using `std::min`. But if `min` is not defined, we need to // specify the `std` namespace. #ifdef min StringLength = min(Length, MAX_LENGTH); #else StringLength = std::min(Length, MAX_LENGTH); #endif } else StringLength = TerminatedStringLength(SourceString); } if (StringLength != 0) { const int BufferSize = StringLength + 1; m_String = StringNew(BufferSize); if (m_String != NULL) { #if __STDC_WANT_SECURE_LIB__ strncpy_s(m_String, BufferSize, SourceString, StringLength); #else strncpy(m_String, SourceString, StringLength); #endif m_OwnString = 1; m_IsModified = 1; } else { m_String = (char*)m_DefaultString; //NULL } } else m_String = (char*)m_DefaultString; //NULL } /*==========================================================================*/ inline SCString::SCString(const char ch) { m_DefaultString = ""; m_String = (char*)m_DefaultString; //NULL m_OwnString= 0; m_IsModified= 0; const int StringLength = 1; const int BufferSize = StringLength + 1; m_String = StringNew(BufferSize); if (m_String != NULL) { m_String[0] = ch; m_String[StringLength] = '\0'; m_OwnString = 1; m_IsModified = 1; } else m_String = (char*)m_DefaultString; //NULL } /*==========================================================================*/ inline SCString::~SCString() { if (m_OwnString && m_String != NULL) StringDelete(m_String); } /*==========================================================================*/ inline void SCString::Initialize() { if (m_OwnString && m_String != NULL) StringDelete(m_String); m_String = (char*)m_DefaultString; //NULL m_OwnString = 0; m_IsModified = 0; } /*==========================================================================*/ inline void SCString::Clear() { Initialize(); } /*==========================================================================*/ inline bool SCString::operator == (const SCString& Rhs) const { return (Compare(Rhs.GetChars()) == 0); } /*==========================================================================*/ inline bool SCString::operator == (const char* Rhs) const { return (Compare(Rhs) == 0); } /*==========================================================================*/ inline bool SCString::operator != (const SCString& Rhs) const { return (Compare(Rhs.GetChars()) != 0); } /*==========================================================================*/ inline bool SCString::operator != (const char* Rhs) const { return (Compare(Rhs) != 0); } /*==========================================================================*/ inline bool SCString::operator < (const SCString& Rhs) const { return Compare(Rhs.GetChars()) < 0; } /*==========================================================================*/ inline bool SCString::operator < (const char* Rhs) const { return Compare(Rhs) < 0; } /*==========================================================================*/ inline SCString& SCString::operator = (const SCString& Rhs) { if (&Rhs == this) return *this; if (Rhs.IsEmpty() && IsEmpty() ) return *this; if (Rhs.m_String) Copy(Rhs.m_String, TerminatedStringLength(Rhs.m_String)); else Initialize(); m_IsModified = 1; return *this; } /*==========================================================================*/ inline SCString& SCString::operator = (const char* String) { if ((String == NULL || String[0] == '\0') && IsEmpty()) return *this;//nothing to do if (String) Copy(String, TerminatedStringLength(String)); else Initialize(); m_IsModified = 1; return *this; } /*==========================================================================*/ inline SCString& SCString::operator += (const SCString& Rhs) { return Append(Rhs); } /*==========================================================================*/ inline SCString SCString::operator + (const SCString& Rhs) const { SCString Result(*this); Result += Rhs; return Result; } /*==========================================================================*/ inline SCString::operator const char* () const { if (m_String) return m_String; else return ""; } /*==========================================================================*/ inline SCString& SCString::Format(const char* String, ...) { Initialize(); va_list ArgumentList; va_start(ArgumentList, String); InternalAppendFormat(String, ArgumentList); va_end(ArgumentList); return *this; } /*==========================================================================*/ inline SCString& SCString::AppendFormat(const char* String, ...) { va_list ArgumentList; va_start(ArgumentList, String); InternalAppendFormat(String, ArgumentList); va_end(ArgumentList); return *this; } /*==========================================================================*/ inline int SCString::Compare(const char* StringToCompare, int NumChars) const { const char* InternalString= ""; if (m_String) InternalString=m_String; if (StringToCompare != NULL) { if (NumChars == 0) return strcmp(StringToCompare, InternalString); else return strncmp(StringToCompare, InternalString, NumChars); } else return 0; } /*==========================================================================*/ inline int SCString::CompareNoCase(const char* StringToCompare, int NumChars) const { const char* InternalString= ""; if (m_String) InternalString=m_String; #if _MSC_VER >= 1400 if (NumChars == 0) return _stricmp(StringToCompare, InternalString); else return _strnicmp(StringToCompare, InternalString, NumChars); #else if (NumChars == 0) return stricmp(StringToCompare, InternalString); else return strnicmp(StringToCompare, InternalString, NumChars); #endif } /*==========================================================================*/ inline int SCString::CompareNoCase(const SCString& StringToCompare, int NumChars) const { return CompareNoCase(StringToCompare.GetChars(),NumChars); } /*==========================================================================*/ inline int SCString::IsModified() const { return m_IsModified; } /*==========================================================================*/ inline int SCString::IsEmpty() const { if (m_String == NULL) return 1; return (m_String[0] == '\0') ? 1 : 0; } /*==========================================================================*/ inline const char* SCString::GetChars() const { if (m_String) return m_String; else return ""; } /*==========================================================================*/ inline int SCString::GetLength() const { return TerminatedStringLength(m_String); } /*==========================================================================*/ inline int SCString::IndexOf(char Delimiter, int StartIndex) const { if (m_String == NULL) return -1; for (int i = StartIndex; i < GetLength(); i++) { if (m_String[i] == Delimiter) return i; } return -1; } /*==========================================================================*/ inline int SCString::LastIndexOf(char SearchCharacter, int StartIndex) const { if (m_String == NULL) return -1; const int Length = GetLength(); if (StartIndex >= Length) StartIndex = Length - 1; for (int CharacterIndex = StartIndex; CharacterIndex >= 0; CharacterIndex--) { if (m_String[CharacterIndex] == SearchCharacter) return CharacterIndex; } return -1; } /*==========================================================================*/ inline SCString SCString::GetSubString(int SubstringLength, int StartIndex) const { if (m_String == NULL) return SCString(); const int Length = GetLength(); if (StartIndex >= Length) return SCString(); if (SubstringLength > Length - StartIndex) SubstringLength = Length - StartIndex; SCString Result; Result.Copy(m_String + StartIndex, SubstringLength); return Result; } /*==========================================================================*/ inline void SCString::ParseLines(std::vector& Lines) { int StartIndex = 0; while(true) { int Pos = IndexOf('\n', StartIndex); if (Pos == -1) Pos = GetLength(); SCString Line; Line = GetSubString(Pos - StartIndex, StartIndex); Lines.push_back(Line); StartIndex = Pos + 1; if(StartIndex >= GetLength()) break; } } /*==========================================================================*/ inline void SCString::ParseLineItemsAsFloats(std::vector& FloatValues) { char FieldsDelimitter = ','; int find_delim = IndexOf(FieldsDelimitter); int pos = 0; int ArraySize = 1000; int CurrentItem = 0; while (find_delim > 0 && CurrentItem < ArraySize) { SCString NextStr = GetSubString(find_delim - pos, pos); FloatValues.push_back((float)atof(NextStr)); pos = find_delim + 1; find_delim = IndexOf(FieldsDelimitter,find_delim + 1); CurrentItem++; } } /*==========================================================================*/ inline int SCString::Tokenize(const char* Delim, std::vector& Tokens) { Tokens.erase(Tokens.begin(), Tokens.end()); if (m_String == NULL) return 0; // The object must own the string for this method because this method // modifies the string. if (!m_OwnString) Copy(m_String, TerminatedStringLength(m_String)); Tokens.push_back(m_String); if (Delim == NULL) return 1; int StrLen = GetLength(); int DelimLen = TerminatedStringLength(Delim); if (DelimLen == 0) return 1; // Not worth splitting every character for (int a = 0; a < StrLen; a++) { // Look for the delimiter bool DelimFound = true; for (int b = 0; b < DelimLen; b++) { if (a + b >= StrLen) { DelimFound = false; break; } if (m_String[a + b] != Delim[b]) { DelimFound = false; break; } } if (DelimFound) { m_String[a] = '\0'; Tokens.push_back(m_String + a + DelimLen); a += DelimLen - 1; } } return static_cast(Tokens.size()); } /*==========================================================================*/ inline SCString& SCString::Append(const SCString& Rhs) { int RightStringLength = Rhs.GetLength(); if (RightStringLength == 0) return *this; const int LeftStringLength = GetLength(); // Make sure the new string length does not exceed MAX_LENGTH. if (RightStringLength > MAX_LENGTH - LeftStringLength) RightStringLength = MAX_LENGTH - LeftStringLength; const int NewStringLength = LeftStringLength + RightStringLength; char* NewString = StringNew(NewStringLength + 1); if (NewString) { const char*InternalString = ""; if (m_String) InternalString =m_String; #if __STDC_WANT_SECURE_LIB__ strncpy_s(NewString, NewStringLength + 1, InternalString, LeftStringLength); strncpy_s(NewString + LeftStringLength, NewStringLength + 1 - LeftStringLength, Rhs.m_String, RightStringLength); #else strncpy(NewString, InternalString, LeftStringLength); strncpy(NewString + LeftStringLength, Rhs.m_String, RightStringLength); #endif NewString[NewStringLength] = '\0'; Initialize(); m_String = NewString; m_OwnString = 1; } m_IsModified = 1; return *this; } /*==========================================================================*/ inline SCString SCString::Left(int Count) const { const int StringLength = GetLength(); if (Count >= StringLength) return *this; else if (Count > 0) return SCString(m_String, Count); else if (Count < 0) { int TargetLength = StringLength + Count; if (TargetLength <= 0) return SCString(); else return SCString(m_String, TargetLength); } else return SCString(); } /*==========================================================================*/ inline SCString SCString::Right(int Count) const { int StringLength = GetLength(); if (Count >= StringLength) return *this; else if (Count > 0) return SCString(m_String + (StringLength - Count), Count); else if (Count < 0) { int TargetLength = StringLength + Count; if (TargetLength <= 0) return SCString(); else return SCString(m_String + (StringLength - TargetLength), TargetLength); } else return SCString(); } /*============================================================================ Static ----------------------------------------------------------------------------*/ inline int SCString::TerminatedStringLength(const char* String) { if (String == NULL) return 0; const size_t StringLength = strlen(String); if (StringLength > MAX_LENGTH) return MAX_LENGTH; return static_cast(StringLength); } /*============================================================================ Static ----------------------------------------------------------------------------*/ inline char* SCString::StringNew(const int NumBytes) { if (NumBytes <= 0) return NULL; char* p_Block = (char*)HeapAlloc(GetProcessHeap(), 0, NumBytes); if (p_Block != NULL) memset(p_Block, 0, NumBytes); return p_Block; } /*============================================================================ Static ----------------------------------------------------------------------------*/ inline void SCString::StringDelete(char* String) { if (String != NULL) HeapFree(GetProcessHeap(), 0, String); } /*==========================================================================*/ inline SCString& SCString::Copy(const char* String, int StringLength) { if (String == NULL) return *this; Initialize(); if (StringLength != 0) { if (StringLength > MAX_LENGTH) StringLength = MAX_LENGTH; const int BufferSize = StringLength + 1; m_String = StringNew(BufferSize); if (m_String == NULL) m_String = (char*)m_DefaultString; else { #if __STDC_WANT_SECURE_LIB__ strncpy_s(m_String, BufferSize, String, StringLength); #else strncpy(m_String, String, StringLength); #endif m_String[StringLength] = '\0'; m_OwnString = 1; } } m_IsModified = 1; return *this; } /*==========================================================================*/ inline void SCString::InternalAppendFormat ( const char* FormatString , const va_list& ArgumentList ) { if (FormatString == NULL) return; const int PriorLength = TerminatedStringLength(m_String); const int TargetLength = _vscprintf(FormatString, ArgumentList); if (TargetLength < 0 || TargetLength > MAX_LENGTH - PriorLength) return; char* NewStringBuffer = StringNew(PriorLength + TargetLength + 1); if (NewStringBuffer == NULL) return; // Copy the current string to the new buffer. if (PriorLength > 0) memcpy(NewStringBuffer, m_String, PriorLength); #if __STDC_WANT_SECURE_LIB__ vsprintf_s ( NewStringBuffer + PriorLength , TargetLength + 1 , FormatString , ArgumentList ); #else vsprintf(NewStringBuffer + PriorLength, FormatString, ArgumentList); #endif Clear(); m_String = NewStringBuffer; m_OwnString = 1; m_IsModified = 1; } /*============================================================================ For Sierra Chart internal use only. ----------------------------------------------------------------------------*/ inline void SCString::InternalSetStatic(const char* String) { Initialize(); m_String = const_cast(String); m_OwnString = 0; m_IsModified = 0; } /*==========================================================================*/