View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.impl.dv.xs;
22  
23  import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
24  import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext;
25  import com.sun.org.apache.xerces.internal.xs.datatypes.XSDouble;
26  
27  /**
28   * Represent the schema type "double"
29   *
30   * @xerces.internal
31   *
32   * @author Neeraj Bajaj, Sun Microsystems, inc.
33   * @author Sandy Gao, IBM
34   *
35   * @version $Id: DoubleDV.java,v 1.7 2010-11-01 04:39:46 joehw Exp $
36   */
37  public class DoubleDV extends TypeValidator {
38  
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
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
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
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       */
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;
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 
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 
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
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 
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;
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         }
256         public double getValue() {
257             return value;
258         }
259     }
260 } // class DoubleDV