1690 lines
66 KiB
C++
1690 lines
66 KiB
C++
/*
|
|
* 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 932887 2010-04-11 13:04:59Z borisk $
|
|
*/
|
|
|
|
#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/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 RegularExpression* sXSValueRegEx = 0;
|
|
ValueHashTableOf<XSValue::DataType>* XSValue::fDataTypeRegistry = 0;
|
|
|
|
void XMLInitializer::initializeXSValue()
|
|
{
|
|
sXSValueRegEx = new RegularExpression(
|
|
XMLUni::fgLangPattern, SchemaSymbols::fgRegEx_XOption);
|
|
|
|
XSValue::initializeRegistry();
|
|
}
|
|
|
|
void XMLInitializer::terminateXSValue()
|
|
{
|
|
delete XSValue::fDataTypeRegistry;
|
|
XSValue::fDataTypeRegistry = 0;
|
|
|
|
delete sXSValueRegEx;
|
|
sXSValueRegEx = 0;
|
|
}
|
|
|
|
XSValue::DataType XSValue::getDataType(const XMLCh* const dtString)
|
|
{
|
|
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) {
|
|
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;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
catch (const NumberFormatException&)
|
|
{
|
|
//getActValue()/getCanonical() need to know the failure details
|
|
//if validation is required
|
|
status = st_FOCA0002;
|
|
return false;
|
|
}
|
|
return true; //both valid chars and within boundary
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
return true; //parsing succeed
|
|
}
|
|
|
|
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:
|
|
{
|
|
XMLSize_t 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, true) == 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:
|
|
{
|
|
XMLSize_t 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) {
|
|
if (!sXSValueRegEx) {
|
|
status = st_CantCreateRegEx;
|
|
isValid = false;
|
|
}
|
|
else
|
|
{
|
|
if (sXSValueRegEx->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.fMilliSecond;
|
|
|
|
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:
|
|
{
|
|
XMLSize_t 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;
|
|
}
|
|
|
|
XERCES_CPP_NAMESPACE_END
|