SOL9 2.0 Class: String

 SOL9 C++ Class Library  SOL9 Samples  SOL9 Tutorial  SOL9 FAQ  SOL9 ClassTree 

Source code

/*
 * String.h 
 * Copyright (c) 2012 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */


// SOL++2000
// 1999.09.03 Added a constructor to take a pointer to String.
// 2000/11/11
// 2008/07/07 Modified to define all methods in header file.

// 2009/04/09 Modified to call SecureZeroMemory in private clear() method which 
// can be called in Destructor.
// 2009/04/09 Added a method secureClear() to call SecureZeroMemory 
// and delete the memory area.
// 2009/04/10 Added a method bool isEmpty().

// 2009/10/08 Modified to use TCHAR instead of char.
// 2012/03/07 Updated Constructor to allow a shallowCopy
// 2012/04/10 Added 'contains' and 'split' methods.

#pragma once
#include <sol\Object.h>

#include <sol\OutOfMemoryException.h>
#include <sol\NullPointerException.h>
#include <sol\OutOfRangeException.h>
#include <sol\InvalidArgumentException.h>
#include <sol\StringConverter.h>
#include <sol/StringT.h>

namespace SOL {

class String :public Object {
private:
    int        length;
    TCHAR*    text;
    
private:
    bool copy(const TCHAR* string)
    {
        bool rc = false;
        if (string != NULL) {
            int len = strlen(string);

            TCHAR* temp = new TCHAR[len+1];
            if(temp) {
                strcpy_s(temp, len+1, string);
                if(this->text != string && this->text !=NULL) {
                    //_soltrace("String::copy,1,delete text\n");
                    delete [] this->text;
                }
                this->text = temp;
                this->length = len;
                rc = true;
            } else {
                //Memory allocation error.
            }
        }
        return rc;
    }

public:
    /**
     */
    String()
        :length(0),
        text(NULL)
    {
        //_soltrace("String::String()\n");
    }

public:
    //2012/03/07 
    String(const TCHAR* string, bool deepCopy=true)
    :length(0),
    text(NULL) 
    {     
        if (string) {
            if (deepCopy) {
                if (copy(string) == false) {
                    throw OutOfMemoryException("String::String,1,Failed to create a string");
                }
            } else {
                shallowCopy((TCHAR*)string);
            }
        }
    }
public:
    // 2011/01/31 Added new constructor.
    // The first array parameter can be an array of non-NULL terminated TCHAR.
    // The second len parameter specifies a length of the array of the string parameter.
    String(TCHAR* array, int len)
    :length(0),
    text(NULL) 
    {
        // Create an NULL-termiinated TCHAR string of length len.
        deepCopy(array, len);
    }


#ifndef UNICODE 
public:
    String(const wchar_t* wstring, bool deepCopy=true)
    :length(0),
    text(NULL) 
    {     
        if (wstring) {
            StringConverter converter;
            StringT<char> cstring; 
            converter.toMultiByte(wstring, cstring);
            const char* str = (const char*)cstring; 
            if (deepCopy) {
                if (copy(str) == false) {
                    throw OutOfMemoryException("String::String,1,Failed to create a string");
                }
            } else {
                shallowCopy((char*)str);
            }
        }
    }
#endif


#ifdef UNICODE
public:
 
