XMLDateTime.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:36k
源码类别:

xml/soap/webservice

开发平台:

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