/*
 * 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.
 */

/*
 * $Id: XSValue.cpp 568078 2007-08-21 11:43:25Z amassari $
 */

#include <limits.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>

#include <xercesc/framework/psvi/XSValue.hpp>

#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLStringTokenizer.hpp>

#include <xercesc/util/XMLBigDecimal.hpp>
#include <xercesc/util/XMLBigInteger.hpp>
#include <xercesc/util/XMLFloat.hpp>
#include <xercesc/util/XMLDouble.hpp>
#include <xercesc/util/XMLDateTime.hpp>
#include <xercesc/util/HexBin.hpp>
#include <xercesc/util/Base64.hpp>
#include <xercesc/util/XMLUri.hpp>
#include <xercesc/util/XMLChar.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/util/regx/RegularExpression.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/TransService.hpp>
#include <xercesc/util/NumberFormatException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

/*** issues
 *
 *   1. For float, double, datetime family, the validation is almost similar to getActualValue
 *  
 *
 *   DataType                   DataGroup
 *                             num  dtm  str             validation           canonical      actual-value
 *   ======================================================================================================
 *    dt_string                          str              [2] Char              NA             content
 *    dt_boolean                         str           {true, false, 1, 0}   {true, false}    bool
 *    dt_decimal               num                         lexical only         yes            double
 *    dt_float                 num                         lexical/value        yes            double
 *    dt_double                num                         lexical/value        yes            double
 *    ---------------------------------------------------------------------------------------------------------
 * 5  dt_duration                   dtm                    yes                  NA             struct datetime
 *    dt_dateTime                   dtm                    yes                  yes            struct datetime
 *    dt_time                       dtm                    yes                  yes            struct datetime
 *    dt_date                       dtm                    yes                  NA             struct datetime
 *    dt_gYearMonth                 dtm                    yes                  NA             struct datetime
 *    ---------------------------------------------------------------------------------------------------------
 * 10 dt_gYear                      dtm                    yes                  NA             struct datetime
 *    dt_gMonthDay                  dtm                    yes                  NA             struct datetime
 *    dt_gDay                       dtm                    yes                  NA             struct datetime
 *    dt_gMonth                     dtm                    yes                  NA             struct datetime         
 *    dt_hexBinary                        str              decoding            ([a-f])         unsigned long ?
 *    ---------------------------------------------------------------------------------------------------------
 * 15 dt_base64Binary                     str              decoding             NA (errata?)   unsigned long ?
 *    dt_anyURI                           str              yes                  NA             content
 *    dt_QName                            str              a:b , [6]QName       NA             content
 *    dt_NOTATION                         str              [6]QName             NA             content
 *    dt_normalizedString                 str              no #xD #xA #x9       NA             content
 *    ---------------------------------------------------------------------------------------------------------
 * 20 dt_token                            str              no #xD #xA #x9 traling   NA         content
 *    dt_language                         str              language id          NA             content
 *    dt_NMTOKEN                          str              [7] Nmtoken          NA             content
 *    dt_NMTOKENS                         str              [8] Nmtokens         NA             content
 *    dt_Name                             str              [5] Name             NA             content
 *    ---------------------------------------------------------------------------------------------------------
 * 25 dt_NCName                           str              [4] NCName           NA             content
 *    dt_ID                               str              [4] NCName           NA             content
 *    dt_IDREF                            str              [4] NCName           NA             content
 *    dt_IDREFS                           str              ws seped IDREF       NA             content
 *    dt_ENTITY                           str              [4] NCName           NA             content
 *    ---------------------------------------------------------------------------------------------------------
 * 30 dt_ENTITIES                         str              ws seped ENTITY      NA             content
 *    dt_integer               num                         lexical              yes            long
 *    dt_nonPositiveInteger    num                         lexical              yes            long
 *    dt_negativeInteger       num                         lexical              yes            long
 *    dt_long                  num                         lexical              yes            long
 *    ---------------------------------------------------------------------------------------------------------
 * 35 dt_int                   num                         lexical              yes            int
 *    dt_short                 num                         lexical              yes            short
 *    dt_byte                  num                         lexical              yes            char
 *    dt_nonNegativeInteger    num                         lexical              yes            unsigned long
 *    dt_unsignedLong          num                         lexical              yes            unsigned long
 *    ---------------------------------------------------------------------------------------------------------
 * 40 dt_unsignedInt           num                         lexical              yes            unsigned int
 *    dt_unsignedShort         num                         lexical              yes            unsigned short
 *    dt_unsignedByte          num                         lexical              yes            unsigned char
 *    dt_positiveInteger       num                         lexical              yes            unsigned long
 *
 ***/

const XSValue::DataGroup XSValue::inGroup[XSValue::dt_MAXCOUNT] = 
{
    dg_strings,   dg_strings,   dg_numerics,  dg_numerics,  dg_numerics, 
    dg_datetimes, dg_datetimes, dg_datetimes, dg_datetimes, dg_datetimes,
    dg_datetimes, dg_datetimes, dg_datetimes, dg_datetimes, dg_strings, 
    dg_strings,   dg_strings,   dg_strings,   dg_strings,   dg_strings,        
    dg_strings,   dg_strings,   dg_strings,   dg_strings,   dg_strings, 
    dg_strings,   dg_strings,   dg_strings,   dg_strings,   dg_strings,        
    dg_strings,   dg_numerics,  dg_numerics,  dg_numerics,  dg_numerics, 
    dg_numerics,  dg_numerics,  dg_numerics,  dg_numerics,  dg_numerics,         
    dg_numerics,  dg_numerics,  dg_numerics,  dg_numerics
};

const bool XSValue::numericSign[XSValue::dt_MAXCOUNT] =
{
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, true, true,
    true, true, true, false, false,
    false, false, false, false 
};

// ---------------------------------------------------------------------------
//  Local static functions
// ---------------------------------------------------------------------------
static XMLMutex* sXSValueMutext = 0;
static XMLRegisterCleanup XSValueMutexCleanup;

static RegularExpression* sXSValueRegEx = 0;
static XMLRegisterCleanup XSValueRegExCleanup;

ValueHashTableOf<XSValue::DataType>*  XSValue::fDataTypeRegistry = 0;
static XMLRegisterCleanup XSValueRegistryCleanup;

static XMLMutex& gXSValueMutex()
{
    if (!sXSValueMutext)
    {
        XMLMutexLock lockInit(XMLPlatformUtils::fgAtomicMutex);

        if (!sXSValueMutext)
        {
            sXSValueMutext = new (XMLPlatformUtils::fgMemoryManager) XMLMutex(XMLPlatformUtils::fgMemoryManager);
            XSValueRegExCleanup.registerCleanup(XSValue::reinitMutex);
        }
    }

    return *sXSValueMutext;
}

