XMLDateTime.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:40k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 2001, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: XMLDateTime.cpp,v 1.12 2003/05/22 02:10:52 knoaman Exp $
  58.  * $Log: XMLDateTime.cpp,v $
  59.  * Revision 1.12  2003/05/22 02:10:52  knoaman
  60.  * Default the memory manager.
  61.  *
  62.  * Revision 1.11  2003/05/18 14:02:05  knoaman
  63.  * Memory manager implementation: pass per instance manager.
  64.  *
  65.  * Revision 1.10  2003/05/15 19:07:46  knoaman
  66.  * Partial implementation of the configurable memory manager.
  67.  *
  68.  * Revision 1.9  2003/05/15 16:32:19  gareth
  69.  * We did not allow dateTimes with a timezone due to the last seconds fix.
  70.  *
  71.  * Revision 1.8  2003/03/23 22:54:49  peiyongz
  72.  * invalid second values
  73.  *
  74.  * Revision 1.7  2003/02/22 22:49:09  peiyongz
  75.  * Schema Errata E2-45 24:00:00 allowed
  76.  *
  77.  * Revision 1.6  2003/02/02 23:54:43  peiyongz
  78.  * getFormattedString() added to return original and converted value.
  79.  *
  80.  * Revision 1.5  2003/01/30 21:55:22  tng
  81.  * Performance: create getRawData which is similar to toString but return the internal data directly, user is not required to delete the returned memory.
  82.  *
  83.  * Revision 1.4  2002/11/28 20:39:27  peiyongz
  84.  * Schema Errata: E2-23 seconds part shall have at least one digit after the dot
  85.  *                           if it appears.
  86.  *
  87.  * Revision 1.3  2002/11/06 22:22:21  peiyongz
  88.  * Schema-Errata: E2-12: gMonth
  89.  *
  90.  * Revision 1.2  2002/11/04 15:22:05  tng
  91.  * C++ Namespace Support.
  92.  *
  93.  * Revision 1.1.1.1  2002/02/01 22:22:14  peiyongz
  94.  * sane_include
  95.  *
  96.  * Revision 1.4  2001/11/14 22:04:03  peiyongz
  97.  * Patch to apply check on Year and more rigorous on other fields as well.
  98.  *
  99.  * Revision 1.3  2001/11/12 20:36:54  peiyongz
  100.  * SchemaDateTimeException defined
  101.  *
  102.  * Revision 1.2  2001/11/09 20:41:45  peiyongz
  103.  * Fix: compilation error on Solaris and AIX.
  104.  *
  105.  * Revision 1.1  2001/11/07 19:16:03  peiyongz
  106.  * DateTime Port
  107.  *
  108.  *
  109.  */
  110. // ---------------------------------------------------------------------------
  111. //  Includes
  112. // ---------------------------------------------------------------------------
  113. #include <stdlib.h>
  114. #include <xercesc/util/XMLDateTime.hpp>
  115. #include <xercesc/util/XMLString.hpp>
  116. #include <xercesc/util/XMLUni.hpp>
  117. #include <xercesc/util/Janitor.hpp>
  118. XERCES_CPP_NAMESPACE_BEGIN
  119. //
  120. // constants used to process raw data (fBuffer)
  121. //
  122. // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}['Z']
  123. //                                [{+|-}hh:mm']
  124. //
  125. static const XMLCh DURATION_STARTER     = chLatin_P;              // 'P'
  126. static const XMLCh DURATION_Y           = chLatin_Y;              // 'Y'
  127. static const XMLCh DURATION_M           = chLatin_M;              // 'M'
  128. static const XMLCh DURATION_D           = chLatin_D;              // 'D'
  129. static const XMLCh DURATION_H           = chLatin_H;              // 'H'
  130. static const XMLCh DURATION_S           = chLatin_S;              // 'S'
  131. static const XMLCh DATE_SEPARATOR       = chDash;                 // '-'
  132. static const XMLCh TIME_SEPARATOR       = chColon;                // ':'
  133. static const XMLCh TIMEZONE_SEPARATOR   = chColon;                // ':'
  134. static const XMLCh DATETIME_SEPARATOR   = chLatin_T;              // 'T'
  135. static const XMLCh MILISECOND_SEPARATOR = chPeriod;               // '.'
  136. static const XMLCh UTC_STD_CHAR         = chLatin_Z;              // 'Z'
  137. static const XMLCh UTC_POS_CHAR         = chPlus;                 // '+'
  138. static const XMLCh UTC_NEG_CHAR         = chDash;                 // '-'
  139. static const XMLCh UTC_SET[]            = {UTC_STD_CHAR           //"Z+-"
  140.                                          , UTC_POS_CHAR
  141.                                          , UTC_NEG_CHAR
  142.                                          , chNull};
  143. static const int YMD_MIN_SIZE    = 10;   // CCYY-MM-DD
  144. static const int YMONTH_MIN_SIZE = 7;    // CCYY_MM
  145. static const int TIME_MIN_SIZE   = 8;    // hh:mm:ss
  146. static const int TIMEZONE_SIZE   = 5;    // hh:mm
  147. static const int DAY_SIZE        = 5;    // ---DD
  148. //static const int MONTH_SIZE      = 6;    // --MM--
  149. static const int MONTHDAY_SIZE   = 7;    // --MM-DD
  150. static const int NOT_FOUND       = -1;
  151. //define constants to be used in assigning default values for
  152. //all date/time excluding duration
  153. static const int YEAR_DEFAULT  = 2000;
  154. static const int MONTH_DEFAULT = 01;
  155. static const int DAY_DEFAULT   = 15;
  156. // order-relation on duration is a partial order. The dates below are used to
  157. // for comparison of 2 durations, based on the fact that
  158. // duration x and y is x<=y iff s+x<=s+y
  159. // see 3.2.6 duration W3C schema datatype specs
  160. //
  161. // the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
  162. static const int DATETIMES[][XMLDateTime::TOTAL_SIZE] =
  163. {
  164.     {1696, 9, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
  165. {1697, 2, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
  166. {1903, 3, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
  167. {1903, 7, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD}
  168. };
  169. // ---------------------------------------------------------------------------
  170. //  local methods
  171. // ---------------------------------------------------------------------------
  172. static inline int fQuotient(int a, int b)
  173. {
  174.     div_t div_result = div(a, b);
  175.     return div_result.quot;
  176. }
  177. static inline int fQuotient(int temp, int low, int high)
  178. {
  179.     return fQuotient(temp - low, high - low);
  180. }
  181. static inline int mod(int a, int b, int quotient)
  182. {
  183. return (a - quotient*b) ;
  184. }
  185. static inline int modulo (int temp, int low, int high)
  186. {
  187.     //modulo(a - low, high - low) + low
  188.     int a = temp - low;
  189.     int b = high - low;
  190.     return (mod (a, b, fQuotient(a, b)) + low) ;
  191. }
  192. static inline bool isLeapYear(int year)
  193. {
  194.     return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
  195. }
  196. static int maxDayInMonthFor(int year, int month)
  197. {
  198.     if ( month == 4 || month == 6 || month == 9 || month == 11 )
  199.     {
  200.         return 30;
  201.     }
  202.     else if ( month==2 )
  203.     {
  204.         if ( isLeapYear(year) )
  205.             return 29;
  206.         else
  207.             return 28;
  208.     }
  209.     else
  210.     {
  211.         return 31;
  212.     }
  213. }
  214. // ---------------------------------------------------------------------------
  215. //  static methods : for duration
  216. // ---------------------------------------------------------------------------
  217. /**
  218.  * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration")
  219.  *
  220.  * 3.2.6.2 Order relation on duration
  221.  *
  222.  *     In general, the order-relation on duration is a partial order since there is no
  223.  *  determinate relationship between certain durations such as one month (P1M) and 30 days (P30D).
  224.  *  The order-relation of two duration values x and y is x < y iff s+x < s+y for each qualified
  225.  *  dateTime s in the list below.
  226.  *
  227.  *     These values for s cause the greatest deviations in the addition of dateTimes and durations
  228.  *
  229.  **/
  230. int XMLDateTime::compare(const XMLDateTime* const pDate1
  231.                        , const XMLDateTime* const pDate2
  232.                        , bool  strict)
  233. {
  234.     //REVISIT: this is unoptimazed vs of comparing 2 durations
  235.     //         Algorithm is described in 3.2.6.2 W3C Schema Datatype specs
  236.     //
  237.     int resultA, resultB = INDETERMINATE;
  238.     //try and see if the objects are equal
  239.     if ( (resultA = compareOrder(pDate1, pDate2)) == EQUAL)
  240.         return EQUAL;
  241.     //long comparison algorithm is required
  242.     XMLDateTime tempA(XMLPlatformUtils::fgMemoryManager), *pTempA = &tempA;
  243.     XMLDateTime tempB(XMLPlatformUtils::fgMemoryManager), *pTempB = &tempB;
  244.     addDuration(pTempA, pDate1, 0);
  245.     addDuration(pTempB, pDate2, 0);
  246.     resultA = compareOrder(pTempA, pTempB);
  247.     if ( resultA == INDETERMINATE )
  248.         return INDETERMINATE;
  249.     addDuration(pTempA, pDate1, 1);
  250.     addDuration(pTempB, pDate2, 1);
  251.     resultB = compareOrder(pTempA, pTempB);
  252.     resultA = compareResult(resultA, resultB, strict);
  253.     if ( resultA == INDETERMINATE )
  254.         return INDETERMINATE;
  255.     addDuration(pTempA, pDate1, 2);
  256.     addDuration(pTempB, pDate2, 2);
  257.     resultB = compareOrder(pTempA, pTempB);
  258.     resultA = compareResult(resultA, resultB, strict);
  259.     if ( resultA == INDETERMINATE )
  260.         return INDETERMINATE;
  261.     addDuration(pTempA, pDate1, 3);
  262.     addDuration(pTempB, pDate2, 3);
  263.     resultB = compareOrder(pTempA, pTempB);
  264.     resultA = compareResult(resultA, resultB, strict);
  265.     return resultA;
  266. }
  267. //
  268. // Form a new XMLDateTime with duration and baseDate array
  269. // Note: C++        Java
  270. //       fNewDate   duration
  271. //       fDuration  date
  272. //
  273. void XMLDateTime::addDuration(XMLDateTime*             fNewDate
  274.                             , const XMLDateTime* const fDuration
  275.                             , int index)
  276. {
  277.     //REVISIT: some code could be shared between normalize() and this method,
  278.     //         however is it worth moving it? The structures are different...
  279.     //
  280.     fNewDate->reset();
  281.     //add months (may be modified additionaly below)
  282.     int temp = DATETIMES[index][Month] + fDuration->fValue[Month];
  283.     fNewDate->fValue[Month] = modulo(temp, 1, 13);
  284.     int carry = fQuotient(temp, 1, 13);
  285.     //add years (may be modified additionaly below)
  286.     fNewDate->fValue[CentYear] = DATETIMES[index][CentYear] + fDuration->fValue[CentYear] + carry;
  287.     //add seconds
  288.     temp = DATETIMES[index][Second] + fDuration->fValue[Second];
  289.     carry = fQuotient (temp, 60);
  290.     fNewDate->fValue[Second] =  mod(temp, 60, carry);
  291.     //add minutes
  292.     temp = DATETIMES[index][Minute] + fDuration->fValue[Minute] + carry;
  293.     carry = fQuotient(temp, 60);
  294.     fNewDate->fValue[Minute] = mod(temp, 60, carry);
  295.     //add hours
  296.     temp = DATETIMES[index][Hour] + fDuration->fValue[Hour] + carry;
  297.     carry = fQuotient(temp, 24);
  298.     fNewDate->fValue[Hour] = mod(temp, 24, carry);
  299.     fNewDate->fValue[Day] = DATETIMES[index][Day] + fDuration->fValue[Day] + carry;
  300.     while ( true )
  301.     {
  302.         temp = maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]);
  303.         if ( fNewDate->fValue[Day] < 1 )
  304.         { //original fNewDate was negative
  305.             fNewDate->fValue[Day] += maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]-1);
  306.             carry = -1;
  307.         }
  308.         else if ( fNewDate->fValue[Day] > temp )
  309.         {
  310.             fNewDate->fValue[Day] -= temp;
  311.             carry = 1;
  312.         }
  313.         else
  314.         {
  315.             break;
  316.         }
  317.         temp = fNewDate->fValue[Month] + carry;
  318.         fNewDate->fValue[Month] = modulo(temp, 1, 13);
  319.         fNewDate->fValue[CentYear] += fQuotient(temp, 1, 13);
  320.     }
  321.     //fNewDate->fValue[utc] = UTC_STD_CHAR;
  322.     fNewDate->fValue[utc] = UTC_STD;
  323. }
  324. int XMLDateTime::compareResult(short resultA
  325.                              , short resultB
  326.                              , bool strict)
  327. {
  328.     if ( resultB == INDETERMINATE )
  329.     {
  330.         return INDETERMINATE;
  331.     }
  332.     else if ( (resultA != resultB) &&
  333.               strict                )
  334.     {
  335.         return INDETERMINATE;
  336.     }
  337.     else if ( (resultA != resultB) &&
  338.               !strict               )
  339.     {
  340.         if ( (resultA != EQUAL) &&
  341.              (resultB != EQUAL)  )
  342.         {
  343.             return INDETERMINATE;
  344.         }
  345.         else
  346.         {
  347.             return (resultA != EQUAL)? resultA : resultB;
  348.         }
  349.     }
  350.     return resultA;
  351. }
  352. // ---------------------------------------------------------------------------
  353. //  static methods : for others
  354. // ---------------------------------------------------------------------------
  355. int XMLDateTime::compare(const XMLDateTime* const pDate1
  356.                        , const XMLDateTime* const pDate2)
  357. {
  358.     if (pDate1->fValue[utc] == pDate2->fValue[utc])
  359.     {
  360.         return XMLDateTime::compareOrder(pDate1, pDate2);
  361.     }
  362.     short c1, c2;
  363.     if ( pDate1->isNormalized())
  364.     {
  365.         c1 = compareResult(pDate1, pDate2, false, UTC_POS);
  366.         c2 = compareResult(pDate1, pDate2, false, UTC_NEG);
  367.         return getRetVal(c1, c2);
  368.     }
  369.     else if ( pDate2->isNormalized())
  370.     {
  371.         c1 = compareResult(pDate1, pDate2, true, UTC_POS);
  372.         c2 = compareResult(pDate1, pDate2, true, UTC_NEG);
  373.         return getRetVal(c1, c2);
  374.     }
  375.     return INDETERMINATE;
  376. }
  377. int XMLDateTime::compareResult(const XMLDateTime* const pDate1
  378.                              , const XMLDateTime* const pDate2
  379.                              , bool  set2Left
  380.                              , int   utc_type)
  381. {
  382.     XMLDateTime tmpDate = (set2Left ? *pDate1 : *pDate2);
  383.     tmpDate.fTimeZone[hh] = 14;
  384.     tmpDate.fTimeZone[mm] = 0;
  385.     tmpDate.fValue[utc] = utc_type;
  386.     tmpDate.normalize();
  387.     return (set2Left? XMLDateTime::compareOrder(&tmpDate, pDate2) :
  388.                       XMLDateTime::compareOrder(pDate1, &tmpDate));
  389. }
  390. int XMLDateTime::compareOrder(const XMLDateTime* const lValue
  391.                             , const XMLDateTime* const rValue)
  392. {
  393.     //
  394.     // If any of the them is not normalized() yet,
  395.     // we need to do something here.
  396.     //
  397.     XMLDateTime lTemp = *lValue;
  398.     XMLDateTime rTemp = *rValue;
  399.     lTemp.normalize();
  400.     rTemp.normalize();
  401.     for ( int i = 0 ; i < TOTAL_SIZE; i++ )
  402.     {
  403.         if ( lTemp.fValue[i] < rTemp.fValue[i] )
  404.         {
  405.             return LESS_THAN;
  406.         }
  407.         else if ( lTemp.fValue[i] > rTemp.fValue[i] )
  408.         {
  409.             return GREATER_THAN;
  410.         }
  411.     }
  412.     return EQUAL;
  413. }
  414. // ---------------------------------------------------------------------------
  415. //  ctor and dtor
  416. // ---------------------------------------------------------------------------
  417. XMLDateTime::~XMLDateTime()
  418. {
  419.     if (fBuffer)
  420.         fMemoryManager->deallocate(fBuffer);//delete[] fBuffer;
  421. }
  422. XMLDateTime::XMLDateTime(MemoryManager* const manager)
  423. : fBuffer(0)
  424. , fMemoryManager(manager)
  425. {
  426.     reset();
  427. }
  428. XMLDateTime::XMLDateTime(const XMLCh* const aString,
  429.                          MemoryManager* const manager)
  430. : fBuffer(0)
  431. , fMemoryManager(manager)
  432. {
  433.     setBuffer(aString);
  434. }
  435. // -----------------------------------------------------------------------
  436. // Copy ctor and Assignment operators
  437. // -----------------------------------------------------------------------
  438. XMLDateTime::XMLDateTime(const XMLDateTime &toCopy)
  439. : fBuffer(0)
  440. , fMemoryManager(toCopy.fMemoryManager)
  441. {
  442.     copy(toCopy);
  443. }
  444. XMLDateTime& XMLDateTime::operator=(const XMLDateTime& rhs)
  445. {
  446.     if (this == &rhs)
  447.         return *this;
  448.     copy(rhs);
  449.     return *this;
  450. }
  451. // -----------------------------------------------------------------------
  452. // Implementation of Abstract Interface
  453. // -----------------------------------------------------------------------
  454. //
  455. // We may simply return the handle to fBuffer, but
  456. // for the sake of consistency, we return a duplicated copy
  457. // and the caller is responsible for the release of the buffer
  458. // just like any other things in the XMLNumber family.
  459. //
  460. XMLCh*  XMLDateTime::toString() const
  461. {
  462.     assertBuffer();
  463.     // Return data using global operator new
  464.     XMLCh* retBuf = XMLString::replicate(fBuffer);
  465.     return retBuf;
  466. }
  467. //
  468. // We may simply return the handle to fBuffer
  469. //
  470. XMLCh*  XMLDateTime::getRawData() const
  471. {
  472.     assertBuffer();    
  473.     return fBuffer;
  474. }
  475. const XMLCh*  XMLDateTime::getFormattedString() const
  476. {
  477.     return getRawData();
  478. }
  479. int XMLDateTime::getSign() const
  480. {
  481.     return 0;
  482. }
  483. // ---------------------------------------------------------------------------
  484. //  Parsers
  485. // ---------------------------------------------------------------------------
  486. //
  487. // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}[TimeZone]
  488. //
  489. void XMLDateTime::parseDateTime()
  490. {
  491.     initParser();
  492.     getDate();
  493.     //fStart is supposed to point to 'T'
  494.     if (fBuffer[fStart++] != DATETIME_SEPARATOR)
  495.         ThrowXML1(SchemaDateTimeException
  496.                 , XMLExcepts::DateTime_dt_missingT
  497.                 , fBuffer);
  498.     getTime();
  499.     validateDateTime();
  500.     normalize();
  501. }
  502. //
  503. // [-]{CCYY-MM-DD}[TimeZone]
  504. //
  505. void XMLDateTime::parseDate()
  506. {
  507.     initParser();
  508.     getDate();
  509.     parseTimeZone();
  510.     validateDateTime();
  511.     normalize();
  512. }
  513. void XMLDateTime::parseTime()
  514. {
  515.     initParser();
  516.     // time initialize to default values
  517.     fValue[CentYear]= YEAR_DEFAULT;
  518.     fValue[Month]   = MONTH_DEFAULT;
  519.     fValue[Day]     = DAY_DEFAULT;
  520.     getTime();
  521.     validateDateTime();
  522.     normalize();
  523. }
  524. //
  525. // {---DD}[TimeZone]
  526. //  01234
  527. //
  528. void XMLDateTime::parseDay()
  529. {
  530.     initParser();
  531.     if (fBuffer[0] != DATE_SEPARATOR ||
  532.         fBuffer[1] != DATE_SEPARATOR ||
  533.         fBuffer[2] != DATE_SEPARATOR  )
  534.     {
  535.         ThrowXML1(SchemaDateTimeException
  536.                 , XMLExcepts::DateTime_gDay_invalid
  537.                 , fBuffer);
  538.     }
  539.     //initialize values
  540.     fValue[CentYear] = YEAR_DEFAULT;
  541.     fValue[Month]    = MONTH_DEFAULT;
  542.     fValue[Day]      = parseInt(fStart+3, fStart+5);
  543.     if ( DAY_SIZE < fEnd )
  544.     {
  545.         int sign = findUTCSign(DAY_SIZE);
  546.         if ( sign < 0 )
  547.         {
  548.             ThrowXML1(SchemaDateTimeException
  549.                     , XMLExcepts::DateTime_gDay_invalid
  550.                     , fBuffer);
  551.         }
  552.         else
  553.         {
  554.             getTimeZone(sign);
  555.         }
  556.     }
  557.     validateDateTime();
  558.     normalize();
  559. }
  560. //
  561. // {--MM--}[TimeZone]
  562. // {--MM}[TimeZone]
  563. //  012345
  564. //
  565. void XMLDateTime::parseMonth()
  566. {
  567.     initParser();
  568.     if (fBuffer[0] != DATE_SEPARATOR ||
  569.         fBuffer[1] != DATE_SEPARATOR  )
  570.     {
  571.         ThrowXML1(SchemaDateTimeException
  572.                 , XMLExcepts::DateTime_gMth_invalid
  573.                 , fBuffer);
  574.     }
  575.     //set constants
  576.     fValue[CentYear] = YEAR_DEFAULT;
  577.     fValue[Day]      = DAY_DEFAULT;
  578.     fValue[Month]    = parseInt(2, 4);
  579.     // REVISIT: allow both --MM and --MM-- now. 
  580.     // need to remove the following lines to disallow --MM-- 
  581.     // when the errata is officially in the rec. 
  582.     fStart = 4;
  583.     if ( fEnd >= fStart+2 && fBuffer[fStart] == DATE_SEPARATOR && fBuffer[fStart+1] == DATE_SEPARATOR ) 
  584.     { 
  585.         fStart += 2; 
  586.     } 
  587.     //
  588.     // parse TimeZone if any
  589.     //
  590.     if ( fStart < fEnd )
  591.     {
  592.         int sign = findUTCSign(fStart);
  593.         if ( sign < 0 )
  594.         {
  595.             ThrowXML1(SchemaDateTimeException
  596.                     , XMLExcepts::DateTime_gMth_invalid
  597.                     , fBuffer);
  598.         }
  599.         else
  600.         {
  601.             getTimeZone(sign);
  602.         }
  603.     }
  604.     validateDateTime();
  605.     normalize();
  606. }
  607. //
  608. //[-]{CCYY}[TimeZone]
  609. // 0  1234
  610. //
  611. void XMLDateTime::parseYear()
  612. {
  613.     initParser();
  614.     // skip the first '-' and search for timezone
  615.     //
  616.     int sign = findUTCSign((fBuffer[0] == chDash) ? 1 : 0);
  617.     if (sign == NOT_FOUND)
  618.     {
  619.         fValue[CentYear] = parseIntYear(fEnd);
  620.     }
  621.     else
  622.     {
  623.         fValue[CentYear] = parseIntYear(sign);
  624.         getTimeZone(sign);
  625.     }
  626.     //initialize values
  627.     fValue[Month] = MONTH_DEFAULT;
  628.     fValue[Day]   = DAY_DEFAULT;   //java is 1
  629.     validateDateTime();
  630.     normalize();
  631. }
  632. //
  633. //{--MM-DD}[TimeZone]
  634. // 0123456
  635. //
  636. void XMLDateTime::parseMonthDay()
  637. {
  638.     initParser();
  639.     if (fBuffer[0] != DATE_SEPARATOR ||
  640.         fBuffer[1] != DATE_SEPARATOR ||
  641.         fBuffer[4] != DATE_SEPARATOR )
  642.     {
  643.         ThrowXML1(SchemaDateTimeException
  644.                 , XMLExcepts::DateTime_gMthDay_invalid
  645.                 , fBuffer);
  646.     }
  647.     //initialize
  648.     fValue[CentYear] = YEAR_DEFAULT;
  649.     fValue[Month]    = parseInt(2, 4);
  650.     fValue[Day]      = parseInt(5, 7);
  651.     if ( MONTHDAY_SIZE < fEnd )
  652.     {
  653.         int sign = findUTCSign(MONTHDAY_SIZE);
  654.         if ( sign<0 )
  655.         {
  656.             ThrowXML1(SchemaDateTimeException
  657.                     , XMLExcepts::DateTime_gMthDay_invalid
  658.                     , fBuffer);
  659.         }
  660.         else
  661.         {
  662.             getTimeZone(sign);
  663.         }
  664.     }
  665.     validateDateTime();
  666.     normalize();
  667. }
  668. void XMLDateTime::parseYearMonth()
  669. {
  670.     initParser();
  671.     // get date
  672.     getYearMonth();
  673.     fValue[Day] = DAY_DEFAULT;
  674.     parseTimeZone();
  675.     validateDateTime();
  676.     normalize();
  677. }
  678. //
  679. //PnYn MnDTnH nMnS: -P1Y2M3DT10H30M
  680. //
  681. // [-]{'P'{[n'Y'][n'M'][n'D']['T'][n'H'][n'M'][n'S']}}
  682. //
  683. //  Note: the n above shall be >= 0
  684. //        if no time element found, 'T' shall be absent
  685. //
  686. void XMLDateTime::parseDuration()
  687. {
  688.     initParser();
  689.     // must start with '-' or 'P'
  690.     //
  691.     XMLCh c = fBuffer[fStart++];
  692.     if ( (c != DURATION_STARTER) &&
  693.          (c != chDash)            )
  694.     {
  695.         ThrowXML1(SchemaDateTimeException
  696.                 , XMLExcepts::DateTime_dur_Start_dashP
  697.                 , fBuffer);
  698.     }
  699.     // 'P' must ALWAYS be present in either case
  700.     if ( (c == chDash) &&
  701.          (fBuffer[fStart++]!= DURATION_STARTER ))
  702.     {
  703.         ThrowXML1(SchemaDateTimeException
  704.                 , XMLExcepts::DateTime_dur_noP
  705.                 , fBuffer);
  706.     }
  707.     // java code
  708.     //date[utc]=(c=='-')?'-':0;
  709.     //fValue[utc] = UTC_STD;
  710.     fValue[utc] = (fBuffer[0] == chDash? UTC_NEG : UTC_STD);
  711.     int negate = ( fBuffer[0] == chDash ? -1 : 1);
  712.     //
  713.     // No negative value is allowed after 'P'
  714.     //
  715.     // eg P-1234, invalid
  716.     //
  717.     if (indexOf(fStart, fEnd, chDash) != NOT_FOUND)
  718.     {
  719.         ThrowXML1(SchemaDateTimeException
  720.                 , XMLExcepts::DateTime_dur_DashNotFirst
  721.                 , fBuffer);
  722.     }
  723.     //at least one number and designator must be seen after P
  724.     bool designator = false;
  725.     int endDate = indexOf(fStart, fEnd, DATETIME_SEPARATOR);
  726.     if ( endDate == NOT_FOUND )
  727.     {
  728.         endDate = fEnd;  // 'T' absent
  729.     }
  730.     //find 'Y'
  731.     int end = indexOf(fStart, endDate, DURATION_Y);
  732.     if ( end != NOT_FOUND )
  733.     {
  734.         //scan year
  735.         fValue[CentYear] = negate * parseInt(fStart, end);
  736.         fStart = end+1;
  737.         designator = true;
  738.     }
  739.     end = indexOf(fStart, endDate, DURATION_M);
  740.     if ( end != NOT_FOUND )
  741.     {
  742.         //scan month
  743.         fValue[Month] = negate * parseInt(fStart, end);
  744.         fStart = end+1;
  745.         designator = true;
  746.     }
  747.     end = indexOf(fStart, endDate, DURATION_D);
  748.     if ( end != NOT_FOUND )
  749.     {
  750.         //scan day
  751.         fValue[Day] = negate * parseInt(fStart,end);
  752.         fStart = end+1;
  753.         designator = true;
  754.     }
  755.     if ( (fEnd == endDate) &&   // 'T' absent
  756.          (fStart != fEnd)   )   // something after Day
  757.     {
  758.         ThrowXML1(SchemaDateTimeException
  759.                 , XMLExcepts::DateTime_dur_inv_b4T
  760.                 , fBuffer);
  761.     }
  762.     if ( fEnd != endDate ) // 'T' present
  763.     {
  764.         //scan hours, minutes, seconds
  765.         //
  766.         // skip 'T' first
  767.         end = indexOf(++fStart, fEnd, DURATION_H);
  768.         if ( end != NOT_FOUND )
  769.         {
  770.             //scan hours
  771.             fValue[Hour] = negate * parseInt(fStart, end);
  772.             fStart = end+1;
  773.             designator = true;
  774.         }
  775.         end = indexOf(fStart, fEnd, DURATION_M);
  776.         if ( end != NOT_FOUND )
  777.         {
  778.             //scan min
  779.             fValue[Minute] = negate * parseInt(fStart, end);
  780.             fStart = end+1;
  781.             designator = true;
  782.         }
  783.         end = indexOf(fStart, fEnd, DURATION_S);
  784.         if ( end != NOT_FOUND )
  785.         {
  786.             //scan seconds
  787.             int mlsec = indexOf (fStart, end, MILISECOND_SEPARATOR);
  788.             /***
  789.              * Schema Errata: E2-23
  790.              * at least one digit must follow the decimal point if it appears. 
  791.              * That is, the value of the seconds component must conform 
  792.              * to the following pattern: [0-9]+(.[0-9]+)? 
  793.              */
  794.             if ( mlsec != NOT_FOUND )
  795.             {
  796.                 /***
  797.                  * make usure there is something after the '.' and before the end.
  798.                  */
  799.                 if ( mlsec+1 == end )
  800.                 {
  801.                     ThrowXML1(SchemaDateTimeException
  802.                             , XMLExcepts::DateTime_dur_inv_seconds
  803.                             ,fBuffer);
  804.                 }
  805.                 fValue[Second]     = negate * parseInt(fStart, mlsec);
  806.                 fValue[MiliSecond] = negate * parseInt(mlsec+1, end);
  807.             }
  808.             else
  809.             {
  810.                 fValue[Second] = negate * parseInt(fStart,end);
  811.             }
  812.             fStart = end+1;
  813.             designator = true;
  814.         }
  815.         // no additional data should appear after last item
  816.         // P1Y1M1DT is illigal value as well
  817.         if ( (fStart != fEnd) ||
  818.               fBuffer[--fStart] == DATETIME_SEPARATOR )
  819.         {
  820.             ThrowXML1(SchemaDateTimeException
  821.                     , XMLExcepts::DateTime_dur_NoTimeAfterT
  822.                     ,fBuffer);
  823.         }
  824.     }
  825.     if ( !designator )
  826.     {
  827.         ThrowXML1(SchemaDateTimeException
  828.                 , XMLExcepts::DateTime_dur_NoElementAtAll
  829.                 , fBuffer);
  830.     }
  831. }
  832. // ---------------------------------------------------------------------------
  833. //  Scanners
  834. // ---------------------------------------------------------------------------
  835. //
  836. // [-]{CCYY-MM-DD}
  837. //
  838. // Note: CCYY could be more than 4 digits
  839. //       Assuming fStart point to the beginning of the Date Section
  840. //       fStart updated to point to the position right AFTER the second 'D'
  841. //       Since the lenght of CCYY might be variable, we can't check format upfront
  842. //
  843. void XMLDateTime::getDate()
  844. {
  845.     // Ensure enough chars in buffer
  846.     if ( (fStart+YMD_MIN_SIZE) > fEnd)
  847.         ThrowXML1(SchemaDateTimeException
  848.                 , XMLExcepts::DateTime_date_incomplete
  849.                 , fBuffer);
  850.     getYearMonth();    // Scan YearMonth and
  851.                        // fStart point to the next '-'
  852.     if (fBuffer[fStart++] != DATE_SEPARATOR)
  853.     {
  854.         ThrowXML1(SchemaDateTimeException
  855.                 , XMLExcepts::DateTime_date_invalid
  856.                 , fBuffer);
  857.         //("CCYY-MM must be followed by '-' sign");
  858.     }
  859.     fValue[Day] = parseInt(fStart, fStart+2);
  860.     fStart += 2 ;  //fStart points right after the Day
  861.     return;
  862. }
  863. //
  864. // hh:mm:ss[.msssss]['Z']
  865. // hh:mm:ss[.msssss][['+'|'-']hh:mm]
  866. // 012345678
  867. //
  868. // Note: Assuming fStart point to the beginning of the Time Section
  869. //       fStart updated to point to the position right AFTER the second 's'
  870. //                                                  or ms if any
  871. //
  872. void XMLDateTime::getTime()
  873. {
  874.     // Ensure enough chars in buffer
  875.     if ( (fStart+TIME_MIN_SIZE) > fEnd)
  876.         ThrowXML1(SchemaDateTimeException
  877.                 , XMLExcepts::DateTime_time_incomplete
  878.                 , fBuffer);
  879.         //"Imcomplete Time Format"
  880.     // check (fixed) format first
  881.     if ((fBuffer[fStart + 2] != TIME_SEPARATOR) ||
  882.         (fBuffer[fStart + 5] != TIME_SEPARATOR)  )
  883.     {
  884.         ThrowXML1(SchemaDateTimeException
  885.                 , XMLExcepts::DateTime_time_invalid
  886.                 , fBuffer);
  887.         //("Error in parsing time" );
  888.     }
  889.     //
  890.     // get hours, minute and second
  891.     //
  892.     fValue[Hour]   = parseInt(fStart + 0, fStart + 2);
  893.     fValue[Minute] = parseInt(fStart + 3, fStart + 5);
  894.     fValue[Second] = parseInt(fStart + 6, fStart + 8);
  895.     fStart += 8;
  896.     // to see if any ms and/or utc part after that
  897.     if (fStart >= fEnd)
  898.         return;
  899.     //find UTC sign if any
  900.     int sign = findUTCSign(fStart);
  901.     //parse miliseconds
  902.     int milisec = (fBuffer[fStart] == MILISECOND_SEPARATOR)? fStart : NOT_FOUND;
  903.     if ( milisec != NOT_FOUND )
  904.     {
  905.         fStart++;   // skip the '.'
  906.         // make sure we have some thing between the '.' and fEnd
  907.         if (fStart >= fEnd)
  908.         {
  909.             ThrowXML1(SchemaDateTimeException
  910.                     , XMLExcepts::DateTime_ms_noDigit
  911.                     , fBuffer);
  912.             //("ms shall be present once '.' is present" );
  913.         }
  914.         if ( sign == NOT_FOUND )
  915.         {
  916.             fValue[MiliSecond] = parseInt(fStart, fEnd);  //get ms between '.' and fEnd
  917.             fStart = fEnd;
  918.         }
  919.         else
  920.         {
  921.             fValue[MiliSecond] = parseInt(fStart, sign);  //get ms between UTC sign and fEnd
  922.         }
  923. }
  924.     else if(sign == 0 || sign != fStart)
  925.     {
  926.         // seconds has more than 2 digits
  927.         ThrowXML1(SchemaDateTimeException
  928.                 , XMLExcepts::DateTime_min_invalid
  929.                 , fBuffer);
  930.     }
  931.     //parse UTC time zone (hh:mm)
  932.     if ( sign > 0 ) {
  933.         getTimeZone(sign);
  934.     }
  935. }
  936. //
  937. // [-]{CCYY-MM}
  938. //
  939. // Note: CCYY could be more than 4 digits
  940. //       fStart updated to point AFTER the second 'M' (probably meet the fEnd)
  941. //
  942. void XMLDateTime::getYearMonth()
  943. {
  944.     // Ensure enough chars in buffer
  945.     if ( (fStart+YMONTH_MIN_SIZE) > fEnd)
  946.         ThrowXML1(SchemaDateTimeException
  947.                 , XMLExcepts::DateTime_ym_incomplete
  948.                 , fBuffer);
  949.         //"Imcomplete YearMonth Format";
  950.     // skip the first leading '-'
  951.     int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;
  952.     //
  953.     // search for year separator '-'
  954.     //
  955.     int yearSeparator = indexOf(start, fEnd, DATE_SEPARATOR);
  956.     if ( yearSeparator == NOT_FOUND)
  957.         ThrowXML1(SchemaDateTimeException
  958.                 , XMLExcepts::DateTime_ym_invalid
  959.                 , fBuffer);
  960.         //("Year separator is missing or misplaced");
  961.     fValue[CentYear] = parseIntYear(yearSeparator);
  962.     fStart = yearSeparator + 1;  //skip the '-' and point to the first M
  963.     //
  964.     //gonna check we have enough byte for month
  965.     //
  966.     if ((fStart + 2) > fEnd )
  967.         ThrowXML1(SchemaDateTimeException
  968.                 , XMLExcepts::DateTime_ym_noMonth
  969.                 , fBuffer);
  970.         //"no month in buffer"
  971.     fValue[Month] = parseInt(fStart, yearSeparator + 3);
  972.     fStart += 2;  //fStart points right after the MONTH
  973.     return;
  974. }
  975. void XMLDateTime::parseTimeZone()
  976. {
  977.     if ( fStart < fEnd )
  978.     {
  979.         int sign = findUTCSign(fStart);
  980.         if ( sign < 0 )
  981.         {
  982.             ThrowXML1(SchemaDateTimeException
  983.                     , XMLExcepts::DateTime_tz_noUTCsign
  984.                     , fBuffer);
  985.             //("Error in month parsing");
  986.         }
  987.         else
  988.         {
  989.             getTimeZone(sign);
  990.         }
  991.     }
  992.     return;
  993. }
  994. //
  995. // 'Z'
  996. // ['+'|'-']hh:mm
  997. //
  998. // Note: Assuming fStart points to the beginning of TimeZone section
  999. //       fStart updated to meet fEnd
  1000. //
  1001. void XMLDateTime::getTimeZone(const int sign)
  1002. {
  1003.     if ( fBuffer[sign] == UTC_STD_CHAR )
  1004.     {
  1005.         if ((sign + 1) != fEnd )
  1006.         {
  1007.             ThrowXML1(SchemaDateTimeException
  1008.                     , XMLExcepts::DateTime_tz_stuffAfterZ
  1009.                     , fBuffer);
  1010.             //"Error in parsing time zone");
  1011.         }
  1012.         return;
  1013.     }
  1014.     //
  1015.     // otherwise, it has to be this format
  1016.     // '[+|-]'hh:mm
  1017.     //    1   23456 7
  1018.     //   sign      fEnd
  1019.     //
  1020.     if ( ( ( sign + TIMEZONE_SIZE + 1) != fEnd )      ||
  1021.          ( fBuffer[sign + 3] != TIMEZONE_SEPARATOR ) )
  1022.     {
  1023.         ThrowXML1(SchemaDateTimeException
  1024.                 , XMLExcepts::DateTime_tz_invalid
  1025.                 , fBuffer);
  1026.         //("Error in parsing time zone");
  1027.     }
  1028.     fTimeZone[hh] = parseInt(sign+1, sign+3);
  1029.     fTimeZone[mm] = parseInt(sign+4, fEnd);
  1030.         
  1031.     return;
  1032. }
  1033. // ---------------------------------------------------------------------------
  1034. //  Validator and normalizer
  1035. // ---------------------------------------------------------------------------
  1036. /**
  1037.  * If timezone present - normalize dateTime  [E Adding durations to dateTimes]
  1038.  *
  1039.  * @param date   CCYY-MM-DDThh:mm:ss+03
  1040.  * @return CCYY-MM-DDThh:mm:ssZ
  1041.  */
  1042. void XMLDateTime::normalize()
  1043. {
  1044.     if ((fValue[utc] == UTC_UNKNOWN) ||
  1045.         (fValue[utc] == UTC_STD)      )
  1046.         return;
  1047.     int negate = (fValue[utc] == UTC_POS)? -1: 1;
  1048.     // add mins
  1049.     int temp = fValue[Minute] + negate * fTimeZone[mm];
  1050.     int carry = fQuotient(temp, 60);
  1051.     fValue[Minute] = mod(temp, 60, carry);
  1052.     //add hours
  1053.     temp = fValue[Hour] + negate * fTimeZone[hh] + carry;
  1054.     carry = fQuotient(temp, 24);
  1055.     fValue[Hour] = mod(temp, 24, carry);
  1056.     fValue[Day] += carry;
  1057.     while (1)
  1058.     {
  1059.         temp = maxDayInMonthFor(fValue[CentYear], fValue[Month]);
  1060.         if (fValue[Day] < 1)
  1061.         {
  1062.             fValue[Day] += maxDayInMonthFor(fValue[CentYear], fValue[Month] - 1);
  1063.             carry = -1;
  1064.         }
  1065.         else if ( fValue[Day] > temp )
  1066.         {
  1067.             fValue[Day] -= temp;
  1068.             carry = 1;
  1069.         }
  1070.         else
  1071.         {
  1072.             break;
  1073.         }
  1074.         temp = fValue[Month] + carry;
  1075.         fValue[Month] = modulo(temp, 1, 13);
  1076.         fValue[CentYear] += fQuotient(temp, 1, 13);
  1077.     }
  1078.     // set to normalized
  1079.     fValue[utc] = UTC_STD;
  1080.     return;
  1081. }
  1082. void XMLDateTime::validateDateTime() const
  1083. {
  1084.     //REVISIT: should we throw an exception for not valid dates
  1085.     //          or reporting an error message should be sufficient?
  1086.     if ( fValue[CentYear] == 0 )
  1087.     {
  1088.         ThrowXML1(SchemaDateTimeException
  1089.                 , XMLExcepts::DateTime_year_zero
  1090.                 , fBuffer);
  1091.         //"The year "0000" is an illegal year value");
  1092.     }
  1093.     if ( fValue[Month] < 1  ||
  1094.          fValue[Month] > 12  )
  1095.     {
  1096.         ThrowXML1(SchemaDateTimeException
  1097.                 , XMLExcepts::DateTime_mth_invalid
  1098.                 , fBuffer);
  1099. //"The month must have values 1 to 12");
  1100.     }
  1101.     //validate days
  1102.     if ( fValue[Day] > maxDayInMonthFor( fValue[CentYear], fValue[Month]) ||
  1103.          fValue[Day] == 0 )
  1104.     {
  1105.         ThrowXML1(SchemaDateTimeException
  1106.                 , XMLExcepts::DateTime_day_invalid
  1107.                 , fBuffer);
  1108.         //"The day must have values 1 to 31");
  1109.     }
  1110.     //validate hours
  1111.     if ((fValue[Hour] < 0)  ||
  1112.         (fValue[Hour] > 24) ||
  1113.         ((fValue[Hour] == 24) && ((fValue[Minute] !=0) ||
  1114.                                   (fValue[Second] !=0) ||
  1115.                                   (fValue[MiliSecond] !=0))))
  1116.     {
  1117.         ThrowXML1(SchemaDateTimeException
  1118.                 , XMLExcepts::DateTime_hour_invalid
  1119.                 , fBuffer);
  1120.         //("Hour must have values 0-23");
  1121.     }
  1122.     //validate minutes
  1123.     if ( fValue[Minute] < 0 ||
  1124.          fValue[Minute] > 59 )
  1125.     {
  1126.         ThrowXML1(SchemaDateTimeException
  1127.                 , XMLExcepts::DateTime_min_invalid
  1128.                 , fBuffer);
  1129.         //"Minute must have values 0-59");
  1130.     }
  1131.     //validate seconds
  1132.     if ( fValue[Second] < 0 ||
  1133.          fValue[Second] > 60 )
  1134.     {
  1135.         ThrowXML1(SchemaDateTimeException
  1136.                 , XMLExcepts::DateTime_second_invalid
  1137.                 , fBuffer);
  1138.         //"Second must have values 0-60");
  1139.     }
  1140.     //validate time-zone hours
  1141.     if ( (abs(fTimeZone[hh]) > 14) ||
  1142.          ((abs(fTimeZone[hh]) == 14) && (fTimeZone[mm] != 0)) )
  1143.     {
  1144.         ThrowXML1(SchemaDateTimeException
  1145.                 , XMLExcepts::DateTime_tz_hh_invalid
  1146.                 , fBuffer);
  1147.         //"Time zone should have range -14..+14");
  1148.     }
  1149.     //validate time-zone minutes
  1150.     if ( abs(fTimeZone[mm]) > 59 )
  1151.     {
  1152.         ThrowXML1(SchemaDateTimeException
  1153.                 , XMLExcepts::DateTime_min_invalid
  1154.                 , fBuffer);
  1155.         //("Minute must have values 0-59");
  1156.     }
  1157.     return;
  1158. }
  1159. // -----------------------------------------------------------------------
  1160. // locator and converter
  1161. // -----------------------------------------------------------------------
  1162. int XMLDateTime::indexOf(const int start, const int end, const XMLCh ch) const
  1163. {
  1164.     for ( int i = start; i < end; i++ )
  1165.         if ( fBuffer[i] == ch )
  1166.             return i;
  1167.     return NOT_FOUND;
  1168. }
  1169. int XMLDateTime::findUTCSign (const int start)
  1170. {
  1171.     int  pos;
  1172.     for ( int index = start; index < fEnd; index++ )
  1173.     {
  1174.         pos = XMLString::indexOf(UTC_SET, fBuffer[index]);
  1175.         if ( pos != NOT_FOUND)
  1176.         {
  1177.             fValue[utc] = pos+1;   // refer to utcType, there is 1 diff
  1178.             return index;
  1179.         }
  1180.     }
  1181.     return NOT_FOUND;
  1182. }
  1183. //
  1184. // Note:
  1185. //    start: starting point in fBuffer
  1186. //    end:   ending point in fBuffer (exclusive)
  1187. //    fStart NOT updated
  1188. //
  1189. int XMLDateTime::parseInt(const int start, const int end) const
  1190. {
  1191.     XMLCh* strToScan = (XMLCh*) fMemoryManager->allocate
  1192.     (
  1193.         (end - start + 1) * sizeof(XMLCh)
  1194.     );//new XMLCh[end - start + 1];
  1195.     ArrayJanitor<XMLCh>  jname(strToScan, fMemoryManager);
  1196.     XMLString::subString(strToScan, fBuffer, start, end);
  1197.     unsigned int retVal;
  1198.     XMLString::textToBin(strToScan, retVal);
  1199.     return (int) retVal;
  1200. }
  1201. //
  1202. // [-]CCYY
  1203. //
  1204. // Note: start from fStart
  1205. //       end (exclusive)
  1206. //       fStart NOT updated
  1207. //
  1208. int XMLDateTime::parseIntYear(const int end) const
  1209. {
  1210.     // skip the first leading '-'
  1211.     int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;
  1212.     int length = end - start;
  1213.     if (length < 4)
  1214.     {
  1215.         ThrowXML1(SchemaDateTimeException
  1216.                 , XMLExcepts::DateTime_year_tooShort
  1217.                 , fBuffer);
  1218.         //"Year must have 'CCYY' format");
  1219.     }
  1220.     else if (length > 4 &&
  1221.              fBuffer[start] == chDigit_0)
  1222.     {
  1223.         ThrowXML1(SchemaDateTimeException
  1224.                 , XMLExcepts::DateTime_year_leadingZero
  1225.                 , fBuffer);
  1226.         //"Leading zeros are required if the year value would otherwise have fewer than four digits;
  1227.         // otherwise they are forbidden");
  1228.     }
  1229.     bool negative = (fBuffer[0] == chDash);
  1230.     int  yearVal = parseInt((negative ? 1 : 0), end);
  1231.     return ( negative ? (-1) * yearVal : yearVal );
  1232. }
  1233. XERCES_CPP_NAMESPACE_END