// GSString.X.h
//
// Copyright 1997-1998 Diehl Graphsoft, Inc.
// All Rights Reserved.
//
// Implements a cross platform C/Pascal string class.
//
// Started by David Bowman
//
// SourceSafe information for this version:
//    $Revision: 4 $
//    $Date: 12/22/00 10:33 AM $
//    $Author: Darick $

#ifndef _GSSTRINGX_
#define _GSSTRINGX_

#pragma once

#if !_MINICAD_
// ASSERTTHISCLASS is not available in the external SDK
# ifndef ASSERTTHISCLASS
#  define ASSERTTHISCLASS(toWhom)
# endif
#endif

#include "GSString.h"
#include "MiniCadCallbacks.X.h"

#define NNA_WARN_ABOUT_EMPTY_STRING_RESOURCES 1


enum EEmptyHandling {
	eAllowEmptyResult = eDontWarnAboutEmptyStringResult,
	eDontAllowEmptyResult = eWarnAboutEmptyStringResult 
};


//
// Comments about encoding issues.
// This information is important to know if you're adding any new UI code or new functions available to
// the SDK users that input or output strings.
//
//		VectorWorks generally stores strings in a Mac encoding.  The most common is MacRoman, which is used
// for most European languages (English, German, French, etc.).  If a system is set to Japanese, then it will
// use MacJapanese.  Other common Mac encodings are MacKorean, MacChineseTrad, MacChineseSimp,
// MacGreek, MacHebrew and MacArabic.
//		While the MacRoman encoding is used by the Macintosh OS, the Windows OS has its own equivalent, which
// our code commonly refers to as Ansi (two important methods in TXString are MacToAnsi and AnsiToMac).  A single
// byte character has 256 possible values, and the lowest 128 possible values (0x00 to 0x7F) are the same in
// MacRoman and the Windows equivalent encodings.  The lowercase and uppercase letters in the English alphabet,
// numbers, and most punctuation symbols are in the lowest 128 values, so they are represented the same in 
// the MacRoman and equivalent Windows encodings.  However, many characters we would consider special are commonly 
// used in German, French and other European languages, and they are in the highest 128 values.  Some examples are
// an e with an accent mark or a u with umlauts.  If our code does not properly handle the encoding for strings with
// special characters, the user will see them displayed improperly.
//		Generally VectorWorks keeps strings in the Mac encoding.  When strings are read in from Macintosh resources, 
// they are kept in the Mac encoding (this may not be true for strings from DITL resources, which are usually just
// displayed in a dialog, but these are only used in a few older dialogs).  Strings stored in a VW document are all
// in the Mac encoding.  If a user is running on Windows and enters a string in a dialog, when our code first gets
// the string it will be in the Ansi encoding, and our code will convert it to the Mac encoding.  If a string is
// displayed in a dialog and the user is running in Windows, the string will be converted from Mac format to Ansi
// format before it is passed to the OS to display it.  The layout manager system takes care of all of this, and
// its interface uses the Mac format.  A layout manager fuction for setting static text is passed the text in
// the Mac foramt.  A layout manager function for getting the text from an edit box will return the text in the
// Mac foramt.
//		However most VectorWorks filing code does not keep strings in the Mac encoding, but uses the native encoding
// (Mac when running on the Mac and Ansi when running on Windows).  The interface for the TFileIdentifier and
// TFolderIdentifier classes uses the native encoding.  If code sets a TFileIdentifier, passing it a path, and
// it is running on Windows, the path needs to be passed in Ansi format.  If code gets a path from a TFileIdentifier,
// and it is running on Windows, the path will be returned in Ansi format.
//		We have a lot of Shell code, which has different implementations for Mac and Windows.  Generally, at the Core/Shell
// interface, strings should be in Mac format, and Windows shell code will convert Mac strings to Ansi strings before
// displaying them, and it will convert Ansi strings to Mac strings before passing them to the Core.
//		The interface for VectorScript uses the Mac encoding.  Any string passed to a VS command should be in Mac
// encoding, and any strings received from a VS command are in Mac encoding.  The interface for the SDK uses the Mac
// encoding except for file I/O.  For example, the GetFolderPath SDK function when called on a Windows machine returns
// a folder path in Ansi format.  But an SDK function to return the name of the active class or layer would return the name
// in Mac format on both platforms.
//		Whenever a string needs to be converted from Mac to Ansi format, it is best to use the TXString method MacToAnsi,
// and to convert from Ansi to Mac, use TXString::AnsiToMac.  These methods do nothing when called on the Mac.  If called
// when on a double-byte system (Japanese, Chinese, Korean), these methods only do something for a few non-standard
// Japanese characters.  The shift-JIS Japanese encoding is identical on Mac and Windows except for a few characters.
// Either that is true of the Korean and Chinese encoding, or any strings in those languages will not display properly
// if moved to another platform.  If the system is set to Greek, we use special tables for converting between MacGreek
// and Windows Greek encodings.  If the system is set to any other single-byte language, we use tables for converting
// between MacRoman and the Windows equivalent.  This means our MacToAnsi and AnsiToMac code does not support other
// single-byte scripts.  For example, if a user enters classnames in the Russian script, the classnames will not
// display properly if the VW docuement is moved to the opposite platform.
//
// by Bruce Ferguson on 9/13/2007

