/*
 * ************************************************************************************************************
 * Author: Marcin Załęczny
 * Copyright (C)2010 Marcin Załęczny <mzaleczny@hotmail.com>
 * License: The GNU Lesser General Public License, version 3.0 (LGPLv3)
 * Library Name: mzstd
 * Version: 1.07
 * First release date:   2010-11-08
 * Current release date: 2011-03-04
 *
 *
 * This file is part of mzstd library
 * 
 * mzstd library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * mzstd library 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * ************************************************************************************************************
 */

#ifndef __MZSTD_STRING_H__
#define __MZSTD_STRING_H__

#include "mzstdCommon.h"

#define FORMAT_ALIGN_LEFT       0
#define FORMAT_ALIGN_RIGHT      1


#define ENC_UTF8_WITH_BOM			1
#define ENC_UTF8					2
#define ENC_UNICODE					3
#define ENC_ANSI					10
#define ENC_ISO2					11
#define ENC_OEM_852                 12


class CStringList;
class CString;
class CObject;

// String encoding functions
DECLSPEC_MZSTD LONG WINAPI DetectDataEncoding(BYTE *buf, ULONG buflen);
DECLSPEC_MZSTD VOID WINAPI Iso2ToAnsi(BYTE *buf, ULONG buflen);
DECLSPEC_MZSTD VOID WINAPI AnsiToIso2(BYTE *buf, ULONG buflen);
DECLSPEC_MZSTD VOID WINAPI Oem852ToAnsi(BYTE *buf, ULONG buflen);
DECLSPEC_MZSTD VOID WINAPI AnsiToOem852(BYTE *buf, ULONG buflen);
//DECLSPEC_MZSTD VOID WINAPI UnicodeToAnsi(BYTE *buf, ULONG buflen);


