GME
13
|
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