////////////////////////////////////////////////////////////////////////////////
// TXString //
//////////////

class GS_COMP_API TXString : public TDebugObject
{
public:	
	TXString()													{ Init(30); }
	explicit TXString(size_t nInitialSize)						{ Init(nInitialSize); }
	TXString(const TXString &src)								{ Init(src.GetLength());	SetEqual(src); }
	TXString(const char *src)									{ Init(strlen(src));		SetEqual(src); }
	TXString(const char *src, size_t len)						{ Init(len);				SetEqual(src, len); }
	TXString(ConstGSStringPtr src)								{ Init(src[0]);				SetEqual(src); }
	TXString(char ch, size_t cnt)								{ Init(cnt);				SetEqual(ch, cnt); }
	TXString(short strListID, short index)						{ Init(30);					Load (strListID, index);}

	template <size_t maxCharLen>
	TXString(const PStr<maxCharLen>& src)						{ Init(src[0]);	 			EnsureBufferSize(maxCharLen); SetEqual((ConstGSStringPtr) src); }

	virtual ~TXString();

	// overloaded assignment
	TXString& operator=(const TXString& src)					{ ASSERTTHISCLASS(kEveryone); SetEqual(src); return *this; }
	TXString& operator=(const char *src)						{ ASSERTTHISCLASS(kEveryone); SetEqual(src); return *this; }
	TXString& operator=(ConstGSStringPtr src)					{ ASSERTTHISCLASS(kEveryone); SetEqual(src); return *this; }
	TXString& operator=(char ch)								{ ASSERTTHISCLASS(kEveryone); SetEqual(ch, 1); return *this; }
	
	template <size_t maxCharLen>
	TXString& operator=(const PStr<maxCharLen>& src)			{ ASSERTTHISCLASS(kEveryone); SetEqual((ConstGSStringPtr) src); return *this; }

	size_t GetLength() const									{ ASSERTTHISCLASS(kEveryone); return fLength; }
	unsigned char GetPascalLength() const						{ ASSERTTHISCLASS(kEveryone); return ((unsigned char*)fData)[0]; }
	size_t GetSizeForUniCharRepresentation() const;
	bool SetLength(size_t len);
	bool SetLength(size_t len, char fill);
	void Truncate(size_t len);
	bool IsEmpty() const										{ ASSERTTHISCLASS(kEveryone); return fLength == 0; }
	void Empty(bool bQuick=false);
	void Clear()												{ Empty(true); }
	void FreeExtra();											// Free any extra memory being used to hold string data.

	void CopyInto(GSCStrPtr sz) const;
	void CopyInto(GSStringPtr ps) const;
	void CopyInto(UCStrPtr utf16Array) const;

	char GetAt(size_t nIndex) const								{ ASSERTTHISCLASS(kEveryone); return this->GetCharRef(nIndex, true); }
	char operator[](int nIndex) const							{ ASSERTTHISCLASS(kEveryone); return this->GetCharRef(nIndex, true); }
	char& operator[](int nIndex)								{ ASSERTTHISCLASS(kEveryone); return this->GetCharRef(nIndex, false); }
	void SetAt(size_t nIndex, char ch);

	operator const char*() const								{ ASSERTTHISCLASS(kEveryone); return &fData[1]; }
	operator const unsigned char*() const;
	
	// Use these two functions to pass a TXString as a non-const string parameter.
	// *** NOTE: You MUST call ReleaseUnsafePtr afterwards to reset the TXString length fields
	char* GetUnsafeCharPtr(size_t len)							{ ASSERTTHISCLASS(kEveryone); SetLength(len); return &fData[1]; }
	unsigned char* GetUnsafeUnsignedCharPtr(size_t len)	;
	void ReleaseUnsafePtr()										{ /*TXString not valid*/ UpdateLength(); /*now valid*/ ASSERTTHISCLASS(kEveryone); }

	// This function is older, but we didn't want to change the whole project right away.
	void ReleaseUnsafeCharPtr()									{  ReleaseUnsafePtr(); }
	
	// string concatenation
	const TXString& operator+=(const TXString& string)			{ return ( *this << string ); }
	const TXString& operator+=(char ch)							{ return ( *this << ch ); }
	const TXString& operator+=(const char *sz)					{ return ( *this << sz ); }
	const TXString& operator+=(const unsigned char *ps)			{ return ( *this << ps ); }

	template <size_t maxCharLen>
	const TXString& operator+=(const PStr<maxCharLen>& string)	{ return ( *this << (ConstGSStringPtr) string ); }
	
