source: icXML/icXML-devel/src/xercesc/util/XMLAbstractDoubleFloat.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 19.6 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: XMLAbstractDoubleFloat.cpp 673155 2008-07-01 17:55:39Z dbertoni $
20 */
21
22// ---------------------------------------------------------------------------
23//  Includes
24// ---------------------------------------------------------------------------
25#include <xercesc/util/XMLAbstractDoubleFloat.hpp>
26#include <xercesc/util/XMLBigDecimal.hpp>
27#include <xercesc/util/XMLUniDefs.hpp>
28#include <xercesc/util/NumberFormatException.hpp>
29#include <icxercesc/util/XMLString.hpp>
30#include <xercesc/util/Janitor.hpp>
31
32#include <locale.h>
33#include <float.h>
34#include <errno.h>
35
36XERCES_CPP_NAMESPACE_BEGIN
37
38// ---------------------------------------------------------------------------
39//  local data member
40// ---------------------------------------------------------------------------
41static const int BUF_LEN = 64;
42
43static XMLCh expSign[] = {chLatin_e, chLatin_E, chNull};
44
45// ---------------------------------------------------------------------------
46//  ctor/dtor
47// ---------------------------------------------------------------------------
48XMLAbstractDoubleFloat::XMLAbstractDoubleFloat(MemoryManager* const manager)
49: fValue(0)
50, fType(Normal)
51, fDataConverted(false)
52, fDataOverflowed(false)
53, fSign(0)
54, fRawData(0)
55, fFormattedString(0)
56, fMemoryManager(manager)
57{
58}
59
60XMLAbstractDoubleFloat::~XMLAbstractDoubleFloat()
61{
62     fMemoryManager->deallocate(fRawData);//delete [] fRawData;
63     fMemoryManager->deallocate(fFormattedString);//delete [] fFormattedString;
64}
65
66void XMLAbstractDoubleFloat::init(const XMLCh* const strValue)
67{
68    if ((!strValue) || (!*strValue))
69        ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_emptyString, fMemoryManager);
70
71    fRawData = XMLString::replicate(strValue, fMemoryManager);   // preserve the raw data form
72
73    XMLCh* tmpStrValue = XMLString::replicate(strValue, fMemoryManager);
74    ArrayJanitor<XMLCh> janTmpName(tmpStrValue, fMemoryManager);
75    XMLString::trim(tmpStrValue);
76
77    if (!*tmpStrValue) 
78        ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_emptyString, fMemoryManager);
79
80    normalizeZero(tmpStrValue);
81
82    if (XMLString::equals(tmpStrValue, XMLUni::fgNegINFString) )
83    {
84        fType = NegINF;
85        fSign = -1;
86    }
87    else if (XMLString::equals(tmpStrValue, XMLUni::fgPosINFString) )
88    {
89        fType = PosINF;
90        fSign = 1;
91    }
92    else if (XMLString::equals(tmpStrValue, XMLUni::fgNaNString) )
93    {
94        fType = NaN;
95        fSign = 1;
96    }
97    else
98        //
99        // Normal case
100        //
101    {
102        // Use a stack-based buffer when possible.  Since all
103        // valid doubles or floats will only contain ASCII
104        // digits, a decimal point,  or the exponent character,
105        // they will all be single byte characters, and this will
106        // work.
107        static const XMLSize_t maxStackSize = 100;
108
109        XMLSize_t lenTempStrValue = 0;
110
111       
112        // Need to check that the string only contains valid schema characters
113        // since the call to strtod may allow other values.  For example, AIX
114        // allows "infinity" and "+INF"
115        XMLCh curChar;
116        while ((curChar = tmpStrValue[lenTempStrValue])!=0) {
117            if (!((curChar >= chDigit_0 &&
118                   curChar <= chDigit_9) ||
119                  curChar == chPeriod  ||
120                  curChar == chDash    ||
121                  curChar == chPlus    ||
122                  curChar == chLatin_E ||
123                  curChar == chLatin_e)) {               
124                ThrowXMLwithMemMgr(
125                    NumberFormatException,
126                    XMLExcepts::XMLNUM_Inv_chars,
127                    getMemoryManager());
128            }           
129            lenTempStrValue++;
130        }
131       
132        if (lenTempStrValue < maxStackSize)
133        {
134            char    buffer[maxStackSize + 1];
135
136            XMLString::transcode(
137                tmpStrValue,
138                buffer,
139                sizeof(buffer) - 1,
140                getMemoryManager());
141
142            // Do this for safety, because we've
143            // no guarantee we didn't overrun the
144            // capacity of the buffer when transcoding
145            // a bogus value.
146            buffer[maxStackSize] = '\0';
147
148            // If they aren't the same length, then some
149            // non-ASCII multibyte character was present.
150            // This will only happen in the case where the
151            // string has a bogus character, and it's long
152            // enough to overrun this buffer, but we need
153            // to check, even if it's unlikely to happen.
154            if (XMLString::stringLen(buffer) != lenTempStrValue)
155            {
156                ThrowXMLwithMemMgr(
157                    NumberFormatException,
158                    XMLExcepts::XMLNUM_Inv_chars,
159                    getMemoryManager());
160            }
161
162            checkBoundary(buffer);
163        }
164        else
165        {
166            char *nptr = XMLString::transcode(tmpStrValue, getMemoryManager());
167            const ArrayJanitor<char> janStr(nptr, fMemoryManager);
168
169            checkBoundary(nptr);
170        }
171    }
172
173}
174
175XMLCh*  XMLAbstractDoubleFloat::getRawData() const
176{
177    return fRawData;
178}
179
180const XMLCh*  XMLAbstractDoubleFloat::getFormattedString() const
181{
182    if (!fDataConverted)
183    {
184        return fRawData;
185    }
186    else 
187    {
188        if (!fFormattedString)         
189        {
190            XMLAbstractDoubleFloat *temp = (XMLAbstractDoubleFloat *) this;
191            temp->formatString();
192        }
193
194        return fFormattedString;           
195    }
196
197}
198
199void XMLAbstractDoubleFloat::formatString()
200{
201
202    XMLSize_t rawDataLen = XMLString::stringLen(fRawData);
203    fFormattedString = (XMLCh*) fMemoryManager->allocate
204    (
205        (rawDataLen + 8) * sizeof(XMLCh)
206    );//new XMLCh [ rawDataLen + 8];
207    for (XMLSize_t i = 0; i < rawDataLen + 8; i++)
208        fFormattedString[i] = chNull;
209
210    XMLString::copyString(fFormattedString, fRawData);
211
212    fFormattedString[rawDataLen] = chSpace;
213    fFormattedString[rawDataLen + 1] = chOpenParen;
214
215    switch (fType)
216    {
217    case NegINF:       
218        XMLString::catString(fFormattedString, XMLUni::fgNegINFString);
219        break;
220    case PosINF:
221        XMLString::catString(fFormattedString, XMLUni::fgPosINFString);
222        break;
223    case NaN:
224        XMLString::catString(fFormattedString, XMLUni::fgNaNString);
225        break;
226    default:
227        // its zero
228        XMLString::catString(fFormattedString, XMLUni::fgPosZeroString);
229        break;
230    }
231
232    fFormattedString[XMLString::stringLen(fFormattedString)] = chCloseParen;
233
234}
235
236int XMLAbstractDoubleFloat::getSign() const
237{
238    return fSign;
239}
240
241//
242//
243//
244int XMLAbstractDoubleFloat::compareValues(const XMLAbstractDoubleFloat* const lValue
245                                        , const XMLAbstractDoubleFloat* const rValue
246                                        , MemoryManager* const manager)
247{
248    //
249    // case#1: lValue normal
250    //         rValue normal
251    //
252    if ((!lValue->isSpecialValue()) &&
253        (!rValue->isSpecialValue())  )
254    {
255        if (lValue->fValue == rValue->fValue)
256            return EQUAL;
257        else
258            return (lValue->fValue > rValue->fValue) ? GREATER_THAN : LESS_THAN;
259
260    }
261    //
262    // case#2: lValue special
263    //         rValue special
264    //
265    // Schema Errata E2-40
266    //
267    // Positive Infinity is greater than all other non-NAN value.
268    // Nan equals itself but is not comparable with (neither greater than nor less than)
269    //     any other value in the value space
270    // Negative Infinity is less than all other non-NAN values.
271    //
272    else
273    if ((lValue->isSpecialValue()) &&
274        (rValue->isSpecialValue())  )
275    {
276        if (lValue->fType == rValue->fType)
277            return EQUAL;
278        else
279        {
280            if ((lValue->fType == NaN) ||
281                (rValue->fType == NaN)  )
282            {
283                return INDETERMINATE;
284            }
285            else
286            {
287                return (lValue->fType > rValue->fType) ? GREATER_THAN : LESS_THAN;
288            }
289        }
290
291    }
292    //
293    // case#3: lValue special
294    //         rValue normal
295    //
296    else
297    if ((lValue->isSpecialValue()) &&
298        (!rValue->isSpecialValue())  )
299    {
300        return compareSpecial(lValue, manager);
301    }
302    //
303    // case#4: lValue normal
304    //         rValue special
305    //
306    else
307    {
308        return (-1) * compareSpecial(rValue, manager);
309    }
310}
311
312int XMLAbstractDoubleFloat::compareSpecial(const XMLAbstractDoubleFloat* const specialValue                                         
313                                         , MemoryManager* const manager)
314{
315    switch (specialValue->fType)
316    {
317    case NegINF:
318        return LESS_THAN;
319    case PosINF:
320        return GREATER_THAN;
321    case NaN:
322        // NaN is not comparable to any other value
323        return INDETERMINATE;
324
325    default:
326        XMLCh value1[BUF_LEN+1];
327        XMLString::binToText(specialValue->fType, value1, 16, 10, manager);
328        ThrowXMLwithMemMgr1(NumberFormatException
329                , XMLExcepts::XMLNUM_DBL_FLT_InvalidType
330                , value1, manager);
331        //internal error
332        return 0;
333    }
334}
335
336//
337//  Assumption: no leading space
338//
339//  1. The valid char set is "+-.0"
340//  2. There shall be only one sign at the first position, if there is one.
341//  3. There shall be only one dot '.', if there is one.
342//
343//  Return:
344//
345//  for input comforming to [+]? [0]* '.'? [0]*,
346//            normalize the input to positive zero string
347//  for input comforming to '-' [0]* '.'? [0]*,
348//            normalize the input to negative zero string
349//  otherwise, do nothing
350//
351void XMLAbstractDoubleFloat::normalizeZero(XMLCh* const inData)
352{
353
354        // do a quick check
355        if (!inData  ||
356                !*inData ||
357        (XMLString::equals(inData, XMLUni::fgNegZeroString) ) ||
358        (XMLString::equals(inData, XMLUni::fgPosZeroString) )  )
359        return;
360
361    XMLCh*   srcStr = inData;
362        bool     minusSeen = false;
363    bool     dotSeen = false;
364
365        // process sign if any
366        if (*srcStr == chDash)
367        {
368                minusSeen = true;
369                srcStr++;
370        if (!*srcStr)
371        {
372            ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager());
373        }
374        }
375        else if (*srcStr == chPlus)
376        {
377                srcStr++;
378        if (!*srcStr)
379        {
380            ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager());
381        }
382        }
383    else if (*srcStr == chPeriod)
384    {
385        dotSeen = true;
386        srcStr++;
387        if (!*srcStr)
388        {
389            ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager());
390        }
391    }
392
393        // scan the string
394       
395        bool  isValidStr = true;
396    XMLCh theChar;
397        while ((theChar=*srcStr++)!=0 && isValidStr)
398        {
399                if ( theChar != chPeriod && theChar != chDigit_0 )
400                        isValidStr = false;                     // invalid char
401        else if (theChar == chPeriod)           // process dot
402                        dotSeen ? isValidStr = false : dotSeen = true;
403        }
404
405        // need not to worry about the memory problem
406        // since either fgNegZeroString or fgPosZeroString
407        // is the canonical form (meaning the shortest in length)
408        // of their category respectively.
409        if (isValidStr)
410        {
411                if (minusSeen)
412                        XMLString::copyString(inData, XMLUni::fgNegZeroString);
413                else
414                        XMLString::copyString(inData, XMLUni::fgPosZeroString);
415        }
416    else
417    {
418        // we got to set the sign first, since this string may
419        // eventaully turn out to be beyond the minimum representable
420        // number and reduced to -0 or +0.
421        fSign = minusSeen ? -1 : 1;
422    }
423
424    return;
425} 
426
427void XMLAbstractDoubleFloat::normalizeDecimalPoint(char* const toNormal)
428{
429    // find the locale-specific decimal point delimiter
430    lconv* lc = localeconv();
431    char delimiter = *lc->decimal_point;
432
433    // replace '.' with the locale-specific decimal point delimiter
434    if ( delimiter != '.' )
435    {
436        char* period = strchr( toNormal, '.' );
437        if ( period )
438        {
439            *period = delimiter;
440        }
441    }
442}
443
444
445void
446XMLAbstractDoubleFloat::convert(char* const strValue)
447{
448    normalizeDecimalPoint(strValue);
449
450    char *endptr = 0;
451    errno = 0;
452    fValue = strtod(strValue, &endptr);
453
454    // check if all chars are valid char.  If they are, endptr will
455    // pointer to the null terminator.
456    if (*endptr != '\0')
457    {
458        ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, getMemoryManager());
459    }
460
461    // check if overflow/underflow occurs
462    if (errno == ERANGE)
463    {
464           
465        fDataConverted = true;
466
467        if ( fValue < 0 )
468        {
469            if (fValue > (-1)*DBL_MIN)
470            {
471                fValue = 0;
472            }
473            else
474            {
475                fType = NegINF;
476                fDataOverflowed = true;
477            }
478        }
479        else if ( fValue > 0)
480        {
481            if (fValue < DBL_MIN )
482            {
483                fValue = 0;
484            }
485            else
486            {
487                fType = PosINF;
488                fDataOverflowed = true;
489            }
490        }
491    }
492}
493
494
495
496/***
497 * E2-40
498 *
499 *   3.2.4 float
500 *   3.2.5 double
501 *
502 * . the exponent must be indicated by "E".
503 *   if the exponent is zero, it must be indicated by "E0".
504 *
505 * . For the mantissa,
506 *      the preceding optional "+" sign is prohibited and
507 *      the decimal point is required.
508 *
509 * . For the exponent,
510 *      the preceding optional "+" sign is prohibited.
511 *      Leading zeroes are prohibited.
512 *     
513 * . Leading and trailing zeroes are prohibited subject to the following:
514 *   number representations must be normalized such that
515 *     . there is a single digit, which is non-zero, to the left of the decimal point and
516 *     . at least a single digit to the right of the decimal point.
517 *     . unless the value being represented is zero.
518 *       The canonical representation for zero is 0.0E0
519 *
520 ***/     
521XMLCh* XMLAbstractDoubleFloat::getCanonicalRepresentation(const XMLCh*         const rawData
522                                                        ,       MemoryManager* const memMgr)
523{
524    // before anything, let's look for special tokens since that
525    // breaks the calls to parse below.
526    if(XMLString::equals(rawData, XMLUni::fgNegINFString) || 
527       XMLString::equals(rawData, XMLUni::fgPosINFString) || 
528       XMLString::equals(rawData, XMLUni::fgNaNString)     )
529    {
530        return XMLString::replicate(rawData, memMgr);
531    }
532
533    try
534    {
535        XMLSize_t strLen = XMLString::stringLen(rawData);
536        XMLCh* manStr = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh));
537        ArrayJanitor<XMLCh> janManStr(manStr, memMgr);
538        XMLCh* manBuf = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh));
539        ArrayJanitor<XMLCh> janManBuf(manBuf, memMgr);
540        XMLCh* expStr = (XMLCh*) memMgr->allocate((strLen + 1) * sizeof(XMLCh));
541        ArrayJanitor<XMLCh> janExpStr(expStr, memMgr);
542        XMLCh* retBuffer = (XMLCh*) memMgr->allocate((strLen + 8) * sizeof(XMLCh));
543        ArrayJanitor<XMLCh> janRetBuffer(retBuffer, memMgr);
544        retBuffer[0] = 0;
545
546        int sign, totalDigits, fractDigits, expValue = 0;
547
548        const XMLCh* ePosition = XMLString::findAny(rawData, expSign);
549
550        /***
551         *  parse mantissa and exp separately
552        ***/
553        if (!ePosition)
554        {
555            XMLBigDecimal::parseDecimal(rawData, manBuf, sign, totalDigits, fractDigits, memMgr);
556            expValue = 0;
557        }
558        else
559        {
560            XMLSize_t manLen = ePosition - rawData;
561            XMLString::copyNString(manStr, rawData, manLen);
562            *(manStr + manLen) = chNull;
563            XMLBigDecimal::parseDecimal(manStr, manBuf, sign, totalDigits, fractDigits, memMgr);
564
565            XMLSize_t expLen = strLen - manLen - 1;
566            ePosition++;
567            XMLString::copyNString(expStr, ePosition, expLen);
568            *(expStr + expLen) = chNull;
569            expValue = XMLString::parseInt(expStr); 
570        }
571
572        if ( (sign == 0) || (totalDigits == 0) )
573        {
574            retBuffer[0] = chDigit_0;
575            retBuffer[1] = chPeriod;
576            retBuffer[2] = chDigit_0;
577            retBuffer[3] = chLatin_E;
578            retBuffer[4] = chDigit_0;
579            retBuffer[5] = chNull;
580        }
581        else
582        {
583            XMLCh* retPtr = retBuffer;
584
585            if (sign == -1)
586            {
587                *retPtr++ = chDash;
588            }
589
590            *retPtr++ = manBuf[0];
591            *retPtr++ = chPeriod;
592
593            //XMLBigDecimal::parseDecimal() will eliminate trailing zeros
594            // iff there is a decimal points
595            // eg. 56.7800e0  -> manBuf = 5678, totalDigits = 4, fractDigits = 2
596            // we print it as 5.678e1
597            //
598            // but it wont remove trailing zeros if there is no decimal point.
599            // eg.  567800e0 -> manBuf = 567800, totalDigits = 6, fractDigits = 0
600            // we print it 5.67800e5
601            //
602            // for the latter, we need to print it as 5.678e5 instead
603            //
604            XMLCh* endPtr = manBuf + totalDigits;
605
606            if (fractDigits == 0)
607            {
608                while(*(endPtr - 1) == chDigit_0)
609                    endPtr--;
610            }
611
612            XMLSize_t remainLen = endPtr - &(manBuf[1]);
613
614            if (remainLen)
615            {
616                XMLString::copyNString(retPtr, &(manBuf[1]), remainLen);
617                retPtr += remainLen;
618            }
619            else
620            {
621                *retPtr++ = chDigit_0;
622            }
623
624            /***
625             *
626             *  . adjust expValue
627             *   
628             *  new_fractDigits = totalDigits - 1 
629             *  new_expValue = old_expValue + (new_fractDigits - fractDigits)
630             *
631             ***/
632            expValue += (totalDigits - 1) - fractDigits ;
633            XMLString::binToText(expValue, expStr, strLen, 10, memMgr);
634            *retPtr++  = chLatin_E;
635            *retPtr = chNull;
636
637            XMLString::catString(&(retBuffer[0]), expStr);
638        }
639
640        janRetBuffer.release();
641        return retBuffer;
642    }
643    catch (const NumberFormatException&)
644    {
645        return 0;
646    }
647}       
648
649/***
650 * Support for Serialization/De-serialization
651 ***/
652
653IMPL_XSERIALIZABLE_NOCREATE(XMLAbstractDoubleFloat)
654
655void XMLAbstractDoubleFloat::serialize(XSerializeEngine& serEng)
656{
657    //REVISIT: may not need to call base since it does nothing
658    XMLNumber::serialize(serEng);
659
660    if (serEng.isStoring())
661    {
662        serEng << fValue;
663        serEng << fType;
664        serEng << fDataConverted;
665        serEng << fDataOverflowed;
666        serEng << fSign;
667
668        serEng.writeString(fRawData);
669
670        // Do not serialize fFormattedString
671
672    }
673    else
674    {
675        serEng >> fValue;
676
677        int type = 0;
678        serEng >> type;
679        fType = (LiteralType) type;
680
681        serEng >> fDataConverted;
682        serEng >> fDataOverflowed;
683        serEng >> fSign;
684
685        serEng.readString(fRawData);
686
687        // Set it to 0 force it to re-format if needed
688        fFormattedString = 0;
689
690    }
691
692}
693
694XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.