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: XMLAbstractDoubleFloat.cpp 673155 2008-07-01 17:55:39Z dbertoni $ 00020 */ 00021 00022 // --------------------------------------------------------------------------- 00023 // Includes 00024 // --------------------------------------------------------------------------- 00025 #include <xercesc/util/XMLAbstractDoubleFloat.hpp> 00026 #include <xercesc/util/XMLBigDecimal.hpp> 00027 #include <xercesc/util/XMLUniDefs.hpp> 00028 #include <xercesc/util/NumberFormatException.hpp> 00029 #include <xercesc/util/XMLString.hpp> 00030 #include <xercesc/util/Janitor.hpp> 00031 00032 #include <locale.h> 00033 #include <float.h> 00034 #include <errno.h> 00035 00036 XERCES_CPP_NAMESPACE_BEGIN 00037 00038 // --------------------------------------------------------------------------- 00039 // local data member 00040 // --------------------------------------------------------------------------- 00041 static const int BUF_LEN = 64; 00042 00043 static XMLCh expSign[] = {chLatin_e, chLatin_E, chNull}; 00044 00045 // --------------------------------------------------------------------------- 00046 // ctor/dtor 00047 // --------------------------------------------------------------------------- 00048 XMLAbstractDoubleFloat::XMLAbstractDoubleFloat(MemoryManager* const manager) 00049 : fValue(0) 00050 , fType(Normal) 00051 , fDataConverted(false) 00052 , fDataOverflowed(false) 00053 , fSign(0) 00054 , fRawData(0) 00055 , fFormattedString(0) 00056 , fMemoryManager(manager) 00057 { 00058 } 00059 00060 XMLAbstractDoubleFloat::~XMLAbstractDoubleFloat() 00061 { 00062 fMemoryManager->deallocate(fRawData);//delete [] fRawData; 00063 fMemoryManager->deallocate(fFormattedString);//delete [] fFormattedString; 00064 } 00065 00066 void XMLAbstractDoubleFloat::init(const XMLCh* const strValue) 00067 { 00068 if ((!strValue) || (!*strValue)) 00069 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_emptyString, fMemoryManager); 00070 00071 fRawData = XMLString::replicate(strValue, fMemoryManager); // preserve the raw data form 00072 00073 XMLCh* tmpStrValue = XMLString::replicate(strValue, fMemoryManager); 00074 ArrayJanitor<XMLCh> janTmpName(tmpStrValue, fMemoryManager); 00075 XMLString::trim(tmpStrValue); 00076 00077 if (!*tmpStrValue) 00078 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_emptyString, fMemoryManager); 00079 00080 normalizeZero(tmpStrValue); 00081 00082 if (XMLString::equals(tmpStrValue, XMLUni::fgNegINFString) ) 00083 { 00084 fType = NegINF; 00085 fSign = -1; 00086 } 00087 else if (XMLString::equals(tmpStrValue, XMLUni::fgPosINFString) ) 00088 { 00089 fType = PosINF; 00090 fSign = 1; 00091 } 00092 else if (XMLString::equals(tmpStrValue, XMLUni::fgNaNString) ) 00093 { 00094 fType = NaN; 00095 fSign = 1; 00096 } 00097 else 00098 // 00099 // Normal case 00100 // 00101 { 00102 // Use a stack-based buffer when possible. Since all 00103 // valid doubles or floats will only contain ASCII 00104 // digits, a decimal point, or the exponent character, 00105 // they will all be single byte characters, and this will 00106 // work. 00107 static const XMLSize_t maxStackSize = 100; 00108 00109 XMLSize_t lenTempStrValue = 0; 00110 00111 00112 // Need to check that the string only contains valid schema characters 00113 // since the call to strtod may allow other values. For example, AIX 00114 // allows "infinity" and "+INF" 00115 XMLCh curChar; 00116 while ((curChar = tmpStrValue[lenTempStrValue])!=0) { 00117 if (!((curChar >= chDigit_0 && 00118 curChar <= chDigit_9) || 00119 curChar == chPeriod || 00120 curChar == chDash || 00121 curChar == chPlus || 00122 curChar == chLatin_E || 00123 curChar == chLatin_e)) { 00124 ThrowXMLwithMemMgr( 00125 NumberFormatException, 00126 XMLExcepts::XMLNUM_Inv_chars, 00127 getMemoryManager()); 00128 } 00129 lenTempStrValue++; 00130 } 00131 00132 if (lenTempStrValue < maxStackSize) 00133 { 00134 char buffer[maxStackSize + 1]; 00135 00136 XMLString::transcode( 00137 tmpStrValue, 00138 buffer, 00139 sizeof(buffer) - 1, 00140 getMemoryManager()); 00141 00142 // Do this for safety, because we've 00143 // no guarantee we didn't overrun the 00144 // capacity of the buffer when transcoding 00145 // a bogus value. 00146 buffer[maxStackSize] = '\0'; 00147 00148 // If they aren't the same length, then some 00149 // non-ASCII multibyte character was present. 00150 // This will only happen in the case where the 00151 // string has a bogus character, and it's long 00152 // enough to overrun this buffer, but we need 00153 // to check, even if it's unlikely to happen. 00154 if (XMLString::stringLen(buffer) != lenTempStrValue) 00155 { 00156 ThrowXMLwithMemMgr( 00157 NumberFormatException, 00158 XMLExcepts::XMLNUM_Inv_chars, 00159 getMemoryManager()); 00160 } 00161 00162 checkBoundary(buffer); 00163 } 00164 else 00165 { 00166 char *nptr = XMLString::transcode(tmpStrValue, getMemoryManager()); 00167 const ArrayJanitor<char> janStr(nptr, fMemoryManager); 00168 00169 checkBoundary(nptr); 00170 } 00171 } 00172 00173 } 00174 00175 XMLCh* XMLAbstractDoubleFloat::getRawData() const 00176 { 00177 return fRawData; 00178 } 00179 00180 const XMLCh* XMLAbstractDoubleFloat::getFormattedString() const 00181 { 00182 if (!fDataConverted) 00183 { 00184 return fRawData; 00185 } 00186 else 00187 { 00188 if (!fFormattedString) 00189 { 00190 XMLAbstractDoubleFloat *temp = (XMLAbstractDoubleFloat *) this; 00191 temp->formatString(); 00192 } 00193 00194 return fFormattedString; 00195 } 00196 00197 } 00198 00199 void XMLAbstractDoubleFloat::formatString() 00200 { 00201 00202 XMLSize_t rawDataLen = XMLString::stringLen(fRawData); 00203 fFormattedString = (XMLCh*) fMemoryManager->allocate 00204 ( 00205 (rawDataLen + 8) * sizeof(XMLCh) 00206 );//new XMLCh [ rawDataLen + 8]; 00207 for (XMLSize_t i = 0; i < rawDataLen + 8; i++) 00208 fFormattedString[i] = chNull; 00209 00210 XMLString::copyString(fFormattedString, fRawData); 00211 00212 fFormattedString[rawDataLen] = chSpace; 00213 fFormattedString[rawDataLen + 1] = chOpenParen; 00214 00215 switch (fType) 00216 { 00217 case NegINF: 00218 XMLString::catString(fFormattedString, XMLUni::fgNegINFString); 00219 break; 00220 case PosINF: 00221 XMLString::catString(fFormattedString, XMLUni::fgPosINFString); 00222 break; 00223 case NaN: 00224 XMLString::catString(fFormattedString, XMLUni::fgNaNString); 00225 break; 00226 default: 00227 // its zero 00228 XMLString::catString(fFormattedString, XMLUni::fgPosZeroString); 00229 break; 00230 } 00231 00232 fFormattedString[XMLString::stringLen(fFormattedString)] = chCloseParen; 00233 00234 } 00235 00236 int XMLAbstractDoubleFloat::getSign() const 00237 { 00238 return fSign; 00239 } 00240 00241 // 00242 // 00243 // 00244 int XMLAbstractDoubleFloat::compareValues(const XMLAbstractDoubleFloat* const lValue 00245 , const XMLAbstractDoubleFloat* const rValue 00246 , MemoryManager* const manager) 00247 { 00248 // 00249 // case#1: lValue normal 00250 // rValue normal 00251 // 00252 if ((!lValue->isSpecialValue()) && 00253 (!rValue->isSpecialValue()) ) 00254 { 00255 if (lValue->fValue == rValue->fValue) 00256 return EQUAL; 00257 else 00258 return (lValue->fValue > rValue->fValue) ? GREATER_THAN : LESS_THAN; 00259 00260 } 00261 // 00262 // case#2: lValue special 00263 // rValue special 00264 // 00265 // Schema Errata E2-40 00266 // 00267 // Positive Infinity is greater than all other non-NAN value. 00268 // Nan equals itself but is not comparable with (neither greater than nor less than) 00269 // any other value in the value space 00270 // Negative Infinity is less than all other non-NAN values. 00271 // 00272 else 00273 if ((lValue->isSpecialValue()) && 00274 (rValue->isSpecialValue()) ) 00275 { 00276 if (lValue->fType == rValue->fType) 00277 return EQUAL; 00278 else 00279 { 00280 if ((lValue->fType == NaN) || 00281 (rValue->fType == NaN) ) 00282 { 00283 return INDETERMINATE; 00284 } 00285 else 00286 { 00287 return (lValue->fType > rValue->fType) ? GREATER_THAN : LESS_THAN; 00288 } 00289 } 00290 00291 } 00292 // 00293 // case#3: lValue special 00294 // rValue normal 00295 // 00296 else 00297 if ((lValue->isSpecialValue()) && 00298 (!rValue->isSpecialValue()) ) 00299 { 00300 return compareSpecial(lValue, manager); 00301 } 00302 // 00303 // case#4: lValue normal 00304 // rValue special 00305 // 00306 else 00307 { 00308 return (-1) * compareSpecial(rValue, manager); 00309 } 00310 } 00311 00312 int XMLAbstractDoubleFloat::compareSpecial(const XMLAbstractDoubleFloat* const specialValue 00313 , MemoryManager* const manager) 00314 { 00315 switch (specialValue->fType) 00316 { 00317 case NegINF: 00318 return LESS_THAN; 00319 case PosINF: 00320 return GREATER_THAN; 00321 case NaN: 00322 // NaN is not comparable to any other value 00323 return INDETERMINATE; 00324 00325 default: 00326 XMLCh value1[BUF_LEN+1]; 00327 XMLString::binToText(specialValue->fType, value1, 16, 10, manager); 00328 ThrowXMLwithMemMgr1(NumberFormatException 00329 , XMLExcepts::XMLNUM_DBL_FLT_InvalidType 00330 , value1, manager); 00331 //internal error 00332 return 0; 00333 } 00334 } 00335 00336 // 00337 // Assumption: no leading space 00338 // 00339 // 1. The valid char set is "+-.0" 00340 // 2. There shall be only one sign at the first position, if there is one. 00341 // 3. There shall be only one dot '.', if there is one. 00342 // 00343 // Return: 00344 // 00345 // for input comforming to [+]? [0]* '.'? [0]*, 00346 // normalize the input to positive zero string 00347 // for input comforming to '-' [0]* '.'? [0]*, 00348 // normalize the input to negative zero string 00349 // otherwise, do nothing 00350 // 00351 void XMLAbstractDoubleFloat::normalizeZero(XMLCh* const inData) 00352 { 00353 00354 // do a quick check 00355 if (!inData || 00356 !*inData || 00357 (XMLString::equals(inData, XMLUni::fgNegZeroString) ) || 00358 (XMLString::equals(inData, XMLUni::fgPosZeroString) ) ) 00359 return; 00360 00361 XMLCh* srcStr = inData; 00362 bool minusSeen = false; 00363 bool dotSeen = false; 00364 00365 // process sign if any 00366 if (*srcStr == chDash) 00367 { 00368 minusSeen = true; 00369 srcStr++; 00370 if (!*srcStr) 00371 { 00372 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager()); 00373 } 00374 } 00375 else if (*srcStr == chPlus) 00376 { 00377 srcStr++; 00378 if (!*srcStr) 00379 { 00380 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager()); 00381 } 00382 } 00383 else if (*srcStr == chPeriod) 00384 { 00385 dotSeen = true; 00386 srcStr++; 00387 if (!*srcStr) 00388 { 00389 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager()); 00390 } 00391 } 00392 00393 // scan the string 00394 00395 bool isValidStr = true; 00396 XMLCh theChar; 00397 while ((theChar=*srcStr++)!=0 && isValidStr) 00398 { 00399 if ( theChar != chPeriod && theChar != chDigit_0 ) 00400 isValidStr = false; // invalid char 00401 else if (theChar == chPeriod) // process dot 00402 dotSeen ? isValidStr = false : dotSeen = true; 00403 } 00404 00405 // need not to worry about the memory problem 00406 // since either fgNegZeroString or fgPosZeroString 00407 // is the canonical form (meaning the shortest in length) 00408 // of their category respectively. 00409 if (isValidStr) 00410 { 00411 if (minusSeen) 00412 XMLString::copyString(inData, XMLUni::fgNegZeroString); 00413 else 00414 XMLString::copyString(inData, XMLUni::fgPosZeroString); 00415 } 00416 else 00417 { 00418 // we got to set the sign first, since this string may 00419 // eventaully turn out to be beyond the minimum representable 00420 // number and reduced to -0 or +0. 00421 fSign = minusSeen ? -1 : 1; 00422 } 00423 00424 return; 00425 } 00426 00427 void XMLAbstractDoubleFloat::normalizeDecimalPoint(char* const toNormal) 00428 { 00429 // find the locale-specific decimal point delimiter 00430 lconv* lc = localeconv(); 00431 char delimiter = *lc->decimal_point; 00432 00433 // replace '.' with the locale-specific decimal point delimiter 00434 if ( delimiter != '.' ) 00435 { 00436 char* period = strchr( toNormal, '.' ); 00437 if ( period ) 00438 { 00439 *period = delimiter; 00440 } 00441 } 00442 } 00443 00444 00445 void 00446 XMLAbstractDoubleFloat::convert(char* const strValue) 00447 { 00448 normalizeDecimalPoint(strValue); 00449 00450 char *endptr = 0; 00451 errno = 0; 00452 fValue = strtod(strValue, &endptr); 00453 00454 // check if all chars are valid char. If they are, endptr will 00455 // pointer to the null terminator. 00456 if (*endptr != '\0') 00457 { 00458 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager()); 00459 } 00460 00461 // check if overflow/underflow occurs 00462 if (errno == ERANGE) 00463 { 00464 00465 fDataConverted = true; 00466 00467 if ( fValue < 0 ) 00468 { 00469 if (fValue > (-1)*DBL_MIN) 00470 { 00471 fValue = 0; 00472 } 00473 else 00474 { 00475 fType = NegINF; 00476 fDataOverflowed = true; 00477 } 00478 } 00479 else if ( fValue > 0) 00480 { 00481 if (fValue < DBL_MIN ) 00482 { 00483 fValue = 0; 00484 } 00485 else 00486 { 00487 fType = PosINF; 00488 fDataOverflowed = true; 00489 } 00490 } 00491 } 00492 } 00493 00494 00495 00496 /*** 00497 * E2-40 00498 * 00499 * 3.2.4 float 00500 * 3.2.5 double 00501 * 00502 * . the exponent must be indicated by "E". 00503 * if the exponent is zero, it must be indicated by "E0". 00504 * 00505 * . For the mantissa, 00506 * the preceding optional "+" sign is prohibited and 00507 * the decimal point is required. 00508 * 00509 * . For the exponent, 00510 * the preceding optional "+" sign is prohibited. 00511 * Leading zeroes are prohibited. 00512 * 00513 * . Leading and trailing zeroes are prohibited subject to the following: 00514 * number representations must be normalized such that 00515 * . there is a single digit, which is non-zero, to the left of the decimal point and 00516 * . at least a single digit to the right of the decimal point. 00517 * . unless the value being represented is zero. 00518 * The canonical representation for zero is 0.0E0 00519 * 00520 ***/ 00521 XMLCh* XMLAbstractDoubleFloat::getCanonicalRepresentation(const XMLCh* const rawData 00522 , MemoryManager* const memMgr) 00523 { 00524 // before anything, let's look for special tokens since that 00525 // breaks the calls to parse below. 00526 if(XMLString::equals(rawData, XMLUni::fgNegINFString) || 00527 XMLString::equals(rawData, XMLUni::fgPosINFString) || 00528 XMLString::equals(rawData, XMLUni::fgNaNString) ) 00529 { 00530 return XMLString::replicate(rawData, memMgr); 00531 } 00532 00533 try 00534 { 00535 XMLSize_t strLen = XMLString::stringLen(rawData); 00536 XMLCh* manStr = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh)); 00537 ArrayJanitor<XMLCh> janManStr(manStr, memMgr); 00538 XMLCh* manBuf = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh)); 00539 ArrayJanitor<XMLCh> janManBuf(manBuf, memMgr); 00540 XMLCh* expStr = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh)); 00541 ArrayJanitor<XMLCh> janExpStr(expStr, memMgr); 00542 XMLCh* retBuffer = (XMLCh*) memMgr->allocate((strLen + 8) * sizeof(XMLCh)); 00543 ArrayJanitor<XMLCh> janRetBuffer(retBuffer, memMgr); 00544 retBuffer[0] = 0; 00545 00546 int sign, totalDigits, fractDigits, expValue = 0; 00547 00548 const XMLCh* ePosition = XMLString::findAny(rawData, expSign); 00549 00550 /*** 00551 * parse mantissa and exp separately 00552 ***/ 00553 if (!ePosition) 00554 { 00555 XMLBigDecimal::parseDecimal(rawData, manBuf, sign, totalDigits, fractDigits, memMgr); 00556 expValue = 0; 00557 } 00558 else 00559 { 00560 XMLSize_t manLen = ePosition - rawData; 00561 XMLString::copyNString(manStr, rawData, manLen); 00562 *(manStr + manLen) = chNull; 00563 XMLBigDecimal::parseDecimal(manStr, manBuf, sign, totalDigits, fractDigits, memMgr); 00564 00565 XMLSize_t expLen = strLen - manLen - 1; 00566 ePosition++; 00567 XMLString::copyNString(expStr, ePosition, expLen); 00568 *(expStr + expLen) = chNull; 00569 expValue = XMLString::parseInt(expStr); 00570 } 00571 00572 if ( (sign == 0) || (totalDigits == 0) ) 00573 { 00574 retBuffer[0] = chDigit_0; 00575 retBuffer[1] = chPeriod; 00576 retBuffer[2] = chDigit_0; 00577 retBuffer[3] = chLatin_E; 00578 retBuffer[4] = chDigit_0; 00579 retBuffer[5] = chNull; 00580 } 00581 else 00582 { 00583 XMLCh* retPtr = retBuffer; 00584 00585 if (sign == -1) 00586 { 00587 *retPtr++ = chDash; 00588 } 00589 00590 *retPtr++ = manBuf[0]; 00591 *retPtr++ = chPeriod; 00592 00593 //XMLBigDecimal::parseDecimal() will eliminate trailing zeros 00594 // iff there is a decimal points 00595 // eg. 56.7800e0 -> manBuf = 5678, totalDigits = 4, fractDigits = 2 00596 // we print it as 5.678e1 00597 // 00598 // but it wont remove trailing zeros if there is no decimal point. 00599 // eg. 567800e0 -> manBuf = 567800, totalDigits = 6, fractDigits = 0 00600 // we print it 5.67800e5 00601 // 00602 // for the latter, we need to print it as 5.678e5 instead 00603 // 00604 XMLCh* endPtr = manBuf + totalDigits; 00605 00606 if (fractDigits == 0) 00607 { 00608 while(*(endPtr - 1) == chDigit_0) 00609 endPtr--; 00610 } 00611 00612 XMLSize_t remainLen = endPtr - &(manBuf[1]); 00613 00614 if (remainLen) 00615 { 00616 XMLString::copyNString(retPtr, &(manBuf[1]), remainLen); 00617 retPtr += remainLen; 00618 } 00619 else 00620 { 00621 *retPtr++ = chDigit_0; 00622 } 00623 00624 /*** 00625 * 00626 * . adjust expValue 00627 * 00628 * new_fractDigits = totalDigits - 1 00629 * new_expValue = old_expValue + (new_fractDigits - fractDigits) 00630 * 00631 ***/ 00632 expValue += (totalDigits - 1) - fractDigits ; 00633 XMLString::binToText(expValue, expStr, strLen, 10, memMgr); 00634 *retPtr++ = chLatin_E; 00635 *retPtr = chNull; 00636 00637 XMLString::catString(&(retBuffer[0]), expStr); 00638 } 00639 00640 janRetBuffer.release(); 00641 return retBuffer; 00642 } 00643 catch (const NumberFormatException&) 00644 { 00645 return 0; 00646 } 00647 } 00648 00649 /*** 00650 * Support for Serialization/De-serialization 00651 ***/ 00652 00653 IMPL_XSERIALIZABLE_NOCREATE(XMLAbstractDoubleFloat) 00654 00655 void XMLAbstractDoubleFloat::serialize(XSerializeEngine& serEng) 00656 { 00657 //REVISIT: may not need to call base since it does nothing 00658 XMLNumber::serialize(serEng); 00659 00660 if (serEng.isStoring()) 00661 { 00662 serEng << fValue; 00663 serEng << fType; 00664 serEng << fDataConverted; 00665 serEng << fDataOverflowed; 00666 serEng << fSign; 00667 00668 serEng.writeString(fRawData); 00669 00670 // Do not serialize fFormattedString 00671 00672 } 00673 else 00674 { 00675 serEng >> fValue; 00676 00677 int type = 0; 00678 serEng >> type; 00679 fType = (LiteralType) type; 00680 00681 serEng >> fDataConverted; 00682 serEng >> fDataOverflowed; 00683 serEng >> fSign; 00684 00685 serEng.readString(fRawData); 00686 00687 // Set it to 0 force it to re-format if needed 00688 fFormattedString = 0; 00689 00690 } 00691 00692 } 00693 00694 XERCES_CPP_NAMESPACE_END