static RegularExpression* getRegEx()
{
    if (!sXSValueRegEx)
    {
        // Lock the mutex
        XMLMutexLock lockInit(&gXSValueMutex());

        if (!sXSValueRegEx)
        {
            try {
                sXSValueRegEx = new (XMLPlatformUtils::fgMemoryManager) 
                         RegularExpression(
                                            XMLUni::fgLangPattern
                                          , SchemaSymbols::fgRegEx_XOption
                                          , XMLPlatformUtils::fgMemoryManager
                                          );
            }
            catch(const OutOfMemoryException&)
            {
                throw;
            }
            catch (...)
            {
                return 0;
            }

            XSValueRegExCleanup.registerCleanup(XSValue::reinitRegEx);
        }
    }

    return sXSValueRegEx;
}

void XMLInitializer::initializeXSValueStatics()
{
    sXSValueRegEx = new RegularExpression(XMLUni::fgLangPattern, SchemaSymbols::fgRegEx_XOption);
    if (sXSValueRegEx) {
        XSValueRegExCleanup.registerCleanup(XSValue::reinitRegEx);
    }

    XSValue::initializeRegistry();
}

XSValue::DataType  XSValue::getDataType(const XMLCh* const dtString)
{
    if (!fDataTypeRegistry)
    {
	    // Lock the mutex
	    XMLMutexLock lockInit(&gXSValueMutex());

        if (!fDataTypeRegistry)
		{
            try {
                initializeRegistry();
            }
            catch(const OutOfMemoryException&)
            {
                throw;
            }
            catch (...) {
                return dt_MAXCOUNT;
            }
        }
    }

    if (fDataTypeRegistry->containsKey(dtString)) {
        return fDataTypeRegistry->get(dtString);
    }

    return dt_MAXCOUNT;
}

void XSValue::initializeRegistry()
{
    //using the XMLPlatformUtils::fgMemoryManager
    fDataTypeRegistry  = new ValueHashTableOf<XSValue::DataType>(43);

    if (fDataTypeRegistry) {
        XSValueRegistryCleanup.registerCleanup(XSValue::reinitRegistry);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_STRING,             XSValue::dt_string);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_BOOLEAN,            XSValue::dt_boolean);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DECIMAL,            XSValue::dt_decimal);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_FLOAT,              XSValue::dt_float);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DOUBLE,             XSValue::dt_double);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DURATION,           XSValue::dt_duration);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DATETIME,           XSValue::dt_dateTime);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_TIME,               XSValue::dt_time);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DATE,               XSValue::dt_date);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_YEARMONTH,          XSValue::dt_gYearMonth);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_YEAR,               XSValue::dt_gYear);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_MONTHDAY,           XSValue::dt_gMonthDay);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_DAY,                XSValue::dt_gDay);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_MONTH,              XSValue::dt_gMonth);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_HEXBINARY,          XSValue::dt_hexBinary);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_BASE64BINARY,       XSValue::dt_base64Binary);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_ANYURI,             XSValue::dt_anyURI);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_QNAME,              XSValue::dt_QName);
        fDataTypeRegistry->put((void*) XMLUni::fgNotationString,               XSValue::dt_NOTATION);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NORMALIZEDSTRING,   XSValue::dt_normalizedString);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_TOKEN,              XSValue::dt_token);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_LANGUAGE,           XSValue::dt_language);
        fDataTypeRegistry->put((void*) XMLUni::fgNmTokenString,                XSValue::dt_NMTOKEN);
        fDataTypeRegistry->put((void*) XMLUni::fgNmTokensString,               XSValue::dt_NMTOKENS);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NAME,               XSValue::dt_Name);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NCNAME,             XSValue::dt_NCName);
        fDataTypeRegistry->put((void*) XMLUni::fgIDString,                     XSValue::dt_ID);
        fDataTypeRegistry->put((void*) XMLUni::fgIDRefString,                  XSValue::dt_IDREF);
        fDataTypeRegistry->put((void*) XMLUni::fgIDRefsString,                 XSValue::dt_IDREFS);
        fDataTypeRegistry->put((void*) XMLUni::fgEntityString,                 XSValue::dt_ENTITY);
        fDataTypeRegistry->put((void*) XMLUni::fgEntitiesString,               XSValue::dt_ENTITIES);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_INTEGER,            XSValue::dt_integer);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NONPOSITIVEINTEGER, XSValue::dt_nonPositiveInteger);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NEGATIVEINTEGER,    XSValue::dt_negativeInteger);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_LONG,               XSValue::dt_long);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_INT,                XSValue::dt_int);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_SHORT,              XSValue::dt_short);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_BYTE,               XSValue::dt_byte);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_NONNEGATIVEINTEGER, XSValue::dt_nonNegativeInteger);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_ULONG,              XSValue::dt_unsignedLong);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_UINT,               XSValue::dt_unsignedInt);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_USHORT,             XSValue::dt_unsignedShort);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_UBYTE,              XSValue::dt_unsignedByte);
        fDataTypeRegistry->put((void*) SchemaSymbols::fgDT_POSITIVEINTEGER,    XSValue::dt_positiveInteger);
    }
}

static bool checkTimeZoneError(XSValue::DataType       const &datatype
                             , SchemaDateTimeException const &e       )
{
    return (((datatype == XSValue::dt_dateTime) || (datatype == XSValue::dt_time) || (datatype == XSValue::dt_date)) &&
            ((e.getCode() == XMLExcepts::DateTime_tz_noUTCsign)   ||
             (e.getCode() == XMLExcepts::DateTime_tz_stuffAfterZ) ||
             (e.getCode() == XMLExcepts::DateTime_tz_invalid)     ||
             (e.getCode() == XMLExcepts::DateTime_tz_hh_invalid)));
}

// ---------------------------------------------------------------------------
//  Local Data
// ---------------------------------------------------------------------------
          
static const XMLCh Separator_20[] = {chSpace, chNull};
static const XMLCh Separator_ws[] = {chSpace, chLF, chCR, chHTab, chNull};

// ---------------------------------------------------------------------------
//  XSValue: Constructors and Destructor
// ---------------------------------------------------------------------------
XSValue::XSValue(DataType        const dt
               , MemoryManager*  const manager)
    :fMemAllocated(false)
    ,fMemoryManager(manager)
{
    fData.f_datatype = dt;
}

XSValue::~XSValue()
{
    if (fMemAllocated)
        fMemoryManager->deallocate(fData.fValue.f_byteVal);
}
  