	TXString& operator<<(const TXString& str)					{ return ( *this << (const char*) str ); }
	TXString& operator<<(char ch);
	TXString& operator<<(const char *sz);
	TXString& operator<<(const unsigned char *ps);
	TXString& operator<<(long n);

	template <size_t maxCharLen>
	TXString& operator<<(const PStr<maxCharLen>& str)			{ return ( *this << (ConstGSStringPtr) str ); }

	// string comparison
	int Compare(const TXString &str) const						{ return this->Compare((const char*)str); }
	int Compare(const char *sz) const;
	int Compare(const unsigned char *pstr) const;
	template <size_t maxCharLen>
	int Compare(const PStr<maxCharLen> &str) const				{ return this->Compare((ConstGSStringPtr) str); }

	int CompareNoCase(const TXString &str) const				{ return this->CompareNoCase((const char*)str); }
	int CompareNoCase(const char *sz) const;
	int CompareNoCase(const unsigned char *pstr) const;
	template <size_t maxCharLen>
	int CompareNoCase(const PStr<maxCharLen> &str) const		{ return this->CompareNoCase((ConstGSStringPtr)str); }

	// simple sub-string extraction
	TXString Mid(size_t nFirst, size_t nCount) const;
	TXString Mid(size_t nFirst) const							{ return this->Mid(nFirst, fLength - nFirst); }
	TXString Left(size_t nCount) const							{ return this->Mid(0, nCount); }
	TXString Right(size_t nCount) const							{ return this->Mid(fLength - nCount, nCount); }

	TXString SpanIncluding(const TXString &str) const			{ return SpanIncluding( (const char*)str ); }
	TXString SpanIncluding(const char *sz) const				{ return Span(true, sz); }
	TXString SpanIncluding(const unsigned char *ps) const		{ return Span(true, ps); }
	TXString SpanExcluding(const TXString &str) const			{ return SpanExcluding( (const char*)str ); }
	TXString SpanExcluding(const char *sz) const				{ return Span(false, sz); }
	TXString SpanExcluding(const unsigned char *ps) const		{ return Span(false, ps); }

	// Deleting and Inserting
	void Delete(size_t pos, size_t len);
	void Insert(size_t pos, const char *sz);
	void Insert(size_t pos, const unsigned char *ps);
	void Insert(size_t pos, char ch, size_t cnt = 1);
	void Replace(const char *oldStr, const char *newStr, bool bIgnoreCase = false);
	void Replace(const char *oldStr, char newChar, bool bIgnoreCase = false);

	// upper/lower/reverse conversion
	void MakeUpper();
	void MakeLower();
	void MakeReverse();

	// Trimming whitespace (either side).
	void Trim()													{ TrimLeft(); TrimRight(); }
	void TrimLeft();
	void TrimRight();

	// Searching from left to right.  Return starting index, or -1 if not found.
	int Find(char ch, int nStart = 0) const;
	int FindNoSJISCheck(char ch, int nStart = 0) const;
	int FindOneOf(const TXString &charSet) const;
	int FindOneOf(const char *szCharSet) const;
	int FindOneOf(const unsigned char *psCharSet) const;
	int FindNotOneOf(const TXString &charSet) const;
	int FindNotOneOf(const char *szCharSet) const;
	int FindNotOneOf(const unsigned char *psCharSet) const;

	// Searching from right to left.  Return starting index, or -1 if not found.
	int ReverseFind(char ch, bool checkForJISChar = true) const;
	int ReverseFindOneOf(const TXString &charSet) const;
	int ReverseFindOneOf(const char *szCharSet) const;
	int ReverseFindOneOf(const unsigned char *pstrCharSet) const;
	int ReverseFindNotOneOf(const TXString &charSet) const;
	int ReverseFindNotOneOf(const char *szCharSet) const;
	int ReverseFindNotOneOf(const unsigned char *pstrCharSet) const;

	// Look for a specific sub-string.
	int Find(const TXString &sub, bool bIgnoreCase = false) const					{ return this->Find((const char*) sub, bIgnoreCase); }
	int Find(const char *szSub, bool bIgnoreCase = false) const						{ return this->Find(0, szSub, bIgnoreCase); }
	int Find(const unsigned char *psSub, bool bIgnoreCase = false) const			{ return this->Find(0, psSub, bIgnoreCase); }
	int Find(size_t nFirst, const TXString &sub, bool bIgnoreCase = false) const	{ return this->Find(nFirst, (const char*) sub, bIgnoreCase); }
	int Find(size_t nFirst, const char *szSub, bool bIgnoreCase = false) const;
	int Find(size_t nFirst, const unsigned char *psSub, bool bIgnoreCase = false) const;

	#if _MINICAD_
	// Load from resources.
	bool Load(short strListID, short index, EEmptyHandling allowEmpty = eDontAllowEmptyResult);
	bool Load(short strID, EEmptyHandling allowEmpty = eDontAllowEmptyResult);
	#if _WINDOWS
		bool WLoad(int index, EEmptyHandling allowEmpty = eDontAllowEmptyResult);
	#endif
	#else
	bool Load(short strListID, short index, EEmptyHandling allowEmpty = eDontAllowEmptyResult);
	#endif

