osncore/osncore/src/ustringimpl.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:18 +0100
branchRCL_3
changeset 26 0e9bb658ef58
parent 0 e83bab7cf002
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  String class implementation
*
*/


#include "ustringimpl.h"

#include <gstring.h>
#include <stdexcept>
#if defined(__GNUC__)
#include <string.h>
#else
#include <string.h>
#endif
#include <osn/osnnew.h>
using namespace std;

 
namespace osncore
{

const int KMaxUtf8Length = 6;


// -------------------------------------------------------------------------
// Returns the byte count for aStr with aCharCount length
// -------------------------------------------------------------------------
//
static long bytesFromCharacters(const Utf8* aStr, long aCharCount)
    {
    int byteCount = 0;
    
    if (aStr)
        {
        const char* srcEndOffset = g_utf8_offset_to_pointer(aStr,aCharCount); 
        byteCount = srcEndOffset - aStr;    
        }
    
    return byteCount;
    }

// -------------------------------------------------------------------------
// Initializes the string from stack or heap depending on its length
// -------------------------------------------------------------------------
//
void UStringImpl::initialize(const Utf8* aStr)
    {
    if (len < MAX_STR_LEN)
        {
        str = internalStr;
        memcpy(internalStr, aStr, len);
        }
    else
        {
        str = (gchar*)calloc(len+1, sizeof (gchar));
    	if(!str)
    		{
    		throw bad_alloc();
    		}
    	memcpy(str,aStr,len);
    	isInHeap = true;
        }
	
	str[len] = 0;
	allocated_len = len+1;    
    }
    
// -------------------------------------------------------------------------
// Allocates memory from heap if needed, throws if allocation fails
// -------------------------------------------------------------------------
//
void UStringImpl::checkBuffer(unsigned int aLength)
	{
	if (aLength < allocated_len)
		{
		return;
		}
    if (aLength >= MAX_STR_LEN)
        {
        if (!isInHeap) //str is in stack, move it to heap
            {
            gchar* temp = (gchar*)calloc(aLength + 1, sizeof(gchar));
            if (!temp)
                {
        		throw bad_alloc();
                }
            if(str)
                {
                memcpy(temp, str, len);
                }
            str = temp;
            isInHeap = true;
            }
        else
            {
        	gchar* tmp(0);
        	tmp = (gchar*)realloc(str,aLength+1);
        	if(!tmp)
        		{
        		throw bad_alloc();
        		}
        	str = tmp;
            }
        }
    else
        {
        // if ustring is constructed with null or "" set internal buffer to
        // point to str
        if (!str)
            str = internalStr;
        }
	allocated_len = aLength+1;

     
	// reset allocated space
	memset(str+len, 0, allocated_len-len);
	}
// -------------------------------------------------------------------------
// Implements the actual insertion functionality
// -------------------------------------------------------------------------
//
void UStringImpl::insertImpl(unsigned int aIndex, const char* aInsertChars, unsigned int aInsertLength)
	{
    // Ensure that we have enough space.
	checkBuffer(len + aInsertLength); 
	// Move tail to make space for inserted characters.
    memmove(str+aIndex+aInsertLength, str+aIndex, len-aIndex);
    // Insert characters.
    memcpy(str+aIndex, aInsertChars, aInsertLength);
    // Update len
    len += aInsertLength;
	}  
// -------------------------------------------------------------------------
// Implements the actual append functionality
// -------------------------------------------------------------------------
//
void UStringImpl::appendImpl(const char* aStr, unsigned int aLength)
	{
	insertImpl(len, aStr, aLength);
	}
// -------------------------------------------------------------------------
// Implements the actual erase functionality
// -------------------------------------------------------------------------
//
void UStringImpl::eraseImpl(unsigned int aIndex, unsigned int aLength)
	{
	if(aIndex > len)
		{
		throw out_of_range("out_of_range");
		}
	
	if(aIndex+aLength >= len)
		{
		// erase from given index to end of the string
		if(aIndex<len)
			{
			len = aIndex;
			}
		memset(str+aIndex,0,len-aIndex);
		}
	else
		{
		// Move tail (remove begin or between) to given index.
	    memmove(str+aIndex, str+aIndex+aLength, len-(aIndex+aLength));
		len -=  aLength;
		memset(str+len,0,allocated_len-len);
		}
	}
    
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
//
UStringImpl::UStringImpl():str(0),len(0),allocated_len(0), isInHeap(0)
	{
#ifdef _DEBUG
	g_setenv("G_SLICE","always-malloc",1);
#endif
	}
// -------------------------------------------------------------------------
// Constructs the string from aStr
// -------------------------------------------------------------------------
//
UStringImpl::UStringImpl(const Utf8* aStr)
    :str(0),len(0),allocated_len(0), isInHeap(0)
    {
#ifdef _DEBUG    
    g_setenv("G_SLICE","always-malloc",1);
#endif    
    //NULL byte not accepted
    if (aStr)
        {
        len = strlen(aStr); 
        initialize(aStr);
        }   
    }

// -------------------------------------------------------------------------
// Constructs the string from aStr with aByteCount length
// -------------------------------------------------------------------------
//
UStringImpl::UStringImpl(const Utf8* aStr, int aByteCount)
    :str(0),len(0),allocated_len(0), isInHeap(0)
    {
#ifdef _DEBUG    
    g_setenv("G_SLICE","always-malloc",1);
#endif    
    //NULL byte not accepted
    if (aStr)
        {
        len = aByteCount;
        initialize(aStr);
        }    
    }

// -------------------------------------------------------------------------
// Constructs the string from aCodePoint
// -------------------------------------------------------------------------
//
UStringImpl::UStringImpl(Unicode aCodePoint)
    :str(0),len(0),allocated_len(0), isInHeap(0)
    {
#ifdef _DEBUG    
    g_setenv("G_SLICE","always-malloc",1);
#endif    
        
    char string[KMaxUtf8Length]; 
    long usedBytes = g_unichar_to_utf8((unsigned int)aCodePoint,&string[0]);
    if(usedBytes > 0)
        {
        len = usedBytes;
        initialize(&string[0]);
        }
    }

// -------------------------------------------------------------------------
// Copy constructor
// -------------------------------------------------------------------------
//
UStringImpl::UStringImpl(const UStringImpl& aUStringImpl)
    :str(0),len(aUStringImpl.len),allocated_len(0), isInHeap(0)
    {
#ifdef _DEBUG    
    g_setenv("G_SLICE","always-malloc",1);
#endif    
    if(aUStringImpl.str)
        {
        initialize(aUStringImpl.str);
        }
    }


// -------------------------------------------------------------------------
// Destructor
// -------------------------------------------------------------------------
//
UStringImpl::~UStringImpl()
	{
	if (str && isInHeap)
	    {
	    delete str;
	    }
	}	
// -------------------------------------------------------------------------
// Returns true if the string is empty
// -------------------------------------------------------------------------
//
bool UStringImpl::empty()const
	{
	return (len > 0) ? false : true;
	}

// -------------------------------------------------------------------------
// Returns true if the string is a null string
// -------------------------------------------------------------------------
//
bool UStringImpl::null()const
	{
	return (str) ? false : true;
	}
	
// -------------------------------------------------------------------------
// Returns the length of the string in characters 
// -------------------------------------------------------------------------
//
long UStringImpl::length()const
    {
    long ret(0);
    if(str && (len > 0))
        {
        ret = g_utf8_strlen(str, len);
        }
    return ret;    
    }        

// -------------------------------------------------------------------------
// Returns the length of the string in bytes
// -------------------------------------------------------------------------
//
long UStringImpl::bytes()const
    {
    return (long)len;    
    }        

	
// -------------------------------------------------------------------------
// Returns the utf8 type string
// -------------------------------------------------------------------------
//
const Utf8* UStringImpl::utf8()const
    {
    return str;
    }
    
// -------------------------------------------------------------------------
// Compares the string to another UString with strcmp
// -------------------------------------------------------------------------
//
int UStringImpl::compare(const UStringImpl& aUStringImpl)const
    {
    int ret(1);
    if(!str && !aUStringImpl.str)
        {
        ret = 0;    
        }
    else if(str && aUStringImpl.str)
        {
        ret = strcmp(str, aUStringImpl.str);
        }
    else if(!str)
        {
        ret = -1;
        }
  
    return ret;
    }	 	
// -------------------------------------------------------------------------
// Compares the string to Utf8 string with strcmp
// -------------------------------------------------------------------------
//
int UStringImpl::compare(const Utf8* aStr)const
    {    
    int ret(1);
    if(str && aStr)
        {
        ret = strcmp(str, aStr);
        }
    else if(!str && !strlen(aStr))
        {
        ret = 0;    
        }
    else if(!str)
        {
        ret = -1;
        }
   
    return ret;
    }	 

// -------------------------------------------------------------------------
// Compares the string to another UString using the linguistically
// correct rules for the current locale
// -------------------------------------------------------------------------
//
int UStringImpl::compareC(const UStringImpl& aUStringImpl)const
    {
    int ret(1);
    if(!str && !aUStringImpl.str)
        {
        ret = 0;    
        }
    else if(str && aUStringImpl.str)
        {
        ret = g_utf8_collate(str, aUStringImpl.str);
        }
    else if(!str)
        {
        ret = -1;
        }
  
    return ret;
    }	 	
// -------------------------------------------------------------------------
// Compares the string to Utf8 string using the linguistically
// correct rules for the current locale
// -------------------------------------------------------------------------
//
int UStringImpl::compareC(const Utf8* aStr)const
    {    
    int ret(1);
    if(str && aStr)
        {
        ret = g_utf8_collate(str, aStr);
        }
    else if(!str && !strlen(aStr))
        {
        ret = 0;    
        }
    else if(!str)
        {
        ret = -1;
        }
   
    return ret;
    } 

// -------------------------------------------------------------------------
// Appends another UString to this string 
// -------------------------------------------------------------------------
//
void UStringImpl::append(const UStringImpl& aUStringImpl)
    {
    if(str && aUStringImpl.str)
        {
        appendImpl(aUStringImpl.str, aUStringImpl.len);
        }
    }	 
// -------------------------------------------------------------------------
// Appends a Utf8 string to this string
// -------------------------------------------------------------------------
//
void UStringImpl::append(const Utf8* aStr)
    {
    if(aStr && (strlen(aStr) !=0))
        {
        appendImpl(aStr, strlen(aStr));
        }
    }

// -------------------------------------------------------------------------
// Inserts Utf8 string to this string 
// -------------------------------------------------------------------------
//
void UStringImpl::insert( 
    long aPos, 
    const Utf8* aStr)
    {
   
    if(aStr)
       {
       if (!str)
           checkBuffer(0);
       long dstCharCount = g_utf8_strlen(str, -1);
       if(aPos < -1 || aPos > dstCharCount)
           {
           throw out_of_range("out_of_range");  
           }
        // find out byte position for given character position
       long startBytePos(-1);
       if(aPos >= 0)
           {
           if(str)
               {
               const char* startOffset = g_utf8_offset_to_pointer(str, aPos);
               startBytePos = startOffset - str;
               }
           }
       if(aPos == -1)
    	   {
    	   appendImpl(aStr, strlen(aStr));
    	   }
       else
    	   {
    	   insertImpl(startBytePos, aStr, strlen(aStr));
    	   }
       }
    }
   
// -------------------------------------------------------------------------
// Inserts Utf8 string to this string with length of the Utf8 specified
// -------------------------------------------------------------------------
//
void UStringImpl::insert( 
    long aPos, 
    const Utf8* aStr,
    long aCharCount)
    {
    if (aCharCount < 1)
        {
        throw out_of_range("out_of_range");    
        }
    
    if (aStr)
        {
        long srcByteLen = bytesFromCharacters(aStr, aCharCount);
        if(!str)
            checkBuffer(0);
        
        // calculate how many bytes are needed for given characters
        long srcCharCount = g_utf8_strlen(aStr, srcByteLen);
        long dstCharCount = g_utf8_strlen(str, -1); 
        long startBytePos(-1); // appends end of the string

        if(aPos < -1 || aPos > dstCharCount-1 || aCharCount > srcCharCount)
            {
            throw out_of_range("out_of_range");  
            }
           
        if(aPos != -1)
            {
            const char* startOffset = g_utf8_offset_to_pointer(str, aPos); 
            startBytePos = startOffset - str; 
            }
        const char* endOffset = g_utf8_offset_to_pointer(aStr, aCharCount);
        long insertByteLength = endOffset - aStr;   

        if(aPos == -1)
            {
            appendImpl(aStr, insertByteLength);
            }
        else
            {
            insertImpl(startBytePos, aStr, srcByteLen);
            }
        }
    }

// -------------------------------------------------------------------------
// Replaces Utf8 string to this string 
// -------------------------------------------------------------------------
//
void UStringImpl::replace(
    long aPos, 
    const Utf8* aStr)
    {
    if (aStr)
        {
        if (!str)
            checkBuffer(0);
        
        long srcByteLen = strlen(aStr);
        long srcCharCount = g_utf8_strlen(aStr,-1); 
        long dstCharCount = g_utf8_strlen(str, -1);
        if(aPos > dstCharCount || aPos < 0)
            {
            throw out_of_range("out_of_range");    
            }
        
        // calculate start byte position
        if(str)
            {
            const char* startOffset = g_utf8_offset_to_pointer(str, aPos);
            long startBytePos = startOffset - str; 
            
            // calculate erasable character count in bytes
                if(startOffset)
                    {
	                const char* endOffset = g_utf8_offset_to_pointer(startOffset, srcCharCount);
	                long eraseByteLength = endOffset - startOffset;  
	                // erase existing characters
	                eraseImpl(startBytePos, eraseByteLength);
                    }
            insertImpl(startBytePos, aStr, srcByteLen);
            }
        }
   }  
      
   
// -------------------------------------------------------------------------
// Replaces a Utf8 string to this string with length of the Utf8 specified
// -------------------------------------------------------------------------
//
void UStringImpl::replace(
    long aPosOffset, 
    const Utf8* aStr,
    long aCharCount)
    {
    if (aCharCount < 1)
        {
        throw out_of_range("out_of_range");    
        }
        
    if (aStr)
        {
        long srcByteLen = bytesFromCharacters(aStr, aCharCount);
        if(!str)
            checkBuffer(0);
        
        long srcCharCount = g_utf8_strlen(aStr, srcByteLen); 
        long dstCharCount = g_utf8_strlen(str, -1);
        if(aPosOffset > dstCharCount || aPosOffset < 0 || aCharCount > srcCharCount)
            {
            throw out_of_range("out_of_range");    
            }
        // calculate start byte position
        if(str)
            {
            const char* startOffset = g_utf8_offset_to_pointer(str, aPosOffset);
            long startBytePos = startOffset - str; 
        
        // calculate erasable character count in bytes
            if(startOffset)
                {
                const char* endOffset = g_utf8_offset_to_pointer(startOffset, srcCharCount);
                long eraseByteLength = endOffset - startOffset;  
                // erase existing characters
                eraseImpl(startBytePos, eraseByteLength);
                }
            insertImpl(startBytePos, aStr, srcByteLen);
            }
        }
   }  
 
// -------------------------------------------------------------------------
// Erases aCharCount characters from the string at position specified by 
// aPosOffset
// -------------------------------------------------------------------------
//
void UStringImpl::erase(
    long aPosOffset, 
    long aCharCount)
    {
    
    if(str)
        {
        long srcCharCount = g_utf8_strlen(str, -1); 
        
        if (aPosOffset < 0 || aCharCount < 1 || aCharCount > srcCharCount)
            {
            throw out_of_range("out_of_range"); 
            }
        
        // calc startpos
        const char* startOffset = g_utf8_offset_to_pointer(str, aPosOffset); 
        long startBytePos = startOffset - str; 
        
        // calc bytes to erase
        const char* endOffset = g_utf8_offset_to_pointer(startOffset, aCharCount); 
        long eraseByteLength = endOffset - startOffset; 
       
        eraseImpl(startBytePos, eraseByteLength);
        }
   }  

// -------------------------------------------------------------------------
// Returns unicode at aIndex position in the string
// -------------------------------------------------------------------------
//
Unicode UStringImpl::operator[](long aIndex)
   {
   Unicode ret(0xF8FF);
    
   if(str)
       {
       long charCount = g_utf8_strlen(str, -1);
       if(aIndex < 0 || aIndex > charCount-1)
           {
           throw out_of_range("out_of_range"); 
           }
       // calc startpos
       const char* uniChar = g_utf8_offset_to_pointer(str, aIndex); 
        
       ret = g_utf8_get_char(uniChar);        
       }
   return ret;     
   }  

}