// ---------------------------------------------------------------------------
//  XSValue: Public Interface
//
//    No exception is thrown from these methods
//
// ---------------------------------------------------------------------------
bool XSValue::validate(const XMLCh*         const content    
                      ,      DataType             datatype
                      ,      Status&              status
                      ,      XMLVersion           version
                      ,      MemoryManager* const manager)
{
    if (!content || 
        !*content ||
        ((version == ver_10) && (XMLChar1_0::isAllSpaces(content, XMLString::stringLen(content)))) ||
        ((version == ver_11) && (XMLChar1_1::isAllSpaces(content, XMLString::stringLen(content)))) ) {

        switch (datatype) {
        case XSValue::dt_string:
        case XSValue::dt_normalizedString:
        case XSValue::dt_token:
        case XSValue::dt_anyURI:
        case XSValue::dt_hexBinary:
        case XSValue::dt_base64Binary:
            status = st_Init;
            return true;
            break;
        default:
            status = st_NoContent;
            return false;
            break;
        }
    }  

    status = st_Init;

    switch (inGroup[datatype]) {
    case XSValue::dg_numerics:
        return validateNumerics(content, datatype, status, manager);
        break;
    case XSValue::dg_datetimes:
        return validateDateTimes(content, datatype, status, manager);
        break;
    case XSValue::dg_strings:
        return validateStrings(content, datatype, status, version, manager);
        break;
    default:
        status = st_UnknownType;
        
        return false;
        break;
    }
}

XMLCh* 
XSValue::getCanonicalRepresentation(const XMLCh*         const content    
                                   ,      DataType             datatype
                                   ,      Status&              status
                                   ,      XMLVersion           version
                                   ,      bool                 toValidate
                                   ,      MemoryManager* const manager)
{ 
    if (!content || 
        !*content ||
        ((version == ver_10) && (XMLChar1_0::isAllSpaces(content, XMLString::stringLen(content)))) ||
        ((version == ver_11) && (XMLChar1_1::isAllSpaces(content, XMLString::stringLen(content)))) ) {
        status = st_NoContent;
        return 0;
    }
    
    status = st_Init;

    switch (inGroup[datatype]) {
    case XSValue::dg_numerics:
        return getCanRepNumerics(content, datatype,  status, toValidate, manager);
        break;
    case XSValue::dg_datetimes:
        return getCanRepDateTimes(content, datatype,  status, toValidate, manager);
        break;
    case XSValue::dg_strings:
        return getCanRepStrings(content, datatype,  status, version, toValidate, manager);
        break;
    default:
        status = st_UnknownType;
        
        return 0;
        break;
    }
}

XSValue* XSValue::getActualValue(const XMLCh*         const content    
                               ,       DataType             datatype
                               ,       Status&              status
                               ,       XMLVersion           version
                               ,       bool                 toValidate
                               ,       MemoryManager* const manager)
{
    if (!content || 
        !*content ||
        ((version == ver_10) && (XMLChar1_0::isAllSpaces(content, XMLString::stringLen(content)))) ||
        ((version == ver_11) && (XMLChar1_1::isAllSpaces(content, XMLString::stringLen(content)))) ) {
        status = st_NoContent;
        return 0;
    }

    status = st_Init;

    switch (inGroup[datatype]) {
    case XSValue::dg_numerics:
        return getActValNumerics(content, datatype,  status, toValidate, manager);
        break;
    case XSValue::dg_datetimes:
        return getActValDateTimes(content, datatype,  status, manager);
        break;
    case XSValue::dg_strings:
        return getActValStrings(content, datatype,  status, version, toValidate, manager);
        break;
    default:
        status = st_UnknownType;       
        return 0;
        break;
    }    
}

// ---------------------------------------------------------------------------
//  XSValue: Helpers
// --------------------------------------------------------------------------- 

/***
 *
 *  Boundary checking is done against Schema Type's lexcial space
 ***/
bool 
XSValue::validateNumerics(const XMLCh*         const content    
                        ,       DataType             datatype
                        ,       Status&              status                        
                        ,       MemoryManager* const manager)
{

    try {

        switch (datatype) {
        case XSValue::dt_decimal:        
            XMLBigDecimal::parseDecimal(content, manager);
            break;            
        case XSValue::dt_float:
            {
                //XMLFloat takes care of 0, -0, -INF, INF and NaN
                //XMLFloat::checkBoundary() handles error and outofbound issues
                XMLFloat data(content, manager);
                break;
            }
        case XSValue::dt_double:
            {
                //XMLDouble takes care of 0, -0, -INF, INF and NaN
                //XMLDouble::checkBoundary() handles error and outofbound issues
                XMLDouble  data(content, manager);
                break;
            }
        /***
         *   For all potentially unrepresentable types
         *   
         *   For dt_long, dt_unsignedLong, doing lexical space
         *   checking ensures consistent behaviour on 32/64 boxes
         *
         ***/
        case XSValue::dt_integer:
        case XSValue::dt_negativeInteger:
        case XSValue::dt_nonPositiveInteger:
        case XSValue::dt_nonNegativeInteger:
        case XSValue::dt_positiveInteger:
        case XSValue::dt_long:
        case XSValue::dt_unsignedLong:
            {
                XMLCh* compareData = (XMLCh*) manager->allocate((XMLString::stringLen(content) + 1) * sizeof(XMLCh));
                ArrayJanitor<XMLCh> janName(compareData, manager);
                int    signValue = 0;
                XMLBigInteger::parseBigInteger(content, compareData, signValue,  manager);

                switch (datatype) { 
                case XSValue::dt_integer:
                    //error: no
                    break;
                case XSValue::dt_negativeInteger:
                    // error: > -1                    
                    if  (XMLBigInteger::compareValues(compareData
                                                    , signValue
                                                    , &(XMLUni::fgNegOne[1])
                                                    , -1
                                                    , manager) 
                                                    == XMLNumber::GREATER_THAN)
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                case XSValue::dt_nonPositiveInteger:
                    // error: > 0                    
                     if (XMLBigInteger::compareValues(compareData
                                                   , signValue
                                                   , XMLUni::fgValueZero
                                                   , 0
                                                   , manager) 
                                                   == XMLNumber::GREATER_THAN)
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                case XSValue::dt_nonNegativeInteger:
                    // error: < 0                
                    if (XMLBigInteger::compareValues(compareData
                                                   , signValue
                                                   , XMLUni::fgValueZero
                                                   , 0
                                                   , manager) 
                                                   == XMLNumber::LESS_THAN)
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                case XSValue::dt_positiveInteger:
                    // error: < 1                
                    if (XMLBigInteger::compareValues(compareData
                                                   , signValue
                                                   , XMLUni::fgValueOne
                                                   , 1
                                                   , manager) 
                                                   == XMLNumber::LESS_THAN)
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                case XSValue::dt_long:
                    // error: < -9223372036854775808 || > 9223372036854775807                
                    if ((XMLBigInteger::compareValues(compareData
                                                    , signValue
                                                    , &(XMLUni::fgLongMinInc[1])
                                                    , -1
                                                    , manager) 
                                                    == XMLNumber::LESS_THAN) ||
                        (XMLBigInteger::compareValues(compareData
                                                    , signValue
                                                    , XMLUni::fgLongMaxInc
                                                    , 1
                                                    , manager) 
                                                    == XMLNumber::GREATER_THAN))
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                case XSValue::dt_unsignedLong:
                    // error: < 0 || > 18446744073709551615                 
                    if ((XMLBigInteger::compareValues(compareData
                                                    , signValue
                                                    , XMLUni::fgValueZero
                                                    , 0
                                                    , manager) 
                                                    == XMLNumber::LESS_THAN) ||
                        (XMLBigInteger::compareValues(compareData
                                                    , signValue
                                                    , XMLUni::fgULongMaxInc
                                                    , 1
                                                    , manager) 
                                                    == XMLNumber::GREATER_THAN))
                    {
                        status = st_FOCA0002;
                        return false;
                    }                
                    break;
                default:
                    status = st_NotSupported;                    
                    return false;
                    break;
                }
                break;
            }       
        case XSValue::dt_int:
        case XSValue::dt_short:
        case XSValue::dt_byte:
        case XSValue::dt_unsignedInt:
        case XSValue::dt_unsignedShort:
        case XSValue::dt_unsignedByte:      
            {
                t_value   actVal;

                if ( !getActualNumericValue( 
                                  content
                                , status                                                               
                                , actVal                                
                                , manager
                                , datatype
                                 )
                )
                {                
                    return false;
                }
                break;
            }
        default:            
            return false;            
        } // end switch
        return true;  //both valid chars and within boundary
    }
    catch (const NumberFormatException&)
    {
        //getActValue()/getCanonical() need to know the failure details
        //if validation is required
        status = st_FOCA0002; 
        return false; 
    }
}