	// simple formatting
	// passing a class reference before a variable-length argument list doesn't work in windows
	void Format(const char *szFormat, ...);
	void Format(const unsigned char *psFormat, ...);
	void Format(short strList, short index, ...);
	void VFormat(const char *szFormat, va_list marker);
	void itoa(int value);
	int atoi() const;
	Real64 atof() const;
	operator int() const										{ return atoi(); }
	operator Real64() const										{ return atof(); }

	short AnsiToMac();	// these functions 
	short MacToAnsi();	//  do nothing on Mac
	
	void  UTF8ToMac();	// this is for dealing with displaying POSIX paths;  interface utilities expect Mac encoding,
						//  but POSIX paths are UTF-8 encoded.  This function does nothing on Windows.

			/** 
				@brief Converts windows new line characters to mac new line characters
			
				The Mac has only a single line feed character (10) as a new line while
				Windows has a carriage return (13) followed by a line feed (10). This
				function removes any line feed characters in the string.
			*/
	void	WinToMacNewLine ();

			/** 
				@brief Converts mac new line characters to windows new line characters
				
				Prepends a carriage return (13) to an existing line feed character (10)
				if one does not already exist.
			*/
	void	MacToWinNewLine ();	

	// File functions.
	#if _WINDOWS
		void AppendBackslash();
	#endif

	// Iterators.
	class TConstForwardIterator
	{
	public:
		TConstForwardIterator(const TXString &str, int nStart=0) { fStr = (TXString*)&str; i = nStart; }
		TConstForwardIterator& operator++()						{ ++i; return *this; }
		TConstForwardIterator& operator--()						{ --i; return *this; }
		operator bool() const									{ return i < (int)fStr->GetLength(); }
		bool operator==(char ch) const							{ return this->GetChar() == ch; }
		int GetPosition() const									{ return i; }
		char GetChar() const									{ return fStr->GetAt(i); }
		char GetNextChar() const								{ return i < (int)fStr->GetLength() ? fStr->GetAt(i+1) : 0; }
		char GetPrevChar() const								{ return i > 0 ? fStr->GetAt(i-1) : 0; }
	protected:
		TXString *fStr;
		int i;
	};
	class TConstReverseIterator
	{
	public:
		TConstReverseIterator(const TXString &str)				{ fStr = (TXString*)&str; i = str.GetLength()-1; }
		TConstReverseIterator& operator++()						{ ++i; return *this; }
		TConstReverseIterator& operator--()						{ --i; return *this; }
		operator bool() const									{ return i >= 0; }
		bool operator==(char ch) const							{ return this->GetChar() == ch; }
		int GetPosition() const									{ return (int) i; }
		char GetChar() const									{ return fStr->GetAt(i); }
		char GetNextChar() const								{ return i < (int)(fStr->GetLength() - 1) ? fStr->GetAt(i+1) : 0; }
		char GetPrevChar() const								{ return i > 0 ? fStr->GetAt(i-1) : 0; }
	protected:
		TXString *fStr;
		int i;
	};
	class TForwardIterator : public TConstForwardIterator
	{
	public:
		TForwardIterator(const TXString &str, int nStart=0) : TConstForwardIterator(str, nStart) { }
		TXString& operator*() const								{ return *fStr; }			
		TXString* operator->() const							{ return fStr; }			
	};
	class TReverseIterator : public TConstReverseIterator
	{
	public:
		TReverseIterator(const TXString &str) : TConstReverseIterator(str) { }
		TXString& operator*() const								{ return *fStr; }			
		TXString* operator->() const							{ return fStr; }			
	};

	DECLARE_CLASS_DEBUGGING

protected:
	void SetEqual(const TXString &src)							{ Empty(true); *this << src; }
	void SetEqual(const char *sz)								{ Empty(true); *this << sz; }
	void SetEqual(const char *sz, size_t len);
	void SetEqual(const unsigned char *ps)						{ Empty(true); *this << ps; }
	void SetEqual(char ch, size_t cnt);

	bool EnsureBufferSize(size_t size);
	bool ReallocBuffer(size_t newSize);
	void FreeBuffer();
	void UpdateLength();
	void UpdateLength(size_t len);

	char &GetCharRef(size_t nIndex, bool bAllowNull) const;

	TXString Span(bool include, const char *sz) const;
	TXString Span(bool include, const unsigned char *ps) const;

private:
	void Init(size_t nInitialSize);

	size_t fBufSize;
	size_t fLength;
	char *fData;

	// The entire purpose of this variable is to enable the Visual C++ debugger
	// display the string in a readable form if you add
	//    TXString =len=<fLength> str=<fCStringData,s>
	// to the file "AutoExp.dat".
	char *fCStringData; // Should alway point to fData+1.

