1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.xerces.internal.impl.dv.xs;
23 
24 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
25 import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext;
26 import com.sun.org.apache.xerces.internal.xs.datatypes.XSDouble;
27 
28 /**
29  * Represent the schema type "double"
30  *
31  * @xerces.internal
32  *
33  * @author Neeraj Bajaj, Sun Microsystems, inc.
34  * @author Sandy Gao, IBM
35  *
36  */
37 public class DoubleDV extends TypeValidator {
38 
getAllowedFacets()39     public short getAllowedFacets(){
40         return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE  | XSSimpleTypeDecl.FACET_MINEXCLUSIVE  );
41     }//getAllowedFacets()
42 
43     //convert a String to Double form, we have to take care of cases specified in spec like INF, -INF and NaN
getActualValue(String content, ValidationContext context)44     public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException {
45         try{
46             return new XDouble(content);
47         } catch (NumberFormatException ex){
48             throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "double"});
49         }
50     }//getActualValue()
51 
52     // Can't call Double#compareTo method, because it's introduced in jdk 1.2
compare(Object value1, Object value2)53     public int compare(Object value1, Object value2) {
54         return ((XDouble)value1).compareTo((XDouble)value2);
55     }//compare()
56 
57     //distinguishes between identity and equality for double datatype
58     //0.0 is equal but not identical to -0.0
isIdentical(Object value1, Object value2)59     public boolean isIdentical (Object value1, Object value2) {
60         if (value2 instanceof XDouble) {
61             return ((XDouble)value1).isIdentical((XDouble)value2);
62         }
63         return false;
64     }//isIdentical()
65 
66     /**
67      * Returns true if it's possible that the given
68      * string represents a valid floating point value
69      * (excluding NaN, INF and -INF).
70      */
isPossibleFP(String val)71     static boolean isPossibleFP(String val) {
72         final int length = val.length();
73         for (int i = 0; i < length; ++i) {
74             char c = val.charAt(i);
75             if (!(c >= '0' && c <= '9' || c == '.' ||
76                 c == '-' || c == '+' || c == 'E' || c == 'e')) {
77                 return false;
78             }
79         }
80         return true;
81     }
82 
83     private static final class XDouble implements XSDouble {
84         private final double value;
XDouble(String s)85         public XDouble(String s) throws NumberFormatException {
86             if (isPossibleFP(s)) {
87                 value = Double.parseDouble(s);
88             }
89             else if ( s.equals("INF") ) {
90                 value = Double.POSITIVE_INFINITY;
91             }
92             else if ( s.equals("-INF") ) {
93                 value = Double.NEGATIVE_INFINITY;
94             }
95             else if ( s.equals("NaN" ) ) {
96                 value = Double.NaN;
97             }
98             else {
99                 throw new NumberFormatException(s);
100             }
101         }
102 
equals(Object val)103         public boolean equals(Object val) {
104             if (val == this)
105                 return true;
106 
107             if (!(val instanceof XDouble))
108                 return false;
109             XDouble oval = (XDouble)val;
110 
111             // NOTE: we don't distinguish 0.0 from -0.0
112             if (value == oval.value)
113                 return true;
114 
115             if (value != value && oval.value != oval.value)
116                 return true;
117 
118             return false;
119         }
120 
hashCode()121         public int hashCode() {
122             // This check is necessary because doubleToLongBits(+0) != doubleToLongBits(-0)
123             if (value == 0d) {
124                 return 0;
125             }
126             long v = Double.doubleToLongBits(value);
127             return (int) (v ^ (v >>> 32));
128         }
129 
130         // NOTE: 0.0 is equal but not identical to -0.0
isIdentical(XDouble val)131         public boolean isIdentical (XDouble val) {
132             if (val == this) {
133                 return true;
134             }
135 
136             if (value == val.value) {
137                 return (value != 0.0d ||
138                     (Double.doubleToLongBits(value) == Double.doubleToLongBits(val.value)));
139             }
140 
141             if (value != value && val.value != val.value)
142                 return true;
143 
144             return false;
145         }
146 
compareTo(XDouble val)147         private int compareTo(XDouble val) {
148             double oval = val.value;
149 
150             // this < other
151             if (value < oval)
152                 return -1;
153             // this > other
154             if (value > oval)
155                 return 1;
156             // this == other
157             // NOTE: we don't distinguish 0.0 from -0.0
158             if (value == oval)
159                 return 0;
160 
161             // one of the 2 values or both is/are NaN(s)
162 
163             if (value != value) {
164                 // this = NaN = other
165                 if (oval != oval)
166                     return 0;
167                 // this is NaN <> other
168                 return INDETERMINATE;
169             }
170 
171             // other is NaN <> this
172             return INDETERMINATE;
173         }
174 
175         private String canonical;
toString()176         public synchronized String toString() {
177             if (canonical == null) {
178                 if (value == Double.POSITIVE_INFINITY)
179                     canonical = "INF";
180                 else if (value == Double.NEGATIVE_INFINITY)
181                     canonical = "-INF";
182                 else if (value != value)
183                     canonical = "NaN";
184                 // NOTE: we don't distinguish 0.0 from -0.0
185                 else if (value == 0)
186                     canonical = "0.0E1";
187                 else {
188                     // REVISIT: use the java algorithm for now, because we
189                     // don't know what to output for 1.1d (which is no
190                     // actually 1.1)
191                     canonical = Double.toString(value);
192                     // if it contains 'E', then it should be a valid schema
193                     // canonical representation
194                     if (canonical.indexOf('E') == -1) {
195                         int len = canonical.length();
196                         // at most 3 longer: E, -, 9
197                         char[] chars = new char[len+3];
198                         canonical.getChars(0, len, chars, 0);
199                         // expected decimal point position
200                         int edp = chars[0] == '-' ? 2 : 1;
201                         // for non-zero integer part
202                         if (value >= 1 || value <= -1) {
203                             // decimal point position
204                             int dp = canonical.indexOf('.');
205                             // move the digits: ddd.d --> d.ddd
206                             for (int i = dp; i > edp; i--) {
207                                 chars[i] = chars[i-1];
208                             }
209                             chars[edp] = '.';
210                             // trim trailing zeros: d00.0 --> d.000 --> d.
211                             while (chars[len-1] == '0')
212                                 len--;
213                             // add the last zero if necessary: d. --> d.0
214                             if (chars[len-1] == '.')
215                                 len++;
216                             // append E: d.dd --> d.ddE
217                             chars[len++] = 'E';
218                             // how far we shifted the decimal point
219                             int shift = dp - edp;
220                             // append the exponent --> d.ddEd
221                             // the exponent is at most 7
222                             chars[len++] = (char)(shift + '0');
223                         }
224                         else {
225                             // non-zero digit point
226                             int nzp = edp + 1;
227                             // skip zeros: 0.003
228                             while (chars[nzp] == '0')
229                                 nzp++;
230                             // put the first non-zero digit to the left of '.'
231                             chars[edp-1] = chars[nzp];
232                             chars[edp] = '.';
233                             // move other digits (non-zero) to the right of '.'
234                             for (int i = nzp+1, j = edp+1; i < len; i++, j++)
235                                 chars[j] = chars[i];
236                             // adjust the length
237                             len -= nzp - edp;
238                             // append 0 if nessary: 0.03 --> 3. --> 3.0
239                             if (len == edp + 1)
240                                 chars[len++] = '0';
241                             // append E-: d.dd --> d.ddE-
242                             chars[len++] = 'E';
243                             chars[len++] = '-';
244                             // how far we shifted the decimal point
245                             int shift = nzp - edp;
246                             // append the exponent --> d.ddEd
247                             // the exponent is at most 3
248                             chars[len++] = (char)(shift + '0');
249                         }
250                         canonical = new String(chars, 0, len);
251                     }
252                 }
253             }
254             return canonical;
255         }
getValue()256         public double getValue() {
257             return value;
258         }
259     }
260 } // class DoubleDV
261