1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (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 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is TransforMiiX XSLT processor code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * The MITRE Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsString.h"
39 : #include "txCore.h"
40 : #include "txXMLUtils.h"
41 : #include <math.h>
42 : #include <stdlib.h>
43 : #ifdef WIN32
44 : #include <float.h>
45 : #endif
46 : #include "prdtoa.h"
47 :
48 : /*
49 : * Utility class for doubles
50 : */
51 :
52 : //-- Initialize Double related constants
53 : const dpun txDouble::NaN = DOUBLE_NaN;
54 : #ifdef IS_BIG_ENDIAN
55 : const dpun txDouble::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}};
56 : const dpun txDouble::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}};
57 : #else
58 : const dpun txDouble::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}};
59 : const dpun txDouble::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}};
60 : #endif
61 :
62 : /*
63 : * Determines whether the given double represents positive or negative
64 : * inifinity
65 : */
66 0 : bool txDouble::isInfinite(double aDbl)
67 : {
68 0 : return ((DOUBLE_HI32(aDbl) & ~DOUBLE_HI32_SIGNBIT) == DOUBLE_HI32_EXPMASK &&
69 0 : !DOUBLE_LO32(aDbl));
70 : }
71 :
72 : /*
73 : * Determines whether the given double is NaN
74 : */
75 0 : bool txDouble::isNaN(double aDbl)
76 : {
77 0 : return DOUBLE_IS_NaN(aDbl);
78 : }
79 :
80 : /*
81 : * Determines whether the given double is negative
82 : */
83 0 : bool txDouble::isNeg(double aDbl)
84 : {
85 0 : return (DOUBLE_HI32(aDbl) & DOUBLE_HI32_SIGNBIT) != 0;
86 : }
87 :
88 : /*
89 : * Converts the given String to a double, if the String value does not
90 : * represent a double, NaN will be returned
91 : */
92 : class txStringToDouble
93 42 : {
94 : public:
95 : typedef PRUnichar input_type;
96 : typedef PRUnichar value_type;
97 42 : txStringToDouble(): mState(eWhitestart), mSign(ePositive) {}
98 :
99 : void
100 42 : write(const input_type* aSource, PRUint32 aSourceLength)
101 : {
102 42 : if (mState == eIllegal) {
103 0 : return;
104 : }
105 42 : PRUint32 i = 0;
106 : PRUnichar c;
107 42 : for ( ; i < aSourceLength; ++i) {
108 42 : c = aSource[i];
109 42 : switch (mState) {
110 : case eWhitestart:
111 42 : if (c == '-') {
112 0 : mState = eDecimal;
113 0 : mSign = eNegative;
114 : }
115 42 : else if (c >= '0' && c <= '9') {
116 0 : mState = eDecimal;
117 0 : mBuffer.Append((char)c);
118 : }
119 42 : else if (c == '.') {
120 0 : mState = eMantissa;
121 0 : mBuffer.Append((char)c);
122 : }
123 42 : else if (!XMLUtils::isWhitespace(c)) {
124 42 : mState = eIllegal;
125 42 : return;
126 : }
127 0 : break;
128 : case eDecimal:
129 0 : if (c >= '0' && c <= '9') {
130 0 : mBuffer.Append((char)c);
131 : }
132 0 : else if (c == '.') {
133 0 : mState = eMantissa;
134 0 : mBuffer.Append((char)c);
135 : }
136 0 : else if (XMLUtils::isWhitespace(c)) {
137 0 : mState = eWhiteend;
138 : }
139 : else {
140 0 : mState = eIllegal;
141 0 : return;
142 : }
143 0 : break;
144 : case eMantissa:
145 0 : if (c >= '0' && c <= '9') {
146 0 : mBuffer.Append((char)c);
147 : }
148 0 : else if (XMLUtils::isWhitespace(c)) {
149 0 : mState = eWhiteend;
150 : }
151 : else {
152 0 : mState = eIllegal;
153 0 : return;
154 : }
155 0 : break;
156 : case eWhiteend:
157 0 : if (!XMLUtils::isWhitespace(c)) {
158 0 : mState = eIllegal;
159 0 : return;
160 : }
161 0 : break;
162 : default:
163 0 : break;
164 : }
165 : }
166 : }
167 :
168 : double
169 42 : getDouble()
170 : {
171 42 : if (mState == eIllegal || mBuffer.IsEmpty() ||
172 0 : (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
173 42 : return txDouble::NaN;
174 : }
175 0 : return mSign*PR_strtod(mBuffer.get(), 0);
176 : }
177 : private:
178 : nsCAutoString mBuffer;
179 : enum {
180 : eWhitestart,
181 : eDecimal,
182 : eMantissa,
183 : eWhiteend,
184 : eIllegal
185 : } mState;
186 : enum {
187 : eNegative = -1,
188 : ePositive = 1
189 : } mSign;
190 : };
191 :
192 42 : double txDouble::toDouble(const nsAString& aSrc)
193 : {
194 84 : txStringToDouble sink;
195 42 : nsAString::const_iterator fromBegin, fromEnd;
196 42 : copy_string(aSrc.BeginReading(fromBegin), aSrc.EndReading(fromEnd), sink);
197 42 : return sink.getDouble();
198 : }
199 :
200 : /*
201 : * Converts the value of the given double to a String, and places
202 : * The result into the destination String.
203 : * @return the given dest string
204 : */
205 0 : void txDouble::toString(double aValue, nsAString& aDest)
206 : {
207 :
208 : // check for special cases
209 :
210 0 : if (isNaN(aValue)) {
211 0 : aDest.AppendLiteral("NaN");
212 0 : return;
213 : }
214 0 : if (isInfinite(aValue)) {
215 0 : if (aValue < 0)
216 0 : aDest.Append(PRUnichar('-'));
217 0 : aDest.AppendLiteral("Infinity");
218 0 : return;
219 : }
220 :
221 : // Mantissa length is 17, so this is plenty
222 0 : const int buflen = 20;
223 : char buf[buflen];
224 :
225 : PRIntn intDigits, sign;
226 : char* endp;
227 0 : PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
228 :
229 : // compute length
230 0 : PRInt32 length = endp - buf;
231 0 : if (length > intDigits) {
232 : // decimal point needed
233 0 : ++length;
234 0 : if (intDigits < 1) {
235 : // leading zeros, -intDigits + 1
236 0 : length += 1 - intDigits;
237 : }
238 : }
239 : else {
240 : // trailing zeros, total length given by intDigits
241 0 : length = intDigits;
242 : }
243 0 : if (aValue < 0)
244 0 : ++length;
245 : // grow the string
246 0 : PRUint32 oldlength = aDest.Length();
247 0 : if (!EnsureStringLength(aDest, oldlength + length))
248 0 : return; // out of memory
249 0 : nsAString::iterator dest;
250 0 : aDest.BeginWriting(dest).advance(PRInt32(oldlength));
251 0 : if (aValue < 0) {
252 0 : *dest = '-'; ++dest;
253 : }
254 : int i;
255 : // leading zeros
256 0 : if (intDigits < 1) {
257 0 : *dest = '0'; ++dest;
258 0 : *dest = '.'; ++dest;
259 0 : for (i = 0; i > intDigits; --i) {
260 0 : *dest = '0'; ++dest;
261 : }
262 : }
263 : // mantissa
264 0 : int firstlen = NS_MIN<size_t>(intDigits, endp - buf);
265 0 : for (i = 0; i < firstlen; i++) {
266 0 : *dest = buf[i]; ++dest;
267 : }
268 0 : if (i < endp - buf) {
269 0 : if (i > 0) {
270 0 : *dest = '.'; ++dest;
271 : }
272 0 : for (; i < endp - buf; i++) {
273 0 : *dest = buf[i]; ++dest;
274 : }
275 : }
276 : // trailing zeros
277 0 : for (; i < intDigits; i++) {
278 0 : *dest = '0'; ++dest;
279 : }
280 : }
|