    String(const char* string, bool deepCopy=true)
    :length(0),
    text(NULL) 
    {     
        if (string) {
            StringConverter converter;
            StringT<wchar_t> wstring;
            
            converter.toWideChar(string, wstring);
            const wchar_t* str = (const wchar_t*)wstring;
            if (deepCopy) {
                if (copy(str) == false) {
                    throw OutOfMemoryException("String::String,1,Failed to create a string");
                }
            } else {
                shallowCopy((wchar_t*)str);
            }
        }
    }
#endif

// 1999.09.03 Added

public:
    String(const String* string)
    :length(0),
    text(NULL) 
    {     
        if (string) {
            const TCHAR*    str = string->getContents();
            if (str == NULL) {
                return;
            }
            else {
                if (copy(str) == false) {
                    throw OutOfMemoryException("String::String,2,Failed to create a string");
                }
            }
        }
    }


public:
    String(const String& string)
    :length(0),
    text(NULL)
    {
        //this->length = string.getLength();
        //this->text = NULL;
        const TCHAR* str = (const TCHAR*)string;
        if (str == NULL) {
            return;
        } else {
            if (copy(str) == false) {
                throw OutOfMemoryException("Failed to create a string");
            }
        }
    }

public:
    String(const StringT<char>& string)
    :length(0),
    text(NULL)
    {
        //this->length = string.getLength();
        //this->text = NULL;
        const char* cstring  = (const char*)string;
        if (cstring == NULL) {
            return;
        }
        else {
#ifdef UNICODE
            StringConverter converter;

            StringT<wchar_t> wstring;
            converter.toWideChar(cstring, wstring);
            const wchar_t* str = (const wchar_t*)wstring;
#else 
            const char* str = cstring;
#endif
        
            if (copy(str) == false) {
                throw OutOfMemoryException("Failed to create a string");
            }
        }
    }


public:
    String(const StringT<wchar_t>& string)
    :length(0),
    text(NULL)
    {
        //this->length = string.getLength();
        //this->text = NULL;
        const wchar_t* wstring  = (const wchar_t*)string;
        if (wstring == NULL) {
            return;
        }
        else {
#ifdef UNICODE
            const wchar_t* str = wstring;

#else 
            StringConverter converter;

            StringT<char> cstring;
            converter.toMultiByte(wstring, cstring);
            const char* str = (const char*)cstring;

#endif
        
            if (copy(str) == false) {
                throw OutOfMemoryException("Failed to create a string");
            }
        }
    }

public:
    ~String() { 
        clear();
    }

private:
    // 2009/04/09 Modiffied to call SecureZeroMemory
    void clear() { 
        if (this->text) {
            //2009/04/09
            SecureZeroMemory(this->text, this->length);
            delete [] this->text;
        }
        this->text =NULL;
        this->length = 0;
    }

public:
    // 2009/04/09 Call SecureZeroMemory() and  delete the memory area
    void secureClear() { 
        if (this->text) {
            SecureZeroMemory(this->text, this->length);
            delete [] this->text;
        }
        this->text =NULL;
        this->length = 0;
    }

public:
    TCHAR*   getContents() const { 
        return this->text; 
    }

public:
    int     getLength() const  { 
        return this->length; 
    }

public:
    //2009/04/10
    bool isEmpty() {
        bool rc = false;
        if (this->length>0 && this->text !=NULL) {
            rc = true;
        }
        return rc;
    }


public:
    operator TCHAR*() const{
        return this->text;
    }

public:
    operator const TCHAR*() const{
        return this->text;
    }

public:
    String& operator=(const TCHAR* string)
    { 
        _soltrace("String::operator=(const TCHAR*)\n");
        if (string != NULL) {
            if(copy(string) == false) {
                throw OutOfMemoryException("Failed to substitue a string");
            }
        }
        return *this;
    }

#ifdef UNICODE
public:
    String& operator=(const char* string)
    { 
        //_soltrace("String::operator=(const TCHAR*)\n");
        if (string != NULL) {
            StringConverter converter;
            StringT<wchar_t> wstring;
            converter.toWideChar(string, wstring);

            const wchar_t* str = (const wchar_t*)wstring;
            if(copy(str) == false) {
                throw OutOfMemoryException("Failed to substitue a string");
            }
        }
        return *this;
    }
#endif

#ifndef UNICODE
public:
    String& operator=(const wchar_t* wstring)
    { 
        //_soltrace("String::operator=(const TCHAR*)\n");
        if (wstring != NULL) {
            StringConverter converter;
            StringT<char> cstring;
            converter.toMultiByte(wstring, cstring);
            const char* str = (const char*)cstring;
            if(copy(str) == false) {
                throw OutOfMemoryException("Failed to substitue a string");
            }
        }
        return *this;
    }
#endif

public:
    //2011/01/28
    // The string parameter can be non-NULL terminated.
    void deepCopy(TCHAR* string, int length)
    {
        if (string != NULL && length>0) {
            if (this->text != string) {
                clear();
            }
            int len = length;

            TCHAR* temp = new TCHAR[len+1];
            memcpy(temp, string, len);
            temp[len] = NULL;    //Put a NULL char at this len position to make a NULL terminated string
            this->text = temp;
            this->length = len;
        } else {
            clear();

            this->text   = NULL;
            this->length = 0;
        }
    }

public:
    void shallowCopy(TCHAR* string)
    { 
        // Accept a string of NULL
        _soltrace("String::shallowCopy(const TCHAR*)\n");
        if (string) {
            if (this->text != string) {
                clear();
            }
            this->text   = string;
            this->length = strlen(string);
        }
        else {
            clear();

            this->text   = string;    //NULL
            this->length = 0;
            //throw InvalidArgumentException("String::shallowCopy,InvalidArgument");
        }        
    }

public:
    String& operator=(const String& string)
    {        
        _soltrace("String::operator=(const String&)\n");

        //this->length = string.getLength();
        TCHAR* str = string.getContents();
        if (str) {
            if (copy(str) == false) {
                throw OutOfMemoryException("Failed to substitue a string");
            }
        } else {
            //str = NULL;
            clear();

            this->text = str;
            this->length = 0;
        }
        return *this;
    }

public:
    int operator==(const TCHAR* string)
    {
        int rc = 0;
        if (this->text == NULL && string ==NULL) {
            rc = 1;
        }

        //2008/07/08
        if (this->text != NULL && string != NULL) {
            if(strcmp(this->text, string) == 0) {
                rc = 1;
            }
        }
        return rc;
    }


