/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "XalanDOMString.hpp"



#include <cassert>
#include <cstdlib>
#include <cstring>



namespace XALAN_CPP_NAMESPACE {



const XalanDOMChar  XalanDOMString::s_empty = 0;

const XalanDOMString::size_type  XalanDOMString::npos = static_cast<XalanDOMString::size_type>(-1);


XalanDOMString::XalanDOMString(MemoryManager&  theManager) :
    m_data(theManager),
    m_size(0)
{
}



XalanDOMString::XalanDOMString(
            const XalanDOMString&   theSource,
            MemoryManager&      theManager,
            size_type               theStartPosition,
            size_type               theCount) :
    m_data(theManager),
    m_size(0)
{
    if (theSource.length() != 0)
    {
        append(theSource, theStartPosition, theCount);
    }
}



XalanDOMString::XalanDOMString(
            const XalanDOMChar*     theString,
            MemoryManager&      theManager,
            size_type               theCount) :
    m_data(theManager),
    m_size(0)
{
    assert(theString != 0);

    if (*theString != 0)
    {
        append(theString, theCount);
    }
}



XalanDOMString::XalanDOMString(
            const char*         theString,
            MemoryManager&  theManager,
            size_type           theCount) :
    m_data(theManager),
    m_size(0)
{
    assert(theString != 0);

    if (*theString != 0)
    {
        append(theString, theCount);
    }

    invariants();
}



XalanDOMString*
XalanDOMString::clone(MemoryManager&  theManager)
{
    typedef XalanDOMString  ThisType;

    XalanAllocationGuard    theGuard(theManager, theManager.allocate(sizeof(ThisType)));

    ThisType* const     theResult =
        new (theGuard.get()) ThisType(*this, theManager);

    theGuard.release();

    return theResult;
}



XalanDOMString::XalanDOMString(
            size_type           theCount,
            XalanDOMChar        theChar,
            MemoryManager&  theManager) :
    m_data(theManager),
    m_size(0)
{
    if (theCount != 0)
    {
        XalanDOMCharVectorType(theCount + 1, theChar, theManager).swap(m_data);

        // Null-terminate it...
        m_data.back() = 0;

        m_size = theCount;
    }

    invariants();
}



void
XalanDOMString::resize(
            size_type       theCount,
            XalanDOMChar    theChar)
{
    invariants();

    const size_type     theOldSize = size();

    if (theCount != theOldSize)
    {
        if (theOldSize == 0)
        {
            // If the string is of 0 length, resize but add an
            // extra byte for the terminating byte.
            m_data.resize(theCount + 1, theChar);
        }
        else
        {
            // If the string is not of 0 length, resize but
            // put a copy of theChar where the terminating
            // byte used to be.
            m_data.resize(theCount + 1, theChar);
        }

        m_size = theCount;

        // Terminate...
        m_data.back() = 0;
    }

    invariants();
}



XalanDOMString&
XalanDOMString::erase(
            size_type   theStartPosition,
            size_type   theCount)
{
    invariants();

    const size_type     theActualCount =
            theCount == size_type(npos) ? length() - theStartPosition : theCount;
    assert(theStartPosition + theActualCount <= length());

    if (theStartPosition == 0 && theCount >= size())
    {
        m_data.erase(m_data.begin(), m_data.end());

        m_size = 0;
    }
    else
    {
        const iterator      i = getIteratorForPosition(theStartPosition);

        m_data.erase(i, i + (theActualCount));

        const size_type     theNewSize = size_type(m_data.size());
        assert(size_type(m_data.size()) == theNewSize);

        if (theNewSize < 2)
        {
            m_size = 0;
        }
        else
        {
            m_size = theNewSize - 1;
        }
    }

    invariants();

    return *this;
}



XalanDOMString&
XalanDOMString::assign(
            const XalanDOMString&   theSource,
            size_type               thePosition,
            size_type               theCount)
{
    invariants();

    assert(thePosition < theSource.size() && thePosition + theCount <= theSource.size());

    if (&theSource != this)
    {
        erase();

        append(theSource, thePosition, theCount);
    }
    else
    {
        if (thePosition == 0)
        {
            // See if we're being asked to
            // assign everything to ourself,
            // which is a noop...
            if (theCount != m_size)
            {
                // We're being asked to truncate...
                resize(theCount);
            }
        }
        else
        {
            // Yuck.  We have to move data...
            std::memmove(&*begin(), &*begin() + thePosition, theCount * sizeof(XalanDOMChar));

            resize(theCount);
        }
    }

    invariants();

    return *this;
}



XalanDOMString&
XalanDOMString::assign(
            iterator    theFirstPosition,
            iterator    theLastPosition)
{
    invariants();

    m_data.reserve(theLastPosition - theFirstPosition + 1);

    m_data.assign(theFirstPosition, theLastPosition);

    m_data.push_back(XalanDOMChar(0));

    m_size = size_type(m_data.size()) - 1;
    assert(m_data.size() - 1 == m_size);

    invariants();

    return *this;
}



XalanDOMString&
XalanDOMString::append(
            const XalanDOMChar*     theString,
            size_type               theCount)
{
    const size_type     theLength =
            theCount == size_type(npos) ? length(theString) : theCount;

    if (theLength != 0)
    {
        if (m_data.empty() == true)
        {
            m_data.reserve(theLength + 1);

            m_data.insert(m_data.end(), theString, theString + theLength);

            m_data.push_back(0);

            m_size = theLength;

            assert(length() == theLength);
        }
        else
        {
            m_data.insert(getBackInsertIterator(), theString, theString + theLength);

            m_size += theCount;
        }
    }

    invariants();

    return *this;
}



inline void
doTranscode(
            const char*                 theString,
            XalanDOMString::size_type   theCount,
            bool                        theSourceStringIsNullTerminated,
            XalanDOMCharVectorType&     theVector,
            bool                        fTerminate)
{
    assert(theString != 0);

    if (theCount == XalanDOMString::size_type(XalanDOMString::npos))
    {
        if (TranscodeFromLocalCodePage(
                theString,
                theVector,
                fTerminate) == false)
        {
            throw XalanDOMString::TranscodingError();
        }
    }
    else
    {
        if (TranscodeFromLocalCodePage(
                theString,
                theCount,
                theSourceStringIsNullTerminated,
                theVector,
                fTerminate) == false)
        {
            throw XalanDOMString::TranscodingError();
        }
    }
}



XalanDOMString&
XalanDOMString::append(
            const char*     theString,
            size_type       theCount)
{
    invariants();

    const size_type     theLength =
            theCount == size_type(npos) ? length(theString) : theCount;

    if (theLength != 0)
    {
        if (empty() == true)
        {
            doTranscode(theString, theLength, theCount == size_type(npos), m_data, true);
        }
        else
        {
            XalanDOMCharVectorType  theTempVector(getMemoryManager());

            doTranscode(theString, theLength, theCount == size_type(npos), theTempVector, false);

            append(&*theTempVector.begin(), size_type(theTempVector.size()));
        }

        m_size = size_type(m_data.size()) - 1;
        assert(m_data.size() - 1 == m_size);
    }

    invariants();

    return *this;
}


XalanDOMString&
XalanDOMString::append(
            size_type       theCount,
            XalanDOMChar    theChar)
{
    invariants();

    if (m_data.empty() == true)
    {
        m_data.insert(m_data.end(), theCount + 1, theChar);

        m_data.back() = 0;

        m_size = theCount;

        assert(length() == theCount);
    }
    else
    {
        m_data.insert(getBackInsertIterator(), theCount, theChar);

        m_size += theCount;
    }

    invariants();

    return *this;
}



XalanDOMString&
XalanDOMString::insert(
            size_type               thePosition,
            const XalanDOMChar*     theString,
            size_type               theCount)
{
    invariants();

    if (m_data.empty() == true)
    {
        assert(thePosition == 0);

        append(theString, theCount);

        assert(length() == theCount);
    }
    else
    {
        m_data.insert(getIteratorForPosition(thePosition), theString, theString + theCount);

        m_size += theCount;
    }

    invariants();

    return *this;
}



XalanDOMString&
XalanDOMString::insert(
            size_type       thePosition,
            size_type       theCount,
            XalanDOMChar    theChar)
{
    invariants();

    if (m_data.empty() == true)
    {
        assert(thePosition == 0);

        assign(theCount, theChar);
    }
    else
    {
        m_data.insert(getIteratorForPosition(thePosition), theCount, theChar);

        m_size += theCount;
    }

    invariants();

    return *this;
}



XalanDOMString::iterator
XalanDOMString::insert(
            iterator        thePosition,
            XalanDOMChar    theChar)
{
    invariants();

    if (m_data.empty() == true)
    {
        assert(thePosition == m_data.end() || thePosition == m_data.begin());

        assign(1, theChar);

        assert(length() == 1);

        thePosition = m_data.begin();
    }
    else
    {
        thePosition = m_data.insert(thePosition, theChar);

        ++m_size;
    }

    assert(*thePosition == theChar);

    invariants();

    return thePosition;
}



void
XalanDOMString::insert(
            iterator        thePosition,
            size_type       theCount,
            XalanDOMChar    theChar)
{
    invariants();

    if (m_data.empty() == true)
    {
        assert(thePosition == m_data.end() || thePosition == m_data.begin());

        assign(theCount, theChar);

        assert(length() == theCount);
    } 
    else
    {
        m_data.insert(thePosition, theCount, theChar);

        m_size += theCount;
    }

    invariants();
}



void
XalanDOMString::insert(
        iterator        theInsertPosition,
        iterator    theFirstPosition,
        iterator    theLastPosition)
{
    invariants();

    if (m_data.empty() == true)
    {
        assert(theInsertPosition == m_data.end() || theInsertPosition == m_data.begin());

        assign(theFirstPosition, theLastPosition);
    }
    else
    {
        m_data.insert(theInsertPosition, theFirstPosition, theLastPosition);

        m_size = size_type(m_data.size()) - 1;

        assert(m_size == m_data.size() - 1);
    }

    invariants();
}



template <class Type, class SizeType>
inline int
doCompare(
            const Type*     theLHS,
            SizeType        theLHSLength,
            const Type*     theRHS,
            SizeType        theRHSLength)
{
    int                 theResult = 0;

    if (theLHSLength != 0 || theRHSLength != 0)
    {
        Type        theLHSChar = Type(0);
        Type        theRHSChar = Type(0);

        SizeType    i = 0;

        for(; i < theLHSLength && i < theRHSLength; i++)
        {
            theLHSChar = theLHS[i];
            theRHSChar = theRHS[i];

            if (theLHSChar != theRHSChar)
            {
                break;
            }
        }

        if (i == theLHSLength)
        {
            // We reached the end of theLHS...
            if (i != theRHSLength)
            {
                // but not the end of theRHS.
                theResult = -1;
            }
        }
        else if (i == theRHSLength)
        {
            // We reached the end of theRHS string...
            if (i != theLHSLength)
            {
                // but not the end of theLHS string.
                theResult = 1;
            }
        }
        else
        {
            // We didn't reach the end of _either_ string, so
            // return the difference between the two characters
            // that caused the problem.
            theResult = theLHSChar - theRHSChar;
        }
    }

    return theResult;
}



int
XalanDOMString::compare(const XalanDOMChar*     theString) const
{
    invariants();

    return doCompare(c_str(), length(), theString, length(theString));
}



int
XalanDOMString::compare(
            size_type               thePosition1,
            size_type               theCount1,
            const XalanDOMChar*     theString,
            size_type               theCount2) const
{
    invariants();

    return doCompare(c_str() + thePosition1, theCount1, theString, theCount2);
}



template<class Type>
inline void
reset_func(XalanDOMString& obj, MemoryManager&    theManager, Type string)
{
    assert( string != 0 );

    XalanDOMString tmpString(string, theManager);

    obj.swap(tmpString);
}



void 
XalanDOMString::reset(MemoryManager&    theManager,
                      const char*           theString)
{
    reset_func(*this, theManager, theString);
}



void 
XalanDOMString::reset(MemoryManager&    theManager,
                      const XalanDOMChar*   theString)
{
    reset_func(*this, theManager, theString);
}



void
XalanDOMString::transcode(CharVectorType&   theResult) const
{
    invariants();

    if (TranscodeToLocalCodePage(c_str(), length(), theResult, true) == false)
    {
        throw TranscodingError();
    }
}



inline XalanDOMString::size_type
length(const XalanDOMChar*  theString)
{
    assert(theString != 0);

    const XalanDOMChar*     theStringPointer = theString;

    while(*theStringPointer != 0)
    {
        theStringPointer++;
    }

    return XalanDOMString::size_type(theStringPointer - theString);
}



bool
XalanDOMString::equals(
            const XalanDOMChar*     theLHS,
            size_type               theLHSLength,
            const XalanDOMChar*     theRHS,
            size_type               theRHSLength)
{
    if (theLHSLength != theRHSLength)
    {
        return false;
    }
    else if (theLHSLength == 0)
    {
        return true;
    }
    else
    {
        const XalanDOMChar* const   theEnd = theLHS + theLHSLength;

        while(*theLHS == *theRHS)
        {
            ++theLHS;

            if (theLHS == theEnd)
            {
                return true;
            }
            else
            {
                ++theRHS;
            }
        }

        return false;
    }
}



bool
XalanDOMString::equals(
            const XalanDOMString&   theLHS,
            const XalanDOMString&   theRHS)
{
    const XalanDOMString::size_type     theLHSLength = theLHS.size();
    const XalanDOMString::size_type     theRHSLength = theRHS.size();

    if (theLHSLength != theRHSLength)
    {
        return false;
    }
    else
    {
        return equals(theLHS.c_str(), theLHSLength, theRHS.c_str(), theRHSLength);
    }
}



XalanDOMString::size_type
XalanDOMString::length(const XalanDOMChar*  theString)
{
    return xalanc::length(theString);
}



XalanDOMString::size_type
XalanDOMString::length(const char*  theString)
{
    assert(theString != 0);

    assert(std::strlen(theString) < size_type(npos));

    return size_type(std::strlen(theString));
}


}



