#include "../../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include "ATDurationOrDerivedImpl.hpp" #include #include #include "../../exceptions/XPath2TypeCastException.hpp" #include #include #include #include #include #include #include #include #include #include #include "../../utils/DateUtils.hpp" ATDurationOrDerivedImpl:: ATDurationOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const XMLCh* value, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDurationOrDerived(memMgr), _typeName(typeName), _typeURI(typeURI) { // Lexical representation : PnYnMnDTnHnMnS setDuration(value, context); if(this->isInstanceOfType (FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_DAYTIMEDURATION, context)) { durationType = DAY_TIME_DURATION; } else if (this->isInstanceOfType (FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_YEARMONTHDURATION, context)) { durationType = YEAR_MONTH_DURATION; } else { durationType = DURATION; } } ATDurationOrDerivedImpl:: ATDurationOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const ATDecimalOrDerived* year,const ATDecimalOrDerived* month, const ATDecimalOrDerived* day, const ATDecimalOrDerived* hour, const ATDecimalOrDerived* minute, const ATDecimalOrDerived* sec, bool isPositive, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDurationOrDerived(memMgr), _isPositive(isPositive), _year(year), _month(month), _day(day), _hour(hour), _minute(minute), _sec(sec), _typeName(typeName), _typeURI(typeURI){ if(this->isInstanceOfType (FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_DAYTIMEDURATION, context)) { durationType = DAY_TIME_DURATION; } else if (this->isInstanceOfType (FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_YEARMONTHDURATION, context)) { durationType = YEAR_MONTH_DURATION; } else { durationType = DURATION; } } /* Get the name of the primitive type (basic type) of this type * (ie "decimal" for xs:decimal) */ const XMLCh* ATDurationOrDerivedImpl::getPrimitiveTypeName() const { return this->getPrimitiveName(); } const XMLCh* ATDurationOrDerivedImpl::getPrimitiveName() { return XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DURATION; } /* Get the name of this type (ie "integer" for xs:integer) */ const XMLCh* ATDurationOrDerivedImpl::getTypeName() const { return _typeName; } /* Get the namespace URI for this type */ const XMLCh* ATDurationOrDerivedImpl::getTypeURI() const { return _typeURI; } AnyAtomicType::AtomicObjectType ATDurationOrDerivedImpl::getTypeIndex() { return AnyAtomicType::DURATION; } /* If possible, cast this type to the target type */ const AnyAtomicType* ATDurationOrDerivedImpl::castAsInternal(const XMLCh* targetURI, const XMLCh* targetType, const DynamicContext* context) const { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); // checking if what we're casting to by using isTypeOrDerivedFrom is expensive so we will // determine what we are casting to and then what type we actually are. if(context->isTypeOrDerivedFromType(targetURI, targetType, FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_YEARMONTHDURATION)) { //we're casting to a yearMonthDuration if (durationType == DAY_TIME_DURATION) { //we are a dayTimeDuration so we can't do this DSLthrow(XPath2TypeCastException,X("ATDurationOrDerivedImpl::castAsInternal"), X("Invalid representation of duration")); } else if (durationType == YEAR_MONTH_DURATION) { return DatatypeFactory::STR2AT::createDurationOrDerived(context->getMemoryManager(), targetURI, targetType, this->asString(context), context); } else { //else we're a duration and we must remove the day and time components if(this->_year->isZero() && this->_month->isZero()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } else { if ( !_isPositive ) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); if(!this->_year->isZero()) { buf.append(this->_year->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_Y); } if(!this->_month->isZero()) { buf.append(this->_month->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } } return DatatypeFactory::STR2AT::createDurationOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } } else if (context->isTypeOrDerivedFromType(targetURI, targetType, FunctionConstructor::XMLChXPath2DatatypesURI, ATDurationOrDerived::fgDT_DAYTIMEDURATION)) { //we're casting to a dayTimeDuration if (durationType == YEAR_MONTH_DURATION) { //we are a yearMonthDuration so we can't do this DSLthrow(XPath2TypeCastException,X("ATDurationOrDerivedImpl::castAsInternal"), X("Invalid representation of duration")); } else if (durationType == DAY_TIME_DURATION) { return DatatypeFactory::STR2AT::createDurationOrDerived(context->getMemoryManager(), targetURI, targetType, this->asString(context), context); } else { //else we're a duration and we must remove the year and month components if (this->_day->isZero() && this->_hour->isZero() && this->_minute->isZero() && this->_sec->isZero() ) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); } else { if ( !_isPositive ) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); if(!this->_day->isZero()) { buf.append(this->_day->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_D); } // mandatory center 'T', if the time is not zero if(!(this->_hour->isZero() && this->_minute->isZero() && this->_sec->isZero())) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); if(!this->_hour->isZero()) { buf.append(this->_hour->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_H); } if(!this->_minute->isZero()) { buf.append(this->_minute->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } if(!this->_sec->isZero()) { buf.append(this->_sec->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); } } } return DatatypeFactory::STR2AT::createDurationOrDerived(context->getMemoryManager(), targetURI, targetType, buf.getRawBuffer(), context); } } else { //else we're casting to a duration or some other type and the base castAs will handle it. return AnyAtomicType::castAsInternal(targetURI, targetType, context); } } /* returns the XMLCh* (canonical) representation of this type */ const XMLCh* ATDurationOrDerivedImpl::asString(const DynamicContext* context) const { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buffer(1023, context->getMemoryManager()); const ATDurationOrDerivedImpl* toSerialize; if(durationType != DURATION) { toSerialize = (const ATDurationOrDerivedImpl*)this->normalize(context); } else { toSerialize = this; } // if the value of this duration is zero, return 'PT0S' or 'P0M' if(toSerialize->_year->isZero() && toSerialize->_month->isZero() && toSerialize->_day->isZero() && toSerialize->_hour->isZero() && toSerialize->_minute->isZero() && toSerialize->_sec->isZero() ) { if(durationType == YEAR_MONTH_DURATION) { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } else { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); } } else { if ( !_isPositive ) { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); } // madatory leading 'P' buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); if(!toSerialize->_year->isZero()) { buffer.append(toSerialize->_year->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_Y); } if(!toSerialize->_month->isZero()) { buffer.append(toSerialize->_month->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } // append the day and time information if this is not a yearMonthDuration if(durationType != YEAR_MONTH_DURATION) { if(!toSerialize->_day->isZero()) { buffer.append(toSerialize->_day->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_D); } // mandatory center 'T', if the time is not zero if(!(toSerialize->_hour->isZero() && toSerialize->_minute->isZero() && toSerialize->_sec->isZero())) { buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); if(!toSerialize->_hour->isZero()) { buffer.append(toSerialize->_hour->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_H); } if(!toSerialize->_minute->isZero()) { buffer.append(toSerialize->_minute->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); } if(!toSerialize->_sec->isZero()) { buffer.append(toSerialize->_sec->asString(context)); buffer.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); } } } } return context->getMemoryManager()->getPooledString(buffer.getRawBuffer()); } /* returns true if this duration is an instance of a xdt:dayTimeDuration */ bool ATDurationOrDerivedImpl::isDayTimeDuration() const { return durationType == DAY_TIME_DURATION; } /* returns true if this duration is an instance of a xdt:yearMonthDuration */ bool ATDurationOrDerivedImpl::isYearMonthDuration() const { return durationType == YEAR_MONTH_DURATION; } /* returns true if the two objects have the same boolean value * false otherwise */ bool ATDurationOrDerivedImpl::equals(const AnyAtomicType* target, const DynamicContext* context) const { if(this->getPrimitiveTypeIndex() != target->getPrimitiveTypeIndex()) { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::equals"), X("Equality operator for given types not supported")); } const ATDurationOrDerivedImpl* targetImpl = (const ATDurationOrDerivedImpl*)target; if( (durationType == DAY_TIME_DURATION && targetImpl->durationType == DAY_TIME_DURATION) || (durationType == YEAR_MONTH_DURATION && targetImpl->durationType == YEAR_MONTH_DURATION)) { // only allowed to compare dayTimeDurations and yearMonthDurations // const ATDurationOrDerivedImpl* thisDurationNorm = (const ATDurationOrDerivedImpl*)this->normalize(context); const ATDurationOrDerivedImpl* otherDurationNorm = (const ATDurationOrDerivedImpl*)((const ATDurationOrDerived*)target)->normalize(context); return (thisDurationNorm->_isPositive == otherDurationNorm->_isPositive && thisDurationNorm->_year->equals(otherDurationNorm->_year, context) && thisDurationNorm->_month->equals(otherDurationNorm->_month, context) && thisDurationNorm->_day->equals(otherDurationNorm->_day, context) && thisDurationNorm->_hour->equals(otherDurationNorm->_hour, context) && thisDurationNorm->_minute->equals(otherDurationNorm->_minute, context) && thisDurationNorm->_sec->equals(otherDurationNorm->_sec, context) ); } else { DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::equals"), X("Equality operator for given types not supported")); } } bool ATDurationOrDerivedImpl::lessThan(const ATDurationOrDerived* other, const DynamicContext* context) const { const ATDurationOrDerivedImpl* otherImpl = (const ATDurationOrDerivedImpl*)other; if(durationType == DAY_TIME_DURATION && otherImpl->durationType == DAY_TIME_DURATION ) { // if we are comparing xdt:dayTimeDurations // return dayTimeLessThan(other, context); } else if(durationType == YEAR_MONTH_DURATION && otherImpl->durationType == YEAR_MONTH_DURATION) { // if we are comparing xdt:yearMonthDuration's // return yearMonthLessThan(other, context); } else { // if we are trying to compare anything else -- error // DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::lessThan"), X("less-than operator for given types not supported")); } } bool ATDurationOrDerivedImpl::greaterThan(const ATDurationOrDerived* other, const DynamicContext* context) const { const ATDurationOrDerivedImpl* otherImpl = (const ATDurationOrDerivedImpl*)other; if(durationType == DAY_TIME_DURATION && otherImpl->durationType == DAY_TIME_DURATION) { // if we are comparing xdt:dayTimeDurations // return dayTimeGreaterThan(other, context); } else if(durationType == YEAR_MONTH_DURATION && otherImpl->durationType == YEAR_MONTH_DURATION) { // if we are comparing xdt:yearMonthDuration's // return yearMonthGreaterThan(other, context); } else { // if we are trying to compare anything else -- error // DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::greaterThan"), X("greater-than operator for given types not supported")); } } /** Compare two dayTimeDurations, return true if this < duration */ bool ATDurationOrDerivedImpl::dayTimeLessThan(const ATDurationOrDerived* dayTimeDuration, const DynamicContext* context) const { ATDurationOrDerivedImpl* durationImpl = (ATDurationOrDerivedImpl*)dayTimeDuration; if ( _isPositive != durationImpl->_isPositive) return !_isPositive; // if one is positive and the other is negative, then the lesser one is the negative one // now we know both 'this' and 'duration' have the same sign. // since the variables are always stored as non-negative integers, // if(this >= duration) { // return false if we are positive // return true if we are negative // } // ie if(this >= duration) return !_isPositive if(( _day->greaterThan(durationImpl->_day, context)) || ( _day->equals(durationImpl->_day, context) && _hour->greaterThan(durationImpl->_hour, context)) || ( _day->equals(durationImpl->_day, context) && _hour->equals(durationImpl->_hour, context) && _minute->greaterThan(durationImpl->_minute, context) ) || ( _day->equals(durationImpl->_day, context) && _hour->equals(durationImpl->_hour, context) && _minute->equals(durationImpl->_minute, context) && !(_sec->lessThan(durationImpl->_sec, context)) ) ) { return !_isPositive; } return _isPositive; } /** Compare two dayTimeDurations, return true if this > duration */ bool ATDurationOrDerivedImpl::dayTimeGreaterThan(const ATDurationOrDerived* dayTimeDuration, const DynamicContext* context) const { ATDurationOrDerivedImpl* durationImpl = (ATDurationOrDerivedImpl*)dayTimeDuration; if ( _isPositive != durationImpl->_isPositive) return _isPositive; // if one is positive and the other is negative, the greater one is the positive one // now we know both 'this' and 'duration' have the same sign. // since the variables are always stored as non-negative integers, // if(this <= duration) { // return false if we are positive // return true if we are negative // } // ie if(this <= duration) return !_isPositive if(( _day->lessThan(durationImpl->_day, context)) || ( _day->equals(durationImpl->_day, context) && _hour->lessThan(durationImpl->_hour, context)) || ( _day->equals(durationImpl->_day, context) && _hour->equals(durationImpl->_hour, context) && _minute->lessThan(durationImpl->_minute, context) ) || ( _day->equals(durationImpl->_day, context) && _hour->equals(durationImpl->_hour, context) && _minute->equals(durationImpl->_minute, context) && !(_sec->greaterThan(durationImpl->_sec, context)) ) ) return !_isPositive; return _isPositive; } /** Compare two yearMonthDurations, return true if this < duration */ bool ATDurationOrDerivedImpl::yearMonthLessThan(const ATDurationOrDerived* yearMonthDuration, const DynamicContext* context) const { const ATDurationOrDerivedImpl* thisDurationNorm = (const ATDurationOrDerivedImpl*)this->normalize(context); const ATDurationOrDerivedImpl* otherDurationNorm = (const ATDurationOrDerivedImpl*)yearMonthDuration->normalize(context); if ( _isPositive != otherDurationNorm->_isPositive) return !_isPositive; // if one is positive and the other is negative, then the lesser one is the negative one // now we know both 'this' and 'duration' have the same sign. if ( thisDurationNorm->getYears()->greaterThan(otherDurationNorm->getYears(), context) ) { return !_isPositive; } else if ( thisDurationNorm->getYears()->equals(otherDurationNorm->getYears(), context) && !(thisDurationNorm->getMonths()->lessThan(otherDurationNorm->getMonths(), context) ) ) { return !_isPositive; } return _isPositive; } /** Compare two yearMonthDurations, return true if this > duration */ bool ATDurationOrDerivedImpl::yearMonthGreaterThan(const ATDurationOrDerived* yearMonthDuration, const DynamicContext* context) const { const ATDurationOrDerivedImpl* thisDurationNorm = (const ATDurationOrDerivedImpl*)this->normalize(context); const ATDurationOrDerivedImpl* otherDurationNorm = (const ATDurationOrDerivedImpl*)yearMonthDuration->normalize(context); if ( _isPositive != otherDurationNorm->_isPositive) return _isPositive; // if one is positive and the other is negative, the greater one is the positive one // now we know both 'this' and 'duration' have the same sign. if ( thisDurationNorm->getYears()->lessThan(otherDurationNorm->getYears(), context) ) { return !_isPositive; } else if ( thisDurationNorm->getYears()->equals(otherDurationNorm->getYears(), context) && !(thisDurationNorm->getMonths()->greaterThan(otherDurationNorm->getMonths(), context) ) ) { return !_isPositive; } return _isPositive; } /** Divide this duration by a number -- only available for xdt:dayTimeDuration * and xdt:yearMonthDuration */ const ATDurationOrDerived* ATDurationOrDerivedImpl::divide(const ATDecimalOrDerived* divisor, const DynamicContext* context) const { if(durationType == DAY_TIME_DURATION) { // if we are dividing a xdt:dayTimeDurations // return dayTimeDivide(divisor, context); } else if(durationType == YEAR_MONTH_DURATION) { // if we are comparing xdt:yearMonthDuration's // return yearMonthDivide(divisor->asMAPM(), context); } else { // if we are trying to compare anything else -- error // DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::divide"), X("divide operator for given types not supported")); } } /* Divide a xdt:dayTimeDuration by a xs:decimal */ const ATDurationOrDerived* ATDurationOrDerivedImpl::dayTimeDivide(const ATDecimalOrDerived* divisor, const DynamicContext* context) const { const ATDecimalOrDerived* asSeconds = (const ATDecimalOrDerived*)this->asSeconds(context)->divide(divisor, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (asSeconds->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); asSeconds = (const ATDecimalOrDerived*)asSeconds->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(asSeconds->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } /* Divide a xdt:yearMonthDuration by an xs:decimal */ const ATDurationOrDerived* ATDurationOrDerivedImpl::yearMonthDivide(MAPM divisor, const DynamicContext* context) const { MAPM asMonths = ((_year->asMAPM() * 12 + _month->asMAPM()) / divisor + 0.5).floor(); if (this->isNegative()) { asMonths = asMonths.neg(); } XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (asMonths < MM_Zero) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); asMonths = asMonths.abs(); } const ATDecimalOrDerived* MM = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), asMonths, context); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(MM->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); return DatatypeFactory::STR2AT::createYearMonthDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } AnyAtomicType::AtomicObjectType ATDurationOrDerivedImpl::getPrimitiveTypeIndex() const { return this->getTypeIndex(); } /** Multiply this duration by a number -- only available for xdt:dayTimeDuration * and xdt:yearMonthDuration */ const ATDurationOrDerived* ATDurationOrDerivedImpl::multiply(const ATDecimalOrDerived* multiplier, const DynamicContext* context) const { if(durationType == DAY_TIME_DURATION) { // multiplying an xdt: const ATDecimalOrDerived* asSeconds = (const ATDecimalOrDerived*)this->asSeconds(context)->multiply(multiplier, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (asSeconds->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); asSeconds = (const ATDecimalOrDerived*)asSeconds->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(asSeconds->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else if(durationType == YEAR_MONTH_DURATION) { // multiplying an xdt:yearMonthDuration const ATDecimalOrDerived* i12 = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 12,context); const ATDecimalOrDerived* asMonths = (const ATDecimalOrDerived*)_year->multiply(i12, context)-> add(_month, context)->multiply(multiplier, context)->round(context); if (this->isNegative()) { asMonths = (const ATDecimalOrDerived*)asMonths->invert(context); } XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (asMonths->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); asMonths = (const ATDecimalOrDerived*)asMonths->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(asMonths->asString(2, context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); return DatatypeFactory::STR2AT::createYearMonthDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else { // if we are trying to compare anything else -- error // DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::multiply"), X("multiply operator for given types not supported")); } } /** Add a duration to this duration -- only available for xdt:dayTimeDuration * and xdt:yearMonthDuration */ const ATDurationOrDerived* ATDurationOrDerivedImpl::add(const ATDurationOrDerived* other, const DynamicContext* context) const { if(this->isDayTimeDuration() && other->isDayTimeDuration()) { const ATDurationOrDerivedImpl* otherImpl = (const ATDurationOrDerivedImpl*)other; const Numeric* thisSeconds = this->asSeconds(context); const Numeric* otherSeconds = otherImpl->asSeconds(context); const Numeric* sum = thisSeconds->add(otherSeconds, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (sum->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); sum = sum->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(sum->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else if(this->isYearMonthDuration() && other->isYearMonthDuration() ) { const ATDecimalOrDerived* i12 = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 12,context); const Numeric* thisMonths = _year->multiply(i12, context)->add(_month, context); if(this->isNegative()) { thisMonths = thisMonths->invert(context); } const Numeric* otherMonths = other->getYears()->multiply(i12, context)->add(other->getMonths(), context); if(other->isNegative()) { otherMonths = otherMonths->invert(context); } const Numeric* sum = thisMonths->add(otherMonths, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (sum->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); sum = sum->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(sum->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); return DatatypeFactory::STR2AT::createYearMonthDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else { DSLthrow(IllegalArgumentException, X("ATDurationOrDerivedImpl::add"), X("add operation not supported for given types")); } } /** Subtract a duration from this duration -- only available for xdt:dayTimeDuration * and xdt:yearMonthDuration */ const ATDurationOrDerived* ATDurationOrDerivedImpl::subtract(const ATDurationOrDerived* other, const DynamicContext* context) const { if(this->isDayTimeDuration() && other->isDayTimeDuration()) { const ATDurationOrDerivedImpl* otherImpl = (const ATDurationOrDerivedImpl*)other; const Numeric* thisSeconds = this->asSeconds(context); const Numeric* otherSeconds = otherImpl->asSeconds(context); const Numeric* diff = thisSeconds->subtract(otherSeconds, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (diff->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); diff = diff->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_T); buf.append(diff->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_S); return DatatypeFactory::STR2AT::createDayTimeDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else if(this->isYearMonthDuration() && other->isYearMonthDuration() ) { const ATDecimalOrDerived* i12 = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 12,context); const Numeric* thisMonths = _year->multiply(i12, context)->add(_month, context); if(this->isNegative()) { thisMonths = thisMonths->invert(context); } const Numeric* otherMonths = other->getYears()->multiply(i12, context)->add(other->getMonths(), context); if(other->isNegative()) { otherMonths = otherMonths->invert(context); } const Numeric* diff = thisMonths->subtract(otherMonths, context); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); if (diff->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); diff = diff->invert(context); } buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P); buf.append(diff->asString(context)); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chLatin_M); return DatatypeFactory::STR2AT::createYearMonthDuration(context->getMemoryManager(), buf.getRawBuffer(), context); } else { DSLthrow(IllegalArgumentException, X("ATDurationOrDerivedImpl::subtract"), X("subtract operation not supported for given types")); } } /** Releases the memory used by this Item */ void ATDurationOrDerivedImpl::release() const { //TODO needs to check for ownership before releasing! getMemoryManager()->deallocate((void*)this); } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getYears() const { return _year; } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getMonths() const { return _month; } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getDays() const { return _day; } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getHours() const { return _hour; } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getMinutes() const { return _minute; } const ATDecimalOrDerived* ATDurationOrDerivedImpl::getSeconds() const { return _sec; } bool ATDurationOrDerivedImpl::isNegative() const { return !_isPositive; } const ATDurationOrDerived* ATDurationOrDerivedImpl::normalize(const DynamicContext* context) const { if(durationType == DAY_TIME_DURATION) { // if we are comparing xdt:dayTimeDurations // return normalizeDayTimeDuration(context); } else if(durationType == YEAR_MONTH_DURATION) { // if we are comparing xdt:yearMonthDuration's // return normalizeYearMonthDuration(context); } else { // if we are trying to compare anything else -- error // DSLthrow(IllegalArgumentException,X("ATDurationOrDerivedImpl::normalize"), X("normalize for given type not supported")); } } const ATDurationOrDerived* ATDurationOrDerivedImpl::normalizeDayTimeDuration(const DynamicContext* context) const { const ATDecimalOrDerived* zero = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 0,context); // normalize MAPM asSeconds =_day->asMAPM() * DateUtils::g_secondsPerDay + _hour->asMAPM() * DateUtils::g_secondsPerHour + _minute->asMAPM() * DateUtils::g_secondsPerMinute + _sec->asMAPM().floor(); // take care of fractional seconds later MAPM day = (asSeconds / DateUtils::g_secondsPerDay).floor(); MAPM remainder = DateUtils::modulo(asSeconds, DateUtils::g_secondsPerDay); MAPM hour = (remainder / DateUtils::g_secondsPerHour).floor(); remainder = DateUtils::modulo(remainder, DateUtils::g_secondsPerHour); MAPM minute = (remainder / DateUtils::g_secondsPerMinute).floor(); remainder = DateUtils::modulo(remainder, DateUtils::g_secondsPerMinute); MAPM sec = remainder + _sec->asMAPM() - _sec->asMAPM().floor(); // add frac. secs return new (context->getMemoryManager()) ATDurationOrDerivedImpl(this->getTypeURI(), this->getTypeName(), zero, zero, DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), day, context), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), hour, context), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), minute, context), DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), sec, context), _isPositive, context->getMemoryManager(), context); } const ATDurationOrDerived* ATDurationOrDerivedImpl::normalizeYearMonthDuration(const DynamicContext* context) const { const ATDecimalOrDerived* zero = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 0,context); MAPM year = _year->asMAPM()+(_month->asMAPM() / 12).floor(); MAPM month = DateUtils::modulo(_month->asMAPM(),12); return new (context->getMemoryManager()) ATDurationOrDerivedImpl(this->getTypeURI(), this->getTypeName(), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), year, context), DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), month, context), zero, zero, zero, zero, _isPositive, context->getMemoryManager(), context); } /* return this duration in forms of seconds -- only for dayTimeDuration */ const ATDecimalOrDerived* ATDurationOrDerivedImpl::asSeconds(const DynamicContext* context) const { if(durationType != DAY_TIME_DURATION) { DSLthrow(IllegalArgumentException, X("ATDurationOrDerivedImpl::asSeconds"), X("asSeconds for given type not supported")); } MAPM asSeconds =_day->asMAPM() * DateUtils::g_secondsPerDay + _hour->asMAPM() * DateUtils::g_secondsPerHour + _minute->asMAPM() * DateUtils::g_secondsPerMinute + _sec->asMAPM(); if(this->isNegative()) asSeconds=asSeconds.neg(); return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), asSeconds, context); } void ATDurationOrDerivedImpl::setDuration(const XMLCh* const s, const DynamicContext* context) { unsigned int length = XERCES_CPP_NAMESPACE_QUALIFIER XMLString::stringLen(s); if(s == 0) { DSLthrow(XPath2TypeCastException,X("XSDurationImpl::setDuration"), X("Invalid representation of duration")); } // State variables etc. bool gotDot = false; bool gotDigit = false; bool stop = false; bool Texist = false; unsigned int pos = 0; long int tmpnum = 0; double decplace = 1; double tmpdec = 0; // defaulting values _isPositive = true; MAPM year = 0; MAPM month = 0; MAPM day = 0; MAPM hour = 0; MAPM minute = 0; MAPM sec = 0; int state = 0 ; // 0 = year / 1 = month / 2 = day / 3 = hour / 4 = minutes / 5 = sec XMLCh tmpChar; bool wrongformat = false; // check initial 'negative' sign and the P character if ( length > 1 && s[0] == L'-' && s[1] == L'P' ) { _isPositive = false; pos = 2; } else if ( length > 1 && s[0] == L'P' ) { _isPositive = true; pos = 1; } else { wrongformat = true; } while ( ! wrongformat && !stop && pos < length) { tmpChar = s[pos]; pos++; switch(tmpChar) { // a dot, only will occur when parsing the second case L'.': { if (! gotDot && gotDigit) { gotDot = true; sec = tmpnum; gotDigit = false; tmpnum = 0; break; } wrongformat = true; break; } case 0x0030: case 0x0031: case 0x0032: case 0x0033: case 0x0034: case 0x0035: case 0x0036: case 0x0037: case 0x0038: case 0x0039: { if ( gotDot ) { decplace *= 10; } tmpnum *= 10; tmpnum += static_cast(tmpChar - 0x0030); gotDigit = true; break; } case L'Y' : { if ( state == 0 && gotDigit && !gotDot ) { year = tmpnum; state = 1; tmpnum = 0; gotDigit = false; } else { wrongformat = true; } break; } case L'M' : { if ( gotDigit) { if ( state < 4 && Texist && !gotDot) { minute = tmpnum; state = 4; gotDigit = false; tmpnum = 0; break; } else if ( state < 2 && ! Texist && !gotDot) { month = tmpnum; state = 1; gotDigit = false; tmpnum = 0; break; } } wrongformat = true; break; } case L'D' : { if ( state < 2 && gotDigit && !gotDot) { day = tmpnum; state = 2; gotDigit = false; tmpnum = 0; } else { wrongformat = true; } break; } case L'T' : { if ( state < 3 && !gotDigit && !gotDot) { Texist = true; } else { wrongformat = true; } break; } case L'H' : { if ( state < 3 && gotDigit && Texist && !gotDot) { hour = tmpnum; state = 3; gotDigit = false; tmpnum = 0; } else { wrongformat = true; } break; } case L'S' : { if ( state < 5 && gotDigit && Texist) { tmpdec = tmpnum / decplace; sec += tmpdec; state = 5; gotDigit = false; tmpnum = 0; } else { wrongformat = true; } break; } default: wrongformat = true; } } // check duration format if ( wrongformat || (Texist && state < 3) || gotDigit) { DSLthrow(XPath2TypeCastException,X("ATDurationOrDerivedImpl::setDuration"), X("Invalid representation of duration")); } _year = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), year, context); _month = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), month, context); _day = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), day, context); _hour = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), hour, context); _minute = DatatypeFactory::POD2AT::createNonNegativeInteger(context->getMemoryManager(), minute, context); _sec = DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), sec, context); }