bool XSValue::validateDateTimes(const XMLCh*         const input_content    
                              ,       DataType             datatype
                              ,       Status&              status
                              ,       MemoryManager* const manager)
{
    XMLCh* content = XMLString::replicate(input_content, manager);
    ArrayJanitor<XMLCh> janTmpName(content, manager);
    XMLString::trim(content);   
    try
    {
        XMLDateTime coreDate = XMLDateTime(content, manager);

        switch (datatype) { 
        case XSValue::dt_duration:
            coreDate.parseDuration();
            break;
        case XSValue::dt_dateTime:
            coreDate.parseDateTime();
            break;
        case XSValue::dt_time:
            coreDate.parseTime();
            break;
        case XSValue::dt_date:
            coreDate.parseDate();
            break;
        case XSValue::dt_gYearMonth:
            coreDate.parseYearMonth();
            break;
        case XSValue::dt_gYear:
            coreDate.parseYear();
            break;
        case XSValue::dt_gMonthDay:
            coreDate.parseMonthDay();
            break;
        case XSValue::dt_gDay:
            coreDate.parseDay();
            break;
        case XSValue::dt_gMonth:
            coreDate.parseMonth();
            break;
        default:
            return false;
            break;
        }

        return true; //parsing succeed
    }

    catch (const SchemaDateTimeException &e)
    {       
        status = checkTimeZoneError(datatype, e)? XSValue::st_FODT0003 : st_FOCA0002;
        return false;
    }
    catch (const NumberFormatException&)
    {
        //getActValue()/getCanonical() need to know the failure details
        //if validation is required
        status = st_FOCA0002;
        return false; 
    }      
}