	// static string buffer to be used as data memory when the string is small enough to fit
	// this is part of optimizations on memory usage from the TXString
	char fStaticStringBuffer[ 128 ];
};

#if GS_MAC
/**
	@brief Given a CFString, returns a TXString.
	@param inString the CFString to grab the data from.
	@returns TXString that contains the text in the CFString
*/
TXString NNA_CreateTXStringFromCFString(const CFStringRef& inString, bool bUseUTF8Encoding=false);
#endif


// Concatenation helpers
TXString operator+(const TXString& string1, const TXString& string2);
TXString operator+(const TXString& string, char ch);
TXString operator+(const TXString& string, const char *sz);
TXString operator+(const TXString& string, const unsigned char *str);
TXString operator+(char ch, const TXString& string);
TXString operator+(const char *sz, const TXString& string);
TXString operator+(const unsigned char *str, const TXString& string);

template <size_t maxCharLen>
TXString operator+(const TXString& string1, const PStr<maxCharLen>& string2)	{ return string1 + (ConstGSStringPtr) string2; }
template <size_t maxCharLen>
TXString operator+(const char* string1, const PStr<maxCharLen>& string2)	{ return string1 + string2; }


// Compare helpers
inline bool operator==(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) == 0; }
inline bool operator==(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) == 0; }
inline bool operator==(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) == 0; }
// CodeWarrior complains that it can't tell the difference between 'operator==(int, int)' and 'operator==(const char, const TXString &)'
//inline bool operator==(const TXString& s, const char c)			{ return s.GetLength() == 1 && s.GetAt(0) == c; }
//inline bool operator==(const char c, const TXString& s)			{ return s.GetLength() == 1 && s.GetAt(0) == c; }
inline bool operator!=(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) != 0; }
inline bool operator!=(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) != 0; }
inline bool operator!=(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) != 0; }
// CodeWarrior complains that it can't tell the difference between 'operator==(int, int)' and 'operator==(const char, const TXString &)'
// inline bool operator!=(const TXString& s, const char c)			{ return s.GetLength() != 1 || s.GetAt(0) != c; }
// inline bool operator!=(const char c, const TXString& s)			{ return s.GetLength() != 1 || s.GetAt(0) != c; }
inline bool operator<(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) < 0; }
inline bool operator<(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) < 0; }
inline bool operator<(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) >= 0; }
inline bool operator>(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) > 0; }
inline bool operator>(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) > 0; }
inline bool operator>(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) <= 0; }
inline bool operator<=(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) <= 0; }
inline bool operator<=(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) <= 0; }
inline bool operator<=(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) > 0; }
inline bool operator>=(const TXString& s1, const TXString& s2)	{ return s1.CompareNoCase(s2) >= 0; }
inline bool operator>=(const TXString& s1, const char *s2)		{ return s1.CompareNoCase(s2) >= 0; }
inline bool operator>=(const char *s1, const TXString& s2)		{ return s2.CompareNoCase(s1) < 0; }


////////////////////////////////////////////////////////////////////////////////
// TXStringArray //
///////////////////

class TXStringArray
{
public:
	TXStringArray(int nInitialSize=0, int nGrowBy=10);
	TXStringArray(const TXStringArray &src);
	~TXStringArray();

	TXStringArray&	operator=(const TXStringArray &src);

	int GetSize() const									{ return fNumStringsStored; }
	bool SetSize(Uint32 nSize);

	const TXString& GetAt(Uint32 nIndex) const			{ ASSERTN(kDave, nIndex < fNumStringsStored); return *fStringsPtr[nIndex]; }
	TXString& GetAt(Uint32 nIndex)						{ ASSERTN(kDave, nIndex < fNumStringsStored); return *fStringsPtr[nIndex]; }
	const TXString& operator[](Uint32 nIndex) const		{ return GetAt(nIndex); }
	TXString& operator[](Uint32 nIndex)					{ return GetAt(nIndex); }

	void SetAt(Uint32 nIndex, const TXString &string);
	void SetAt(Uint32 nIndex, ConstGSCStrPtr string);
	void SetAt(Uint32 nIndex, ConstGSStringPtr string);

	#if _MINICAD_
	bool AppendStringResourceList( short stringID );
	#endif
	
	bool Append(const TXString &string);
	bool Append(ConstGSCStrPtr string);
	bool Append(ConstGSStringPtr string);
	bool Append(const TXStringArray &src);

	bool Append(const PString &string)					{ return this->Append((ConstGSStringPtr) string); }

	void RemoveAt(Uint32 nIndex, Uint32 nCount = 1);
	void RemoveAll();

	Uint32	FindString (const char* str, bool& bFound);

private:
	void Init(int nInitialSize, int nGrowBy);
	bool EnsureArraySize(Uint32 nSize);

	Uint32		fGrowBy;
	Uint32		fNumStringsStored;
	Uint32		fMaxStringsStored;
	TXString	  **fStringsPtr;
};


