GME  13
XMLAbstractDoubleFloat.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: 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