bool XSValue::validateStrings(const XMLCh*         const content    
                            ,       DataType             datatype
                            ,       Status&              status
                            ,       XMLVersion           version
                            ,       MemoryManager* const manager)
{
    bool isValid = true;
    
    switch (datatype) { 
        case XSValue::dt_boolean:
            {
                unsigned int i = 0;
                XMLCh* tmpStrValue = XMLString::replicate(content, manager);
                ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
                XMLString::trim(tmpStrValue);    
                for (; i < XMLUni::fgBooleanValueSpaceArraySize; i++) {
                    if (XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[i]))
                        break;
                }

                if (XMLUni::fgBooleanValueSpaceArraySize == i) {
                    isValid = false;
                }
                break;
            }
        case XSValue::dt_hexBinary:
            {
            XMLCh* tmpStrValue = XMLString::replicate(content, manager);
            ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
            XMLString::trim(tmpStrValue);
            if (HexBin::getDataLength(tmpStrValue) == -1) {
               isValid = false;                	
            }
            }
            break;
        case XSValue::dt_base64Binary:            
            if (Base64::getDataLength(content, manager) == -1) {
                isValid = false;                	
            }            
            break;
        case XSValue::dt_anyURI:
            if (XMLUri::isValidURI(true, content) == false) {
                isValid = false;
            }        
            break;
        case XSValue::dt_QName:
            {
            XMLCh* tmpStrValue = XMLString::replicate(content, manager);
            ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
            XMLString::trim(tmpStrValue);
            isValid = (version == ver_10) ? 
                XMLChar1_0::isValidQName(tmpStrValue, XMLString::stringLen(tmpStrValue)) :
                XMLChar1_1::isValidQName(tmpStrValue, XMLString::stringLen(tmpStrValue));
            }
            break;
        case XSValue::dt_NOTATION:
            {
            XMLCh* tmpStrValue = XMLString::replicate(content, manager);
            ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
            XMLString::trim(tmpStrValue);
            if ( XMLString::isValidNOTATION(tmpStrValue, manager) == false) {
            	isValid = false;
            }
            }
            break;
        case XSValue::dt_string:
            {
                const XMLCh*   rawPtr = content;

                if (version == ver_10) {
                    while (*rawPtr) 
                        if (!XMLChar1_0::isXMLChar(*rawPtr++)) {
                            isValid = false;
                            break;
                        }
                }
                else {                
                    while (*rawPtr) 
                        if (!XMLChar1_1::isXMLChar(*rawPtr++)) {                        
                            isValid = false;
                            break;
                        }
                }
                break;
            }            
        case XSValue::dt_normalizedString:
            {
                const XMLCh*   rawPtr = content;

                if (version == ver_10) {                
                    while (*rawPtr) {                    
                        if (!XMLChar1_0::isXMLChar(*rawPtr)) {                        
                            isValid = false;
                            break;
                        }
                        else if (*rawPtr == chCR || *rawPtr == chLF || *rawPtr == chHTab) {                        
                            isValid = false;
                            break;
                        }
                        else {                        
                            rawPtr++;
                        }
                    }
                }
                else {                
                    while (*rawPtr) {                    
                        if (!XMLChar1_1::isXMLChar(*rawPtr)) {                        
                            isValid = false;
                            break;
                        }
                        else if (*rawPtr == chCR || *rawPtr == chLF || *rawPtr == chHTab) {                        
                            isValid = false;
                            break;
                        }
                        else {                        
                            rawPtr++;
                        }
                                            	
                    }
                }
                break;
            }            
        case XSValue::dt_token:
        case XSValue::dt_language:
            {
                unsigned int strLen = XMLString::stringLen(content);
                const XMLCh*  rawPtr = content;
                bool     inWS = false;

                if (version == ver_10) {                
                    // Check leading/Trailing white space
                    if (XMLChar1_0::isWhitespace(content[0])      ||
                        XMLChar1_0::isWhitespace(content[strLen - 1])  ) {                    
                        isValid = false;
                    }
                    else {                    
                        while (*rawPtr) {                        
                            if (!XMLChar1_0::isXMLChar(*rawPtr)) {                            
                                isValid = false;
                                break;
                            }
                            else if (*rawPtr == chCR || *rawPtr == chLF || *rawPtr == chHTab) {                            
                                isValid = false;
                                break;
                            }                            
                            else if (XMLChar1_0::isWhitespace(*rawPtr)) {                            
                                if (inWS) {                                
                                    isValid = false;
                                    break;
                                }
                                else {                                
                                    inWS = true;
                                }
                            }
                            else {                            
                                inWS = false;
                            }

                            rawPtr++;
                        }
                    }
                }
                else {                
                    // Check leading/Trailing white space
                    if (XMLChar1_1::isWhitespace(content[0])      ||
                        XMLChar1_1::isWhitespace(content[strLen - 1])  ) {                    
                        isValid = false;
                    }
                    else {                    
                        while (*rawPtr) {                        
                            if (!XMLChar1_1::isXMLChar(*rawPtr)) {                            
                                isValid = false;
                                break;
                            }
                            else if (*rawPtr == chCR || *rawPtr == chLF || *rawPtr == chHTab) {                            
                                isValid = false;
                                break;
                            }                            
                            else if (XMLChar1_1::isWhitespace(*rawPtr)) {                            
                                if (inWS) {                                
                                    isValid = false;
                                    break;
                                }
                                else {                                
                                    inWS = true;
                                }
                            }
                            else {                            
                                inWS = false;
                            }
                            rawPtr++;
                        }
                    }                   
                }
                if (isValid == true && datatype == XSValue::dt_language) {                
                    RegularExpression* regEx = getRegEx();
                    if (!regEx) {                   
                        status = st_CantCreateRegEx;
                        isValid = false;
                    }
                    else {                    
                        if (regEx->matches(content, manager) == false) {                        
                            isValid = false;
                        }
                    }
                }
                break;
            }
        case XSValue::dt_NMTOKEN:
            isValid = (version == ver_10) ? 
                XMLChar1_0::isValidNmtoken(content, XMLString::stringLen(content)) :
                XMLChar1_1::isValidNmtoken(content, XMLString::stringLen(content));
            break;
        case XSValue::dt_NMTOKENS:
            // [8]    Nmtokens   ::=    Nmtoken (#x20 Nmtoken)*
            {
                XMLStringTokenizer tokenizer(content, Separator_20, manager);

                if (version ==  ver_10) {                
                    while (tokenizer.hasMoreTokens()) {
                        const XMLCh* token = tokenizer.nextToken();

                        if (!XMLChar1_0::isValidNmtoken(token, XMLString::stringLen(token))) {                        
                            isValid = false;
                            break;
                        }                        
                    }
                }
                else {                
                    while (tokenizer.hasMoreTokens()) {                    
                        const XMLCh* token = tokenizer.nextToken();

                        if (!XMLChar1_1::isValidNmtoken(token, XMLString::stringLen(token))) {                        
                            isValid = false;
                            break;
                        }                        
                    }
                }
                break;
            }            
        case XSValue::dt_Name:
            isValid = (version == ver_10) ? 
                XMLChar1_0::isValidName(content) :
                XMLChar1_1::isValidName(content);
            break;
        case XSValue::dt_NCName:
        case XSValue::dt_ID:
        case XSValue::dt_IDREF:
        case XSValue::dt_ENTITY:
            isValid = (version == ver_10) ? 
                XMLChar1_0::isValidNCName(content, XMLString::stringLen(content)) :
                XMLChar1_1::isValidNCName(content, XMLString::stringLen(content));
            break;
        case XSValue::dt_ENTITIES:
        case XSValue::dt_IDREFS:
            {
                XMLStringTokenizer tokenizer(content, Separator_ws, manager);

                if (version ==  ver_10 ) {                
                    while (tokenizer.hasMoreTokens()) {                    
                        const XMLCh* token = tokenizer.nextToken();

                        if (!XMLChar1_0::isValidNCName(token, XMLString::stringLen(token))) {                        
                            isValid = false;
                            break;
                        }                        
                    }
                }
                else {                
                    while (tokenizer.hasMoreTokens()) {                    
                        const XMLCh* token = tokenizer.nextToken();

                        if (!XMLChar1_1::isValidNCName(token, XMLString::stringLen(token))) {                        
                            isValid = false;
                            break;
                        }                        
                    }
                }
            }
            break;
        default:
            status = st_NotSupported;
            isValid = false;        
            break;        
    }

    if (isValid == false && status == st_Init) {
        status = st_FOCA0002;
    }

    return isValid;
}


XMLCh* XSValue::getCanRepNumerics(const XMLCh*         const content    
                                ,       DataType             datatype
                                ,       Status&              status                                
                                ,       bool                 toValidate
                                ,       MemoryManager* const manager)
{
    try 
    {

        // getCanonicalRepresentation does lexical space validation only
        // (no range checking), therefore if validation is required,
        // we need to pass the content to the validate interface for complete checking
        if (toValidate && !validateNumerics(content, datatype, status, manager))
            return 0;

        XMLCh* retVal = 0;

        if (datatype == XSValue::dt_decimal)
        {
            retVal = XMLBigDecimal::getCanonicalRepresentation(content, manager);

            if (!retVal)
                status = st_FOCA0002;

            return retVal;

        }
        else if (datatype == XSValue::dt_float || datatype == XSValue::dt_double  )
        {
            // In XML4C, no float or double is treated as out of range
            // it gets converted to INF, -INF or zero.
            // The getCanonical method should treat double & float the
            // same way as the rest of XML4C for consistentcy so need
            // to getActualValue and see if it was converted.
            XSValue* xsval = getActValNumerics(content, datatype, status, false, manager);
            if (!xsval) {
                status = st_FOCA0002;
                return retVal;
            }

            DoubleFloatType enumVal;
            if (datatype == XSValue::dt_float) {
                enumVal = xsval->fData.fValue.f_floatType.f_floatEnum;
            }
            else {
                enumVal = xsval->fData.fValue.f_doubleType.f_doubleEnum;
            }
            delete xsval;
            
            switch(enumVal) {
            case DoubleFloatType_NegINF:
                retVal = XMLString::replicate(XMLUni::fgNegINFString, manager);        
                break;
            case DoubleFloatType_PosINF:
                retVal = XMLString::replicate(XMLUni::fgPosINFString, manager);        
                break;
            case DoubleFloatType_NaN:
                retVal = XMLString::replicate(XMLUni::fgNaNString, manager);        
                break;
            case DoubleFloatType_Zero:
                retVal = XMLString::replicate(XMLUni::fgPosZeroString, manager);
                break;
            default: //DoubleFloatType_Normal         
                retVal = XMLAbstractDoubleFloat::getCanonicalRepresentation(content, manager);

                if (!retVal)
                    status = st_FOCA0002;
                break;
            }
            return retVal;
        }  
        else 
        {
            retVal = XMLBigInteger::getCanonicalRepresentation(content, manager, datatype == XSValue::dt_nonPositiveInteger);

            if (!retVal)
                status = st_FOCA0002;

            return retVal;
        }
    }
    catch (const NumberFormatException&)
    {
        status = st_FOCA0002;
        return 0;
    }

}