////////////////////////////////////////////////////////////////////////////////
// TXStringResource //
//////////////////////

#if COMPILE_TXStringResource

class TXStringResource : public TDebugObject
{
	public:
		TXStringResource(short strList, short index) { fStrList = strList; fIndex = index; fLoaded = false; }
		TXStringResource(short strID)				 { fStrList = -14; fIndex = strID; fLoaded = false; }
		operator const TXString &()								{ ASSERTTHISCLASS(kDave); LoadIt(); return fStr; }
		operator const char *()									{ ASSERTTHISCLASS(kDave); LoadIt(); return fStr; }
		operator const unsigned char *()						{ ASSERTTHISCLASS(kDave); LoadIt(); return fStr; }
	
		// I advise you don't call these.  They require you to know if the string
		// came from an index or not.
		void GetID(short &strList, short &index) const			{ ASSERTTHISCLASS(kDave); ASSERTN(kDave, fStrList != -14); strList = fStrList; index = fIndex ; }
		void GetID(short &strID) const							{ ASSERTTHISCLASS(kDave); ASSERTN(kDave, fStrList == -14); strID = fIndex; }
	
		DECLARE_CLASS_DEBUGGING
	
	protected:
		void LoadIt();
	
	private:
		short	fStrList,
				fIndex;
		bool	fLoaded;
		TXString fStr;
};

#endif // COMPILE_TXStringResource


/*============================================================================*/
/***************/
/* TXUniString */
/***************/

class GS_COMP_API TXUniString : public TDebugObject {
	public:
		/* Constructors */
		TXUniString ();
		explicit TXUniString (UCCharCnt numChars);
		TXUniString (const TXUniString& srcStr);
		TXUniString (ConstUCStrPtr pCharsTerm);
		TXUniString (ConstUCCharPtr pChars, UCCharCnt length);
		TXUniString (UCChar uch, UCCharCnt repeatCount);
		TXUniString (GSTextEncoding srcEncoding, const char* srcStr);
		TXUniString (GSTextEncoding srcEncoding, ConstGSStr255Param srcStr);
		
		/* Destructor */
		virtual ~TXUniString ();
		
		/* Operators */
		TXUniString& operator= (const TXUniString& string)
			{ (void)SetValue(string);  return(*this); }
		TXUniString& operator= (ConstUCStrPtr pCharsTerm)
			{ (void)SetValue(pCharsTerm);  return(*this); }
		TXUniString& operator= (UCChar uch)
			{ (void)SetValue(uch, 1);  return(*this); }
		TXUniString& operator<< (const TXUniString& string)
			{ (void)Append(string);  return(*this); }
		TXUniString& operator<< (ConstUCStrPtr pCharsTerm)
			{ (void)Append(pCharsTerm);  return(*this); }
		TXUniString& operator<< (UCChar uch)
			{ (void)Append(uch, 1);  return(*this); }
		TXUniString& operator<< (long n);
		
		/* Casting (const class only!!!) */
		// There is a NULL UCChar at the end of the buffer pointed to
		//  as defined for UCStrPtr, but this also casts to UCCharPtr
		operator const UCStrPtr() const
			{ ASSERTTHISCLASS(kEveryone);  return(&fData[0]); }
#if 0  // TBW
		operator Uint32() const
			{ return atoi(); }
		operator Real64() const
			{ return atof(); }
#endif  // TBW
		
		/* String Value Assignment and Retrieval */
		bool SetValue (const TXUniString &string)
			{ Empty(true);  return(Append(string)); }
		bool SetValue (ConstUCStrPtr pCharsTerm)
			{ Empty(true);  return(Append(pCharsTerm)); }
		bool SetValue (ConstUCCharPtr pChars, UCCharCnt len)
			{ Empty(true);  return(Append(pChars, len)); }
		bool SetValue (UCChar uch, UCCharCnt repeatCount)
			{ Empty(true);  return(Append(uch, repeatCount)); }
		// maxChars must include space for a NULL UCChar at the end of pChars,
		//  but this is not counted in the returned pLen (standard length value)
		void GetValue (UCStrPtr pCharsTerm, UCCharCnt maxChars) const;
		void GetValue (UCCharPtr pChars, UCCharCnt maxChars, UCCharCnt* pLen) const;
		
		/* Length Getters, Length Setters, and Buffer Sizers */
		UCCharCnt GetLength () const
			{ ASSERTTHISCLASS(kEveryone);  return(fLength); }
		bool IsEmpty () const
			{ ASSERTTHISCLASS(kEveryone);  return(fLength == 0); }
		bool GrowLength (UCCharCnt len, UCChar fill);
		void Truncate (UCCharCnt maxLen);
		void Empty (bool keepBuffer);
		bool GrowBuffer (UCCharCnt minNumChars);
		void FreeExtraBuffer ();
		
