Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/xslt/base/txDouble.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "mozilla/FloatingPoint.h"
7
8
#include "nsString.h"
9
#include "txCore.h"
10
#include "txXMLUtils.h"
11
#include <math.h>
12
#include <stdlib.h>
13
#include <algorithm>
14
#ifdef WIN32
15
#include <float.h>
16
#endif
17
#include "prdtoa.h"
18
19
/*
20
 * Utility class for doubles
21
 */
22
23
/*
24
 * Converts the given String to a double, if the String value does not
25
 * represent a double, NaN will be returned
26
 */
27
class txStringToDouble
28
{
29
public:
30
0
    txStringToDouble(): mState(eWhitestart), mSign(ePositive) {}
31
32
    void
33
    Parse(const nsAString& aSource)
34
0
    {
35
0
        if (mState == eIllegal) {
36
0
            return;
37
0
        }
38
0
        uint32_t i = 0;
39
0
        char16_t c;
40
0
        auto len = aSource.Length();
41
0
        for ( ; i < len; ++i) {
42
0
            c = aSource[i];
43
0
            switch (mState) {
44
0
                case eWhitestart:
45
0
                    if (c == '-') {
46
0
                        mState = eDecimal;
47
0
                        mSign = eNegative;
48
0
                    }
49
0
                    else if (c >= '0' && c <= '9') {
50
0
                        mState = eDecimal;
51
0
                        mBuffer.Append((char)c);
52
0
                    }
53
0
                    else if (c == '.') {
54
0
                        mState = eMantissa;
55
0
                        mBuffer.Append((char)c);
56
0
                    }
57
0
                    else if (!XMLUtils::isWhitespace(c)) {
58
0
                        mState = eIllegal;
59
0
                        return;
60
0
                    }
61
0
                    break;
62
0
                case eDecimal:
63
0
                    if (c >= '0' && c <= '9') {
64
0
                        mBuffer.Append((char)c);
65
0
                    }
66
0
                    else if (c == '.') {
67
0
                        mState = eMantissa;
68
0
                        mBuffer.Append((char)c);
69
0
                    }
70
0
                    else if (XMLUtils::isWhitespace(c)) {
71
0
                        mState = eWhiteend;
72
0
                    }
73
0
                    else {
74
0
                        mState = eIllegal;
75
0
                        return;
76
0
                    }
77
0
                    break;
78
0
                case eMantissa:
79
0
                    if (c >= '0' && c <= '9') {
80
0
                        mBuffer.Append((char)c);
81
0
                    }
82
0
                    else if (XMLUtils::isWhitespace(c)) {
83
0
                        mState = eWhiteend;
84
0
                    }
85
0
                    else {
86
0
                        mState = eIllegal;
87
0
                        return;
88
0
                    }
89
0
                    break;
90
0
                case eWhiteend:
91
0
                    if (!XMLUtils::isWhitespace(c)) {
92
0
                        mState = eIllegal;
93
0
                        return;
94
0
                    }
95
0
                    break;
96
0
                default:
97
0
                    break;
98
0
            }
99
0
        }
100
0
    }
101
102
    double
103
    getDouble()
104
0
    {
105
0
        if (mState == eIllegal || mBuffer.IsEmpty() ||
106
0
            (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
107
0
            return mozilla::UnspecifiedNaN<double>();
108
0
        }
109
0
        return mSign*PR_strtod(mBuffer.get(), 0);
110
0
    }
111
private:
112
    nsAutoCString mBuffer;
113
    enum {
114
        eWhitestart,
115
        eDecimal,
116
        eMantissa,
117
        eWhiteend,
118
        eIllegal
119
    } mState;
120
    enum {
121
        eNegative = -1,
122
        ePositive = 1
123
    } mSign;
124
};
125
126
double txDouble::toDouble(const nsAString& aSrc)
127
0
{
128
0
    txStringToDouble sink;
129
0
    sink.Parse(aSrc);
130
0
    return sink.getDouble();
131
0
}
132
133
/*
134
 * Converts the value of the given double to a String, and places
135
 * The result into the destination String.
136
 * @return the given dest string
137
 */
138
void txDouble::toString(double aValue, nsAString& aDest)
139
0
{
140
0
141
0
    // check for special cases
142
0
143
0
    if (mozilla::IsNaN(aValue)) {
144
0
        aDest.AppendLiteral("NaN");
145
0
        return;
146
0
    }
147
0
    if (mozilla::IsInfinite(aValue)) {
148
0
        if (aValue < 0)
149
0
            aDest.Append(char16_t('-'));
150
0
        aDest.AppendLiteral("Infinity");
151
0
        return;
152
0
    }
153
0
154
0
    // Mantissa length is 17, so this is plenty
155
0
    const int buflen = 20;
156
0
    char buf[buflen];
157
0
158
0
    int intDigits, sign;
159
0
    char* endp;
160
0
    PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
161
0
162
0
    // compute length
163
0
    int32_t length = endp - buf;
164
0
    if (length > intDigits) {
165
0
        // decimal point needed
166
0
        ++length;
167
0
        if (intDigits < 1) {
168
0
            // leading zeros, -intDigits + 1
169
0
            length += 1 - intDigits;
170
0
        }
171
0
    }
172
0
    else {
173
0
        // trailing zeros, total length given by intDigits
174
0
        length = intDigits;
175
0
    }
176
0
    if (aValue < 0)
177
0
        ++length;
178
0
    // grow the string
179
0
    uint32_t oldlength = aDest.Length();
180
0
    if (!aDest.SetLength(oldlength + length, mozilla::fallible))
181
0
        return; // out of memory
182
0
    auto dest = aDest.BeginWriting();
183
0
    std::advance(dest, oldlength);
184
0
    if (aValue < 0) {
185
0
        *dest = '-'; ++dest;
186
0
    }
187
0
    int i;
188
0
    // leading zeros
189
0
    if (intDigits < 1) {
190
0
        *dest = '0'; ++dest;
191
0
        *dest = '.'; ++dest;
192
0
        for (i = 0; i > intDigits; --i) {
193
0
            *dest = '0'; ++dest;
194
0
        }
195
0
    }
196
0
    // mantissa
197
0
    int firstlen = std::min<size_t>(intDigits, endp - buf);
198
0
    for (i = 0; i < firstlen; i++) {
199
0
        *dest = buf[i]; ++dest;
200
0
    }
201
0
    if (i < endp - buf) {
202
0
        if (i > 0) {
203
0
            *dest = '.'; ++dest;
204
0
        }
205
0
        for (; i < endp - buf; i++) {
206
0
            *dest = buf[i]; ++dest;
207
0
        }
208
0
    }
209
0
    // trailing zeros
210
0
    for (; i < intDigits; i++) {
211
0
        *dest = '0'; ++dest;
212
0
    }
213
0
}