    //int operator==(String& string)
public:
    int operator==(String& string)
    {
        int rc = 0;
        const TCHAR* str = (const TCHAR*)string;
        if (this->text == NULL && str ==NULL) {
            rc = 1;
        }

        if (this->text != NULL && str != NULL) {
            if(strcmp(this->text, str) == 0) {
                rc = 1;
            }
        }
        return rc;
    }

public:
    String& operator+(const TCHAR* string)
    {
        if(string == NULL) {
            return *this;
        }

        this->length += strlen(string);
        TCHAR* temp = new TCHAR[this->length+1];
        _stprintf_s(temp, this->length+1, _T("%s%s"), this->text, string);
        /*
        */
        if(this->text != string) {
            delete [] text;
        }
        text = temp;
        return *this;
    }

#ifdef UNICODE
public:
    String& operator+(const char* string)
    {
        if(string == NULL) {
            return *this;
        }
        StringConverter converter;
        wchar_t* wstring = converter.toWideChar(string);

        this->length += strlen(wstring);
        wchar_t* temp = new wchar_t[this->length+1];
        _stprintf_s(temp, this->length+1, _T("%s%s"), this->text, wstring);

        if(this->text != wstring) {
            delete [] text;
        }
        text = temp;

        delete [] wstring;

        return *this;
    }
#endif

#ifndef UNICODE
public:
    String& operator+(const wchar_t* wstring)
    {
        if(wstring == NULL) {
            return *this;
        }
        StringConverter converter;
        const char* cstring = converter.toMultiByte(wstring);

        this->length += strlen(cstring);
        char* temp = new char[this->length+1];
        sprintf_s(temp, this->length+1, "%s%s", this->text, cstring);

        if(this->text != temp) {
            delete [] text;
        }
        text = temp;

        delete [] cstring;

        return *this;
    }
#endif

public:
    int compare(Object* object)
    {
        int rc = 0;
        if (object==NULL) {
            return rc;
        }

        String* string = (String*)object;
        const TCHAR* p1 = this->text;

        const TCHAR* p2 = (const TCHAR*)(*string);
        if (p1 == NULL && p2 == NULL) {
            rc = 1;
        }
        if (p1 != NULL && p2 != NULL) {
            rc = strcmp(p1, p2);
        }
        return rc;
    }


public:
    //2012/04/10
    bool contains(const TCHAR* string)    
    {
        bool rc = false;
        if (find(string)) {
            rc = true;
        }
        return rc;
    }

public:
    const TCHAR* find(const TCHAR* string)    
    {
        const TCHAR* ptr = NULL;
        if (this->text && string) {
            ptr = strstr(this->text, string);
        }
        return ptr;
    }

public:
    int split(__in const TCHAR ch, __out String& string1, __out String& string2)    
    {
        int rc = 0;

        if (this->text) {
            TCHAR* ptr = (TCHAR*)strchr(this->text, ch);
            if (ptr) {
                int len1 = ptr - text;
                if (len1 > 0) {
                    string1.deepCopy(text, len1);
                    //_tprintf(_T("1=[%s]\n"), (const TCHAR*)string1);
                    rc++;
                }
            
                int len2 = this->length - len1-1;
                if (len2 > 0) {
                    string2.deepCopy(++ptr, len2);
                    //_tprintf(_T("2=[%s]\n"), (const TCHAR*)string2);
                    rc++;
                }
            }
        }
        return rc;
    }

public:
    int replace(TCHAR oc, TCHAR nc)
    {
        int    n = 0;
        if (this->text) {
            for (int i = 0; i<this->length; i++) {
                if (text[i] == oc) {
                    text[i] = nc;
                    n++;
                }
            }
        }
        return n;
    }
public:
    //2009/11/16
    bool removeBackSlash()
    {
        bool rc = false;
        if (this->text && this->length>0) {
            if (this->text[this->length-1] == '\\') {
                this->text[this->length-1] = '\0';
                this->length--;
                rc = true;
            }
        }
        return rc;
    }


//<added date="2000/11/10">
public:
    String& operator+(TCHAR ch)
    {
        TCHAR string[80];
        //sprintf_s(string, sizeof(string), "%c", ch);
        string[0] = ch;
        string[1] = (TCHAR)0;//Zero;

        return String::operator+(string);
    }

public:
#ifdef UNICODE
    String& operator+(char ch)
    {
        TCHAR string[80];
        //sprintf_s(string, sizeof(string), "%c", ch);
        string[0] = (TCHAR)ch;
        string[1] = (TCHAR)0;//Zero;

        return String::operator+(string);
    }
#endif

public:
    String& operator+(int num)
    {
        TCHAR string[80];
        _stprintf_s(string, SizeOf(string), _T("%d"), num);

        return String::operator+(string);
    }

public:
    bool equals(const TCHAR* str) {
        bool rc = false;
        if(this->text != NULL && str != NULL) {
            if(strcmp(this->text, str) == 0) {
                   rc = true;
            }
        }
        return rc;
    }

public:
    bool equals(const String& str) {
        return equals((const TCHAR*)str);
    }

public:
    bool equalsIgnoreCase(const TCHAR* str) const {
        bool rc = false;

        if(this->text != NULL && str != NULL) {
            //strcmpi -> stricmp
            if(_stricmp(this->text, str) == 0) {
                   rc = true;
            }
        }
        return rc;
    }

public:
    bool equalsIgnoreCase(const String& str) const {
        return equalsIgnoreCase((const TCHAR*)str);
    }

public:
    String& operator+(float num)
    {
        TCHAR string[80];
        _stprintf_s(string, SizeOf(string), _T("%f"), num);

        return String::operator+(string);
    }

public:
    void trim()
    {
        TCHAR* rt = String::trim(this->text);

        if (rt) {
            clear();
            //Shallow copy
            this->text = rt;
            this->length = strlen(rt);
        }
    }

public:
    void trimOnNewLine() {
        if (this->text) {
            TCHAR* ptr = (TCHAR*)strstr(this->text, _T("\r\n"));
            if (ptr) {
                //Terminate this text on this ptr position by putting '\0';
                *ptr = '\0';
                this->length = strlen(this->text);
            }
        }
    }


public:
    /**
     */    
    bool     startsWith(const TCHAR* start) {
        return String::startsWith(this->text, start);
    }

public:
    /**
     */    
    bool     startsWithIgnoreCase(const TCHAR* start) {
        return String::startsWithIgnoreCase(this->text, start);
    }

public:
    /**
     */    
    bool     endsWith(const TCHAR* end) {
        return String::endsWith(this->text, end);
    }

public:
    /**
     */    
    bool     endsWithIgnoreCase(const TCHAR* end) {
        return String::endsWithIgnoreCase(this->text, end);
    }

public:
    //2009/11/12
    const TCHAR* findLast(const TCHAR* string)
    {
        return String::findLast(this->text, string);
    }

public:
    //2009/11/12
    static const TCHAR* findLast(const TCHAR* text, const TCHAR* string)
    {
        const TCHAR* ptr = NULL;

        if (text && string) {
            int tlen = strlen(text);
            int slen = strlen(string);
            if (tlen < slen) {
                return ptr;
            } else {
                for(int i = tlen - slen; i>=0; i--) {
                    int n= strncmp(text + i, string, slen);
                    if (n == 0) {
                        ptr = text + i;
                        break;
                    }
                }
            }    
        }
        return ptr;
    }

public:
    //2009/11/12
    const TCHAR* findFirst(const TCHAR* string) {
        return String::findFirst(this->text, string);        
    }

public:
    //2009/11/12
    static const TCHAR* findFirst(const TCHAR* text, const TCHAR* string) {
        const TCHAR* ptr = NULL;
        if (text && string) {
            ptr = strstr(text, string);
        }
        return ptr;
    }


public:
    TCHAR&    operator[](int n) 
    {
        if (this->text == NULL) {
            throw NullPointerException("String::operator[] - Text is NULL");
        }
        if (n <=0 || n>this->length) {
            throw OutOfRangeException("String::operator[] - Index is out of range");
        }
        
        return text[n]; 
    }


public:
    // If UNICODE environment, then this->text is wcstring.
    //  convert it to mbstring and return it to parameter string.
    // If not, then this->text is mbstring, and return it to parameter string. 
    // 2009/10/26 Addecd cnst
    bool getString(__out StringT<char>& tstring) const
    {
        bool rc = false;

        if (text == NULL) {
            return rc;            
        }
#ifdef UNICODE
        
        wchar_t* wcstring = text;
        
        int cb = WideCharToMultiByte(CP_ACP, 0, 
                wcstring, -1, NULL, 0, NULL, NULL);
        
        if (cb > 0) {
            char* mbstring = new char[cb];
            mbstring[0] = Zero;
            WideCharToMultiByte(CP_ACP, 0, wcstring, -1, mbstring, cb, NULL, NULL);
            tstring.shallowCopy(mbstring);
            rc = true;
        }

#else 
        //2009/11/01
        tstring = (char*)text;
        rc = true;
#endif

        return rc;
    }


public:
    // If UNICODE environment, then this->text is wcstring.
    //  and return it to parameter string.
    // If not, then this->text is mbstring, and return convert it to
    // wcstring and return it to parameter string. 
    // 2009/10/26 Addecd cnst
    bool getString(__out StringT<wchar_t>& tstring) const
    {
        bool rc = false;

        if (text == NULL) {
            return rc;            
        }

#ifdef UNICODE
        tstring = text;
        rc = true;
#else 
        rc = true;
        char* mbstring = text;
        int cb = MultiByteToWideChar(CP_ACP, 0, mbstring, -1, NULL, 0); 
        if (cb >0) {
            wchar_t* wcstring = new wchar_t[cb];
            wcstring[0] = Zero;
            MultiByteToWideChar(CP_ACP, 0, mbstring, -1, wcstring, cb);
            tstring.shallowCopy(wcstring);
            rc = true;
        }
#endif

        return rc;
    }


//////////////////////////////////////////////////////////////////
//@static methods

public:
    static char* trim(__in char* string) {
        if (string == NULL) {
            return NULL;
        }
        
        size_t slen = strlen(string)+1;

        char* temp = new char[slen];
        strcpy_s(temp, slen, string);
        char* p = temp;

        while (*p == ' ' || *p == '\t' || *p =='\r' || *p=='\n') {
            p++;
        }

        char* t = p + strlen(p) -1;
        while (*t == ' ' || *t == '\t' || *t =='\r' || *t=='\n') {
            if (p == t) break;
            *t = '\0';
            t--;
        }

        size_t plen = strlen(p)+1;
        char* rt = new char[plen];
        strcpy_s(rt, plen, p);

        delete [] temp;

        return rt;
    }

public:
    static wchar_t* trim(__in wchar_t* string) {
        if (string == NULL) {
            return NULL;
        }
        
        size_t slen = strlen(string)+1;

        wchar_t* temp = new wchar_t[slen];
        strcpy_s(temp, slen, string);
        wchar_t* p = temp;

        while (*p == ' ' || *p == '\t' || *p =='\r' || *p=='\n') {
            p++;
        }

        wchar_t* t = p + strlen(p) -1;
        while (*t == ' ' || *t == '\t' || *t =='\r' || *t=='\n') {
            if (p == t) break;
            *t = '\0';
            t--;
        }

        size_t plen = strlen(p)+1;
        wchar_t* rt = new wchar_t[plen];
        strcpy_s(rt, plen, p);

        delete [] temp;

        return rt;
    }

public:
    static bool trim(__in TCHAR* string, __out String& tstring) {
        bool rc = false;
        if (string == NULL) {
            return rc;
        }

        TCHAR* trimmed = trim(string);
        if (trimmed) {
            tstring = trimmed;
        }
        return rc;
    }
public:
    static bool trim(__in char* string, __out StringT<char>& tstring) {
        bool rc = false;
        if (string == NULL) {
            return rc;
        }

        char* trimmed = trim(string);
        if (trimmed) {
            tstring.shallowCopy(trimmed);
        }
        return rc;
    }

public:
    static bool trim(__in wchar_t* string, __out StringT<wchar_t>& tstring) {
        bool rc = false;
        if (string == NULL) {
            return rc;
        }

        wchar_t* trimmed = trim(string);
        if (trimmed) {
            tstring.shallowCopy(trimmed);
        }
        return rc;
    }

public:
    /**
     * 
     * @param string    
     * @param start
     * @return bool
     */    
    static bool  startsWith(__in const char* string, __in const char* start) {
        bool rc = false;
        if (string != NULL && start != NULL) {
            if (strncmp(string, start, strlen(start)) ==0) {
                rc = true;
            }
        }
        return rc;
    }

public:
    static bool  startsWith(__in const wchar_t* string, __in const wchar_t* start) {
        bool rc = false;
        if (string != NULL && start != NULL) {
            if (strncmp(string, start, strlen(start)) ==0) {
                rc = true;
            }
        }
        return rc;
    }

public:
    /**
     * 
     * @param string
     * @param start
     * @return bool
     */    
    static bool  startsWithIgnoreCase(__in const char* string, __in const char* start) {
        bool rc = false;
        if (string != NULL && start != NULL) {
            if (_strnicmp(string, start, strlen(start)) ==0) {
                rc = true;
            }
        }
        return rc;
    }

public:
    static bool  startsWithIgnoreCase(__in const wchar_t* string, __in const wchar_t* start) {
        bool rc = false;
        if (string != NULL && start != NULL) {
    
            if (_strnicmp(string, start, strlen(start)) ==0) {
                rc = true;
            }
        }
        return rc;
    }


public:
    /**
     * 
     * @param string
     * @param end
     * @return bool
     */    
    static bool endsWith(__in const char* string, __in const char* end) {
        bool rc = false;
        if (string != NULL && end != NULL) {
            size_t tlen = strlen(string);
            size_t slen = strlen(end);
            if (tlen >= slen) {
                if (strncmp(string+tlen-slen, end, slen) ==0) {
                    rc = true;
                }
            }
        }
        return rc;
    }

public:
    static bool endsWith(__in const wchar_t* string, __in const wchar_t* end) {
        bool rc = false;
        if (string != NULL && end != NULL) {
            size_t tlen = strlen(string);
            size_t slen = strlen(end);
            if (tlen >= slen) {
                if (strncmp(string+tlen-slen, end, slen) ==0) {
                    rc = true;
                }
            }
        }
        return rc;
    }

public:
    /**
     * 
     * @param string
     * @param end    
     * @return bool
     */    
    static bool endsWithIgnoreCase(__in const char* string, __in const char* end) {
        bool rc = false;
        if (string != NULL && end != NULL) {
            size_t tlen = strlen(string);
            size_t slen = strlen(end);
            if (tlen >= slen) {
                if (_strnicmp(string+tlen-slen, end, slen) ==0) {
                    rc = true;
                }
            }
        }
        return rc;
    }

public:
    static bool endsWithIgnoreCase(__in const wchar_t* string, __in const wchar_t* end) {
        bool rc = false;
        if (string != NULL && end != NULL) {
            size_t tlen = strlen(string);
            size_t slen = strlen(end);
            if (tlen >= slen) {
                if (_strnicmp(string+tlen-slen, end, slen) ==0) {
                    rc = true;
                }
            }
        }
        return rc;
    }


};

}


Last modified: 17 Apr 2012

Copyright (c) 2009-2012 Antillia.com ALL RIGHTS RESERVED.