		/* Appending, Inserting, Deleting, and Replacing */
		bool Append (const TXUniString& string);
		bool Append (ConstUCStrPtr pCharsTerm);
		bool Append (ConstUCCharPtr pChars, UCCharCnt len);
		bool Append (UCChar uch, UCCharCnt repeatCount);
		bool Insert (UCCharCnt pos, const TXUniString& string);
		bool Insert (UCCharCnt pos, ConstUCStrPtr pCharsTerm);
		bool Insert (UCCharCnt pos, ConstUCCharPtr pChars, UCCharCnt len);
		bool Insert (UCCharCnt pos, UCChar uch, UCCharCnt repeatCount);
		void Delete (UCCharCnt pos, UCCharCnt len);
		bool Replace (ConstUCStrPtr pOldStrTerm, ConstUCStrPtr pNewStrTerm,
		               bool ignoreCase);
		bool Replace (ConstUCCharPtr pOldStr, UCCharCnt oldLen,
		               ConstUCCharPtr pNewStr, UCCharCnt newLen, bool ignoreCase);
		
		/* Whitespace Trimming */
		void TrimLeft ();
		void TrimRight ();
		void Trim ()
			{ TrimLeft();  TrimRight(); }
		
		/* Case Conversion */
		void MakeUpperCase ();
		void MakeLowerCase ();
		
		/* Comparison */
		// IsEqual may be much faster than Compare on the Mac for testing equality
		bool IsEqual (const TXUniString& string, bool ignoreCase) const;
		bool IsEqual (ConstUCStrPtr pCharsTerm, bool ignoreCase) const;
		bool IsEqual (ConstUCCharPtr pChars, UCCharCnt len, bool ignoreCase) const;
		Sint32 Compare (const TXUniString& string, bool ignoreCase) const;
		Sint32 Compare (ConstUCStrPtr pCharsTerm, bool ignoreCase) const;
		Sint32 Compare (ConstUCCharPtr pChars, UCCharCnt len, bool ignoreCase) const;
		
		/* Sub-String Extraction */
		TXUniString Left (UCCharCnt len) const
			{ return(this->Mid(0, len)); }
		TXUniString Mid (UCCharCnt pos, UCCharCnt len) const;
		TXUniString MidToEnd (UCCharCnt pos) const
			{ return(this->Mid(pos, (fLength-pos))); }
		TXUniString Right (UCCharCnt len) const
			{ return(this->Mid((fLength-len), len)); }
#if 0  // TBW
		TXUniString SpanIncluding (const TXUniString& string) const
			{ return(SpanIncluding ((const UCCharPtr)string, string.GetLength())); }
		TXUniString SpanIncluding(const UCCharPtr pStr, UCCharCnt len) const
			{ return(Span(true, pStr, len)); }
		TXUniString SpanExcluding (const TXUniString& &string) const
			{ return(SpanExcluding((const UCCharPtr)string, string.GetLength()));}
		TXUniString SpanExcluding (const UCCharPtr)pStr, UCCharCnt len) const
			{ return(Span(false, pStr, len)); }
#endif  // TBW
		
		/* Searches for a String */
		bool Find (const TXUniString& findStr, UCCharCnt startPos,
		      bool ignoreCase, UCCharCnt* pFndBegPos, UCCharCnt* pFndEndPos) const;
		bool Find (ConstUCStrPtr pFindCharsT, UCCharCnt startPos,
		      bool ignoreCase, UCCharCnt* pFndBegPos, UCCharCnt* pFndEndPos) const;
		bool Find (ConstUCCharPtr pFindChars, UCCharCnt len, UCCharCnt startPos,
		      bool ignoreCase, UCCharCnt* pFndBegPos, UCCharCnt* pFndEndPos) const;
		bool Find (UCChar findUch, bool forward, UCCharCnt startPos,
		      bool ignoreCase, UCCharCnt* pFndBegPos, UCCharCnt* pFndEndPos) const;
		
#if 0  // TBW
		/* Searching for character set from left to right; */
		/*  returns starting index, or -1 if not found     */
		Sint32 FindOneOf (const TXUniString &charSet) const;
		Sint32 FindOneOf (const UCCharPtr pCharSet, UCCharCnt len) const;
		Sint32 FindNotOneOf (const TXUniString &charSet) const;
		Sint32 FindNotOneOf (const UCCharPtr pCharSet, UCCharCnt len) const;
		
		/* Searching for character set from right to left; */
		/*  returns starting index, or -1 if not found     */
		Sint32 ReverseFindOneOf (const TXUniString &charSet) const;
		Sint32 ReverseFindOneOf (const UCCharPtr pCharSet, UCCharCnt len) const;
		Sint32 ReverseFindNotOneOf (const TXUniString &charSet) const;
		Sint32 ReverseFindNotOneOf (const UCCharPtr pCharSet, UCCharCnt len) const;
		
		/* simple formatting */
		void Format(const TXUniString &format, ...);
		void Format(const UCCharPtr psFormat, ...);
		void Format(short strList, short index, ...);
		void VFormat(const UCCharPtr psFormat, va_list marker);
		void itoa(int value);
		Sint32 atoi() const;
		Real64 atof() const;
