| /* | 
 |  * 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$ | 
 |  */ | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  Includes | 
 | // --------------------------------------------------------------------------- | 
 | #include <stdlib.h> | 
 | #include <assert.h> | 
 | #include <errno.h> | 
 |  | 
 | #include <xercesc/util/XMLDateTime.hpp> | 
 | #include <xercesc/util/XMLString.hpp> | 
 | #include <xercesc/util/XMLUni.hpp> | 
 | #include <xercesc/util/Janitor.hpp> | 
 | #include <xercesc/util/NumberFormatException.hpp> | 
 |  | 
 | XERCES_CPP_NAMESPACE_BEGIN | 
 |  | 
 | // | 
 | // constants used to process raw data (fBuffer) | 
 | // | 
 | // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}['Z'] | 
 | //                                [{+|-}hh:mm'] | 
 | // | 
 |  | 
 | static const XMLCh DURATION_STARTER     = chLatin_P;              // 'P' | 
 | static const XMLCh DURATION_Y           = chLatin_Y;              // 'Y' | 
 | static const XMLCh DURATION_M           = chLatin_M;              // 'M' | 
 | static const XMLCh DURATION_D           = chLatin_D;              // 'D' | 
 | static const XMLCh DURATION_H           = chLatin_H;              // 'H' | 
 | static const XMLCh DURATION_S           = chLatin_S;              // 'S' | 
 |  | 
 | static const XMLCh DATE_SEPARATOR       = chDash;                 // '-' | 
 | static const XMLCh TIME_SEPARATOR       = chColon;                // ':' | 
 | static const XMLCh TIMEZONE_SEPARATOR   = chColon;                // ':' | 
 | static const XMLCh DATETIME_SEPARATOR   = chLatin_T;              // 'T' | 
 | static const XMLCh MILISECOND_SEPARATOR = chPeriod;               // '.' | 
 |  | 
 | static const XMLCh UTC_STD_CHAR         = chLatin_Z;              // 'Z' | 
 | static const XMLCh UTC_POS_CHAR         = chPlus;                 // '+' | 
 | static const XMLCh UTC_NEG_CHAR         = chDash;                 // '-' | 
 |  | 
 | static const XMLCh UTC_SET[]            = {UTC_STD_CHAR           //"Z+-" | 
 |                                          , UTC_POS_CHAR | 
 |                                          , UTC_NEG_CHAR | 
 |                                          , chNull}; | 
 |  | 
 | static const int YMD_MIN_SIZE    = 10;   // CCYY-MM-DD | 
 | static const int YMONTH_MIN_SIZE = 7;    // CCYY_MM | 
 | static const int TIME_MIN_SIZE   = 8;    // hh:mm:ss | 
 | static const int TIMEZONE_SIZE   = 5;    // hh:mm | 
 | static const int DAY_SIZE        = 5;    // ---DD | 
 | //static const int MONTH_SIZE      = 6;    // --MM-- | 
 | static const int MONTHDAY_SIZE   = 7;    // --MM-DD | 
 | static const int NOT_FOUND       = -1; | 
 |  | 
 | //define constants to be used in assigning default values for | 
 | //all date/time excluding duration | 
 | static const int YEAR_DEFAULT  = 2000; | 
 | static const int MONTH_DEFAULT = 01; | 
 | static const int DAY_DEFAULT   = 15; | 
 |  | 
 | // order-relation on duration is a partial order. The dates below are used to | 
 | // for comparison of 2 durations, based on the fact that | 
 | // duration x and y is x<=y iff s+x<=s+y | 
 | // see 3.2.6 duration W3C schema datatype specs | 
 | // | 
 | // the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone} | 
 | static const int DATETIMES[][XMLDateTime::TOTAL_SIZE] = | 
 | { | 
 |     {1696, 9, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD}, | 
 | 	{1697, 2, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD}, | 
 | 	{1903, 3, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD}, | 
 | 	{1903, 7, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD} | 
 | }; | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  local methods | 
 | // --------------------------------------------------------------------------- | 
 | static inline int fQuotient(int a, int b) | 
 | { | 
 |     div_t div_result = div(a, b); | 
 |     return div_result.quot; | 
 | } | 
 |  | 
 | static inline int fQuotient(int temp, int low, int high) | 
 | { | 
 |     return fQuotient(temp - low, high - low); | 
 | } | 
 |  | 
 | static inline int mod(int a, int b, int quotient) | 
 | { | 
 | 	return (a - quotient*b) ; | 
 | } | 
 |  | 
 | static inline int modulo (int temp, int low, int high) | 
 | { | 
 |     //modulo(a - low, high - low) + low | 
 |     int a = temp - low; | 
 |     int b = high - low; | 
 |     return (mod (a, b, fQuotient(a, b)) + low) ; | 
 | } | 
 |  | 
 | static inline bool isLeapYear(int year) | 
 | { | 
 |     return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); | 
 | } | 
 |  | 
 | static int maxDayInMonthFor(int year, int month) | 
 | { | 
 |  | 
 |     if ( month == 4 || month == 6 || month == 9 || month == 11 ) | 
 |     { | 
 |         return 30; | 
 |     } | 
 |     else if ( month==2 ) | 
 |     { | 
 |         if ( isLeapYear(year) ) | 
 |             return 29; | 
 |         else | 
 |             return 28; | 
 |     } | 
 |     else | 
 |     { | 
 |         return 31; | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  static methods : for duration | 
 | // --------------------------------------------------------------------------- | 
 | /** | 
 |  * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration") | 
 |  * | 
 |  * 3.2.6.2 Order relation on duration | 
 |  * | 
 |  *     In general, the order-relation on duration is a partial order since there is no | 
 |  *  determinate relationship between certain durations such as one month (P1M) and 30 days (P30D). | 
 |  *  The order-relation of two duration values x and y is x < y iff s+x < s+y for each qualified | 
 |  *  dateTime s in the list below. | 
 |  * | 
 |  *     These values for s cause the greatest deviations in the addition of dateTimes and durations | 
 |  * | 
 |  **/ | 
 | int XMLDateTime::compare(const XMLDateTime* const pDate1 | 
 |                        , const XMLDateTime* const pDate2 | 
 |                        , bool  strict) | 
 | { | 
 |     //REVISIT: this is unoptimazed vs of comparing 2 durations | 
 |     //         Algorithm is described in 3.2.6.2 W3C Schema Datatype specs | 
 |     // | 
 |  | 
 |     int resultA, resultB = INDETERMINATE; | 
 |  | 
 |     //try and see if the objects are equal | 
 |     if ( (resultA = compareOrder(pDate1, pDate2)) == EQUAL) | 
 |         return EQUAL; | 
 |  | 
 |     //long comparison algorithm is required | 
 |     XMLDateTime tempA(XMLPlatformUtils::fgMemoryManager), *pTempA = &tempA; | 
 |     XMLDateTime tempB(XMLPlatformUtils::fgMemoryManager), *pTempB = &tempB; | 
 |  | 
 |     addDuration(pTempA, pDate1, 0); | 
 |     addDuration(pTempB, pDate2, 0); | 
 |     resultA = compareOrder(pTempA, pTempB); | 
 |     if ( resultA == INDETERMINATE ) | 
 |         return INDETERMINATE; | 
 |  | 
 |     addDuration(pTempA, pDate1, 1); | 
 |     addDuration(pTempB, pDate2, 1); | 
 |     resultB = compareOrder(pTempA, pTempB); | 
 |     resultA = compareResult(resultA, resultB, strict); | 
 |     if ( resultA == INDETERMINATE ) | 
 |         return INDETERMINATE; | 
 |  | 
 |     addDuration(pTempA, pDate1, 2); | 
 |     addDuration(pTempB, pDate2, 2); | 
 |     resultB = compareOrder(pTempA, pTempB); | 
 |     resultA = compareResult(resultA, resultB, strict); | 
 |     if ( resultA == INDETERMINATE ) | 
 |         return INDETERMINATE; | 
 |  | 
 |     addDuration(pTempA, pDate1, 3); | 
 |     addDuration(pTempB, pDate2, 3); | 
 |     resultB = compareOrder(pTempA, pTempB); | 
 |     resultA = compareResult(resultA, resultB, strict); | 
 |  | 
 |     return resultA; | 
 |  | 
 | } | 
 |  | 
 | // | 
 | // Form a new XMLDateTime with duration and baseDate array | 
 | // Note: C++        Java | 
 | //       fNewDate   duration | 
 | //       fDuration  date | 
 | // | 
 |  | 
 | void XMLDateTime::addDuration(XMLDateTime*             fNewDate | 
 |                             , const XMLDateTime* const fDuration | 
 |                             , int index) | 
 |  | 
 | { | 
 |  | 
 |     //REVISIT: some code could be shared between normalize() and this method, | 
 |     //         however is it worth moving it? The structures are different... | 
 |     // | 
 |  | 
 |     fNewDate->reset(); | 
 |     //add months (may be modified additionaly below) | 
 |     int temp = DATETIMES[index][Month] + fDuration->fValue[Month]; | 
 |     fNewDate->fValue[Month] = modulo(temp, 1, 13); | 
 |     int carry = fQuotient(temp, 1, 13); | 
 |     if (fNewDate->fValue[Month] <= 0) { | 
 |         fNewDate->fValue[Month]+= 12; | 
 |         carry--; | 
 |     } | 
 |  | 
 |     //add years (may be modified additionaly below) | 
 |     fNewDate->fValue[CentYear] = DATETIMES[index][CentYear] + fDuration->fValue[CentYear] + carry; | 
 |  | 
 |     //add seconds | 
 |     temp = DATETIMES[index][Second] + fDuration->fValue[Second]; | 
 |     carry = fQuotient (temp, 60); | 
 |     fNewDate->fValue[Second] =  mod(temp, 60, carry); | 
 |     if (fNewDate->fValue[Second] < 0) { | 
 |         fNewDate->fValue[Second]+= 60; | 
 |         carry--; | 
 |     } | 
 |      | 
 |     //add minutes | 
 |     temp = DATETIMES[index][Minute] + fDuration->fValue[Minute] + carry; | 
 |     carry = fQuotient(temp, 60); | 
 |     fNewDate->fValue[Minute] = mod(temp, 60, carry); | 
 |     if (fNewDate->fValue[Minute] < 0) { | 
 |         fNewDate->fValue[Minute]+= 60; | 
 |         carry--; | 
 |     } | 
 |  | 
 |     //add hours | 
 |     temp = DATETIMES[index][Hour] + fDuration->fValue[Hour] + carry; | 
 |     carry = fQuotient(temp, 24); | 
 |     fNewDate->fValue[Hour] = mod(temp, 24, carry); | 
 |     if (fNewDate->fValue[Hour] < 0) { | 
 |         fNewDate->fValue[Hour]+= 24; | 
 |         carry--; | 
 |     } | 
 |      | 
 |     fNewDate->fValue[Day] = DATETIMES[index][Day] + fDuration->fValue[Day] + carry; | 
 |  | 
 |     while ( true ) | 
 |     { | 
 |         temp = maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]); | 
 |         if ( fNewDate->fValue[Day] < 1 ) | 
 |         { //original fNewDate was negative | 
 |             fNewDate->fValue[Day] += maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]-1); | 
 |             carry = -1; | 
 |         } | 
 |         else if ( fNewDate->fValue[Day] > temp ) | 
 |         { | 
 |             fNewDate->fValue[Day] -= temp; | 
 |             carry = 1; | 
 |         } | 
 |         else | 
 |         { | 
 |             break; | 
 |         } | 
 |  | 
 |         temp = fNewDate->fValue[Month] + carry; | 
 |         fNewDate->fValue[Month] = modulo(temp, 1, 13); | 
 |         if (fNewDate->fValue[Month] <= 0) { | 
 |             fNewDate->fValue[Month]+= 12; | 
 |             fNewDate->fValue[CentYear]--; | 
 |         } | 
 |         fNewDate->fValue[CentYear] += fQuotient(temp, 1, 13); | 
 |     } | 
 |  | 
 |     //fNewDate->fValue[utc] = UTC_STD_CHAR; | 
 |     fNewDate->fValue[utc] = UTC_STD; | 
 | } | 
 |  | 
 | int XMLDateTime::compareResult(int resultA | 
 |                              , int resultB | 
 |                              , bool strict) | 
 | { | 
 |  | 
 |     if ( resultB == INDETERMINATE ) | 
 |     { | 
 |         return INDETERMINATE; | 
 |     } | 
 |     else if ( (resultA != resultB) && | 
 |               strict                ) | 
 |     { | 
 |         return INDETERMINATE; | 
 |     } | 
 |     else if ( (resultA != resultB) && | 
 |               !strict               ) | 
 |     { | 
 |         if ( (resultA != EQUAL) && | 
 |              (resultB != EQUAL)  ) | 
 |         { | 
 |             return INDETERMINATE; | 
 |         } | 
 |         else | 
 |         { | 
 |             return (resultA != EQUAL)? resultA : resultB; | 
 |         } | 
 |     } | 
 |  | 
 |     return resultA; | 
 | 	 | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  static methods : for others | 
 | // --------------------------------------------------------------------------- | 
 | int XMLDateTime::compare(const XMLDateTime* const pDate1 | 
 |                        , const XMLDateTime* const pDate2) | 
 | { | 
 |  | 
 |     if (pDate1->fValue[utc] == pDate2->fValue[utc]) | 
 |     { | 
 |         return XMLDateTime::compareOrder(pDate1, pDate2); | 
 |     } | 
 |  | 
 |     int c1, c2; | 
 |  | 
 |     if ( pDate1->isNormalized()) | 
 |     { | 
 |         c1 = compareResult(pDate1, pDate2, false, UTC_POS); | 
 |         c2 = compareResult(pDate1, pDate2, false, UTC_NEG); | 
 |         return getRetVal(c1, c2); | 
 |     } | 
 |     else if ( pDate2->isNormalized()) | 
 |     { | 
 |         c1 = compareResult(pDate1, pDate2, true, UTC_POS); | 
 |         c2 = compareResult(pDate1, pDate2, true, UTC_NEG); | 
 |         return getRetVal(c1, c2); | 
 |     } | 
 |  | 
 |     return INDETERMINATE;	 | 
 | } | 
 |  | 
 | int XMLDateTime::compareResult(const XMLDateTime* const pDate1 | 
 |                              , const XMLDateTime* const pDate2 | 
 |                              , bool  set2Left | 
 |                              , int   utc_type) | 
 | { | 
 |     XMLDateTime tmpDate = (set2Left ? *pDate1 : *pDate2); | 
 |  | 
 |     tmpDate.fTimeZone[hh] = 14; | 
 |     tmpDate.fTimeZone[mm] = 0; | 
 |     tmpDate.fValue[utc] = utc_type; | 
 |     tmpDate.normalize(); | 
 |  | 
 |     return (set2Left? XMLDateTime::compareOrder(&tmpDate, pDate2) : | 
 |                       XMLDateTime::compareOrder(pDate1, &tmpDate)); | 
 | } | 
 |  | 
 | int XMLDateTime::compareOrder(const XMLDateTime* const lValue | 
 |                             , const XMLDateTime* const rValue) | 
 |                             //, MemoryManager* const memMgr) | 
 | { | 
 |     // | 
 |     // If any of the them is not normalized() yet, | 
 |     // we need to do something here. | 
 |     // | 
 |     XMLDateTime lTemp = *lValue; | 
 |     XMLDateTime rTemp = *rValue; | 
 |  | 
 |     lTemp.normalize(); | 
 |     rTemp.normalize(); | 
 |  | 
 |     for ( int i = 0 ; i < TOTAL_SIZE; i++ ) | 
 |     { | 
 |         if ( lTemp.fValue[i] < rTemp.fValue[i] ) | 
 |         { | 
 |             return LESS_THAN; | 
 |         } | 
 |         else if ( lTemp.fValue[i] > rTemp.fValue[i] ) | 
 |         { | 
 |             return GREATER_THAN; | 
 |         } | 
 |     } | 
 |  | 
 |     if ( lTemp.fHasTime) | 
 |     { | 
 |         if ( lTemp.fMiliSecond < rTemp.fMiliSecond ) | 
 |         { | 
 |             return LESS_THAN; | 
 |         } | 
 |         else if ( lTemp.fMiliSecond > rTemp.fMiliSecond ) | 
 |         { | 
 |             return GREATER_THAN; | 
 |         } | 
 |     } | 
 |  | 
 |     return EQUAL; | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  ctor and dtor | 
 | // --------------------------------------------------------------------------- | 
 | XMLDateTime::~XMLDateTime() | 
 | {     | 
 |     if (fBuffer) | 
 |         fMemoryManager->deallocate(fBuffer);//delete[] fBuffer;   | 
 | } | 
 |  | 
 | XMLDateTime::XMLDateTime(MemoryManager* const manager) | 
 | : fStart(0) | 
 | , fEnd(0) | 
 | , fBufferMaxLen(0) | 
 | , fMiliSecond(0) | 
 | , fHasTime(false) | 
 | , fBuffer(0) | 
 | , fMemoryManager(manager) | 
 | { | 
 |     reset(); | 
 | } | 
 |  | 
 | XMLDateTime::XMLDateTime(const XMLCh* const aString, | 
 |                          MemoryManager* const manager) | 
 | : fStart(0) | 
 | , fEnd(0) | 
 | , fBufferMaxLen(0) | 
 | , fMiliSecond(0) | 
 | , fHasTime(false) | 
 | , fBuffer(0) | 
 | , fMemoryManager(manager) | 
 | { | 
 |     setBuffer(aString); | 
 | } | 
 |  | 
 | // ----------------------------------------------------------------------- | 
 | // Copy ctor and Assignment operators | 
 | // ----------------------------------------------------------------------- | 
 |  | 
 | XMLDateTime::XMLDateTime(const XMLDateTime &toCopy) | 
 | : XMLNumber(toCopy) | 
 | , fBufferMaxLen(0) | 
 | , fBuffer(0) | 
 | , fMemoryManager(toCopy.fMemoryManager) | 
 | { | 
 |     copy(toCopy); | 
 | } | 
 |  | 
 | XMLDateTime& XMLDateTime::operator=(const XMLDateTime& rhs) | 
 | { | 
 |     if (this == &rhs) | 
 |         return *this; | 
 |  | 
 |     copy(rhs); | 
 |     return *this; | 
 | } | 
 |  | 
 | // ----------------------------------------------------------------------- | 
 | // Implementation of Abstract Interface | 
 | // ----------------------------------------------------------------------- | 
 |  | 
 | // | 
 | // We may simply return the handle to fBuffer, but | 
 | // for the sake of consistency, we return a duplicated copy | 
 | // and the caller is responsible for the release of the buffer | 
 | // just like any other things in the XMLNumber family. | 
 | // | 
 | XMLCh*  XMLDateTime::toString() const | 
 | { | 
 |     assertBuffer(); | 
 |  | 
 |     // Return data using global operator new | 
 |     XMLCh* retBuf = XMLString::replicate(fBuffer); | 
 |     return retBuf; | 
 | } | 
 |  | 
 | // | 
 | // We may simply return the handle to fBuffer | 
 | // | 
 | XMLCh*  XMLDateTime::getRawData() const | 
 | { | 
 |     assertBuffer();     | 
 |     return fBuffer; | 
 | } | 
 |  | 
 |  | 
 | const XMLCh*  XMLDateTime::getFormattedString() const | 
 | { | 
 |     return getRawData(); | 
 | } | 
 |  | 
 | int XMLDateTime::getSign() const | 
 | { | 
 |     return 0; | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  Parsers | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | // | 
 | // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}[TimeZone] | 
 | // | 
 | void XMLDateTime::parseDateTime() | 
 | { | 
 |     initParser(); | 
 |     getDate(); | 
 |  | 
 |     //fStart is supposed to point to 'T' | 
 |     if (fBuffer[fStart++] != DATETIME_SEPARATOR) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dt_missingT | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |  | 
 |     getTime(); | 
 |     validateDateTime(); | 
 |     normalize(); | 
 |     fHasTime = true; | 
 | } | 
 |  | 
 | // | 
 | // [-]{CCYY-MM-DD}[TimeZone] | 
 | // | 
 | void XMLDateTime::parseDate() | 
 | { | 
 |     initParser(); | 
 |     getDate(); | 
 |     parseTimeZone(); | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | void XMLDateTime::parseTime() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     // time initialize to default values | 
 |     fValue[CentYear]= YEAR_DEFAULT; | 
 |     fValue[Month]   = MONTH_DEFAULT; | 
 |     fValue[Day]     = DAY_DEFAULT; | 
 |  | 
 |     getTime(); | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 |     fHasTime = true; | 
 | } | 
 |  | 
 | // | 
 | // {---DD}[TimeZone] | 
 | //  01234 | 
 | // | 
 | void XMLDateTime::parseDay() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     if (fBuffer[0] != DATE_SEPARATOR || | 
 |         fBuffer[1] != DATE_SEPARATOR || | 
 |         fBuffer[2] != DATE_SEPARATOR  ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_gDay_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     //initialize values | 
 |     fValue[CentYear] = YEAR_DEFAULT; | 
 |     fValue[Month]    = MONTH_DEFAULT; | 
 |     fValue[Day]      = parseInt(fStart+3, fStart+5); | 
 |  | 
 |     if ( DAY_SIZE < fEnd ) | 
 |     {         | 
 |         int pos = XMLString::indexOf(UTC_SET, fBuffer[DAY_SIZE]); | 
 |         if (pos == -1 ) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_gDay_invalid | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |         } | 
 |         else | 
 |         { | 
 |             fValue[utc] = pos+1; | 
 |             getTimeZone(DAY_SIZE); | 
 |         } | 
 |     } | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | // | 
 | // {--MM--}[TimeZone] | 
 | // {--MM}[TimeZone] | 
 | //  012345 | 
 | // | 
 | void XMLDateTime::parseMonth() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     if (fBuffer[0] != DATE_SEPARATOR || | 
 |         fBuffer[1] != DATE_SEPARATOR  ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_gMth_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     //set constants | 
 |     fValue[CentYear] = YEAR_DEFAULT; | 
 |     fValue[Day]      = DAY_DEFAULT; | 
 |     fValue[Month]    = parseInt(2, 4); | 
 |  | 
 |     // REVISIT: allow both --MM and --MM-- now.  | 
 |     // need to remove the following lines to disallow --MM--  | 
 |     // when the errata is officially in the rec.  | 
 |     fStart = 4; | 
 |     if ( fEnd >= fStart+2 && fBuffer[fStart] == DATE_SEPARATOR && fBuffer[fStart+1] == DATE_SEPARATOR )  | 
 |     {  | 
 |         fStart += 2;  | 
 |     }  | 
 |  | 
 |     // | 
 |     // parse TimeZone if any | 
 |     // | 
 |     if ( fStart < fEnd ) | 
 |     {       | 
 |         int pos = XMLString::indexOf(UTC_SET, fBuffer[fStart]); | 
 |         if ( pos == NOT_FOUND ) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_gMth_invalid | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |         } | 
 |         else | 
 |         { | 
 |             fValue[utc] = pos+1; | 
 |             getTimeZone(fStart); | 
 |         } | 
 |     } | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | // | 
 | //[-]{CCYY}[TimeZone] | 
 | // 0  1234 | 
 | // | 
 | void XMLDateTime::parseYear() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     // skip the first '-' and search for timezone | 
 |     // | 
 |     int sign = findUTCSign((fBuffer[0] == chDash) ? 1 : 0); | 
 |  | 
 |     if (sign == NOT_FOUND) | 
 |     { | 
 |         fValue[CentYear] = parseIntYear(fEnd); | 
 |     } | 
 |     else | 
 |     { | 
 |         fValue[CentYear] = parseIntYear(sign); | 
 |         getTimeZone(sign); | 
 |     } | 
 |  | 
 |     //initialize values | 
 |     fValue[Month] = MONTH_DEFAULT; | 
 |     fValue[Day]   = DAY_DEFAULT;   //java is 1 | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | // | 
 | //{--MM-DD}[TimeZone] | 
 | // 0123456 | 
 | // | 
 | void XMLDateTime::parseMonthDay() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     if (fBuffer[0] != DATE_SEPARATOR || | 
 |         fBuffer[1] != DATE_SEPARATOR || | 
 |         fBuffer[4] != DATE_SEPARATOR ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_gMthDay_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |  | 
 |     //initialize | 
 |     fValue[CentYear] = YEAR_DEFAULT; | 
 |     fValue[Month]    = parseInt(2, 4);	 | 
 |     fValue[Day]      = parseInt(5, 7); | 
 |  | 
 |     if ( MONTHDAY_SIZE < fEnd ) | 
 |     {         | 
 |         int pos = XMLString::indexOf(UTC_SET, fBuffer[MONTHDAY_SIZE]); | 
 |         if ( pos == NOT_FOUND ) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_gMthDay_invalid | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |         } | 
 |         else | 
 |         { | 
 |             fValue[utc] = pos+1; | 
 |             getTimeZone(MONTHDAY_SIZE); | 
 |         } | 
 |     } | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | void XMLDateTime::parseYearMonth() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     // get date | 
 |     getYearMonth(); | 
 |     fValue[Day] = DAY_DEFAULT; | 
 |     parseTimeZone(); | 
 |  | 
 |     validateDateTime(); | 
 |     normalize(); | 
 | } | 
 |  | 
 | // | 
 | //PnYn MnDTnH nMnS: -P1Y2M3DT10H30M | 
 | // | 
 | // [-]{'P'{[n'Y'][n'M'][n'D']['T'][n'H'][n'M'][n'S']}} | 
 | // | 
 | //  Note: the n above shall be >= 0 | 
 | //        if no time element found, 'T' shall be absent | 
 | // | 
 | void XMLDateTime::parseDuration() | 
 | { | 
 |     initParser(); | 
 |  | 
 |     // must start with '-' or 'P' | 
 |     // | 
 |     XMLCh c = fBuffer[fStart++]; | 
 |     if ( (c != DURATION_STARTER) && | 
 |          (c != chDash)            ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dur_Start_dashP | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     // 'P' must ALWAYS be present in either case | 
 |     if ( (c == chDash) && | 
 |          (fBuffer[fStart++]!= DURATION_STARTER )) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dur_noP | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     // java code | 
 |     //date[utc]=(c=='-')?'-':0; | 
 |     //fValue[utc] = UTC_STD; | 
 |     fValue[utc] = (fBuffer[0] == chDash? UTC_NEG : UTC_STD); | 
 |  | 
 |     int negate = ( fBuffer[0] == chDash ? -1 : 1); | 
 |  | 
 |     // | 
 |     // No negative value is allowed after 'P' | 
 |     // | 
 |     // eg P-1234, invalid | 
 |     // | 
 |     if (indexOf(fStart, fEnd, chDash) != NOT_FOUND) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dur_DashNotFirst | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     //at least one number and designator must be seen after P | 
 |     bool designator = false; | 
 |  | 
 |     int endDate = indexOf(fStart, fEnd, DATETIME_SEPARATOR); | 
 |     if ( endDate == NOT_FOUND ) | 
 |     { | 
 |         endDate = fEnd;  // 'T' absent | 
 |     } | 
 |  | 
 |     //find 'Y' | 
 |     int end = indexOf(fStart, endDate, DURATION_Y); | 
 |     if ( end != NOT_FOUND ) | 
 |     { | 
 |         //scan year | 
 |         fValue[CentYear] = negate * parseInt(fStart, end); | 
 |         fStart = end+1; | 
 |         designator = true; | 
 |     } | 
 |  | 
 |     end = indexOf(fStart, endDate, DURATION_M); | 
 |     if ( end != NOT_FOUND ) | 
 |     { | 
 |         //scan month | 
 |         fValue[Month] = negate * parseInt(fStart, end); | 
 |         fStart = end+1; | 
 |         designator = true; | 
 |     } | 
 |  | 
 |     end = indexOf(fStart, endDate, DURATION_D); | 
 |     if ( end != NOT_FOUND ) | 
 |     { | 
 |         //scan day | 
 |         fValue[Day] = negate * parseInt(fStart,end); | 
 |         fStart = end+1; | 
 |         designator = true; | 
 |     } | 
 |  | 
 |     if ( (fEnd == endDate) &&   // 'T' absent | 
 |          (fStart != fEnd)   )   // something after Day | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dur_inv_b4T | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     if ( fEnd != endDate ) // 'T' present | 
 |     { | 
 |         //scan hours, minutes, seconds | 
 |         // | 
 |  | 
 |         // skip 'T' first | 
 |         end = indexOf(++fStart, fEnd, DURATION_H); | 
 |         if ( end != NOT_FOUND ) | 
 |         { | 
 |             //scan hours | 
 |             fValue[Hour] = negate * parseInt(fStart, end); | 
 |             fStart = end+1; | 
 |             designator = true; | 
 |         } | 
 |  | 
 |         end = indexOf(fStart, fEnd, DURATION_M); | 
 |         if ( end != NOT_FOUND ) | 
 |         { | 
 |             //scan min | 
 |             fValue[Minute] = negate * parseInt(fStart, end); | 
 |             fStart = end+1; | 
 |             designator = true; | 
 |         } | 
 |  | 
 |         end = indexOf(fStart, fEnd, DURATION_S); | 
 |         if ( end != NOT_FOUND ) | 
 |         { | 
 |             //scan seconds | 
 |             int mlsec = indexOf (fStart, end, MILISECOND_SEPARATOR); | 
 |  | 
 |             /*** | 
 |              * Schema Errata: E2-23 | 
 |              * at least one digit must follow the decimal point if it appears.  | 
 |              * That is, the value of the seconds component must conform  | 
 |              * to the following pattern: [0-9]+(.[0-9]+)?  | 
 |              */ | 
 |             if ( mlsec != NOT_FOUND ) | 
 |             { | 
 |                 /*** | 
 |                  * make usure there is something after the '.' and before the end. | 
 |                  */ | 
 |                 if ( mlsec+1 == end ) | 
 |                 { | 
 |                     ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                             , XMLExcepts::DateTime_dur_inv_seconds | 
 |                             , fBuffer | 
 |                             , fMemoryManager); | 
 |                 } | 
 |  | 
 |                 fValue[Second]     = negate * parseInt(fStart, mlsec); | 
 |                 fMiliSecond        = negate * parseMiliSecond(mlsec+1, end); | 
 |             } | 
 |             else | 
 |             { | 
 |                 fValue[Second] = negate * parseInt(fStart,end); | 
 |             } | 
 |  | 
 |             fStart = end+1; | 
 |             designator = true; | 
 |         } | 
 |  | 
 |         // no additional data should appear after last item | 
 |         // P1Y1M1DT is illigal value as well | 
 |         if ( (fStart != fEnd) || | 
 |               fBuffer[--fStart] == DATETIME_SEPARATOR ) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_dur_NoTimeAfterT | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |         } | 
 |     } | 
 |  | 
 |     if ( !designator ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_dur_NoElementAtAll | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  Scanners | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | // | 
 | // [-]{CCYY-MM-DD} | 
 | // | 
 | // Note: CCYY could be more than 4 digits | 
 | //       Assuming fStart point to the beginning of the Date Section | 
 | //       fStart updated to point to the position right AFTER the second 'D' | 
 | //       Since the lenght of CCYY might be variable, we can't check format upfront | 
 | // | 
 | void XMLDateTime::getDate() | 
 | { | 
 |  | 
 |     // Ensure enough chars in buffer | 
 |     if ( (fStart+YMD_MIN_SIZE) > fEnd) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_date_incomplete | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |  | 
 |     getYearMonth();    // Scan YearMonth and | 
 |                        // fStart point to the next '-' | 
 |  | 
 |     if (fBuffer[fStart++] != DATE_SEPARATOR) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_date_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("CCYY-MM must be followed by '-' sign"); | 
 |     } | 
 |  | 
 |     fValue[Day] = parseInt(fStart, fStart+2); | 
 |     fStart += 2 ;  //fStart points right after the Day | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | // | 
 | // hh:mm:ss[.msssss]['Z'] | 
 | // hh:mm:ss[.msssss][['+'|'-']hh:mm] | 
 | // 012345678 | 
 | // | 
 | // Note: Assuming fStart point to the beginning of the Time Section | 
 | //       fStart updated to point to the position right AFTER the second 's' | 
 | //                                                  or ms if any | 
 | // | 
 | void XMLDateTime::getTime() | 
 | { | 
 |  | 
 |     // Ensure enough chars in buffer | 
 |     if ( (fStart+TIME_MIN_SIZE) > fEnd) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_time_incomplete | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Imcomplete Time Format" | 
 |  | 
 |     // check (fixed) format first | 
 |     if ((fBuffer[fStart + 2] != TIME_SEPARATOR) || | 
 |         (fBuffer[fStart + 5] != TIME_SEPARATOR)  ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_time_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("Error in parsing time" ); | 
 |     } | 
 |  | 
 |     // | 
 |     // get hours, minute and second | 
 |     // | 
 |     fValue[Hour]   = parseInt(fStart + 0, fStart + 2); | 
 |     fValue[Minute] = parseInt(fStart + 3, fStart + 5); | 
 |     fValue[Second] = parseInt(fStart + 6, fStart + 8); | 
 |     fStart += 8; | 
 |  | 
 |     // to see if any ms and/or utc part after that | 
 |     if (fStart >= fEnd) | 
 |         return; | 
 |  | 
 |     //find UTC sign if any | 
 |     int sign = findUTCSign(fStart); | 
 |  | 
 |     //parse miliseconds | 
 |     int milisec = (fBuffer[fStart] == MILISECOND_SEPARATOR)? fStart : NOT_FOUND; | 
 |     if ( milisec != NOT_FOUND ) | 
 |     { | 
 |         fStart++;   // skip the '.' | 
 |         // make sure we have some thing between the '.' and fEnd | 
 |         if (fStart >= fEnd) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_ms_noDigit | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |             //("ms shall be present once '.' is present" ); | 
 |         } | 
 |  | 
 |         if ( sign == NOT_FOUND ) | 
 |         { | 
 |             fMiliSecond = parseMiliSecond(fStart, fEnd);  //get ms between '.' and fEnd | 
 |             fStart = fEnd; | 
 |         } | 
 |         else | 
 |         { | 
 |             fMiliSecond = parseMiliSecond(fStart, sign);  //get ms between UTC sign and fEnd | 
 |         } | 
 | 	} | 
 |     else if(sign == 0 || sign != fStart) | 
 |     { | 
 |         // seconds has more than 2 digits | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_min_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |     } | 
 |  | 
 |     //parse UTC time zone (hh:mm) | 
 |     if ( sign > 0 ) { | 
 |         getTimeZone(sign); | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | // | 
 | // [-]{CCYY-MM} | 
 | // | 
 | // Note: CCYY could be more than 4 digits | 
 | //       fStart updated to point AFTER the second 'M' (probably meet the fEnd) | 
 | // | 
 | void XMLDateTime::getYearMonth() | 
 | { | 
 |  | 
 |     // Ensure enough chars in buffer | 
 |     if ( (fStart+YMONTH_MIN_SIZE) > fEnd) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_ym_incomplete | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Imcomplete YearMonth Format"; | 
 |  | 
 |     // skip the first leading '-' | 
 |     int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart; | 
 |  | 
 |     // | 
 |     // search for year separator '-' | 
 |     // | 
 |     int yearSeparator = indexOf(start, fEnd, DATE_SEPARATOR); | 
 |     if ( yearSeparator == NOT_FOUND) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_ym_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("Year separator is missing or misplaced"); | 
 |  | 
 |     fValue[CentYear] = parseIntYear(yearSeparator); | 
 |     fStart = yearSeparator + 1;  //skip the '-' and point to the first M | 
 |  | 
 |     // | 
 |     //gonna check we have enough byte for month | 
 |     // | 
 |     if ((fStart + 2) > fEnd ) | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_ym_noMonth | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"no month in buffer" | 
 |  | 
 |     fValue[Month] = parseInt(fStart, yearSeparator + 3); | 
 |     fStart += 2;  //fStart points right after the MONTH | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | void XMLDateTime::parseTimeZone() | 
 | { | 
 |     //fStart points right after the date   	  | 
 |   	if ( fStart < fEnd ) { | 
 |         int pos = XMLString::indexOf(UTC_SET, fBuffer[fStart]); | 
 |     	if (pos == NOT_FOUND) { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_tz_noUTCsign | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |    		} | 
 |    		else {  | 
 |             fValue[utc] = pos+1; | 
 |   	        getTimeZone(fStart);   		 | 
 |    		} | 
 |     } | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | // | 
 | // 'Z' | 
 | // ['+'|'-']hh:mm | 
 | // | 
 | // Note: Assuming fStart points to the beginning of TimeZone section | 
 | //       fStart updated to meet fEnd | 
 | // | 
 | void XMLDateTime::getTimeZone(const int sign) | 
 | { | 
 |  | 
 |     if ( fBuffer[sign] == UTC_STD_CHAR ) | 
 |     { | 
 |         if ((sign + 1) != fEnd ) | 
 |         { | 
 |             ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                     , XMLExcepts::DateTime_tz_stuffAfterZ | 
 |                     , fBuffer | 
 |                     , fMemoryManager); | 
 |             //"Error in parsing time zone"); | 
 |         }		 | 
 |  | 
 |         return;	 | 
 |     } | 
 |  | 
 |     // | 
 |     // otherwise, it has to be this format | 
 |     // '[+|-]'hh:mm | 
 |     //    1   23456 7 | 
 |     //   sign      fEnd | 
 |     // | 
 |     if ( ( ( sign + TIMEZONE_SIZE + 1) != fEnd )      || | 
 |          ( fBuffer[sign + 3] != TIMEZONE_SEPARATOR ) ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_tz_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("Error in parsing time zone"); | 
 |     } | 
 |  | 
 |     fTimeZone[hh] = parseInt(sign+1, sign+3);		 | 
 |     fTimeZone[mm] = parseInt(sign+4, fEnd); | 
 |         		 | 
 |     return; | 
 | } | 
 |  | 
 | // --------------------------------------------------------------------------- | 
 | //  Validator and normalizer | 
 | // --------------------------------------------------------------------------- | 
 |  | 
 | /** | 
 |  * If timezone present - normalize dateTime  [E Adding durations to dateTimes] | 
 |  * | 
 |  * @param date   CCYY-MM-DDThh:mm:ss+03 | 
 |  * @return CCYY-MM-DDThh:mm:ssZ | 
 |  */ | 
 | void XMLDateTime::normalize() | 
 | { | 
 |  | 
 |     if ((fValue[utc] == UTC_UNKNOWN) || | 
 |         (fValue[utc] == UTC_STD)      ) | 
 |         return; | 
 |  | 
 |     int negate = (fValue[utc] == UTC_POS)? -1: 1; | 
 |     int temp; | 
 |     int carry; | 
 |      | 
 |  | 
 |     // we normalize a duration so could have 200M... | 
 |     //update months (may be modified additionaly below) | 
 |     temp = fValue[Month]; | 
 |     fValue[Month] = modulo(temp, 1, 13); | 
 |     carry = fQuotient(temp, 1, 13); | 
 |     if (fValue[Month] <= 0) { | 
 |         fValue[Month]+= 12; | 
 |         carry--; | 
 |     } | 
 |  | 
 |     //add years (may be modified additionaly below) | 
 |     fValue[CentYear] += carry; | 
 |  | 
 |     // add mins | 
 |     temp = fValue[Minute] + negate * fTimeZone[mm]; | 
 |     carry = fQuotient(temp, 60); | 
 |     fValue[Minute] = mod(temp, 60, carry); | 
 |     if (fValue[Minute] < 0) { | 
 |         fValue[Minute] += 60; | 
 |         carry--; | 
 |     } | 
 |     | 
 |     //add hours | 
 |     temp = fValue[Hour] + negate * fTimeZone[hh] + carry; | 
 |     carry = fQuotient(temp, 24); | 
 |     fValue[Hour] = mod(temp, 24, carry); | 
 |     if (fValue[Hour] < 0) { | 
 |         fValue[Hour] += 24; | 
 |         carry--; | 
 |     } | 
 |  | 
 |     fValue[Day] += carry;    | 
 |  | 
 |     while (1) | 
 |     { | 
 |         temp = maxDayInMonthFor(fValue[CentYear], fValue[Month]); | 
 |         if (fValue[Day] < 1) | 
 |         { | 
 |             fValue[Day] += maxDayInMonthFor(fValue[CentYear], fValue[Month] - 1); | 
 |             carry = -1; | 
 |         } | 
 |         else if ( fValue[Day] > temp ) | 
 |         { | 
 |             fValue[Day] -= temp; | 
 |             carry = 1; | 
 |         } | 
 |         else | 
 |         { | 
 |             break; | 
 |         } | 
 |  | 
 |         temp = fValue[Month] + carry; | 
 |         fValue[Month] = modulo(temp, 1, 13); | 
 |         if (fValue[Month] <=0) { | 
 |             fValue[Month]+= 12; | 
 |             fValue[CentYear]--; | 
 |         } | 
 |         fValue[CentYear] += fQuotient(temp, 1, 13); | 
 |     } | 
 |  | 
 |     // set to normalized | 
 |     fValue[utc] = UTC_STD; | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | void XMLDateTime::validateDateTime() const | 
 | { | 
 |  | 
 |     //REVISIT: should we throw an exception for not valid dates | 
 |     //          or reporting an error message should be sufficient? | 
 |     if ( fValue[CentYear] == 0 ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_year_zero | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"The year \"0000\" is an illegal year value"); | 
 |     } | 
 |  | 
 |     if ( fValue[Month] < 1  || | 
 |          fValue[Month] > 12  ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_mth_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 | 		//"The month must have values 1 to 12"); | 
 |     } | 
 |  | 
 |     //validate days | 
 |     if ( fValue[Day] > maxDayInMonthFor( fValue[CentYear], fValue[Month]) || | 
 |          fValue[Day] == 0 ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_day_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"The day must have values 1 to 31"); | 
 |     } | 
 |  | 
 |     //validate hours | 
 |     if ((fValue[Hour] < 0)  || | 
 |         (fValue[Hour] > 24) || | 
 |         ((fValue[Hour] == 24) && ((fValue[Minute] !=0) || | 
 |                                   (fValue[Second] !=0) || | 
 |                                   (fMiliSecond    !=0)))) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_hour_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("Hour must have values 0-23"); | 
 |     } | 
 |  | 
 |     //validate minutes | 
 |     if ( fValue[Minute] < 0 || | 
 |          fValue[Minute] > 59 ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_min_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Minute must have values 0-59"); | 
 |     } | 
 |  | 
 |     //validate seconds | 
 |     if ( fValue[Second] < 0 || | 
 |          fValue[Second] > 60 ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_second_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Second must have values 0-60"); | 
 |     } | 
 |  | 
 |     //validate time-zone hours | 
 |     if ( (abs(fTimeZone[hh]) > 14) || | 
 |          ((abs(fTimeZone[hh]) == 14) && (fTimeZone[mm] != 0)) ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_tz_hh_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Time zone should have range -14..+14"); | 
 |     } | 
 |  | 
 |     //validate time-zone minutes | 
 |     if ( abs(fTimeZone[mm]) > 59 ) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_min_invalid | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //("Minute must have values 0-59"); | 
 |     } | 
 | 	 | 
 |     return; | 
 | } | 
 |  | 
 | // ----------------------------------------------------------------------- | 
 | // locator and converter | 
 | // ----------------------------------------------------------------------- | 
 | int XMLDateTime::indexOf(const int start, const int end, const XMLCh ch) const | 
 | { | 
 |     for ( int i = start; i < end; i++ ) | 
 |         if ( fBuffer[i] == ch ) | 
 |             return i; | 
 |  | 
 |     return NOT_FOUND; | 
 | } | 
 |  | 
 | int XMLDateTime::findUTCSign (const int start) | 
 | { | 
 |     int  pos; | 
 |     for ( int index = start; index < fEnd; index++ ) | 
 |     { | 
 |         pos = XMLString::indexOf(UTC_SET, fBuffer[index]); | 
 |         if ( pos != NOT_FOUND) | 
 |         { | 
 |             fValue[utc] = pos+1;   // refer to utcType, there is 1 diff | 
 |             return index; | 
 |         } | 
 |     } | 
 |  | 
 |     return NOT_FOUND; | 
 | } | 
 |  | 
 | // | 
 | // Note: | 
 | //    start: starting point in fBuffer | 
 | //    end:   ending point in fBuffer (exclusive) | 
 | //    fStart NOT updated | 
 | // | 
 | int XMLDateTime::parseInt(const int start, const int end) const | 
 | { | 
 |     unsigned int retVal = 0; | 
 |     for (int i=start; i < end; i++) { | 
 |  | 
 |         if (fBuffer[i] < chDigit_0 || fBuffer[i] > chDigit_9) | 
 |             ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, fMemoryManager); | 
 |  | 
 |         retVal = (retVal * 10) + (unsigned int) (fBuffer[i] - chDigit_0); | 
 |     } | 
 |  | 
 |     return (int) retVal; | 
 | } | 
 |  | 
 | // | 
 | // Note: | 
 | //    start: pointing to the first digit after the '.' | 
 | //    end:   pointing to one position after the last digit | 
 | //    fStart NOT updated | 
 | // | 
 | double XMLDateTime::parseMiliSecond(const int start, const int end) const | 
 | { | 
 |     double div = 10; | 
 |     double retval = 0; | 
 |      | 
 |     for (int i=start; i < end; i++) { | 
 |  | 
 |         if (fBuffer[i] < chDigit_0 || fBuffer[i] > chDigit_9) | 
 |             ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, fMemoryManager); | 
 |  | 
 |         retval += (fBuffer[i] == chDigit_0) ? 0 : ((double) (fBuffer[i] - chDigit_0)/div); | 
 |         div *= 10; | 
 |     } | 
 |  | 
 |     // we don't check underflow occurs since | 
 |     // nothing we can do about it. | 
 |     return retval; | 
 | } | 
 |  | 
 | // | 
 | // [-]CCYY | 
 | // | 
 | // Note: start from fStart | 
 | //       end (exclusive) | 
 | //       fStart NOT updated | 
 | // | 
 | int XMLDateTime::parseIntYear(const int end) const | 
 | { | 
 |     // skip the first leading '-' | 
 |     int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart; | 
 |  | 
 |     int length = end - start; | 
 |     if (length < 4) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_year_tooShort | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Year must have 'CCYY' format"); | 
 |     } | 
 |     else if (length > 4 && | 
 |              fBuffer[start] == chDigit_0) | 
 |     { | 
 |         ThrowXMLwithMemMgr1(SchemaDateTimeException | 
 |                 , XMLExcepts::DateTime_year_leadingZero | 
 |                 , fBuffer | 
 |                 , fMemoryManager); | 
 |         //"Leading zeros are required if the year value would otherwise have fewer than four digits; | 
 |         // otherwise they are forbidden"); | 
 |     } | 
 |  | 
 |     bool negative = (fBuffer[0] == chDash); | 
 |     int  yearVal = parseInt((negative ? 1 : 0), end); | 
 |     return ( negative ? (-1) * yearVal : yearVal ); | 
 | } | 
 |  | 
 | /*** | 
 |  * E2-41 | 
 |  * | 
 |  *  3.2.7.2 Canonical representation | 
 |  *  | 
 |  *  Except for trailing fractional zero digits in the seconds representation,  | 
 |  *  '24:00:00' time representations, and timezone (for timezoned values),  | 
 |  *  the mapping from literals to values is one-to-one. Where there is more  | 
 |  *  than one possible representation, the canonical representation is as follows:  | 
 |  *  redundant trailing zero digits in fractional-second literals are prohibited.  | 
 |  *  An hour representation of '24' is prohibited. Timezoned values are canonically | 
 |  *  represented by appending 'Z' to the nontimezoned representation. (All  | 
 |  *  timezoned dateTime values are UTC.)  | 
 |  * | 
 |  *  .'24:00:00' -> '00:00:00' | 
 |  *  .milisecond: trailing zeros removed | 
 |  *  .'Z' | 
 |  * | 
 |  ***/ | 
 | XMLCh* XMLDateTime::getDateTimeCanonicalRepresentation(MemoryManager* const memMgr) const | 
 | { | 
 |     XMLCh *miliStartPtr, *miliEndPtr; | 
 |     searchMiliSeconds(miliStartPtr, miliEndPtr); | 
 |     int miliSecondsLen = miliEndPtr - miliStartPtr; | 
 |     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1; | 
 |  | 
 |     MemoryManager* toUse = memMgr? memMgr : fMemoryManager; | 
 |     XMLCh* retBuf = (XMLCh*) toUse->allocate( (21 + miliSecondsLen + utcSize + 1) * sizeof(XMLCh)); | 
 |     XMLCh* retPtr = retBuf; | 
 |  | 
 |     // (-?) cc+yy-mm-dd'T'hh:mm:ss'Z'    ('.'s+)? | 
 |     //      2+  8       1      8   1 | 
 |     // | 
 |     int additionalLen = fillYearString(retPtr, fValue[CentYear]); | 
 |     if(additionalLen != 0) | 
 |     { | 
 |         // very bad luck; have to resize the buffer... | 
 |         XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen+21+miliSecondsLen +2) * sizeof(XMLCh)); | 
 |         XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen); | 
 |         retPtr = tmpBuf+(retPtr-retBuf); | 
 |         toUse->deallocate(retBuf); | 
 |         retBuf = tmpBuf; | 
 |     } | 
 |     *retPtr++ = DATE_SEPARATOR; | 
 |     fillString(retPtr, fValue[Month], 2); | 
 |     *retPtr++ = DATE_SEPARATOR; | 
 |     fillString(retPtr, fValue[Day], 2); | 
 |     *retPtr++ = DATETIME_SEPARATOR; | 
 |  | 
 |     fillString(retPtr, fValue[Hour], 2); | 
 |     if (fValue[Hour] == 24) | 
 |     { | 
 |         *(retPtr - 2) = chDigit_0; | 
 |         *(retPtr - 1) = chDigit_0; | 
 |     } | 
 |     *retPtr++ = TIME_SEPARATOR; | 
 |     fillString(retPtr, fValue[Minute], 2); | 
 |     *retPtr++ = TIME_SEPARATOR; | 
 |     fillString(retPtr, fValue[Second], 2); | 
 |  | 
 |     if (miliSecondsLen) | 
 |     { | 
 |         *retPtr++ = chPeriod; | 
 |         XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen); | 
 |         retPtr += miliSecondsLen; | 
 |     } | 
 |  | 
 |     if (utcSize) | 
 |         *retPtr++ = UTC_STD_CHAR; | 
 |     *retPtr = chNull; | 
 |  | 
 |     return retBuf; | 
 | } | 
 |  | 
 | /*** | 
 |  * E2-41 | 
 |  * | 
 |  *  3.2.9.2 Canonical representation | 
 |  *  | 
 |  * Given a member of the date value space, the date  | 
 |  * portion of the canonical representation (the entire  | 
 |  * representation for nontimezoned values, and all but | 
 |  * the timezone representation for timezoned values)  | 
 |  * is always the date portion of the dateTime canonical | 
 |  * representation of the interval midpoint (the  | 
 |  * dateTime representation, truncated on the right | 
 |  * to eliminate 'T' and all following characters).  | 
 |  * For timezoned values, append the canonical  | 
 |  * representation of the recoverable timezone.  | 
 |  * | 
 |  ***/ | 
 | XMLCh* XMLDateTime::getDateCanonicalRepresentation(MemoryManager* const memMgr) const | 
 | {     | 
 |     /* | 
 |      * Case Date               Actual Value    Canonical Value | 
 |      *    1 yyyy-mm-dd         yyyy-mm-dd          yyyy-mm-dd | 
 |      *    2 yyyy-mm-ddZ        yyyy-mm-ddT00:00Z   yyyy-mm-ddZ | 
 |      *    3 yyyy-mm-dd+00:00   yyyy-mm-ddT00:00Z   yyyy-mm-ddZ | 
 |      *    4 yyyy-mm-dd+00:01   YYYY-MM-DCT23:59Z   yyyy-mm-dd+00:01               | 
 |      *    5 yyyy-mm-dd+12:00   YYYY-MM-DCT12:00Z   yyyy-mm-dd+12:00     | 
 |      *    6 yyyy-mm-dd+12:01   YYYY-MM-DCT11:59Z   YYYY-MM-DC-11:59  | 
 |      *    7 yyyy-mm-dd+14:00   YYYY-MM-DCT10:00Z   YYYY-MM-DC-10:00  | 
 |      *    8 yyyy-mm-dd-00:00   yyyy-mm-ddT00:00Z   yyyy-mm-ddZ | 
 |      *    9 yyyy-mm-dd-00:01   yyyy-mm-ddT00:01Z   yyyy-mm-dd-00:01  | 
 |      *   11 yyyy-mm-dd-11:59   yyyy-mm-ddT11:59Z   YYYY-MM-DD-11:59 | 
 |      *   10 yyyy-mm-dd-12:00   yyyy-mm-ddT12:00Z   YYYY-MM-DD+12:00       | 
 |      *   12 yyyy-mm-dd-14:00   yyyy-mm-ddT14:00Z   YYYY-MM-DD+10:00 | 
 |      */ | 
 |     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1; | 
 |     // YYYY-MM-DD  + chNull  | 
 |     // 1234567890  + 1 | 
 |     int memLength = 10 + 1 + utcSize; | 
 |  | 
 |     if (fTimeZone[hh] != 0 || fTimeZone[mm] != 0) { | 
 |         // YYYY-MM-DD+HH:MM  (utcSize will be 1 so drop that) | 
 |         // 1234567890123456 | 
 |         memLength += 5; // 6 - 1 for utcSize | 
 |     } | 
 |  | 
 |     MemoryManager* toUse = memMgr? memMgr : fMemoryManager; | 
 |     XMLCh* retBuf = (XMLCh*) toUse->allocate( (memLength) * sizeof(XMLCh)); | 
 |     XMLCh* retPtr = retBuf; | 
 |  | 
 |     if (fValue[Hour] < 12) { | 
 |          | 
 |         int additionalLen = fillYearString(retPtr, fValue[CentYear]); | 
 |         if (additionalLen != 0) { | 
 |             // very bad luck; have to resize the buffer... | 
 |             XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen + memLength ) * sizeof(XMLCh)); | 
 |             XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen); | 
 |             retPtr = tmpBuf+(retPtr-retBuf); | 
 |             toUse->deallocate(retBuf); | 
 |             retBuf = tmpBuf; | 
 |         } | 
 |         *retPtr++ = DATE_SEPARATOR; | 
 |         fillString(retPtr, fValue[Month], 2); | 
 |         *retPtr++ = DATE_SEPARATOR; | 
 |         fillString(retPtr, fValue[Day], 2);         | 
 |  | 
 |         if (utcSize) { | 
 |             if (fTimeZone[hh] != 0 || fTimeZone[mm] != 0) { | 
 |                 *retPtr++ = UTC_NEG_CHAR;                | 
 |                 fillString(retPtr, fValue[Hour], 2); | 
 |                 *retPtr++ = TIME_SEPARATOR; | 
 |                 fillString(retPtr, fValue[Minute], 2); | 
 |             } | 
 |             else { | 
 |                 *retPtr++ = UTC_STD_CHAR; | 
 |             } | 
 |         } | 
 |         *retPtr = chNull;     | 
 |     } | 
 |     else { | 
 |         /* | 
 |          * Need to reconvert things to get a recoverable time zone between | 
 |          * +12:00 and -11:59 | 
 |          */ | 
 |         int carry; | 
 |         int minute; | 
 |         int hour; | 
 |         int day; | 
 |         int month; | 
 |         int year; | 
 |         if (fValue[Minute] == 0) { | 
 |             minute = 0; | 
 |             carry = 0; | 
 |         } | 
 |         else { | 
 |             minute = 60 - fValue[Minute]; | 
 |             carry = 1; | 
 |         } | 
 |         hour  = 24 - fValue[Hour] - carry; | 
 |         day   = fValue[Day] + 1; | 
 |         month = fValue[Month]; | 
 |         year  = fValue[CentYear]; | 
 |  | 
 |         while (1) { | 
 |             int temp = maxDayInMonthFor(year, month); | 
 |             if (day < 1) { | 
 |                 day += maxDayInMonthFor(year, month - 1); | 
 |                 carry = -1; | 
 |             } | 
 |             else if (day > temp) { | 
 |                 day -= temp; | 
 |                 carry = 1; | 
 |             } | 
 |             else { | 
 |                 break; | 
 |             } | 
 |  | 
 |             temp = month + carry; | 
 |             month = modulo(temp, 1, 13); | 
 |             if (month <= 0) { | 
 |                 month+= 12; | 
 |                 year--; | 
 |             } | 
 |             year += fQuotient(temp, 1, 13);          | 
 |         } | 
 |  | 
 |         int additionalLen = fillYearString(retPtr, year); | 
 |         if (additionalLen != 0) { | 
 |             // very bad luck; have to resize the buffer... | 
 |             XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen + memLength ) * sizeof(XMLCh)); | 
 |             XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen); | 
 |             retPtr = tmpBuf+(retPtr-retBuf); | 
 |             toUse->deallocate(retBuf); | 
 |             retBuf = tmpBuf; | 
 |         } | 
 |         *retPtr++ = DATE_SEPARATOR; | 
 |         fillString(retPtr, month, 2); | 
 |         *retPtr++ = DATE_SEPARATOR; | 
 |         fillString(retPtr, day, 2);         | 
 |         | 
 |         *retPtr++ = UTC_POS_CHAR;                | 
 |         fillString(retPtr, hour, 2); | 
 |         *retPtr++ = TIME_SEPARATOR; | 
 |         fillString(retPtr, minute, 2);                                 | 
 |         *retPtr = chNull; | 
 |     }       | 
 |     return retBuf; | 
 | } | 
 |  | 
 |  | 
 | /*** | 
 |  * 3.2.8 time | 
 |  * | 
 |  *  . either the time zone must be omitted or,  | 
 |  *    if present, the time zone must be Coordinated Universal Time (UTC) indicated by a "Z".    | 
 |  * | 
 |  *  . Additionally, the canonical representation for midnight is 00:00:00. | 
 |  * | 
 | ***/ | 
 | XMLCh* XMLDateTime::getTimeCanonicalRepresentation(MemoryManager* const memMgr) const | 
 | { | 
 |     XMLCh *miliStartPtr, *miliEndPtr; | 
 |     searchMiliSeconds(miliStartPtr, miliEndPtr); | 
 |     int miliSecondsLen = miliEndPtr - miliStartPtr; | 
 |     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1; | 
 |      | 
 |     MemoryManager* toUse = memMgr? memMgr : fMemoryManager; | 
 |     XMLCh* retBuf = (XMLCh*) toUse->allocate( (10 + miliSecondsLen + utcSize + 1) * sizeof(XMLCh)); | 
 |     XMLCh* retPtr = retBuf; | 
 |  | 
 |     // 'hh:mm:ss'Z'    ('.'s+)? | 
 |     //      8    1 | 
 |     // | 
 |  | 
 |     fillString(retPtr, fValue[Hour], 2); | 
 |     if (fValue[Hour] == 24) | 
 |     { | 
 |         *(retPtr - 2) = chDigit_0; | 
 |         *(retPtr - 1) = chDigit_0; | 
 |     } | 
 |     *retPtr++ = TIME_SEPARATOR; | 
 |     fillString(retPtr, fValue[Minute], 2); | 
 |     *retPtr++ = TIME_SEPARATOR; | 
 |     fillString(retPtr, fValue[Second], 2); | 
 |  | 
 |     if (miliSecondsLen) | 
 |     { | 
 |         *retPtr++ = chPeriod; | 
 |         XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen); | 
 |         retPtr += miliSecondsLen; | 
 |     } | 
 |  | 
 |     if (utcSize) | 
 |         *retPtr++ = UTC_STD_CHAR; | 
 |     *retPtr = chNull; | 
 |  | 
 |     return retBuf; | 
 | } | 
 |  | 
 | void XMLDateTime::fillString(XMLCh*& ptr, int value, int expLen) const | 
 | { | 
 |     XMLCh strBuffer[16]; | 
 |     assert(expLen < 16); | 
 |     XMLString::binToText(value, strBuffer, expLen, 10, fMemoryManager); | 
 |     int   actualLen = XMLString::stringLen(strBuffer); | 
 |     int   i; | 
 |     //append leading zeros | 
 |     for (i = 0; i < expLen - actualLen; i++) | 
 |     { | 
 |         *ptr++ = chDigit_0; | 
 |     } | 
 |  | 
 |     for (i = 0; i < actualLen; i++) | 
 |     { | 
 |         *ptr++ = strBuffer[i]; | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | int XMLDateTime::fillYearString(XMLCh*& ptr, int value) const | 
 | { | 
 |     XMLCh strBuffer[16]; | 
 |     // let's hope we get no years of 15 digits... | 
 |     XMLString::binToText(value, strBuffer, 15, 10, fMemoryManager); | 
 |     int   actualLen = XMLString::stringLen(strBuffer); | 
 |     // don't forget that years can be negative... | 
 |     int negativeYear = 0; | 
 |     if(strBuffer[0] == chDash) | 
 |     { | 
 |         *ptr++ = strBuffer[0]; | 
 |         negativeYear = 1; | 
 |     } | 
 |     int   i; | 
 |     //append leading zeros | 
 |     for (i = 0; i < 4 - actualLen+negativeYear; i++) | 
 |     { | 
 |         *ptr++ = chDigit_0; | 
 |     } | 
 |  | 
 |     for (i = negativeYear; i < actualLen; i++) | 
 |     { | 
 |         *ptr++ = strBuffer[i]; | 
 |     } | 
 |     if(actualLen > 4) | 
 |         return actualLen-4; | 
 |     return 0; | 
 | } | 
 |  | 
 | /*** | 
 |  * | 
 |  *   .check if the rawData has the mili second component | 
 |  *   .capture the substring | 
 |  * | 
 |  ***/ | 
 | void XMLDateTime::searchMiliSeconds(XMLCh*& miliStartPtr, XMLCh*& miliEndPtr) const | 
 | { | 
 |     miliStartPtr = miliEndPtr = 0; | 
 |  | 
 |     int milisec = XMLString::indexOf(fBuffer, MILISECOND_SEPARATOR); | 
 |     if (milisec == -1) | 
 |         return; | 
 |  | 
 |     miliStartPtr = fBuffer + milisec + 1; | 
 |     miliEndPtr   = miliStartPtr; | 
 |     while (*miliEndPtr) | 
 |     { | 
 |         if ((*miliEndPtr < chDigit_0) || (*miliEndPtr > chDigit_9)) | 
 |             break; | 
 |  | 
 |         miliEndPtr++; | 
 |     } | 
 |  | 
 |     //remove trailing zeros | 
 |     while( *(miliEndPtr - 1) == chDigit_0) | 
 |         miliEndPtr--; | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | /*** | 
 |  * Support for Serialization/De-serialization | 
 |  ***/ | 
 |  | 
 | IMPL_XSERIALIZABLE_TOCREATE(XMLDateTime) | 
 |  | 
 | void XMLDateTime::serialize(XSerializeEngine& serEng) | 
 | { | 
 |     //REVISIT: may not need to call base since it does nothing | 
 |     XMLNumber::serialize(serEng); | 
 |  | 
 |     int i = 0; | 
 |  | 
 |     if (serEng.isStoring()) | 
 |     { | 
 |         for (i = 0; i < TOTAL_SIZE; i++) | 
 |         { | 
 |             serEng<<fValue[i]; | 
 |         } | 
 |  | 
 |         for (i = 0; i < TIMEZONE_ARRAYSIZE; i++) | 
 |         { | 
 |             serEng<<fTimeZone[i]; | 
 |         } | 
 |  | 
 |         serEng<<fStart; | 
 |         serEng<<fEnd; | 
 |  | 
 |         serEng.writeString(fBuffer, fBufferMaxLen, XSerializeEngine::toWriteBufferLen); | 
 |     } | 
 |     else | 
 |     { | 
 |         for (i = 0; i < TOTAL_SIZE; i++) | 
 |         { | 
 |             serEng>>fValue[i]; | 
 |         } | 
 |  | 
 |         for (i = 0; i < TIMEZONE_ARRAYSIZE; i++) | 
 |         { | 
 |             serEng>>fTimeZone[i]; | 
 |         } | 
 |  | 
 |         serEng>>fStart; | 
 |         serEng>>fEnd; | 
 |  | 
 |         int dataLen = 0; | 
 |         serEng.readString(fBuffer, fBufferMaxLen, dataLen ,XSerializeEngine::toReadBufferLen); | 
 |  | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | XERCES_CPP_NAMESPACE_END |