DECLSPEC_MZSTD WORD WINAPI getCharType(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharUpper(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharLower(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharDigit(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharSpace(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharPunct(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharCntrl(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharBlank(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharXdigit(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharAlpha(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharDefined(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharAlphanumeric(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharPrintable(WCHAR ch);
DECLSPEC_MZSTD BOOL WINAPI isCharSentenceBoundary(WCHAR ch);

DECLSPEC_MZSTD BOOL WINAPI isDecimal(WCHAR* str);
DECLSPEC_MZSTD BOOL WINAPI isDouble(WCHAR* str);
DECLSPEC_MZSTD CString WINAPI FormatString(const CString& s, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatTimeValue(SYSTEMTIME* value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatDateValue(SYSTEMTIME* value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatDateTimeValue(SYSTEMTIME* value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatStringValue(WCHAR* value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatLongValue(LONG value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatBoolValue(BOOL value, BOOL uppercase, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatCharValue(CHAR value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatWcharValue(WCHAR value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatULongValue(ULONG value, LONG align, WCHAR fillChar, ULONG width);
DECLSPEC_MZSTD CString WINAPI FormatFloatValue(float value, LONG align, WCHAR fillChar, ULONG width, LONG precision);
DECLSPEC_MZSTD CString WINAPI FormatDoubleValue(double value, LONG align, WCHAR fillChar, ULONG width, LONG precision);
DECLSPEC_MZSTD CString WINAPI FormatHexValue(ULONG value, LONG align, WCHAR fillChar, ULONG width, BOOL prepend0x, BOOL appendH, BOOL useSmallAlpha, LONG minLen);
DECLSPEC_MZSTD CString __cdecl FormatMessage(WCHAR* format, ...);
DECLSPEC_MZSTD CString __cdecl FormatMessage(WCHAR* format, va_list paramList);
DECLSPEC_MZSTD VOID __cdecl Stdout(WCHAR* format, ...);
DECLSPEC_MZSTD VOID __cdecl Stdout(CString format, ...);
DECLSPEC_MZSTD VOID __cdecl Stderr(WCHAR* format, ...);
DECLSPEC_MZSTD VOID __cdecl StdoutInEnc(LONG outputEncoding, WCHAR* format, ...);
DECLSPEC_MZSTD VOID __cdecl StderrInEnc(LONG outputEncoding, WCHAR* format, ...);

// Zwraca łańcuch z postacią heksadecymalną dla podanej liczby. Zwracany jest np ciąg 0x45.
// Parametr minHexNumber określa minimalną liczbę znaków po ciągu '0x'. Jeśli jest on wiekszy
// niż wynikowy łańcuch, to wtedy ten wynikowy łańcuch jest uzupełniany 0-ami po lewej stronie.
// Jeśli useSmallAlpah jest równe TRUE, to dla cyfr 10..15 użyte są znaki 'a'..'f', w przeciwnym
// razie użyte są znaki 'A'..'F'
DECLSPEC_MZSTD CString WINAPI intToHex(ULONG num, LONG minHexNumberLength = 2, BOOL useSmallAlpha = TRUE, BOOL prependx0 = TRUE);
DECLSPEC_MZSTD LONG WINAPI hexToInt(CString hex);

class DECLSPEC_MZSTD CString {
public:
    // WARNING!
    // this two private attributes must be first in class structure, to allow proper CString* class
    // recognition.
    WCHAR* _originClassName;
    WCHAR* _realClassName;
    
public:    
	WINAPI CString();
	WINAPI CString(const CString &s);
	WINAPI CString(const WCHAR* string);
	WINAPI CString(WCHAR *string, ULONG buf_size);
	WINAPI CString(const CHAR* string);
	WINAPI CString(WCHAR ch);
	WINAPI CString(WCHAR ch, LONG repeatCount);
	WINAPI CString(CHAR ch);
	WINAPI CString(UCHAR ch);
	WINAPI CString(INT number, BOOL toHex = FALSE, LONG minDigits = 0);
	WINAPI CString(UINT number, BOOL toHex = FALSE, LONG minDigits = 0);
	WINAPI CString(LONG number, BOOL toHex = FALSE, LONG minDigits = 0);
	WINAPI CString(ULONG number, BOOL toHex = FALSE, LONG minDigits = 0);
    WINAPI CString(BOOL value, WCHAR uppercase); // uppercase can be: 'T'/'t' meaning uppercase/lowercase
	WINAPI CString(double number, LONG precision = 2);
	virtual WINAPI ~CString();

    virtual BOOL WINAPI equals(CObject* obj);
    virtual BOOL WINAPI equals(CString* str);
    virtual CString WINAPI toString();

	inline ULONG WINAPI length() const { return wcslen(this->buf); }
    // Returns length of buffer till first double NULL character. if double NULL not found result is 0.
	ULONG WINAPI lengthDoubleNull();
	inline BOOL WINAPI empty() { return this->length() == 0; }
	inline WCHAR* WINAPI getBuffer() const { return this->buf; }
	inline WCHAR* WINAPI toWCHAR() const { return this->buf; }
	VOID WINAPI setBuffer(WCHAR *buf, ULONG buf_size);
	inline ULONG WINAPI getBufferSize() const { return this->buf_size; }

    LONG WINAPI charCount(CHAR ch);
    LONG WINAPI charCount(WCHAR ch);
    ULONG WINAPI wordCount();
    CString WINAPI getFirstToken(WCHAR* tokenBoundaryChars);
    CString WINAPI popFirstToken(WCHAR* tokenBoundaryChars);
    CString WINAPI getLastToken(WCHAR* tokenBoundaryChars);
    CString WINAPI popLastToken(WCHAR* tokenBoundaryChars);
    CString WINAPI getFirstWord();
    CString WINAPI popFirstWord();
    CString WINAPI getLastWord();
    CString WINAPI popLastWord();

    CString WINAPI substr(LONG start, LONG length = -1);

	// Funkcja sprawdza, czy string przechowuje wartość numeryczną. Jeśli dodatkowo
	// zostały podane niezerowe wskaźniki na zmienne isInt i isDouble, to zwracana
	// jest informacja, czy wartość jest liczbą całkowitą czy liczbą rzeczywistą.
	BOOL WINAPI isNumeric(BOOL *isInt = NULL, BOOL *isDouble = NULL);
	BOOL WINAPI isInt();
	BOOL WINAPI isDouble();
	LONG WINAPI toInt();
	LONG WINAPI toIntRound();
	LONG WINAPI toIntFloor();
	LONG WINAPI toIntCeil();
	double WINAPI toDouble();
    // Konwertuje przechowywany łańcuch UNICODE do ANSI i kopiuje wynik do podanego bufora.
    // Zwraca ilość skopiowanych znaków.
    ULONG WINAPI toCharString(CHAR* dest, DWORD destSize, LONG outputEncoding = ENC_ANSI) const;
    ULONG WINAPI toAnsi(CHAR* dest, DWORD destSize) const {
        return this->toCharString(dest, destSize, ENC_ANSI);
    };
    ULONG WINAPI toIso2(CHAR* dest, DWORD destSize) const {
        return this->toCharString(dest, destSize, ENC_ISO2);
    };
    ULONG WINAPI toOem852(CHAR* dest, DWORD destSize) const {
        return this->toCharString(dest, destSize, ENC_OEM_852);
    };

    // Splits string at specified character and returns string list
    // if maxItems == 0, then splitting is unlimited
    CStringList* WINAPI explode(WCHAR ch, ULONG maxItems = 0);
    // Splits string at specified character under constraintant that each item has minimum
    // minItemLength characters
    CStringList* WINAPI explodeAfterMinLength(WCHAR ch, ULONG minItemLength);
    // Splits string into substrings of specified count words
    CStringList* WINAPI explodeToWords(ULONG wordCount);
    
    // Splits string at each of the specified characters and returns string list
    CStringList* WINAPI explodeAtChar(WCHAR* stringOfChars);
    
    VOID WINAPI rtrim(WCHAR ch);
    VOID WINAPI rtrimAllChars(WCHAR* stringOfChars);
    inline VOID WINAPI rtrim() {
        this->rtrimAllChars(L" \t\n\r");
    }
    VOID WINAPI ltrim(WCHAR ch);
    VOID WINAPI ltrimAllChars(WCHAR* stringOfChars);
    inline VOID WINAPI ltrim() {
        this->ltrimAllChars(L" \t\n\r");
    }
    VOID WINAPI trim(WCHAR ch);
    VOID WINAPI trimAllChars(WCHAR* stringOfChars);
    inline VOID WINAPI trim() {
        this->rtrim();
        this->ltrim();
    }
    
    BOOL WINAPI startsWith(CString s);
    BOOL WINAPI startsWithChar(WCHAR ch);
    BOOL WINAPI startsWithOneOfChars(WCHAR* stringOfChars);
    BOOL WINAPI endsWith(CString s);
    BOOL WINAPI endsWithChar(WCHAR ch);
    BOOL WINAPI endsWithOneOfChars(WCHAR* stringOfChars);
    BOOL WINAPI contains(WCHAR ch);
    BOOL WINAPI contains(WCHAR* substring);
    BOOL WINAPI containsOneOfChars(WCHAR* stringOfChars);
    BOOL WINAPI containsWhiteSpace();
    LONG WINAPI strpos(WCHAR* substring, ULONG startFrom = 0);
    LONG WINAPI strposLast(WCHAR* substring, ULONG startFrom = 0);

	// Znajduje ostatnie wystąpienie podanego znaku i wstawia w jego miejsce NULL, czyli
	// obcina łańcuch na ostatnim wystąpieniu tego znaku.
    VOID WINAPI cutAtLast(WCHAR ch);
    VOID WINAPI cutAtLastChar(WCHAR* stringOfChars);
    
    // Zwraca podłańcuch znajdujący się po ostatnim wystąpieniu znaku ch
    CString WINAPI strAfterLast(WCHAR ch);
    // Zwraca podłańcuch znajdujący się po ostatnim wystąpieniu któregokolwiek ze znaków podanych w ciągu
    // 'stringOfChars'
    CString WINAPI strAfterLastChar(WCHAR* stringOfChars);

    // wstawia znak na podanej pozycji
    VOID WINAPI insertCharAt(WCHAR ch, ULONG pos);
    // wstawia podłańcuch na podanej pozycji
    VOID WINAPI insertAt(ULONG pos, const CString& s);
    // usuwa znak na podanej pozycji, przesuwając wszystkie znaki na prawo od niego o jedną pozycję w lewo
    VOID WINAPI deleteCharAt(ULONG pos);
    VOID WINAPI deleteSubstr(ULONG startpos, ULONG length);

	// odcina z końca łańcucha podaną liczbę znaków
	VOID WINAPI truncateAtEnd(ULONG numChars);
	// dokleja na początku łańcucha znak ch aż do osiągnięcia podanej długości łańcucha.
	// Jeśli długość łańcucha jest większa od podanej wymaganej długści, to nie robi
	// nic.
	VOID WINAPI padLeft(WCHAR ch, ULONG requiredSize);
	// Funkcja identyczna do powyższej z tym, że dokleja znaki na końcu łańcucha.
	VOID WINAPI padRight(WCHAR ch, ULONG requiredSize);

	// zamienia wszystkie wystąpienia znaku src znakiem dst i zwraca ilość
	// podmienionych znaków
	ULONG WINAPI replace(WCHAR src, WCHAR dst);
    // zastępuje wszystkie znaki łańcucha o kodzie mniejszym niż podany kod podanym znakiem
    // i zwraca ilość zastąpionych znaków.
    ULONG WINAPI replaceCharsWithCodeLessThan(WCHAR vkCode, WCHAR dst);
    // zastępuje podłańcuch zaczynający się od znaku o indeksie start i długości length podanym
    // łańcuchem.
	VOID WINAPI replace(ULONG start, ULONG length, const CString& replaceWith);
    // Zastępuje podany łańcuch 'toReplace' łańcuchem 'replaceWith'. Zwraca ilość wykonanych zastąpień
	LONG WINAPI replace(CString toReplace, CString replaceWith, ULONG startFrom = 0, ULONG maxReplacementCount = 0);

	// usuwa z lancucha wszystkie wystąpienia podanego znaku i zwraca ilość
	// usuniętych znaków.
	ULONG WINAPI remove(WCHAR ch);
    // usuwa z łańcucha znaki o kodzie mniejszym niż podany kod i zwraca ilość usuniętych znaków.
    ULONG WINAPI removeCharsWithCodeLessThan(WCHAR vkCode);
    
    // If minLen > 0 and length of the string is less than minLength then extra zeros are added at beginning.
    VOID WINAPI addPrefixZeros(LONG minLen = 0);

    WCHAR getCharAt(LONG i) const {
        return this->buf[i];
    }
    WCHAR lastChar() {
        LONG len = wcslen(this->buf);
        if (len) {
            return this->buf[len - 1];
        }
        return NULL;
    }

    // foreachSubcontentDo
    //    for each found subcontent (in this string) placed between beginTag and endTag calls function doFunc with
    //    pointer to found subcontent, its placement and specified pointer as params. If function doFunc return TRUE, then iterating is stopped.
    //    Return number of found and processed subcontents.
    LONG WINAPI foreachSubcontentDo(WCHAR* beginTag, WCHAR* endTag, BOOL (WINAPI *doFunc)(LONG startPos, LONG endPos, CString* subcontentItem, LPVOID customData), LPVOID customData);
    
	// dokleja na końcu tego łańcucha odpowiedni element i zwraca referencję do tego
	// łańcucha.
    CString& WINAPI append(const CString &s);
    CString& WINAPI append(CHAR *s);
    CString& WINAPI append(WCHAR ch);
    CString& WINAPI append(CHAR ch);
    CString& WINAPI append(UCHAR ch);
    CString& WINAPI append(WCHAR *s);
    CString& WINAPI append(INT num);
    CString& WINAPI append(UINT num);
    CString& WINAPI append(LONG num);
    CString& WINAPI append(ULONG num);
    CString& WINAPI append(double num);
    
	// Appends after end of buffer (after trailing NULL character) specified value. If necessary enlarge internal
    // buffer. At end of appended string appends additiona NULL character (that mean at end of such buffer there
    // are two NULL characters). Appended string is invisible in displaying in standard method. It is for use by
    // such functions as GetOpenFileName (to create filter).
    CString& WINAPI appendAfterEos(const CString &s, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(CHAR *s, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(WCHAR ch, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(CHAR ch, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(UCHAR ch, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(WCHAR *s, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(INT num, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(UINT num, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(LONG num, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(ULONG num, WCHAR glueChar = NULL);
    CString& WINAPI appendAfterEos(double num, WCHAR glueChar = NULL);
    
	// dokleja na początku tego łańcucha odpowiedni element i zwraca referencję do tego
	// łańcucha.
    CString& WINAPI prepend(CString &s);
    CString& WINAPI prepend(CHAR *s);
    CString& WINAPI prepend(WCHAR ch);
    CString& WINAPI prepend(CHAR ch);
    CString& WINAPI prepend(UCHAR ch);
    CString& WINAPI prepend(WCHAR *s);
    CString& WINAPI prepend(INT num);
    CString& WINAPI prepend(UINT num);
    CString& WINAPI prepend(LONG num);
    CString& WINAPI prepend(ULONG num);
    CString& WINAPI prepend(double num);

    ULONG WINAPI linesCount();
    CString& WINAPI prependEachLine(CString &s);
    CString& WINAPI prependEachLine(CHAR *s);
    CString& WINAPI prependEachLine(WCHAR ch);
    CString& WINAPI prependEachLine(CHAR ch);
    CString& WINAPI prependEachLine(UCHAR ch);
    CString& WINAPI prependEachLine(WCHAR *s);
    CString& WINAPI prependEachLine(INT num);
    CString& WINAPI prependEachLine(UINT num);
    CString& WINAPI prependEachLine(LONG num);
    CString& WINAPI prependEachLine(ULONG num);
    CString& WINAPI prependEachLine(double num);

	// przeciążone operatory
    inline BOOL WINAPI operator==(CString &s) { return wcscmp(this->buf, s.getBuffer()) == 0; };
    inline BOOL WINAPI operator==(CHAR *s) { CString cs(s); return (*this) == cs; };
    inline BOOL WINAPI operator==(WCHAR ch) { CString cs(ch); return (*this) == cs; };
    inline BOOL WINAPI operator==(CHAR ch) { CString cs(ch); return (*this) == cs; };
    inline BOOL WINAPI operator==(UCHAR ch) { CString cs(ch); return (*this) == cs; };
    inline BOOL WINAPI operator==(WCHAR *s) { CString cs(s); return (*this) == cs; };
    inline BOOL WINAPI operator==(INT num) { CString cs(num); return (*this) == cs; };
    inline BOOL WINAPI operator==(UINT num) { CString cs(num); return (*this) == cs; };
    inline BOOL WINAPI operator==(LONG num) { CString cs(num); return (*this) == cs; };
    inline BOOL WINAPI operator==(ULONG num) { CString cs(num); return (*this) == cs; };
    inline BOOL WINAPI operator==(double num) { CString cs(num); return (*this) == cs; };

    inline BOOL WINAPI operator!=(CString &s) { return wcscmp(this->buf, s.getBuffer()) != 0; };
    inline BOOL WINAPI operator!=(CHAR *s) { CString cs(s); return (*this) != cs; };
    inline BOOL WINAPI operator!=(WCHAR ch) { CString cs(ch); return (*this) != cs; };
    inline BOOL WINAPI operator!=(CHAR ch) { CString cs(ch); return (*this) != cs; };
    inline BOOL WINAPI operator!=(UCHAR ch) { CString cs(ch); return (*this) != cs; };
    inline BOOL WINAPI operator!=(WCHAR *s) { CString cs(s); return (*this) != cs; };
    inline BOOL WINAPI operator!=(INT num) { CString cs(num); return (*this) != cs; };
    inline BOOL WINAPI operator!=(UINT num) { CString cs(num); return (*this) != cs; };
    inline BOOL WINAPI operator!=(LONG num) { CString cs(num); return (*this) != cs; };
    inline BOOL WINAPI operator!=(ULONG num) { CString cs(num); return (*this) != cs; };
    inline BOOL WINAPI operator!=(double num) { CString cs(num); return (*this) != cs; };

	CString& WINAPI operator=(CString &s);
	CString& WINAPI operator=(CHAR *s);
	CString& WINAPI operator=(WCHAR ch);
	CString& WINAPI operator=(CHAR ch);
	CString& WINAPI operator=(UCHAR ch);
	CString& WINAPI operator=(WCHAR *s);
	CString& WINAPI operator=(INT num);
	CString& WINAPI operator=(UINT num);
	CString& WINAPI operator=(LONG num);
	CString& WINAPI operator=(ULONG num);
	CString& WINAPI operator=(double num);

	CString& WINAPI operator+=(CString &s);
	CString& WINAPI operator+=(CHAR *s);
	CString& WINAPI operator+=(CHAR ch);
	CString& WINAPI operator+=(UCHAR ch);
	CString& WINAPI operator+=(WCHAR ch);
	CString& WINAPI operator+=(WCHAR *s);
	CString& WINAPI operator+=(INT num);
	CString& WINAPI operator+=(UINT num);
	CString& WINAPI operator+=(LONG num);
	CString& WINAPI operator+=(ULONG num);
	CString& WINAPI operator+=(double num);

	CString WINAPI operator+(CString &s);
	CString WINAPI operator+(CHAR *s);
	CString WINAPI operator+(WCHAR ch);
	CString WINAPI operator+(CHAR ch);
	CString WINAPI operator+(UCHAR ch);
	CString WINAPI operator+(WCHAR *s);
	CString WINAPI operator+(INT num);
	CString WINAPI operator+(UINT num);
	CString WINAPI operator+(LONG num);
	CString WINAPI operator+(ULONG num);
	CString WINAPI operator+(double num);

    WCHAR WINAPI operator[](INT i) {
        return this->buf[i];
    }

    
    // Returned position is counted in WCHAR*
    LONG WINAPI findDoubleNullPos();
    VOID WINAPI setStringArray(WCHAR *buf, ULONG bufsize);
    
    static WCHAR WINAPI charToWchar(CHAR ch);
    // Returned position is counted in WCHAR*
    static LONG WINAPI findDoubleNullPos(WCHAR* buf, ULONG bufsize);
    
    // Returns new string consisting of character ch repeated count times.
    static CString WINAPI makeString(WCHAR ch, ULONG count);
    
    VOID WINAPI zeroBuffer();

    CString& WINAPI toUppercase();
    CString& WINAPI toLowercase();
    
protected:
	VOID WINAPI initBuffer();
	VOID WINAPI initBuffer(ULONG size);
	VOID WINAPI extendBuffer(ULONG added_size);
	VOID WINAPI cleanup();

private:
	ULONG buf_size;
	WCHAR *buf;
	ULONG _growBy;

	VOID WINAPI _commonInit();
};
typedef CString* PString;


#endif