#endif  // TBW
		
		DECLARE_CLASS_DEBUGGING
	
	protected:
#if 0 // TBW
		TXUniString Span (bool include, const UCCharPtr pStr, UCCharCnt len) const;
#endif  // TBW
	
	private:
		UCStrPtr		fData;
		UCCharCnt		fBufSize;  // Must be > fLength to hold terminating NULL
		UCCharCnt		fLength;   // Does not count terminating NULL UCChar
		
		bool Init (UCCharCnt numChars);
		bool ReallocBuffer (UCCharCnt numWords);
};

// TXUniString Compare Helper Operators
inline bool operator== (const TXUniString& str1, const TXUniString& str2)
	{ return(str1.IsEqual(str2, kDoIgnoreCase)); }
inline bool operator!= (const TXUniString& str1, const TXUniString& str2)
	{ return(!str1.IsEqual(str2, kDoIgnoreCase)); }
inline bool operator<  (const TXUniString& str1, const TXUniString& str2)
	{ return(str1.Compare(str2, kDoIgnoreCase) < 0); }
inline bool operator>  (const TXUniString& str1, const TXUniString& str2)
	{ return(str1.Compare(str2, kDoIgnoreCase) > 0); }
inline bool operator<= (const TXUniString& str1, const TXUniString& str2)
	{ return(str1.Compare(str2, kDoIgnoreCase) <= 0); }
inline bool operator>= (const TXUniString& str1, const TXUniString& str2)
	{ return(str1.Compare(str2, kDoIgnoreCase) >= 0); }

// TXUniString Concatenation Helper Operators
TXUniString operator+ (const TXUniString& str1, const TXUniString& str2);
TXUniString operator+ (const TXUniString& string, ConstUCStrPtr pCharsTerm);
TXUniString operator+ (ConstUCStrPtr pCharsTerm, const TXUniString& string);
TXUniString operator+ (const TXUniString& string, UCChar uch);
TXUniString operator+ (UCChar uch, const TXUniString& string);


/*============================================================================*/
/********************/
/* TXUniStringArray */
/********************/

class TXUniStringArray {
	public:
		/* Constructors */
		TXUniStringArray (Uint32 initialSize=10, Uint32 growChunk=10);
		TXUniStringArray (const TXUniStringArray& srcArray);
		
		/* Destructor */
		~TXUniStringArray ();
		
		/* Operators */
		const TXUniString& operator[] (Uint32 index) const
			{ return(GetElem(index)); }
		TXUniString& operator[] (Uint32 index)
			{ return(GetElem(index)); }
		
		/* Size Getter, Size Setter, and Buffer Shrinker */
		Uint32 GetSize () const
			{ return(fArraySize); }
		bool SetSize (Uint32 newSize);
		void FreeExtraBuffer ();
		
		/* Element Appending and Deleting */
		bool Append (const TXUniStringArray& strArray);
		bool Append (const TXUniString& string);
		bool Append (ConstUCStrPtr pCharsTerm);
		bool Append (ConstUCCharPtr pChars, UCCharCnt len);
		bool Append (UCChar uch, UCCharCnt repeatCount);
		void Delete (Uint32 index, Uint32 count=1);
		void DeleteAll (bool keepBuffer);
		
		/* Element Value Setters and Getters */
		bool SetElem (Uint32 index, const TXUniString& string);
		bool SetElem (Uint32 index, ConstUCStrPtr pCharsTerm);
		bool SetElem (Uint32 index, ConstUCCharPtr pChars, UCCharCnt len);
		bool SetElem (Uint32 index, UCChar uch, UCCharCnt repeatCount);
		const TXUniString& GetElem (Uint32 index) const
			{ ASSERTN(kMike, (index < fArraySize)); return(*fStringPtrs[index]); }
		TXUniString& GetElem (Uint32 index)
			{ ASSERTN(kMike, (index < fArraySize)); return(*fStringPtrs[index]); }
		
		/* Searches for a String */
		void FindString (const TXUniString& string, Uint32 startIndex,
		                  bool ignoreCase, bool* pFound, Uint32* pIndex) const;
		void FindString (ConstUCStrPtr pCharsTerm, Uint32 startIndex,
		                  bool ignoreCase, bool* pFound, Uint32* pIndex) const;
		void FindString (ConstUCCharPtr pChars, UCCharCnt len, Uint32 startIndex,
		                  bool ignoreCase, bool* pFound, Uint32* pIndex) const;
	
	private:
		TXUniString		**fStringPtrs;
		Uint32			fBufferSize;
		Uint32			fArraySize;
		Uint32			fGrowChunk;
		
		bool Init (Uint32 initialSize, Uint32 growChunk);
		bool GrowBuffer (Uint32 minSize);
		bool ReallocBuffer (Uint32 newSize);
};


/*============================================================================*/

#endif  // _GSSTRINGX_