XMLCh* XSValue::getCanRepDateTimes(const XMLCh*         const input_content    
                                 ,       DataType             datatype
                                 ,       Status&              status                                 
                                 ,       bool                 toValidate
                                 ,       MemoryManager* const manager)
{
    XMLCh* content = XMLString::replicate(input_content, manager);
    ArrayJanitor<XMLCh> janTmpName(content, manager);
    XMLString::trim(content);   
    try
    {

        XMLDateTime coreDate = XMLDateTime(content, manager);

        switch (datatype) { 
        case XSValue::dt_dateTime:
            //we need this parsing
            coreDate.parseDateTime();
            return coreDate.getDateTimeCanonicalRepresentation(manager);
            break;
        case XSValue::dt_time:
            // we need this parsing
            coreDate.parseTime(); 
            return coreDate.getTimeCanonicalRepresentation(manager);
            break;
        case XSValue::dt_date:
            // we need this parsing
            coreDate.parseDate(); 
            return coreDate.getDateCanonicalRepresentation(manager);
            break;
        case XSValue::dt_duration:        
        case XSValue::dt_gYearMonth:
        case XSValue::dt_gYear:
        case XSValue::dt_gMonthDay:
        case XSValue::dt_gDay:
        case XSValue::dt_gMonth:
            {
                if (!(toValidate && !validateDateTimes(content, datatype, status, manager)))               
                    status = st_NoCanRep;

                return 0;
            }
            break;
        default:
            return 0;
            break;
        }
    }

    catch (SchemaDateTimeException &e)
    {
        status = checkTimeZoneError(datatype, e)? XSValue::st_FODT0003 : st_FOCA0002;       
    }
    catch (const NumberFormatException&)
    {
        status = st_FOCA0002;        
    }
    return 0;
}

XMLCh* XSValue::getCanRepStrings(const XMLCh*         const content    
                               ,       DataType             datatype
                               ,       Status&              status
                               ,       XMLVersion           version
                               ,       bool                 toValidate
                               ,       MemoryManager* const manager)
{
    switch (datatype) {        
        case XSValue::dt_boolean:
            {
            XMLCh* tmpStrValue = XMLString::replicate(content, manager);
            ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
            XMLString::trim(tmpStrValue);
            //always validate before getting canRep
            if (XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[0]) ||
                XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[2])  ) 
            {
                return XMLString::replicate(XMLUni::fgBooleanValueSpace[0], manager);
            }
            else if (XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[1]) ||
                     XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[3])  ) 
            {
                return XMLString::replicate(XMLUni::fgBooleanValueSpace[1], manager);
            }
            else
            {
                status = st_FOCA0002;
                return 0;
            }     
            }
            break;
        case XSValue::dt_hexBinary: 
            {
                //HexBin::getCanonicalRepresentation does validation automatically
                XMLCh* tmpStrValue = XMLString::replicate(content, manager);
                ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
                XMLString::trim(tmpStrValue); 

                XMLCh* canRep = HexBin::getCanonicalRepresentation(tmpStrValue, manager);
                if (!canRep)
                    status = st_FOCA0002;

                return canRep;            
                break;
            }
        case XSValue::dt_base64Binary:
            {
                //Base64::getCanonicalRepresentation does validation automatically
                XMLCh* canRep = Base64::getCanonicalRepresentation(content, manager);
                if (!canRep)
                    status = st_FOCA0002;

                return canRep;            
                break;
            }
        case XSValue::dt_anyURI:
        case XSValue::dt_QName:
        case XSValue::dt_NOTATION:
        case XSValue::dt_string:
        case XSValue::dt_normalizedString:
        case XSValue::dt_token:
        case XSValue::dt_language:
        case XSValue::dt_NMTOKEN:
        case XSValue::dt_NMTOKENS:
        case XSValue::dt_Name:
        case XSValue::dt_NCName:
        case XSValue::dt_ID:
        case XSValue::dt_IDREF:
        case XSValue::dt_ENTITY:
        case XSValue::dt_ENTITIES:
        case XSValue::dt_IDREFS:            
            if (toValidate && !validateStrings(content, datatype, status, version, manager))
                status = st_FOCA0002;
            else
                status = st_NoCanRep;

            return 0;            
            break;
        default:
            return 0;
            break;        
    }

    return 0;
}