#include <xercesc/util/XMLString.hpp>



namespace XALAN_CPP_NAMESPACE {


const XalanDOMString::size_type     theOneTranslatedWbCharLen = 10;


// The template function should never fail.
// In case of the unconvertable characters we add the substitution char
// and in case of too small result vector we resize it 
template <class SourceType, class TargetType>
inline void
doXercesTranscode(
            const SourceType*           theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            XalanVector<TargetType>&    theTargetVector,
            bool                        terminate,
            char                        theSubstitutionChar)
{
    assert(
        theSourceStringIsNullTerminated == false ||
        theSourceStringLength == XalanDOMString::length(theSourceString));

    const SourceType*   theRealSourceString = theSourceString;

    XalanVector<SourceType>     theCopiedSource(theTargetVector.getMemoryManager());

    if (theSourceStringIsNullTerminated == false)
    {
        theCopiedSource.reserve(theSourceStringLength + 1);

        theCopiedSource.assign(
            theSourceString,
            theSourceString + theSourceStringLength);

        theCopiedSource.push_back(static_cast<SourceType>(0));

        theRealSourceString = &*theCopiedSource.begin();
    }

    // Initially, let's guess the the transcoded string will be the same
    // length as the source string.
    theTargetVector.resize(theSourceStringLength + 1);

    assert(theRealSourceString != 0);

    bool            fSuccess = false;

    using xercesc::XMLString;

    fSuccess = XMLString::transcode(
        theRealSourceString,
        &*theTargetVector.begin(),
        theTargetVector.size() - 1,
        &theTargetVector.getMemoryManager());

    if (fSuccess == false)
    {
        // Do the "manual" transcoding.  But first, clean up from the
        // previous phase
        theTargetVector.clear();

        // See if there are any unrepresentable characters for the
        // local code page.
        SourceType oneCharArray[2];

        oneCharArray[1] = SourceType(0);

        TargetType theOneTranslatedWbChar[theOneTranslatedWbCharLen]; 

        for (XalanDOMString::size_type i = 0; i < theSourceStringLength; ++i)
        {
            oneCharArray[0] = theRealSourceString[i];

            theOneTranslatedWbChar[0] = TargetType(0);

            fSuccess = XMLString::transcode(
                oneCharArray,
                theOneTranslatedWbChar,
                theOneTranslatedWbCharLen - 1,
                &theTargetVector.getMemoryManager());

            if (fSuccess == false)
            {
                theTargetVector.push_back(theSubstitutionChar);
            }
            else
            {
                XalanDOMString::size_type theRealCharLength =
                    XalanDOMString::length(theOneTranslatedWbChar);

                // When we transcode the character '\0', that looks like "\0\0", 
                // XalanDOMString::length returns a size of 0.  In this case, the
                // real size should be 1
                if (theRealCharLength == 0)
                {
                    theRealCharLength = 1;
                }

                // append the translated set of characters
                theTargetVector.insert(
                    theTargetVector.end(),
                    theOneTranslatedWbChar,
                    theOneTranslatedWbChar + theRealCharLength);
            }
        }

    }

    while(theTargetVector.back() == static_cast<TargetType>(0))
    {
        theTargetVector.pop_back();
    }

    if (terminate == true)
    {
        theTargetVector.push_back(static_cast<TargetType>(0));
    }
}



template <class SourceType, class TargetType>
inline bool
doXercesTranscode(
            const SourceType*           theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            XalanVector<TargetType>&    theTargetVector,
            bool                        terminate)
{
    assert(
        theSourceStringIsNullTerminated == false ||
        theSourceStringLength == XalanDOMString::length(theSourceString));

    const SourceType*   theRealSourceString = theSourceString;

    XalanVector<SourceType>     theCopiedSource(theTargetVector.getMemoryManager());

    if (theSourceStringIsNullTerminated == false)
    {
        theCopiedSource.reserve(theSourceStringLength + 1);

        theCopiedSource.assign(
            theSourceString,
            theSourceString + theSourceStringLength);

        theCopiedSource.push_back(static_cast<SourceType>(0));

        theRealSourceString = &*theCopiedSource.begin();
    }

    // Initially, let's guess the the transcoded string will be the same
    // length as the source string.
    theTargetVector.resize(theSourceStringLength + 1);

    assert(theRealSourceString != 0);

    bool            fSuccess = false;

    do
    {
        using xercesc::XMLString;

        fSuccess = XMLString::transcode(
                    theRealSourceString,
                    &*theTargetVector.begin(),
                    theTargetVector.size() - 1,
                    &theTargetVector.getMemoryManager());

        if (fSuccess == false)
        {
            // We're going to assume that the maximum storage for
            // a transcoded string is 4 times the source string
            // length.  This will only occur in edge cases.
            if (theTargetVector.size() >= theSourceStringLength * 4)
            {
                break;
            }
            else
            {
                theTargetVector.resize(theTargetVector.size() + 10);
            }
        }
    } while (fSuccess == false);

    if (fSuccess == false)
    {
        theTargetVector.clear();
    }
    else
    {
        while(theTargetVector.back() == static_cast<TargetType>(0))
        {
            theTargetVector.pop_back();
        }

        if (terminate == true)
        {
            theTargetVector.push_back(static_cast<TargetType>(0));
        }
    }

    return fSuccess;
}


static void
doTranscodeToLocalCodePage(
            const XalanDOMChar*         theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            CharVectorType&             theTargetVector,
            bool                        terminate,
            char                        theSubstitutionChar)
{
    // Short circuit if it's a null pointer, or of length 0.
    if (!theSourceString || (!theSourceString[0]))
    {
        if (terminate == true)
        {
            theTargetVector.resize(1);

            theTargetVector.back() = '\0';
        }
        else
        {
            theTargetVector.clear();
        }
    }
    else
    {
        doXercesTranscode(
                    theSourceString,
                    theSourceStringLength,
                    theSourceStringIsNullTerminated,
                    theTargetVector,
                    terminate,
                    theSubstitutionChar);
    }
}

static bool
doTranscodeToLocalCodePage(
            const XalanDOMChar*         theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            CharVectorType&             theTargetVector,
            bool                        terminate)
{
    // Short circuit if it's a null pointer, or of length 0.
    if (!theSourceString || (!theSourceString[0]))
    {
        if (terminate == true)
        {
            theTargetVector.resize(1);

            theTargetVector.back() = '\0';
        }
        else
        {
            theTargetVector.clear();
        }

        return true;
    }
    else
    {
        return doXercesTranscode(
                    theSourceString,
                    theSourceStringLength,
                    theSourceStringIsNullTerminated,
                    theTargetVector,
                    terminate);
    }
}

XALAN_DOM_EXPORT_FUNCTION(void)
TranscodeToLocalCodePage(
            const XalanDOMChar*         theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            CharVectorType&             theTargetVector,
            bool                        terminate,
            char                        theSubstitutionChar)
{
    doTranscodeToLocalCodePage(
                            theSourceString, 
                            theSourceStringLength, 
                            false, 
                            theTargetVector, 
                            terminate,
                            theSubstitutionChar);
}



XALAN_DOM_EXPORT_FUNCTION(void)
TranscodeToLocalCodePage(
            const XalanDOMChar*     theSourceString,
            CharVectorType&         theTargetVector,
            bool                    terminate,
            char                    theSubstitutionChar)
{
    doTranscodeToLocalCodePage(
                            theSourceString, 
                            length(theSourceString),
                            true, 
                            theTargetVector, 
                            terminate,
                            theSubstitutionChar);
}



XALAN_DOM_EXPORT_FUNCTION(bool)
TranscodeToLocalCodePage(
            const XalanDOMChar*         theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            CharVectorType&             theTargetVector,
            bool                        terminate)
{
    return doTranscodeToLocalCodePage(
                theSourceString,
                theSourceStringLength,
                false,
                theTargetVector,
                terminate);
}



XALAN_DOM_EXPORT_FUNCTION(bool)
TranscodeToLocalCodePage(
            const XalanDOMChar*     theSourceString,
            CharVectorType&         theTargetVector,
            bool                    terminate)
{
    return doTranscodeToLocalCodePage(
                theSourceString,
                length(theSourceString),
                true,
                theTargetVector,
                terminate);
}



XALAN_DOM_EXPORT_FUNCTION(void)
TranscodeToLocalCodePage(
            const XalanDOMString&   theSourceString,
            CharVectorType&         theTargetVector,
            bool                    terminate,
            char                    theSubstitutionChar)
{
    doTranscodeToLocalCodePage(
        theSourceString.c_str(),
        theSourceString.length(),
        true,
        theTargetVector,
        terminate,
        theSubstitutionChar);
}



static bool
doTranscodeFromLocalCodePage(
            const char*                 theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            XalanDOMCharVectorType&     theTargetVector,
            bool                        terminate)
{
    typedef XalanDOMString::size_type   size_type;

    // Short circuit if it's a null pointer, or of length 0.
    if (!theSourceString || (!theSourceString[0]))
    {
        if (terminate == true)
        {
            theTargetVector.resize(1);

            theTargetVector.back() = '\0';
        }
        else
        {
            theTargetVector.clear();
        }

        return true;
    }
    else
    {
        return doXercesTranscode(
                    theSourceString,
                    theSourceStringLength,
                    theSourceStringIsNullTerminated,
                    theTargetVector,
                    terminate);
    }
}



XALAN_DOM_EXPORT_FUNCTION(bool)
TranscodeFromLocalCodePage(
            const char*                 theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            XalanDOMCharVectorType&     theTargetVector,
            bool                        terminate)
{
    return doTranscodeFromLocalCodePage(
                theSourceString,
                theSourceStringLength,
                false,
                theTargetVector,
                terminate);
}



XALAN_DOM_EXPORT_FUNCTION(bool)
TranscodeFromLocalCodePage(
            const char*                 theSourceString,
            XalanDOMString::size_type   theSourceStringLength,
            bool                        theSourceStringIsNullTerminated,
            XalanDOMCharVectorType&     theTargetVector,
            bool                        terminate)
{
    return doTranscodeFromLocalCodePage(
                theSourceString,
                theSourceStringLength,
                theSourceStringIsNullTerminated,
                theTargetVector,
                terminate);
}



XALAN_DOM_EXPORT_FUNCTION(bool)
TranscodeFromLocalCodePage(
            const char*                 theSourceString,
            XalanDOMCharVectorType&     theTargetVector,
            bool                        terminate)
{
    return doTranscodeFromLocalCodePage(
                theSourceString,
                XalanDOMString::length(theSourceString),
                true,
                theTargetVector,
                terminate);
}



XALAN_DOM_EXPORT_FUNCTION(const XalanDOMString&)
TranscodeFromLocalCodePage(
            const CharVectorType&   theSourceString,
            XalanDOMString&         result)
{
    if (theSourceString.empty() == true)
    {
        result.erase();

        return result;
    }
    else
    {
        typedef XalanDOMString::size_type       size_type;

        const CharVectorType::size_type     theSize = theSourceString.size();

        if (theSourceString[theSize - 1] == CharVectorType::value_type(0))
        {
            return TranscodeFromLocalCodePage(&*theSourceString.begin(), result , size_type(theSize) - 1);
        }
        else
        {
            return TranscodeFromLocalCodePage(&*theSourceString.begin(), result , size_type(theSize));
        }
    }
}



}
