GME  13
XMLDateTime.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: XMLDateTime.cpp 932887 2010-04-11 13:04:59Z borisk $
00020  */
00021 
00022 // ---------------------------------------------------------------------------
00023 //  Includes
00024 // ---------------------------------------------------------------------------
00025 #include <stdlib.h>
00026 #include <assert.h>
00027 #include <errno.h>
00028 
00029 #include <xercesc/util/XMLDateTime.hpp>
00030 #include <xercesc/util/XMLString.hpp>
00031 #include <xercesc/util/XMLUni.hpp>
00032 #include <xercesc/util/Janitor.hpp>
00033 #include <xercesc/util/NumberFormatException.hpp>
00034 
00035 XERCES_CPP_NAMESPACE_BEGIN
00036 
00037 //
00038 // constants used to process raw data (fBuffer)
00039 //
00040 // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}['Z']
00041 //                                [{+|-}hh:mm']
00042 //
00043 
00044 static const XMLCh DURATION_STARTER     = chLatin_P;              // 'P'
00045 static const XMLCh DURATION_Y           = chLatin_Y;              // 'Y'
00046 static const XMLCh DURATION_M           = chLatin_M;              // 'M'
00047 static const XMLCh DURATION_D           = chLatin_D;              // 'D'
00048 static const XMLCh DURATION_H           = chLatin_H;              // 'H'
00049 static const XMLCh DURATION_S           = chLatin_S;              // 'S'
00050 
00051 static const XMLCh DATE_SEPARATOR       = chDash;                 // '-'
00052 static const XMLCh TIME_SEPARATOR       = chColon;                // ':'
00053 static const XMLCh TIMEZONE_SEPARATOR   = chColon;                // ':'
00054 static const XMLCh DATETIME_SEPARATOR   = chLatin_T;              // 'T'
00055 static const XMLCh MILISECOND_SEPARATOR = chPeriod;               // '.'
00056 
00057 static const XMLCh UTC_STD_CHAR         = chLatin_Z;              // 'Z'
00058 static const XMLCh UTC_POS_CHAR         = chPlus;                 // '+'
00059 static const XMLCh UTC_NEG_CHAR         = chDash;                 // '-'
00060 
00061 static const XMLCh UTC_SET[]            = {UTC_STD_CHAR           //"Z+-"
00062                                          , UTC_POS_CHAR
00063                                          , UTC_NEG_CHAR
00064                                          , chNull};
00065 
00066 static const XMLSize_t YMD_MIN_SIZE    = 10;   // CCYY-MM-DD
00067 static const XMLSize_t YMONTH_MIN_SIZE = 7;    // CCYY_MM
00068 static const XMLSize_t TIME_MIN_SIZE   = 8;    // hh:mm:ss
00069 static const XMLSize_t TIMEZONE_SIZE   = 5;    // hh:mm
00070 static const XMLSize_t DAY_SIZE        = 5;    // ---DD
00071 //static const XMLSize_t MONTH_SIZE      = 6;    // --MM--
00072 static const XMLSize_t MONTHDAY_SIZE   = 7;    // --MM-DD
00073 static const int NOT_FOUND       = -1;
00074 
00075 //define constants to be used in assigning default values for
00076 //all date/time excluding duration
00077 static const int YEAR_DEFAULT  = 2000;
00078 static const int MONTH_DEFAULT = 01;
00079 static const int DAY_DEFAULT   = 15;
00080 
00081 // order-relation on duration is a partial order. The dates below are used to
00082 // for comparison of 2 durations, based on the fact that
00083 // duration x and y is x<=y iff s+x<=s+y
00084 // see 3.2.6 duration W3C schema datatype specs
00085 //
00086 // the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
00087 static const int DATETIMES[][XMLDateTime::TOTAL_SIZE] =
00088 {
00089     {1696, 9, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
00090         {1697, 2, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
00091         {1903, 3, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD},
00092         {1903, 7, 1, 0, 0, 0, 0, XMLDateTime::UTC_STD}
00093 };
00094 
00095 // ---------------------------------------------------------------------------
00096 //  local methods
00097 // ---------------------------------------------------------------------------
00098 static inline int fQuotient(int a, int b)
00099 {
00100     div_t div_result = div(a, b);
00101     return div_result.quot;
00102 }
00103 
00104 static inline int fQuotient(int temp, int low, int high)
00105 {
00106     return fQuotient(temp - low, high - low);
00107 }
00108 
00109 static inline int mod(int a, int b, int quotient)
00110 {
00111         return (a - quotient*b) ;
00112 }
00113 
00114 static inline int modulo (int temp, int low, int high)
00115 {
00116     //modulo(a - low, high - low) + low
00117     int a = temp - low;
00118     int b = high - low;
00119     return (mod (a, b, fQuotient(a, b)) + low) ;
00120 }
00121 
00122 static inline bool isLeapYear(int year)
00123 {
00124     return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
00125 }
00126 
00127 static int maxDayInMonthFor(int year, int month)
00128 {
00129 
00130     if ( month == 4 || month == 6 || month == 9 || month == 11 )
00131     {
00132         return 30;
00133     }
00134     else if ( month==2 )
00135     {
00136         if ( isLeapYear(year) )
00137             return 29;
00138         else
00139             return 28;
00140     }
00141     else
00142     {
00143         return 31;
00144     }
00145 
00146 }
00147 
00148 // ---------------------------------------------------------------------------
00149 //  static methods : for duration
00150 // ---------------------------------------------------------------------------
00164 int XMLDateTime::compare(const XMLDateTime* const pDate1
00165                        , const XMLDateTime* const pDate2
00166                        , bool  strict)
00167 {
00168     //REVISIT: this is unoptimazed vs of comparing 2 durations
00169     //         Algorithm is described in 3.2.6.2 W3C Schema Datatype specs
00170     //
00171 
00172     int resultA, resultB = INDETERMINATE;
00173 
00174     //try and see if the objects are equal
00175     if ( (resultA = compareOrder(pDate1, pDate2)) == EQUAL)
00176         return EQUAL;
00177 
00178     //long comparison algorithm is required
00179     XMLDateTime tempA(XMLPlatformUtils::fgMemoryManager), *pTempA = &tempA;
00180     XMLDateTime tempB(XMLPlatformUtils::fgMemoryManager), *pTempB = &tempB;
00181 
00182     addDuration(pTempA, pDate1, 0);
00183     addDuration(pTempB, pDate2, 0);
00184     resultA = compareOrder(pTempA, pTempB);
00185     if ( resultA == INDETERMINATE )
00186         return INDETERMINATE;
00187 
00188     addDuration(pTempA, pDate1, 1);
00189     addDuration(pTempB, pDate2, 1);
00190     resultB = compareOrder(pTempA, pTempB);
00191     resultA = compareResult(resultA, resultB, strict);
00192     if ( resultA == INDETERMINATE )
00193         return INDETERMINATE;
00194 
00195     addDuration(pTempA, pDate1, 2);
00196     addDuration(pTempB, pDate2, 2);
00197     resultB = compareOrder(pTempA, pTempB);
00198     resultA = compareResult(resultA, resultB, strict);
00199     if ( resultA == INDETERMINATE )
00200         return INDETERMINATE;
00201 
00202     addDuration(pTempA, pDate1, 3);
00203     addDuration(pTempB, pDate2, 3);
00204     resultB = compareOrder(pTempA, pTempB);
00205     resultA = compareResult(resultA, resultB, strict);
00206 
00207     return resultA;
00208 
00209 }
00210 
00211 //
00212 // Form a new XMLDateTime with duration and baseDate array
00213 // Note: C++        Java
00214 //       fNewDate   duration
00215 //       fDuration  date
00216 //
00217 
00218 void XMLDateTime::addDuration(XMLDateTime*             fNewDate
00219                             , const XMLDateTime* const fDuration
00220                             , int index)
00221 
00222 {
00223 
00224     //REVISIT: some code could be shared between normalize() and this method,
00225     //         however is it worth moving it? The structures are different...
00226     //
00227 
00228     fNewDate->reset();
00229     //add months (may be modified additionaly below)
00230     int temp = DATETIMES[index][Month] + fDuration->fValue[Month];
00231     fNewDate->fValue[Month] = modulo(temp, 1, 13);
00232     int carry = fQuotient(temp, 1, 13);
00233     if (fNewDate->fValue[Month] <= 0) {
00234         fNewDate->fValue[Month]+= 12;
00235         carry--;
00236     }
00237 
00238     //add years (may be modified additionaly below)
00239     fNewDate->fValue[CentYear] = DATETIMES[index][CentYear] + fDuration->fValue[CentYear] + carry;
00240 
00241     //add seconds
00242     temp = DATETIMES[index][Second] + fDuration->fValue[Second];
00243     carry = fQuotient (temp, 60);
00244     fNewDate->fValue[Second] =  mod(temp, 60, carry);
00245     if (fNewDate->fValue[Second] < 0) {
00246         fNewDate->fValue[Second]+= 60;
00247         carry--;
00248     }
00249 
00250     //add minutes
00251     temp = DATETIMES[index][Minute] + fDuration->fValue[Minute] + carry;
00252     carry = fQuotient(temp, 60);
00253     fNewDate->fValue[Minute] = mod(temp, 60, carry);
00254     if (fNewDate->fValue[Minute] < 0) {
00255         fNewDate->fValue[Minute]+= 60;
00256         carry--;
00257     }
00258 
00259     //add hours
00260     temp = DATETIMES[index][Hour] + fDuration->fValue[Hour] + carry;
00261     carry = fQuotient(temp, 24);
00262     fNewDate->fValue[Hour] = mod(temp, 24, carry);
00263     if (fNewDate->fValue[Hour] < 0) {
00264         fNewDate->fValue[Hour]+= 24;
00265         carry--;
00266     }
00267 
00268     fNewDate->fValue[Day] = DATETIMES[index][Day] + fDuration->fValue[Day] + carry;
00269 
00270     while ( true )
00271     {
00272         temp = maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]);
00273         if ( fNewDate->fValue[Day] < 1 )
00274         { //original fNewDate was negative
00275             fNewDate->fValue[Day] += maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]-1);
00276             carry = -1;
00277         }
00278         else if ( fNewDate->fValue[Day] > temp )
00279         {
00280             fNewDate->fValue[Day] -= temp;
00281             carry = 1;
00282         }
00283         else
00284         {
00285             break;
00286         }
00287 
00288         temp = fNewDate->fValue[Month] + carry;
00289         fNewDate->fValue[Month] = modulo(temp, 1, 13);
00290         if (fNewDate->fValue[Month] <= 0) {
00291             fNewDate->fValue[Month]+= 12;
00292             fNewDate->fValue[CentYear]--;
00293         }
00294         fNewDate->fValue[CentYear] += fQuotient(temp, 1, 13);
00295     }
00296 
00297     //fNewDate->fValue[utc] = UTC_STD_CHAR;
00298     fNewDate->fValue[utc] = UTC_STD;
00299 }
00300 
00301 int XMLDateTime::compareResult(int resultA
00302                              , int resultB
00303                              , bool strict)
00304 {
00305 
00306     if ( resultB == INDETERMINATE )
00307     {
00308         return INDETERMINATE;
00309     }
00310     else if ( (resultA != resultB) &&
00311               strict                )
00312     {
00313         return INDETERMINATE;
00314     }
00315     else if ( (resultA != resultB) &&
00316               !strict               )
00317     {
00318         if ( (resultA != EQUAL) &&
00319              (resultB != EQUAL)  )
00320         {
00321             return INDETERMINATE;
00322         }
00323         else
00324         {
00325             return (resultA != EQUAL)? resultA : resultB;
00326         }
00327     }
00328 
00329     return resultA;
00330 
00331 }
00332 
00333 // ---------------------------------------------------------------------------
00334 //  static methods : for others
00335 // ---------------------------------------------------------------------------
00336 int XMLDateTime::compare(const XMLDateTime* const pDate1
00337                        , const XMLDateTime* const pDate2)
00338 {
00339 
00340     if (pDate1->fValue[utc] == pDate2->fValue[utc])
00341     {
00342         return XMLDateTime::compareOrder(pDate1, pDate2);
00343     }
00344 
00345     int c1, c2;
00346 
00347     if ( pDate1->isNormalized())
00348     {
00349         c1 = compareResult(pDate1, pDate2, false, UTC_POS);
00350         c2 = compareResult(pDate1, pDate2, false, UTC_NEG);
00351         return getRetVal(c1, c2);
00352     }
00353     else if ( pDate2->isNormalized())
00354     {
00355         c1 = compareResult(pDate1, pDate2, true, UTC_POS);
00356         c2 = compareResult(pDate1, pDate2, true, UTC_NEG);
00357         return getRetVal(c1, c2);
00358     }
00359 
00360     return INDETERMINATE;
00361 }
00362 
00363 int XMLDateTime::compareResult(const XMLDateTime* const pDate1
00364                              , const XMLDateTime* const pDate2
00365                              , bool  set2Left
00366                              , int   utc_type)
00367 {
00368     XMLDateTime tmpDate = (set2Left ? *pDate1 : *pDate2);
00369 
00370     tmpDate.fTimeZone[hh] = 14;
00371     tmpDate.fTimeZone[mm] = 0;
00372     tmpDate.fValue[utc] = utc_type;
00373     tmpDate.normalize();
00374 
00375     return (set2Left? XMLDateTime::compareOrder(&tmpDate, pDate2) :
00376                       XMLDateTime::compareOrder(pDate1, &tmpDate));
00377 }
00378 
00379 int XMLDateTime::compareOrder(const XMLDateTime* const lValue
00380                             , const XMLDateTime* const rValue)
00381                             //, MemoryManager* const memMgr)
00382 {
00383     //
00384     // If any of the them is not normalized() yet,
00385     // we need to do something here.
00386     //
00387     XMLDateTime lTemp = *lValue;
00388     XMLDateTime rTemp = *rValue;
00389 
00390     lTemp.normalize();
00391     rTemp.normalize();
00392 
00393     for ( int i = 0 ; i < TOTAL_SIZE; i++ )
00394     {
00395         if ( lTemp.fValue[i] < rTemp.fValue[i] )
00396         {
00397             return LESS_THAN;
00398         }
00399         else if ( lTemp.fValue[i] > rTemp.fValue[i] )
00400         {
00401             return GREATER_THAN;
00402         }
00403     }
00404 
00405     if ( lTemp.fHasTime)
00406     {
00407         if ( lTemp.fMilliSecond < rTemp.fMilliSecond )
00408         {
00409             return LESS_THAN;
00410         }
00411         else if ( lTemp.fMilliSecond > rTemp.fMilliSecond )
00412         {
00413             return GREATER_THAN;
00414         }
00415     }
00416 
00417     return EQUAL;
00418 }
00419 
00420 // ---------------------------------------------------------------------------
00421 //  ctor and dtor
00422 // ---------------------------------------------------------------------------
00423 XMLDateTime::~XMLDateTime()
00424 {
00425     if (fBuffer)
00426         fMemoryManager->deallocate(fBuffer);//delete[] fBuffer;
00427 }
00428 
00429 XMLDateTime::XMLDateTime(MemoryManager* const manager)
00430 : fStart(0)
00431 , fEnd(0)
00432 , fBufferMaxLen(0)
00433 , fMilliSecond(0)
00434 , fHasTime(false)
00435 , fBuffer(0)
00436 , fMemoryManager(manager)
00437 {
00438     reset();
00439 }
00440 
00441 XMLDateTime::XMLDateTime(const XMLCh* const aString,
00442                          MemoryManager* const manager)
00443 : fStart(0)
00444 , fEnd(0)
00445 , fBufferMaxLen(0)
00446 , fMilliSecond(0)
00447 , fHasTime(false)
00448 , fBuffer(0)
00449 , fMemoryManager(manager)
00450 {
00451     setBuffer(aString);
00452 }
00453 
00454 // -----------------------------------------------------------------------
00455 // Copy ctor and Assignment operators
00456 // -----------------------------------------------------------------------
00457 
00458 XMLDateTime::XMLDateTime(const XMLDateTime &toCopy)
00459 : XMLNumber(toCopy)
00460 , fBufferMaxLen(0)
00461 , fBuffer(0)
00462 , fMemoryManager(toCopy.fMemoryManager)
00463 {
00464     copy(toCopy);
00465 }
00466 
00467 XMLDateTime& XMLDateTime::operator=(const XMLDateTime& rhs)
00468 {
00469     if (this == &rhs)
00470         return *this;
00471 
00472     copy(rhs);
00473     return *this;
00474 }
00475 
00476 // -----------------------------------------------------------------------
00477 // Implementation of Abstract Interface
00478 // -----------------------------------------------------------------------
00479 
00480 //
00481 // We may simply return the handle to fBuffer
00482 //
00483 XMLCh*  XMLDateTime::getRawData() const
00484 {
00485     return fBuffer;
00486 }
00487 
00488 const XMLCh*  XMLDateTime::getFormattedString() const
00489 {
00490     return getRawData();
00491 }
00492 
00493 int XMLDateTime::getSign() const
00494 {
00495     return 0;
00496 }
00497 
00498 // ---------------------------------------------------------------------------
00499 //  Parsers
00500 // ---------------------------------------------------------------------------
00501 
00502 //
00503 // [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}[TimeZone]
00504 //
00505 void XMLDateTime::parseDateTime()
00506 {
00507     if (!initParser())
00508         ThrowXMLwithMemMgr1(SchemaDateTimeException
00509                 , XMLExcepts::DateTime_dt_invalid
00510                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00511                 , fMemoryManager);
00512 
00513     getDate();
00514 
00515     //fStart is supposed to point to 'T'
00516     if (fBuffer[fStart++] != DATETIME_SEPARATOR)
00517           ThrowXMLwithMemMgr1(SchemaDateTimeException
00518                 , XMLExcepts::DateTime_dt_missingT
00519                 , fBuffer
00520                 , fMemoryManager);
00521 
00522     getTime();
00523     validateDateTime();
00524     normalize();
00525     fHasTime = true;
00526 }
00527 
00528 //
00529 // [-]{CCYY-MM-DD}[TimeZone]
00530 //
00531 void XMLDateTime::parseDate()
00532 {
00533     if (!initParser())
00534       ThrowXMLwithMemMgr1(SchemaDateTimeException
00535                 , XMLExcepts::DateTime_date_invalid
00536                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00537                 , fMemoryManager);
00538 
00539     getDate();
00540     parseTimeZone();
00541     validateDateTime();
00542     normalize();
00543 }
00544 
00545 void XMLDateTime::parseTime()
00546 {
00547     if (!initParser())
00548         ThrowXMLwithMemMgr1(SchemaDateTimeException
00549                 , XMLExcepts::DateTime_time_invalid
00550                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00551                 , fMemoryManager);
00552 
00553     // time initialize to default values
00554     fValue[CentYear]= YEAR_DEFAULT;
00555     fValue[Month]   = MONTH_DEFAULT;
00556     fValue[Day]     = DAY_DEFAULT;
00557 
00558     getTime();
00559 
00560     validateDateTime();
00561     normalize();
00562     fHasTime = true;
00563 }
00564 
00565 //
00566 // {---DD}[TimeZone]
00567 //  01234
00568 //
00569 void XMLDateTime::parseDay()
00570 {
00571     if (!initParser())
00572         ThrowXMLwithMemMgr1(SchemaDateTimeException
00573                 , XMLExcepts::DateTime_gDay_invalid
00574                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00575                 , fMemoryManager);
00576 
00577     if (fBuffer[0] != DATE_SEPARATOR ||
00578         fBuffer[1] != DATE_SEPARATOR ||
00579         fBuffer[2] != DATE_SEPARATOR  )
00580     {
00581         ThrowXMLwithMemMgr1(SchemaDateTimeException
00582                 , XMLExcepts::DateTime_gDay_invalid
00583                 , fBuffer
00584                 , fMemoryManager);
00585     }
00586 
00587     //initialize values
00588     fValue[CentYear] = YEAR_DEFAULT;
00589     fValue[Month]    = MONTH_DEFAULT;
00590     fValue[Day]      = parseInt(fStart+3, fStart+5);
00591 
00592     if ( DAY_SIZE < fEnd )
00593     {
00594         int pos = XMLString::indexOf(UTC_SET, fBuffer[DAY_SIZE]);
00595         if (pos == -1 )
00596         {
00597             ThrowXMLwithMemMgr1(SchemaDateTimeException
00598                     , XMLExcepts::DateTime_gDay_invalid
00599                     , fBuffer
00600                     , fMemoryManager);
00601         }
00602         else
00603         {
00604             fValue[utc] = pos+1;
00605             getTimeZone(DAY_SIZE);
00606         }
00607     }
00608 
00609     validateDateTime();
00610     normalize();
00611 }
00612 
00613 //
00614 // {--MM--}[TimeZone]
00615 // {--MM}[TimeZone]
00616 //  012345
00617 //
00618 void XMLDateTime::parseMonth()
00619 {
00620     if (!initParser())
00621         ThrowXMLwithMemMgr1(SchemaDateTimeException
00622                 , XMLExcepts::DateTime_gMth_invalid
00623                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00624                 , fMemoryManager);
00625 
00626     if (fBuffer[0] != DATE_SEPARATOR ||
00627         fBuffer[1] != DATE_SEPARATOR  )
00628     {
00629         ThrowXMLwithMemMgr1(SchemaDateTimeException
00630                 , XMLExcepts::DateTime_gMth_invalid
00631                 , fBuffer
00632                 , fMemoryManager);
00633     }
00634 
00635     //set constants
00636     fValue[CentYear] = YEAR_DEFAULT;
00637     fValue[Day]      = DAY_DEFAULT;
00638     fValue[Month]    = parseInt(2, 4);
00639 
00640     // REVISIT: allow both --MM and --MM-- now.
00641     // need to remove the following lines to disallow --MM--
00642     // when the errata is officially in the rec.
00643     fStart = 4;
00644     if ( fEnd >= fStart+2 && fBuffer[fStart] == DATE_SEPARATOR && fBuffer[fStart+1] == DATE_SEPARATOR )
00645     {
00646         fStart += 2;
00647     }
00648 
00649     //
00650     // parse TimeZone if any
00651     //
00652     if ( fStart < fEnd )
00653     {
00654         int pos = XMLString::indexOf(UTC_SET, fBuffer[fStart]);
00655         if ( pos == NOT_FOUND )
00656         {
00657             ThrowXMLwithMemMgr1(SchemaDateTimeException
00658                     , XMLExcepts::DateTime_gMth_invalid
00659                     , fBuffer
00660                     , fMemoryManager);
00661         }
00662         else
00663         {
00664             fValue[utc] = pos+1;
00665             getTimeZone(fStart);
00666         }
00667     }
00668 
00669     validateDateTime();
00670     normalize();
00671 }
00672 
00673 //
00674 //[-]{CCYY}[TimeZone]
00675 // 0  1234
00676 //
00677 void XMLDateTime::parseYear()
00678 {
00679     if (!initParser())
00680         ThrowXMLwithMemMgr1(SchemaDateTimeException
00681                 , XMLExcepts::DateTime_year_invalid
00682                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00683                 , fMemoryManager);
00684 
00685     // skip the first '-' and search for timezone
00686     //
00687     int sign = findUTCSign((fBuffer[0] == chDash) ? 1 : 0);
00688 
00689     if (sign == NOT_FOUND)
00690     {
00691         fValue[CentYear] = parseIntYear(fEnd);
00692     }
00693     else
00694     {
00695         fValue[CentYear] = parseIntYear(sign);
00696         getTimeZone(sign);
00697     }
00698 
00699     //initialize values
00700     fValue[Month] = MONTH_DEFAULT;
00701     fValue[Day]   = DAY_DEFAULT;   //java is 1
00702 
00703     validateDateTime();
00704     normalize();
00705 }
00706 
00707 //
00708 //{--MM-DD}[TimeZone]
00709 // 0123456
00710 //
00711 void XMLDateTime::parseMonthDay()
00712 {
00713     if (!initParser())
00714         ThrowXMLwithMemMgr1(SchemaDateTimeException
00715                 , XMLExcepts::DateTime_gMthDay_invalid
00716                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00717                 , fMemoryManager);
00718 
00719     if (fBuffer[0] != DATE_SEPARATOR ||
00720         fBuffer[1] != DATE_SEPARATOR ||
00721         fBuffer[4] != DATE_SEPARATOR )
00722     {
00723         ThrowXMLwithMemMgr1(SchemaDateTimeException
00724                 , XMLExcepts::DateTime_gMthDay_invalid
00725                 , fBuffer
00726                 , fMemoryManager);
00727     }
00728 
00729 
00730     //initialize
00731     fValue[CentYear] = YEAR_DEFAULT;
00732     fValue[Month]    = parseInt(2, 4);
00733     fValue[Day]      = parseInt(5, 7);
00734 
00735     if ( MONTHDAY_SIZE < fEnd )
00736     {
00737         int pos = XMLString::indexOf(UTC_SET, fBuffer[MONTHDAY_SIZE]);
00738         if ( pos == NOT_FOUND )
00739         {
00740             ThrowXMLwithMemMgr1(SchemaDateTimeException
00741                     , XMLExcepts::DateTime_gMthDay_invalid
00742                     , fBuffer
00743                     , fMemoryManager);
00744         }
00745         else
00746         {
00747             fValue[utc] = pos+1;
00748             getTimeZone(MONTHDAY_SIZE);
00749         }
00750     }
00751 
00752     validateDateTime();
00753     normalize();
00754 }
00755 
00756 void XMLDateTime::parseYearMonth()
00757 {
00758     if (!initParser())
00759         ThrowXMLwithMemMgr1(SchemaDateTimeException
00760                 , XMLExcepts::DateTime_ym_invalid
00761                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00762                 , fMemoryManager);
00763 
00764     // get date
00765     getYearMonth();
00766     fValue[Day] = DAY_DEFAULT;
00767     parseTimeZone();
00768 
00769     validateDateTime();
00770     normalize();
00771 }
00772 
00773 //
00774 //PnYn MnDTnH nMnS: -P1Y2M3DT10H30M
00775 //
00776 // [-]{'P'{[n'Y'][n'M'][n'D']['T'][n'H'][n'M'][n'S']}}
00777 //
00778 //  Note: the n above shall be >= 0
00779 //        if no time element found, 'T' shall be absent
00780 //
00781 void XMLDateTime::parseDuration()
00782 {
00783     if (!initParser())
00784         ThrowXMLwithMemMgr1(SchemaDateTimeException
00785                 , XMLExcepts::DateTime_dur_invalid
00786                 , fBuffer ? fBuffer : XMLUni::fgZeroLenString
00787                 , fMemoryManager);
00788 
00789     // must start with '-' or 'P'
00790     //
00791     XMLCh c = fBuffer[fStart++];
00792     if ( (c != DURATION_STARTER) &&
00793          (c != chDash)            )
00794     {
00795         ThrowXMLwithMemMgr1(SchemaDateTimeException
00796                 , XMLExcepts::DateTime_dur_Start_dashP
00797                 , fBuffer
00798                 , fMemoryManager);
00799     }
00800 
00801     // 'P' must ALWAYS be present in either case
00802     if ( (c == chDash) &&
00803          (fBuffer[fStart++]!= DURATION_STARTER ))
00804     {
00805         ThrowXMLwithMemMgr1(SchemaDateTimeException
00806                 , XMLExcepts::DateTime_dur_noP
00807                 , fBuffer
00808                 , fMemoryManager);
00809     }
00810 
00811     // java code
00812     //date[utc]=(c=='-')?'-':0;
00813     //fValue[utc] = UTC_STD;
00814     fValue[utc] = (fBuffer[0] == chDash? UTC_NEG : UTC_STD);
00815 
00816     int negate = ( fBuffer[0] == chDash ? -1 : 1);
00817 
00818     //
00819     // No negative value is allowed after 'P'
00820     //
00821     // eg P-1234, invalid
00822     //
00823     if (indexOf(fStart, fEnd, chDash) != NOT_FOUND)
00824     {
00825         ThrowXMLwithMemMgr1(SchemaDateTimeException
00826                 , XMLExcepts::DateTime_dur_DashNotFirst
00827                 , fBuffer
00828                 , fMemoryManager);
00829     }
00830 
00831     //at least one number and designator must be seen after P
00832     bool designator = false;
00833 
00834     int endDate = indexOf(fStart, fEnd, DATETIME_SEPARATOR);
00835     if ( endDate == NOT_FOUND )
00836     {
00837         endDate = (int)fEnd;  // 'T' absent
00838     }
00839 
00840     //find 'Y'
00841     int end = indexOf(fStart, endDate, DURATION_Y);
00842     if ( end != NOT_FOUND )
00843     {
00844         //scan year
00845         fValue[CentYear] = negate * parseInt(fStart, end);
00846         fStart = end+1;
00847         designator = true;
00848     }
00849 
00850     end = indexOf(fStart, endDate, DURATION_M);
00851     if ( end != NOT_FOUND )
00852     {
00853         //scan month
00854         fValue[Month] = negate * parseInt(fStart, end);
00855         fStart = end+1;
00856         designator = true;
00857     }
00858 
00859     end = indexOf(fStart, endDate, DURATION_D);
00860     if ( end != NOT_FOUND )
00861     {
00862         //scan day
00863         fValue[Day] = negate * parseInt(fStart,end);
00864         fStart = end+1;
00865         designator = true;
00866     }
00867 
00868     if ( (fEnd == XMLSize_t (endDate)) &&   // 'T' absent
00869          (fStart != fEnd)   )   // something after Day
00870     {
00871         ThrowXMLwithMemMgr1(SchemaDateTimeException
00872                 , XMLExcepts::DateTime_dur_inv_b4T
00873                 , fBuffer
00874                 , fMemoryManager);
00875     }
00876 
00877     if ( fEnd != XMLSize_t (endDate) ) // 'T' present
00878     {
00879         //scan hours, minutes, seconds
00880         //
00881 
00882         // skip 'T' first
00883         end = indexOf(++fStart, fEnd, DURATION_H);
00884         if ( end != NOT_FOUND )
00885         {
00886             //scan hours
00887             fValue[Hour] = negate * parseInt(fStart, end);
00888             fStart = end+1;
00889             designator = true;
00890         }
00891 
00892         end = indexOf(fStart, fEnd, DURATION_M);
00893         if ( end != NOT_FOUND )
00894         {
00895             //scan min
00896             fValue[Minute] = negate * parseInt(fStart, end);
00897             fStart = end+1;
00898             designator = true;
00899         }
00900 
00901         end = indexOf(fStart, fEnd, DURATION_S);
00902         if ( end != NOT_FOUND )
00903         {
00904             //scan seconds
00905             int mlsec = indexOf (fStart, end, MILISECOND_SEPARATOR);
00906 
00907             /***
00908              * Schema Errata: E2-23
00909              * at least one digit must follow the decimal point if it appears.
00910              * That is, the value of the seconds component must conform
00911              * to the following pattern: [0-9]+(.[0-9]+)?
00912              */
00913             if ( mlsec != NOT_FOUND )
00914             {
00915                 /***
00916                  * make usure there is something after the '.' and before the end.
00917                  */
00918                 if ( mlsec+1 == end )
00919                 {
00920                     ThrowXMLwithMemMgr1(SchemaDateTimeException
00921                             , XMLExcepts::DateTime_dur_inv_seconds
00922                             , fBuffer
00923                             , fMemoryManager);
00924                 }
00925 
00926                 fValue[Second]     = negate * parseInt(fStart, mlsec);
00927                 fMilliSecond        = negate * parseMiliSecond(mlsec+1, end);
00928             }
00929             else
00930             {
00931                 fValue[Second] = negate * parseInt(fStart,end);
00932             }
00933 
00934             fStart = end+1;
00935             designator = true;
00936         }
00937 
00938         // no additional data should appear after last item
00939         // P1Y1M1DT is illigal value as well
00940         if ( (fStart != fEnd) ||
00941               fBuffer[--fStart] == DATETIME_SEPARATOR )
00942         {
00943             ThrowXMLwithMemMgr1(SchemaDateTimeException
00944                     , XMLExcepts::DateTime_dur_NoTimeAfterT
00945                     , fBuffer
00946                     , fMemoryManager);
00947         }
00948     }
00949 
00950     if ( !designator )
00951     {
00952         ThrowXMLwithMemMgr1(SchemaDateTimeException
00953                 , XMLExcepts::DateTime_dur_NoElementAtAll
00954                 , fBuffer
00955                 , fMemoryManager);
00956     }
00957 
00958 }
00959 
00960 // ---------------------------------------------------------------------------
00961 //  Scanners
00962 // ---------------------------------------------------------------------------
00963 
00964 //
00965 // [-]{CCYY-MM-DD}
00966 //
00967 // Note: CCYY could be more than 4 digits
00968 //       Assuming fStart point to the beginning of the Date Section
00969 //       fStart updated to point to the position right AFTER the second 'D'
00970 //       Since the lenght of CCYY might be variable, we can't check format upfront
00971 //
00972 void XMLDateTime::getDate()
00973 {
00974 
00975     // Ensure enough chars in buffer
00976     if ( (fStart+YMD_MIN_SIZE) > fEnd)
00977         ThrowXMLwithMemMgr1(SchemaDateTimeException
00978                 , XMLExcepts::DateTime_date_incomplete
00979                 , fBuffer
00980                 , fMemoryManager);
00981 
00982     getYearMonth();    // Scan YearMonth and
00983                        // fStart point to the next '-'
00984 
00985     if (fBuffer[fStart++] != DATE_SEPARATOR)
00986     {
00987         ThrowXMLwithMemMgr1(SchemaDateTimeException
00988                 , XMLExcepts::DateTime_date_invalid
00989                 , fBuffer
00990                 , fMemoryManager);
00991         //("CCYY-MM must be followed by '-' sign");
00992     }
00993 
00994     fValue[Day] = parseInt(fStart, fStart+2);
00995     fStart += 2 ;  //fStart points right after the Day
00996 
00997     return;
00998 }
00999 
01000 //
01001 // hh:mm:ss[.msssss]['Z']
01002 // hh:mm:ss[.msssss][['+'|'-']hh:mm]
01003 // 012345678
01004 //
01005 // Note: Assuming fStart point to the beginning of the Time Section
01006 //       fStart updated to point to the position right AFTER the second 's'
01007 //                                                  or ms if any
01008 //
01009 void XMLDateTime::getTime()
01010 {
01011 
01012     // Ensure enough chars in buffer
01013     if ( (fStart+TIME_MIN_SIZE) > fEnd)
01014         ThrowXMLwithMemMgr1(SchemaDateTimeException
01015                 , XMLExcepts::DateTime_time_incomplete
01016                 , fBuffer
01017                 , fMemoryManager);
01018         //"Imcomplete Time Format"
01019 
01020     // check (fixed) format first
01021     if ((fBuffer[fStart + 2] != TIME_SEPARATOR) ||
01022         (fBuffer[fStart + 5] != TIME_SEPARATOR)  )
01023     {
01024         ThrowXMLwithMemMgr1(SchemaDateTimeException
01025                 , XMLExcepts::DateTime_time_invalid
01026                 , fBuffer
01027                 , fMemoryManager);
01028         //("Error in parsing time" );
01029     }
01030 
01031     //
01032     // get hours, minute and second
01033     //
01034     fValue[Hour]   = parseInt(fStart + 0, fStart + 2);
01035     fValue[Minute] = parseInt(fStart + 3, fStart + 5);
01036     fValue[Second] = parseInt(fStart + 6, fStart + 8);
01037     fStart += 8;
01038 
01039     // to see if any ms and/or utc part after that
01040     if (fStart >= fEnd)
01041         return;
01042 
01043     //find UTC sign if any
01044     int sign = findUTCSign(fStart);
01045 
01046     //parse miliseconds
01047     int milisec = (fBuffer[fStart] == MILISECOND_SEPARATOR)? (int)fStart : NOT_FOUND;
01048     if ( milisec != NOT_FOUND )
01049     {
01050         fStart++;   // skip the '.'
01051         // make sure we have some thing between the '.' and fEnd
01052         if (fStart >= fEnd)
01053         {
01054             ThrowXMLwithMemMgr1(SchemaDateTimeException
01055                     , XMLExcepts::DateTime_ms_noDigit
01056                     , fBuffer
01057                     , fMemoryManager);
01058             //("ms shall be present once '.' is present" );
01059         }
01060 
01061         if ( sign == NOT_FOUND )
01062         {
01063             fMilliSecond = parseMiliSecond(fStart, fEnd);  //get ms between '.' and fEnd
01064             fStart = fEnd;
01065         }
01066         else
01067         {
01068             fMilliSecond = parseMiliSecond(fStart, sign);  //get ms between UTC sign and fEnd
01069         }
01070         }
01071     else if(sign == 0 || XMLSize_t (sign) != fStart)
01072     {
01073         // seconds has more than 2 digits
01074         ThrowXMLwithMemMgr1(SchemaDateTimeException
01075                 , XMLExcepts::DateTime_min_invalid
01076                 , fBuffer
01077                 , fMemoryManager);
01078     }
01079 
01080     //parse UTC time zone (hh:mm)
01081     if ( sign > 0 ) {
01082         getTimeZone(sign);
01083     }
01084 
01085 }
01086 
01087 //
01088 // [-]{CCYY-MM}
01089 //
01090 // Note: CCYY could be more than 4 digits
01091 //       fStart updated to point AFTER the second 'M' (probably meet the fEnd)
01092 //
01093 void XMLDateTime::getYearMonth()
01094 {
01095 
01096     // Ensure enough chars in buffer
01097     if ( (fStart+YMONTH_MIN_SIZE) > fEnd)
01098         ThrowXMLwithMemMgr1(SchemaDateTimeException
01099                 , XMLExcepts::DateTime_ym_incomplete
01100                 , fBuffer
01101                 , fMemoryManager);
01102         //"Imcomplete YearMonth Format";
01103 
01104     // skip the first leading '-'
01105     XMLSize_t start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;
01106 
01107     //
01108     // search for year separator '-'
01109     //
01110     int yearSeparator = indexOf(start, fEnd, DATE_SEPARATOR);
01111     if ( yearSeparator == NOT_FOUND)
01112         ThrowXMLwithMemMgr1(SchemaDateTimeException
01113                 , XMLExcepts::DateTime_ym_invalid
01114                 , fBuffer
01115                 , fMemoryManager);
01116         //("Year separator is missing or misplaced");
01117 
01118     fValue[CentYear] = parseIntYear(yearSeparator);
01119     fStart = yearSeparator + 1;  //skip the '-' and point to the first M
01120 
01121     //
01122     //gonna check we have enough byte for month
01123     //
01124     if ((fStart + 2) > fEnd )
01125         ThrowXMLwithMemMgr1(SchemaDateTimeException
01126                 , XMLExcepts::DateTime_ym_noMonth
01127                 , fBuffer
01128                 , fMemoryManager);
01129         //"no month in buffer"
01130 
01131     fValue[Month] = parseInt(fStart, yearSeparator + 3);
01132     fStart += 2;  //fStart points right after the MONTH
01133 
01134     return;
01135 }
01136 
01137 void XMLDateTime::parseTimeZone()
01138 {
01139     //fStart points right after the date
01140         if ( fStart < fEnd ) {
01141         int pos = XMLString::indexOf(UTC_SET, fBuffer[fStart]);
01142         if (pos == NOT_FOUND) {
01143             ThrowXMLwithMemMgr1(SchemaDateTimeException
01144                     , XMLExcepts::DateTime_tz_noUTCsign
01145                     , fBuffer
01146                     , fMemoryManager);
01147                 }
01148                 else {
01149             fValue[utc] = pos+1;
01150                 getTimeZone(fStart);
01151                 }
01152     }
01153 
01154     return;
01155 }
01156 
01157 //
01158 // 'Z'
01159 // ['+'|'-']hh:mm
01160 //
01161 // Note: Assuming fStart points to the beginning of TimeZone section
01162 //       fStart updated to meet fEnd
01163 //
01164 void XMLDateTime::getTimeZone(const XMLSize_t sign)
01165 {
01166 
01167     if ( fBuffer[sign] == UTC_STD_CHAR )
01168     {
01169         if ((sign + 1) != fEnd )
01170         {
01171             ThrowXMLwithMemMgr1(SchemaDateTimeException
01172                     , XMLExcepts::DateTime_tz_stuffAfterZ
01173                     , fBuffer
01174                     , fMemoryManager);
01175             //"Error in parsing time zone");
01176         }
01177 
01178         return;
01179     }
01180 
01181     //
01182     // otherwise, it has to be this format
01183     // '[+|-]'hh:mm
01184     //    1   23456 7
01185     //   sign      fEnd
01186     //
01187     if ( ( ( sign + TIMEZONE_SIZE + 1) != fEnd )      ||
01188          ( fBuffer[sign + 3] != TIMEZONE_SEPARATOR ) )
01189     {
01190         ThrowXMLwithMemMgr1(SchemaDateTimeException
01191                 , XMLExcepts::DateTime_tz_invalid
01192                 , fBuffer
01193                 , fMemoryManager);
01194         //("Error in parsing time zone");
01195     }
01196 
01197     fTimeZone[hh] = parseInt(sign+1, sign+3);
01198     fTimeZone[mm] = parseInt(sign+4, fEnd);
01199 
01200     return;
01201 }
01202 
01203 // ---------------------------------------------------------------------------
01204 //  Validator and normalizer
01205 // ---------------------------------------------------------------------------
01206 
01213 void XMLDateTime::normalize()
01214 {
01215 
01216     if ((fValue[utc] == UTC_UNKNOWN) ||
01217         (fValue[utc] == UTC_STD)      )
01218         return;
01219 
01220     int negate = (fValue[utc] == UTC_POS)? -1: 1;
01221     int temp;
01222     int carry;
01223 
01224 
01225     // we normalize a duration so could have 200M...
01226     //update months (may be modified additionaly below)
01227     temp = fValue[Month];
01228     fValue[Month] = modulo(temp, 1, 13);
01229     carry = fQuotient(temp, 1, 13);
01230     if (fValue[Month] <= 0) {
01231         fValue[Month]+= 12;
01232         carry--;
01233     }
01234 
01235     //add years (may be modified additionaly below)
01236     fValue[CentYear] += carry;
01237 
01238     // add mins
01239     temp = fValue[Minute] + negate * fTimeZone[mm];
01240     carry = fQuotient(temp, 60);
01241     fValue[Minute] = mod(temp, 60, carry);
01242     if (fValue[Minute] < 0) {
01243         fValue[Minute] += 60;
01244         carry--;
01245     }
01246 
01247     //add hours
01248     temp = fValue[Hour] + negate * fTimeZone[hh] + carry;
01249     carry = fQuotient(temp, 24);
01250     fValue[Hour] = mod(temp, 24, carry);
01251     if (fValue[Hour] < 0) {
01252         fValue[Hour] += 24;
01253         carry--;
01254     }
01255 
01256     fValue[Day] += carry;
01257 
01258     while (1)
01259     {
01260         temp = maxDayInMonthFor(fValue[CentYear], fValue[Month]);
01261         if (fValue[Day] < 1)
01262         {
01263             fValue[Day] += maxDayInMonthFor(fValue[CentYear], fValue[Month] - 1);
01264             carry = -1;
01265         }
01266         else if ( fValue[Day] > temp )
01267         {
01268             fValue[Day] -= temp;
01269             carry = 1;
01270         }
01271         else
01272         {
01273             break;
01274         }
01275 
01276         temp = fValue[Month] + carry;
01277         fValue[Month] = modulo(temp, 1, 13);
01278         if (fValue[Month] <=0) {
01279             fValue[Month]+= 12;
01280             fValue[CentYear]--;
01281         }
01282         fValue[CentYear] += fQuotient(temp, 1, 13);
01283     }
01284 
01285     // set to normalized
01286     fValue[utc] = UTC_STD;
01287 
01288     return;
01289 }
01290 
01291 void XMLDateTime::validateDateTime() const
01292 {
01293 
01294     //REVISIT: should we throw an exception for not valid dates
01295     //          or reporting an error message should be sufficient?
01296     if ( fValue[CentYear] == 0 )
01297     {
01298         ThrowXMLwithMemMgr1(SchemaDateTimeException
01299                 , XMLExcepts::DateTime_year_zero
01300                 , fBuffer
01301                 , fMemoryManager);
01302         //"The year \"0000\" is an illegal year value");
01303     }
01304 
01305     if ( fValue[Month] < 1  ||
01306          fValue[Month] > 12  )
01307     {
01308         ThrowXMLwithMemMgr1(SchemaDateTimeException
01309                 , XMLExcepts::DateTime_mth_invalid
01310                 , fBuffer
01311                 , fMemoryManager);
01312                 //"The month must have values 1 to 12");
01313     }
01314 
01315     //validate days
01316     if ( fValue[Day] > maxDayInMonthFor( fValue[CentYear], fValue[Month]) ||
01317          fValue[Day] == 0 )
01318     {
01319         XMLCh szMaxDay[3];
01320         XMLString::binToText(maxDayInMonthFor( fValue[CentYear], fValue[Month]), szMaxDay, 3, 10, fMemoryManager);
01321         ThrowXMLwithMemMgr2(SchemaDateTimeException
01322                 , XMLExcepts::DateTime_day_invalid
01323                 , fBuffer
01324                 , szMaxDay
01325                 , fMemoryManager);
01326         //"The day must have values 1 to 31");
01327     }
01328 
01329     //validate hours
01330     if ((fValue[Hour] < 0)  ||
01331         (fValue[Hour] > 24) ||
01332         ((fValue[Hour] == 24) && ((fValue[Minute] !=0) ||
01333                                   (fValue[Second] !=0) ||
01334                                   (fMilliSecond    !=0))))
01335     {
01336         ThrowXMLwithMemMgr1(SchemaDateTimeException
01337                 , XMLExcepts::DateTime_hour_invalid
01338                 , fBuffer
01339                 , fMemoryManager);
01340         //("Hour must have values 0-23");
01341     }
01342 
01343     //validate minutes
01344     if ( fValue[Minute] < 0 ||
01345          fValue[Minute] > 59 )
01346     {
01347         ThrowXMLwithMemMgr1(SchemaDateTimeException
01348                 , XMLExcepts::DateTime_min_invalid
01349                 , fBuffer
01350                 , fMemoryManager);
01351         //"Minute must have values 0-59");
01352     }
01353 
01354     //validate seconds
01355     if ( fValue[Second] < 0 ||
01356          fValue[Second] > 60 )
01357     {
01358         ThrowXMLwithMemMgr1(SchemaDateTimeException
01359                 , XMLExcepts::DateTime_second_invalid
01360                 , fBuffer
01361                 , fMemoryManager);
01362         //"Second must have values 0-60");
01363     }
01364 
01365     //validate time-zone hours
01366     if ( (abs(fTimeZone[hh]) > 14) ||
01367          ((abs(fTimeZone[hh]) == 14) && (fTimeZone[mm] != 0)) )
01368     {
01369         ThrowXMLwithMemMgr1(SchemaDateTimeException
01370                 , XMLExcepts::DateTime_tz_hh_invalid
01371                 , fBuffer
01372                 , fMemoryManager);
01373         //"Time zone should have range -14..+14");
01374     }
01375 
01376     //validate time-zone minutes
01377     if ( abs(fTimeZone[mm]) > 59 )
01378     {
01379         ThrowXMLwithMemMgr1(SchemaDateTimeException
01380                 , XMLExcepts::DateTime_min_invalid
01381                 , fBuffer
01382                 , fMemoryManager);
01383         //("Minute must have values 0-59");
01384     }
01385 
01386     return;
01387 }
01388 
01389 // -----------------------------------------------------------------------
01390 // locator and converter
01391 // -----------------------------------------------------------------------
01392 int XMLDateTime::indexOf(const XMLSize_t start, const XMLSize_t end, const XMLCh ch) const
01393 {
01394     for ( XMLSize_t i = start; i < end; i++ )
01395         if ( fBuffer[i] == ch )
01396             return (int)i;
01397 
01398     return NOT_FOUND;
01399 }
01400 
01401 int XMLDateTime::findUTCSign (const XMLSize_t start)
01402 {
01403     int  pos;
01404     for ( XMLSize_t index = start; index < fEnd; index++ )
01405     {
01406         pos = XMLString::indexOf(UTC_SET, fBuffer[index]);
01407         if ( pos != NOT_FOUND)
01408         {
01409             fValue[utc] = pos+1;   // refer to utcType, there is 1 diff
01410             return (int)index;
01411         }
01412     }
01413 
01414     return NOT_FOUND;
01415 }
01416 
01417 //
01418 // Note:
01419 //    start: starting point in fBuffer
01420 //    end:   ending point in fBuffer (exclusive)
01421 //    fStart NOT updated
01422 //
01423 int XMLDateTime::parseInt(const XMLSize_t start, const XMLSize_t end) const
01424 {
01425     unsigned int retVal = 0;
01426     for (XMLSize_t i=start; i < end; i++) {
01427 
01428         if (fBuffer[i] < chDigit_0 || fBuffer[i] > chDigit_9)
01429             ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, fMemoryManager);
01430 
01431         retVal = (retVal * 10) + (unsigned int) (fBuffer[i] - chDigit_0);
01432     }
01433 
01434     return (int) retVal;
01435 }
01436 
01437 //
01438 // Note:
01439 //    start: pointing to the first digit after the '.'
01440 //    end:   pointing to one position after the last digit
01441 //    fStart NOT updated
01442 //
01443 double XMLDateTime::parseMiliSecond(const XMLSize_t start, const XMLSize_t end) const
01444 {
01445     double div = 10;
01446     double retval = 0;
01447 
01448     for (XMLSize_t i=start; i < end; i++) {
01449 
01450         if (fBuffer[i] < chDigit_0 || fBuffer[i] > chDigit_9)
01451             ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, fMemoryManager);
01452 
01453         retval += (fBuffer[i] == chDigit_0) ? 0 : ((double) (fBuffer[i] - chDigit_0)/div);
01454         div *= 10;
01455     }
01456 
01457     // we don't check underflow occurs since
01458     // nothing we can do about it.
01459     return retval;
01460 }
01461 
01462 //
01463 // [-]CCYY
01464 //
01465 // Note: start from fStart
01466 //       end (exclusive)
01467 //       fStart NOT updated
01468 //
01469 int XMLDateTime::parseIntYear(const XMLSize_t end) const
01470 {
01471     // skip the first leading '-'
01472     XMLSize_t start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;
01473 
01474     XMLSize_t length = end - start;
01475     if (length < 4)
01476     {
01477         ThrowXMLwithMemMgr1(SchemaDateTimeException
01478                 , XMLExcepts::DateTime_year_tooShort
01479                 , fBuffer
01480                 , fMemoryManager);
01481         //"Year must have 'CCYY' format");
01482     }
01483     else if (length > 4 &&
01484              fBuffer[start] == chDigit_0)
01485     {
01486         ThrowXMLwithMemMgr1(SchemaDateTimeException
01487                 , XMLExcepts::DateTime_year_leadingZero
01488                 , fBuffer
01489                 , fMemoryManager);
01490         //"Leading zeros are required if the year value would otherwise have fewer than four digits;
01491         // otherwise they are forbidden");
01492     }
01493 
01494     bool negative = (fBuffer[0] == chDash);
01495     int  yearVal = parseInt((negative ? 1 : 0), end);
01496     return ( negative ? (-1) * yearVal : yearVal );
01497 }
01498 
01499 /***
01500  * E2-41
01501  *
01502  *  3.2.7.2 Canonical representation
01503  *
01504  *  Except for trailing fractional zero digits in the seconds representation,
01505  *  '24:00:00' time representations, and timezone (for timezoned values),
01506  *  the mapping from literals to values is one-to-one. Where there is more
01507  *  than one possible representation, the canonical representation is as follows:
01508  *  redundant trailing zero digits in fractional-second literals are prohibited.
01509  *  An hour representation of '24' is prohibited. Timezoned values are canonically
01510  *  represented by appending 'Z' to the nontimezoned representation. (All
01511  *  timezoned dateTime values are UTC.)
01512  *
01513  *  .'24:00:00' -> '00:00:00'
01514  *  .milisecond: trailing zeros removed
01515  *  .'Z'
01516  *
01517  ***/
01518 XMLCh* XMLDateTime::getDateTimeCanonicalRepresentation(MemoryManager* const memMgr) const
01519 {
01520     XMLCh *miliStartPtr, *miliEndPtr;
01521     searchMiliSeconds(miliStartPtr, miliEndPtr);
01522     XMLSize_t miliSecondsLen = miliEndPtr - miliStartPtr;
01523     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1;
01524 
01525     MemoryManager* toUse = memMgr? memMgr : fMemoryManager;
01526     XMLCh* retBuf = (XMLCh*) toUse->allocate( (21 + miliSecondsLen + utcSize + 1) * sizeof(XMLCh));
01527     XMLCh* retPtr = retBuf;
01528 
01529     // (-?) cc+yy-mm-dd'T'hh:mm:ss'Z'    ('.'s+)?
01530     //      2+  8       1      8   1
01531     //
01532     int additionalLen = fillYearString(retPtr, fValue[CentYear]);
01533     if(additionalLen != 0)
01534     {
01535         // very bad luck; have to resize the buffer...
01536         XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen+21+miliSecondsLen +2) * sizeof(XMLCh));
01537         XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen);
01538         retPtr = tmpBuf+(retPtr-retBuf);
01539         toUse->deallocate(retBuf);
01540         retBuf = tmpBuf;
01541     }
01542     *retPtr++ = DATE_SEPARATOR;
01543     fillString(retPtr, fValue[Month], 2);
01544     *retPtr++ = DATE_SEPARATOR;
01545     fillString(retPtr, fValue[Day], 2);
01546     *retPtr++ = DATETIME_SEPARATOR;
01547 
01548     fillString(retPtr, fValue[Hour], 2);
01549     if (fValue[Hour] == 24)
01550     {
01551         *(retPtr - 2) = chDigit_0;
01552         *(retPtr - 1) = chDigit_0;
01553     }
01554     *retPtr++ = TIME_SEPARATOR;
01555     fillString(retPtr, fValue[Minute], 2);
01556     *retPtr++ = TIME_SEPARATOR;
01557     fillString(retPtr, fValue[Second], 2);
01558 
01559     if (miliSecondsLen)
01560     {
01561         *retPtr++ = chPeriod;
01562         XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen);
01563         retPtr += miliSecondsLen;
01564     }
01565 
01566     if (utcSize)
01567         *retPtr++ = UTC_STD_CHAR;
01568     *retPtr = chNull;
01569 
01570     return retBuf;
01571 }
01572 
01573 /***
01574  * E2-41
01575  *
01576  *  3.2.9.2 Canonical representation
01577  *
01578  * Given a member of the date value space, the date
01579  * portion of the canonical representation (the entire
01580  * representation for nontimezoned values, and all but
01581  * the timezone representation for timezoned values)
01582  * is always the date portion of the dateTime canonical
01583  * representation of the interval midpoint (the
01584  * dateTime representation, truncated on the right
01585  * to eliminate 'T' and all following characters).
01586  * For timezoned values, append the canonical
01587  * representation of the recoverable timezone.
01588  *
01589  ***/
01590 XMLCh* XMLDateTime::getDateCanonicalRepresentation(MemoryManager* const memMgr) const
01591 {
01592     /*
01593      * Case Date               Actual Value    Canonical Value
01594      *    1 yyyy-mm-dd         yyyy-mm-dd          yyyy-mm-dd
01595      *    2 yyyy-mm-ddZ        yyyy-mm-ddT00:00Z   yyyy-mm-ddZ
01596      *    3 yyyy-mm-dd+00:00   yyyy-mm-ddT00:00Z   yyyy-mm-ddZ
01597      *    4 yyyy-mm-dd+00:01   YYYY-MM-DCT23:59Z   yyyy-mm-dd+00:01
01598      *    5 yyyy-mm-dd+12:00   YYYY-MM-DCT12:00Z   yyyy-mm-dd+12:00
01599      *    6 yyyy-mm-dd+12:01   YYYY-MM-DCT11:59Z   YYYY-MM-DC-11:59
01600      *    7 yyyy-mm-dd+14:00   YYYY-MM-DCT10:00Z   YYYY-MM-DC-10:00
01601      *    8 yyyy-mm-dd-00:00   yyyy-mm-ddT00:00Z   yyyy-mm-ddZ
01602      *    9 yyyy-mm-dd-00:01   yyyy-mm-ddT00:01Z   yyyy-mm-dd-00:01
01603      *   11 yyyy-mm-dd-11:59   yyyy-mm-ddT11:59Z   YYYY-MM-DD-11:59
01604      *   10 yyyy-mm-dd-12:00   yyyy-mm-ddT12:00Z   YYYY-MM-DD+12:00
01605      *   12 yyyy-mm-dd-14:00   yyyy-mm-ddT14:00Z   YYYY-MM-DD+10:00
01606      */
01607     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1;
01608     // YYYY-MM-DD  + chNull
01609     // 1234567890  + 1
01610     int memLength = 10 + 1 + utcSize;
01611 
01612     if (fTimeZone[hh] != 0 || fTimeZone[mm] != 0) {
01613         // YYYY-MM-DD+HH:MM  (utcSize will be 1 so drop that)
01614         // 1234567890123456
01615         memLength += 5; // 6 - 1 for utcSize
01616     }
01617 
01618     MemoryManager* toUse = memMgr? memMgr : fMemoryManager;
01619     XMLCh* retBuf = (XMLCh*) toUse->allocate( (memLength) * sizeof(XMLCh));
01620     XMLCh* retPtr = retBuf;
01621 
01622     if (fValue[Hour] < 12) {
01623 
01624         int additionalLen = fillYearString(retPtr, fValue[CentYear]);
01625         if (additionalLen != 0) {
01626             // very bad luck; have to resize the buffer...
01627             XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen + memLength ) * sizeof(XMLCh));
01628             XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen);
01629             retPtr = tmpBuf+(retPtr-retBuf);
01630             toUse->deallocate(retBuf);
01631             retBuf = tmpBuf;
01632         }
01633         *retPtr++ = DATE_SEPARATOR;
01634         fillString(retPtr, fValue[Month], 2);
01635         *retPtr++ = DATE_SEPARATOR;
01636         fillString(retPtr, fValue[Day], 2);
01637 
01638         if (utcSize) {
01639             if (fTimeZone[hh] != 0 || fTimeZone[mm] != 0) {
01640                 *retPtr++ = UTC_NEG_CHAR;
01641                 fillString(retPtr, fValue[Hour], 2);
01642                 *retPtr++ = TIME_SEPARATOR;
01643                 fillString(retPtr, fValue[Minute], 2);
01644             }
01645             else {
01646                 *retPtr++ = UTC_STD_CHAR;
01647             }
01648         }
01649         *retPtr = chNull;
01650     }
01651     else {
01652         /*
01653          * Need to reconvert things to get a recoverable time zone between
01654          * +12:00 and -11:59
01655          */
01656         int carry;
01657         int minute;
01658         int hour;
01659         int day;
01660         int month;
01661         int year;
01662         if (fValue[Minute] == 0) {
01663             minute = 0;
01664             carry = 0;
01665         }
01666         else {
01667             minute = 60 - fValue[Minute];
01668             carry = 1;
01669         }
01670         hour  = 24 - fValue[Hour] - carry;
01671         day   = fValue[Day] + 1;
01672         month = fValue[Month];
01673         year  = fValue[CentYear];
01674 
01675         while (1) {
01676             int temp = maxDayInMonthFor(year, month);
01677             if (day < 1) {
01678                 day += maxDayInMonthFor(year, month - 1);
01679                 carry = -1;
01680             }
01681             else if (day > temp) {
01682                 day -= temp;
01683                 carry = 1;
01684             }
01685             else {
01686                 break;
01687             }
01688 
01689             temp = month + carry;
01690             month = modulo(temp, 1, 13);
01691             if (month <= 0) {
01692                 month+= 12;
01693                 year--;
01694             }
01695             year += fQuotient(temp, 1, 13);
01696         }
01697 
01698         int additionalLen = fillYearString(retPtr, year);
01699         if (additionalLen != 0) {
01700             // very bad luck; have to resize the buffer...
01701             XMLCh *tmpBuf = (XMLCh*) toUse->allocate( (additionalLen + memLength ) * sizeof(XMLCh));
01702             XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen);
01703             retPtr = tmpBuf+(retPtr-retBuf);
01704             toUse->deallocate(retBuf);
01705             retBuf = tmpBuf;
01706         }
01707         *retPtr++ = DATE_SEPARATOR;
01708         fillString(retPtr, month, 2);
01709         *retPtr++ = DATE_SEPARATOR;
01710         fillString(retPtr, day, 2);
01711 
01712         *retPtr++ = UTC_POS_CHAR;
01713         fillString(retPtr, hour, 2);
01714         *retPtr++ = TIME_SEPARATOR;
01715         fillString(retPtr, minute, 2);
01716         *retPtr = chNull;
01717     }
01718     return retBuf;
01719 }
01720 
01721 
01722 /***
01723  * 3.2.8 time
01724  *
01725  *  . either the time zone must be omitted or,
01726  *    if present, the time zone must be Coordinated Universal Time (UTC) indicated by a "Z".
01727  *
01728  *  . Additionally, the canonical representation for midnight is 00:00:00.
01729  *
01730 ***/
01731 XMLCh* XMLDateTime::getTimeCanonicalRepresentation(MemoryManager* const memMgr) const
01732 {
01733     XMLCh *miliStartPtr, *miliEndPtr;
01734     searchMiliSeconds(miliStartPtr, miliEndPtr);
01735     XMLSize_t miliSecondsLen = miliEndPtr - miliStartPtr;
01736     int utcSize = (fValue[utc] == UTC_UNKNOWN) ? 0 : 1;
01737 
01738     MemoryManager* toUse = memMgr? memMgr : fMemoryManager;
01739     XMLCh* retBuf = (XMLCh*) toUse->allocate( (10 + miliSecondsLen + utcSize + 1) * sizeof(XMLCh));
01740     XMLCh* retPtr = retBuf;
01741 
01742     // 'hh:mm:ss'Z'    ('.'s+)?
01743     //      8    1
01744     //
01745 
01746     fillString(retPtr, fValue[Hour], 2);
01747     if (fValue[Hour] == 24)
01748     {
01749         *(retPtr - 2) = chDigit_0;
01750         *(retPtr - 1) = chDigit_0;
01751     }
01752     *retPtr++ = TIME_SEPARATOR;
01753     fillString(retPtr, fValue[Minute], 2);
01754     *retPtr++ = TIME_SEPARATOR;
01755     fillString(retPtr, fValue[Second], 2);
01756 
01757     if (miliSecondsLen)
01758     {
01759         *retPtr++ = chPeriod;
01760         XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen);
01761         retPtr += miliSecondsLen;
01762     }
01763 
01764     if (utcSize)
01765         *retPtr++ = UTC_STD_CHAR;
01766     *retPtr = chNull;
01767 
01768     return retBuf;
01769 }
01770 
01771 void XMLDateTime::fillString(XMLCh*& ptr, int value, XMLSize_t expLen) const
01772 {
01773     XMLCh strBuffer[16];
01774     assert(expLen < 16);
01775     XMLString::binToText(value, strBuffer, expLen, 10, fMemoryManager);
01776     XMLSize_t actualLen = XMLString::stringLen(strBuffer);
01777     XMLSize_t i;
01778     //append leading zeros
01779     for (i = 0; i < expLen - actualLen; i++)
01780     {
01781         *ptr++ = chDigit_0;
01782     }
01783 
01784     for (i = 0; i < actualLen; i++)
01785     {
01786         *ptr++ = strBuffer[i];
01787     }
01788 
01789 }
01790 
01791 int XMLDateTime::fillYearString(XMLCh*& ptr, int value) const
01792 {
01793     XMLCh strBuffer[16];
01794     // let's hope we get no years of 15 digits...
01795     XMLString::binToText(value, strBuffer, 15, 10, fMemoryManager);
01796     XMLSize_t actualLen = XMLString::stringLen(strBuffer);
01797     // don't forget that years can be negative...
01798     XMLSize_t negativeYear = 0;
01799     if(strBuffer[0] == chDash)
01800     {
01801         *ptr++ = strBuffer[0];
01802         negativeYear = 1;
01803     }
01804     XMLSize_t i;
01805     //append leading zeros
01806     if(actualLen+negativeYear < 4)
01807         for (i = 0; i < 4 - actualLen+negativeYear; i++)
01808             *ptr++ = chDigit_0;
01809 
01810     for (i = negativeYear; i < actualLen; i++)
01811         *ptr++ = strBuffer[i];
01812 
01813     if(actualLen > 4)
01814         return (int)actualLen-4;
01815     return 0;
01816 }
01817 
01818 /***
01819  *
01820  *   .check if the rawData has the mili second component
01821  *   .capture the substring
01822  *
01823  ***/
01824 void XMLDateTime::searchMiliSeconds(XMLCh*& miliStartPtr, XMLCh*& miliEndPtr) const
01825 {
01826     miliStartPtr = miliEndPtr = 0;
01827 
01828     int milisec = XMLString::indexOf(fBuffer, MILISECOND_SEPARATOR);
01829     if (milisec == -1)
01830         return;
01831 
01832     miliStartPtr = fBuffer + milisec + 1;
01833     miliEndPtr   = miliStartPtr;
01834     while (*miliEndPtr)
01835     {
01836         if ((*miliEndPtr < chDigit_0) || (*miliEndPtr > chDigit_9))
01837             break;
01838 
01839         miliEndPtr++;
01840     }
01841 
01842     //remove trailing zeros
01843     while( *(miliEndPtr - 1) == chDigit_0)
01844         miliEndPtr--;
01845 
01846     return;
01847 }
01848 
01849 /***
01850  * Support for Serialization/De-serialization
01851  ***/
01852 
01853 IMPL_XSERIALIZABLE_TOCREATE(XMLDateTime)
01854 
01855 void XMLDateTime::serialize(XSerializeEngine& serEng)
01856 {
01857     //REVISIT: may not need to call base since it does nothing
01858     XMLNumber::serialize(serEng);
01859 
01860     int i = 0;
01861 
01862     if (serEng.isStoring())
01863     {
01864         for (i = 0; i < TOTAL_SIZE; i++)
01865         {
01866             serEng<<fValue[i];
01867         }
01868 
01869         for (i = 0; i < TIMEZONE_ARRAYSIZE; i++)
01870         {
01871             serEng<<fTimeZone[i];
01872         }
01873 
01874         serEng<<(unsigned long)fStart;
01875         serEng<<(unsigned long)fEnd;
01876 
01877         serEng.writeString(fBuffer, fBufferMaxLen, XSerializeEngine::toWriteBufferLen);
01878     }
01879     else
01880     {
01881         for (i = 0; i < TOTAL_SIZE; i++)
01882         {
01883             serEng>>fValue[i];
01884         }
01885 
01886         for (i = 0; i < TIMEZONE_ARRAYSIZE; i++)
01887         {
01888             serEng>>fTimeZone[i];
01889         }
01890 
01891         serEng>>(unsigned long&)fStart;
01892         serEng>>(unsigned long&)fEnd;
01893 
01894         XMLSize_t dataLen = 0;
01895         serEng.readString(fBuffer, fBufferMaxLen, dataLen ,XSerializeEngine::toReadBufferLen);
01896 
01897     }
01898 
01899 }
01900 
01901 XERCES_CPP_NAMESPACE_END