XSValue*  
XSValue::getActValNumerics(const XMLCh*         const content    
                         ,       DataType             datatype
                         ,       Status&              status
                         ,       bool                 toValidate
                         ,       MemoryManager* const manager)
{

    try {

        switch (datatype) {
        case XSValue::dt_decimal:
        {
            if (toValidate) {
                XMLBigDecimal::parseDecimal(content, manager);
            }
            //Prepare the double value
            XMLDouble  data(content, manager);
            if (data.isDataConverted())
            {
                status = st_FOCA0001;
                return 0;
            }

            XSValue* retVal = new (manager) XSValue(dt_decimal, manager);
            retVal->fData.fValue.f_decimal.f_dvalue = data.getValue();

            return retVal;            
            break;
        }    
        case XSValue::dt_float:
        {
            //XMLFloat takes care of 0, -0, -INF, INF and NaN
            //XMLFloat::checkBoundary() handles error and outofbound issues
            XMLFloat data(content, manager);
            XSValue* retVal = new (manager) XSValue(dt_float, manager);
            
            if (data.isDataConverted())
            {
                retVal->fData.fValue.f_floatType.f_float = 0.0; 
                retVal->fData.fValue.f_floatType.f_floatEnum = DoubleFloatType_Zero;
           
                switch(data.getType()) {
                    case XMLAbstractDoubleFloat::NegINF:
                        retVal->fData.fValue.f_floatType.f_floatEnum = DoubleFloatType_NegINF;
                        break;
                    case XMLAbstractDoubleFloat::PosINF:
                        retVal->fData.fValue.f_floatType.f_floatEnum = DoubleFloatType_PosINF;
                        break;
                    case XMLAbstractDoubleFloat::NaN:
                        retVal->fData.fValue.f_floatType.f_floatEnum = DoubleFloatType_NaN;
                        break;
                    default:
                        break;
                }
            }
            else {
                retVal->fData.fValue.f_floatType.f_floatEnum = DoubleFloatType_Normal;
                retVal->fData.fValue.f_floatType.f_float = (float) data.getValue(); 
            }                                       
            return retVal;
            break;                   
        }
        case XSValue::dt_double:
        {
            //XMLDouble takes care of 0, -0, -INF, INF and NaN
            //XMLDouble::checkBoundary() handles error and outofbound issues
            XMLDouble  data(content, manager);
            XSValue* retVal = new (manager) XSValue(dt_double, manager);
            
            if (data.isDataConverted())
            {
                retVal->fData.fValue.f_doubleType.f_double = 0.0; 
                retVal->fData.fValue.f_doubleType.f_doubleEnum = DoubleFloatType_Zero;
           
                switch(data.getType()) {
                    case XMLAbstractDoubleFloat::NegINF:
                        retVal->fData.fValue.f_doubleType.f_doubleEnum = DoubleFloatType_NegINF;
                        break;
                    case XMLAbstractDoubleFloat::PosINF:
                        retVal->fData.fValue.f_doubleType.f_doubleEnum = DoubleFloatType_PosINF;
                        break;
                    case XMLAbstractDoubleFloat::NaN:
                        retVal->fData.fValue.f_doubleType.f_doubleEnum = DoubleFloatType_NaN;
                        break;
                    default:
                        break;                      
                }
            }
            else {
                retVal->fData.fValue.f_doubleType.f_doubleEnum = DoubleFloatType_Normal;
                retVal->fData.fValue.f_doubleType.f_double = data.getValue(); 
            }                                       
            return retVal;
            break;
        }
        case XSValue::dt_integer:
        case XSValue::dt_negativeInteger:
        case XSValue::dt_nonPositiveInteger:
        case XSValue::dt_nonNegativeInteger:
        case XSValue::dt_positiveInteger:
        case XSValue::dt_long:
        case XSValue::dt_int:
        case XSValue::dt_short:
        case XSValue::dt_byte:
        case XSValue::dt_unsignedLong:                                                   
        case XSValue::dt_unsignedInt:                                                              
        case XSValue::dt_unsignedShort:                                
        case XSValue::dt_unsignedByte:    
        {
            t_value   actVal;                

            if ( !getActualNumericValue( 
                                  content
                                , status                                                               
                                , actVal                                
                                , manager
                                , datatype
                                )
                )
            {
                //status has been set by getActualNumericValue
                return 0;
            }

            XSValue* retVal = new (manager) XSValue(datatype, manager);

            switch (datatype) { 
                case XSValue::dt_integer:                  
                    retVal->fData.fValue.f_long = actVal.f_long;
                    break;
                case XSValue::dt_negativeInteger:                
                    retVal->fData.fValue.f_long = actVal.f_long;
                    break;
                case XSValue::dt_nonPositiveInteger:                
                    retVal->fData.fValue.f_long = actVal.f_long;                    
                    break;
                case XSValue::dt_nonNegativeInteger:                
                    retVal->fData.fValue.f_long = actVal.f_ulong;
                    break;
                case XSValue::dt_positiveInteger:               
                    retVal->fData.fValue.f_long = actVal.f_ulong;
                    break;
                case XSValue::dt_long:                                                    
                    retVal->fData.fValue.f_long = actVal.f_long;                                    
                    break;
                case XSValue::dt_int:                                  
                    retVal->fData.fValue.f_int = (int) actVal.f_long; 
                    break;
                case XSValue::dt_short:                
                    retVal->fData.fValue.f_short = (short) actVal.f_long;
                    break;
                case XSValue::dt_byte:                 
                    retVal->fData.fValue.f_char = (char) actVal.f_long;
                    break;
                case XSValue::dt_unsignedLong:                                                   
                    retVal->fData.fValue.f_ulong = actVal.f_ulong;
                    break; 
                case XSValue::dt_unsignedInt:                                                              
                    retVal->fData.fValue.f_uint = (unsigned int) actVal.f_ulong;           
                    break;
                case XSValue::dt_unsignedShort:                                
                    retVal->fData.fValue.f_ushort = (unsigned short) actVal.f_ulong; 
                    break;
                case XSValue::dt_unsignedByte:                                                                         
                    retVal->fData.fValue.f_uchar = (unsigned char) actVal.f_ulong;                                   
                    break;
                default:                    
                    return 0;
                    break;
            }
            return retVal;
            break;
        }
        default:        
            return 0;
            break;        
        } // end switch
    }
    catch (const NumberFormatException&)
    {
        status = st_FOCA0002;        
    }
    return 0; 
}
             
XSValue*  
XSValue::getActValDateTimes(const XMLCh*         const input_content    
                          ,       DataType             datatype
                          ,       Status&              status                         
                          ,       MemoryManager* const manager)
{
    XMLCh* content = XMLString::replicate(input_content, manager);
    ArrayJanitor<XMLCh> janTmpName(content, manager);
    XMLString::trim(content);   
    try
    {
        //Need not check if validation is requested since
        //parsing functions below does the validation automatically
        XMLDateTime coreDate = XMLDateTime(content, manager);

        switch (datatype) { 
        case XSValue::dt_duration:
            coreDate.parseDuration();
            break;
        case XSValue::dt_dateTime:
            coreDate.parseDateTime();
            break;
        case XSValue::dt_time:
            coreDate.parseTime();
            coreDate.fValue[XMLDateTime::CentYear] = 0;  
            coreDate.fValue[XMLDateTime::Month] = 0;
            coreDate.fValue[XMLDateTime::Day] = 0;
            break;
        case XSValue::dt_date:
            coreDate.parseDate();
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;
            break;
        case XSValue::dt_gYearMonth:
            coreDate.parseYearMonth();
            coreDate.fValue[XMLDateTime::Day] = 0;
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;
            break;
        case XSValue::dt_gYear:
            coreDate.parseYear();            
            coreDate.fValue[XMLDateTime::Month] = 0;
            coreDate.fValue[XMLDateTime::Day] = 0;
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;
            break;
        case XSValue::dt_gMonthDay:
            coreDate.parseMonthDay();
            coreDate.fValue[XMLDateTime::CentYear] = 0;
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;            
            break;
        case XSValue::dt_gDay:
            coreDate.parseDay();
            coreDate.fValue[XMLDateTime::CentYear] = 0;
            coreDate.fValue[XMLDateTime::Month] = 0;      
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;           
            break;
        case XSValue::dt_gMonth:
            coreDate.parseMonth();
            coreDate.fValue[XMLDateTime::CentYear] = 0;            
            coreDate.fValue[XMLDateTime::Day] = 0;
            coreDate.fValue[XMLDateTime::Hour] = 0;
            coreDate.fValue[XMLDateTime::Minute] = 0;
            break;
        default:
            return 0;
            break;
        }

        XSValue* retVal = new (manager) XSValue(datatype, manager);

        retVal->fData.fValue.f_datetime.f_year    = coreDate.fValue[XMLDateTime::CentYear];
        retVal->fData.fValue.f_datetime.f_month   = coreDate.fValue[XMLDateTime::Month];
        retVal->fData.fValue.f_datetime.f_day     = coreDate.fValue[XMLDateTime::Day];
        retVal->fData.fValue.f_datetime.f_hour    = coreDate.fValue[XMLDateTime::Hour];
        retVal->fData.fValue.f_datetime.f_min     = coreDate.fValue[XMLDateTime::Minute];
        retVal->fData.fValue.f_datetime.f_second  = coreDate.fValue[XMLDateTime::Second];
        retVal->fData.fValue.f_datetime.f_milisec = coreDate.fMiliSecond;

        return retVal;
    }
    catch (SchemaDateTimeException const &e)
    {
        status = checkTimeZoneError(datatype, e)? XSValue::st_FODT0003 : st_FOCA0002;        
    }
    catch (const NumberFormatException&)
    {
        status = st_FOCA0002;         
    }
    return 0;
}

