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.XSFloat;
26  
27  /**
28   * Represent the schema type "float"
29   *
30   * @xerces.internal
31   *
32   * @author Neeraj Bajaj, Sun Microsystems, inc.
33   * @author Sandy Gao, IBM
34   *
35   * @version $Id: FloatDV.java,v 1.7 2010-11-01 04:39:47 joehw Exp $
36   */
37  public class FloatDV 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 Float 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 XFloat(content);
47          } catch (NumberFormatException ex){
48              throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "float"});
49          }
50      }//getActualValue()
51  
52      // Can't call Float#compareTo method, because it's introduced in jdk 1.2
53      public int compare(Object value1, Object value2){
54          return ((XFloat)value1).compareTo((XFloat)value2);
55      }//compare()
56  
57      //distinguishes between identity and equality for float datatype
58      //0.0 is equal but not identical to -0.0
59      public boolean isIdentical (Object value1, Object value2) {
60          if (value2 instanceof XFloat) {
61              return ((XFloat)value1).isIdentical((XFloat)value2);
62          }
63          return false;
64      }//isIdentical()
65  
66      private static final class XFloat implements XSFloat {
67  
68          private final float value;
69          public XFloat(String s) throws NumberFormatException {
70              if (DoubleDV.isPossibleFP(s)) {
71                  value = Float.parseFloat(s);
72              }
73              else if ( s.equals("INF") ) {
74                  value = Float.POSITIVE_INFINITY;
75              }
76              else if ( s.equals("-INF") ) {
77                  value = Float.NEGATIVE_INFINITY;
78              }
79              else if ( s.equals("NaN") ) {
80                  value = Float.NaN;
81              }
82              else {
83                  throw new NumberFormatException(s);
84              }
85          }
86  
87          public boolean equals(Object val) {
88              if (val == this)
89                  return true;
90  
91              if (!(val instanceof XFloat))
92                  return false;
93              XFloat oval = (XFloat)val;
94  
95              // NOTE: we don't distinguish 0.0 from -0.0
96              if (value == oval.value)
97                  return true;
98  
99              if (value != value && oval.value != oval.value)
100                 return true;
101 
102             return false;
103         }
104 
105         public int hashCode() {
106             // This check is necessary because floatToIntBits(+0) != floatToIntBits(-0)
107             return (value == 0f) ? 0 : Float.floatToIntBits(value);
108         }
109 
110         // NOTE: 0.0 is equal but not identical to -0.0
111         public boolean isIdentical (XFloat val) {
112             if (val == this) {
113                 return true;
114             }
115 
116             if (value == val.value) {
117                 return (value != 0.0f ||
118                     (Float.floatToIntBits(value) == Float.floatToIntBits(val.value)));
119             }
120 
121             if (value != value && val.value != val.value)
122                 return true;
123 
124             return false;
125         }
126 
127         private int compareTo(XFloat val) {
128             float oval = val.value;
129 
130             // this < other
131             if (value < oval)
132                 return -1;
133             // this > other
134             if (value > oval)
135                 return 1;
136             // this == other
137             // NOTE: we don't distinguish 0.0 from -0.0
138             if (value == oval)
139                 return 0;
140 
141             // one of the 2 values or both is/are NaN(s)
142 
143             if (value != value) {
144                 // this = NaN = other
145                 if (oval != oval)
146                     return 0;
147                 // this is NaN <> other
148                 return INDETERMINATE;
149             }
150 
151             // other is NaN <> this
152             return INDETERMINATE;
153         }
154 
155         private String canonical;
156         public synchronized String toString() {
157             if (canonical == null) {
158                 if (value == Float.POSITIVE_INFINITY)
159                     canonical = "INF";
160                 else if (value == Float.NEGATIVE_INFINITY)
161                     canonical = "-INF";
162                 else if (value != value)
163                     canonical = "NaN";
164                 // NOTE: we don't distinguish 0.0 from -0.0
165                 else if (value == 0)
166                     canonical = "0.0E1";
167                 else {
168                     // REVISIT: use the java algorithm for now, because we
169                     // don't know what to output for 1.1f (which is no
170                     // actually 1.1)
171                     canonical = Float.toString(value);
172                     // if it contains 'E', then it should be a valid schema
173                     // canonical representation
174                     if (canonical.indexOf('E') == -1) {
175                         int len = canonical.length();
176                         // at most 3 longer: E, -, 9
177                         char[] chars = new char[len+3];
178                         canonical.getChars(0, len, chars, 0);
179                         // expected decimal point position
180                         int edp = chars[0] == '-' ? 2 : 1;
181                         // for non-zero integer part
182                         if (value >= 1 || value <= -1) {
183                             // decimal point position
184                             int dp = canonical.indexOf('.');
185                             // move the digits: ddd.d --> d.ddd
186                             for (int i = dp; i > edp; i--) {
187                                 chars[i] = chars[i-1];
188                             }
189                             chars[edp] = '.';
190                             // trim trailing zeros: d00.0 --> d.000 --> d.
191                             while (chars[len-1] == '0')
192                                 len--;
193                             // add the last zero if necessary: d. --> d.0
194                             if (chars[len-1] == '.')
195                                 len++;
196                             // append E: d.dd --> d.ddE
197                             chars[len++] = 'E';
198                             // how far we shifted the decimal point
199                             int shift = dp - edp;
200                             // append the exponent --> d.ddEd
201                             // the exponent is at most 7
202                             chars[len++] = (char)(shift + '0');
203                         }
204                         else {
205                             // non-zero digit point
206                             int nzp = edp + 1;
207                             // skip zeros: 0.003
208                             while (chars[nzp] == '0')
209                                 nzp++;
210                             // put the first non-zero digit to the left of '.'
211                             chars[edp-1] = chars[nzp];
212                             chars[edp] = '.';
213                             // move other digits (non-zero) to the right of '.'
214                             for (int i = nzp+1, j = edp+1; i < len; i++, j++)
215                                 chars[j] = chars[i];
216                             // adjust the length
217                             len -= nzp - edp;
218                             // append 0 if nessary: 0.03 --> 3. --> 3.0
219                             if (len == edp + 1)
220                                 chars[len++] = '0';
221                             // append E-: d.dd --> d.ddE-
222                             chars[len++] = 'E';
223                             chars[len++] = '-';
224                             // how far we shifted the decimal point
225                             int shift = nzp - edp;
226                             // append the exponent --> d.ddEd
227                             // the exponent is at most 3
228                             chars[len++] = (char)(shift + '0');
229                         }
230                         canonical = new String(chars, 0, len);
231                     }
232                 }
233             }
234             return canonical;
235         }
236 
237         public float getValue() {
238             return value;
239         }
240     }
241 } // class FloatDV