XSValue*  
XSValue::getActValStrings(const XMLCh*         const content    
                        ,       DataType             datatype
                        ,       Status&              status
                        ,       XMLVersion           version
                        ,       bool                 toValidate
                        ,       MemoryManager* const manager)
{
    switch (datatype) { 
        case XSValue::dt_boolean: 
            {
            XMLCh* tmpStrValue = XMLString::replicate(content, manager);
            ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
            XMLString::trim(tmpStrValue);            
            //do validation here more efficiently
            if (XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[0]) ||
                XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[2])  )
            {
                XSValue* retVal = new (manager) XSValue(dt_boolean, manager);
                retVal->fData.fValue.f_bool = false;
                return retVal;
            }
            else if (XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[1]) ||
                     XMLString::equals(tmpStrValue, XMLUni::fgBooleanValueSpace[3])  )
            {
                XSValue* retVal = new (manager) XSValue(dt_boolean, manager);
                retVal->fData.fValue.f_bool = true;
                return retVal;
            }
            else
            {
                status = st_FOCA0002;
                return 0;
            }
            }
            break;
        case XSValue::dt_hexBinary:
            {
                XMLCh* tmpStrValue = XMLString::replicate(content, manager);
                ArrayJanitor<XMLCh> janTmpName(tmpStrValue, manager);
                XMLString::trim(tmpStrValue); 

                XMLByte* decodedData = HexBin::decodeToXMLByte(tmpStrValue, manager);

                if (!decodedData)
                {
                    status = st_FOCA0002;
                    return 0;
                }

                XSValue* retVal = new (manager) XSValue(dt_hexBinary, manager);
                retVal->fData.fValue.f_byteVal = decodedData;
                retVal->fMemAllocated = true;
                return retVal;                
                break;
            }                   
        case XSValue::dt_base64Binary:
            {
                unsigned int    len = 0;
                XMLByte* decodedData = Base64::decodeToXMLByte(content, &len, manager);

                if (!decodedData)
                {
                    status = st_FOCA0002;
                    return 0;
                }

                XSValue* retVal = new (manager) XSValue(dt_base64Binary, manager);
                retVal->fData.fValue.f_byteVal = decodedData;
                retVal->fMemAllocated = true;
                return retVal;
                break;
            }            
        case XSValue::dt_anyURI:
        case XSValue::dt_QName:
        case XSValue::dt_NOTATION:
        case XSValue::dt_string:
        case XSValue::dt_normalizedString:
        case XSValue::dt_token:
        case XSValue::dt_language:
        case XSValue::dt_NMTOKEN:
        case XSValue::dt_NMTOKENS:
        case XSValue::dt_Name:
        case XSValue::dt_NCName:
        case XSValue::dt_ID:
        case XSValue::dt_IDREF:
        case XSValue::dt_ENTITY:
        case XSValue::dt_ENTITIES:
        case XSValue::dt_IDREFS:            
            if (toValidate && !validateStrings(content, datatype, status, version, manager))
                status = st_FOCA0002;
            else
                status = st_NoActVal;

            return 0;            
            break;
        default:
            return 0;
            break;        
    }

    return 0; 
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------
bool XSValue::getActualNumericValue(const XMLCh*  const content
                           ,       Status&              status                                                          
                           ,       t_value&             retVal                                          
                           ,       MemoryManager* const manager
                           ,       DataType             datatype)
{
    char *nptr = XMLString::transcode(content, manager);
    ArrayJanitor<char> jan(nptr, manager);    
    char *endptr = 0;
    errno = 0;

    if (XSValue::numericSign[datatype])
    {
        retVal.f_long = strtol(nptr, &endptr, (int)10);
    }
    else
    {
        if (XMLString::indexOf(content, chDash) != -1)
        {
            status = st_FOCA0002; //invalid lexcial value
            return false;
        }

        retVal.f_ulong = strtoul(nptr, &endptr, (int)10);
    }

    // need to check out-of-bounds before checking erange...
    switch (datatype) {                                     
        case XSValue::dt_nonPositiveInteger:
            if (retVal.f_long > 0)
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_negativeInteger:
            if (retVal.f_long >= 0)
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_int:
            // strtol will set value to LONG_MIN/LONG_MAX if ERANGE error
            if ((retVal.f_long < INT_MIN) || 
                (retVal.f_long > INT_MAX) ||
                (errno == ERANGE))
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_short:
            if ((retVal.f_long < SHRT_MIN) || 
                (retVal.f_long > SHRT_MAX))
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_byte:
            if ((retVal.f_long < SCHAR_MIN) || 
                (retVal.f_long > SCHAR_MAX))
            {
                status = st_FOCA0002;
                return false;
            }
            break;        
        case XSValue::dt_unsignedInt:
            // strtoul will set value to LONG_INT if ERANGE error
            if ((retVal.f_ulong > UINT_MAX)  ||
                (errno == ERANGE))
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_unsignedShort:
            if (retVal.f_ulong > USHRT_MAX) 
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        case XSValue::dt_unsignedByte:
            if (retVal.f_ulong > UCHAR_MAX) 
            {
                status = st_FOCA0002;
                return false;
            }              
            break;              
        case XSValue::dt_positiveInteger:
            if (retVal.f_ulong == 0)
            {
                status = st_FOCA0002;
                return false;
            }
            break;
        default:
            break;
    } // end switch
    // check if overflow/underflow occurs
    if (errno == ERANGE)
    {
        status = st_FOCA0003;
        return false;
    }
    // check if all chars are valid char.  If they are, endptr will
    // pointer to the null terminator, or all of the remaining
    // characters will be whitespace characters.
    while (*endptr != '\0')
    {
        const char  ch = *endptr;

        if (ch == '\t' || ch == '\n' || ch == '\r' || ch == ' ')
        {
            ++endptr;
        }
        else
        {
            status = st_FOCA0002;
            return false;
        }
        
    }
    return true;
}

// -----------------------------------------------------------------------
//  Reinitialise the mutex and RegEx
// -----------------------------------------------------------------------
void XSValue::reinitMutex()
{
    delete sXSValueMutext;
    sXSValueMutext = 0;
}

void XSValue::reinitRegEx()
{
	delete sXSValueRegEx;
	sXSValueRegEx = 0;
}

void XSValue::reinitRegistry()
{
	delete fDataTypeRegistry;
	fDataTypeRegistry = 0;
}

XERCES_CPP_NAMESPACE_END


