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.XSFloat;
27 
28 /**
29  * Represent the schema type "float"
30  *
31  * @xerces.internal
32  *
33  * @author Neeraj Bajaj, Sun Microsystems, inc.
34  * @author Sandy Gao, IBM
35  *
36  */
37 public class FloatDV 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 Float 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 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
compare(Object value1, Object value2)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
isIdentical(Object value1, Object value2)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;
XFloat(String s)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 
equals(Object val)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 
hashCode()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
isIdentical(XFloat val)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 
compareTo(XFloat val)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;
toString()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 
getValue()237         public float getValue() {
238             return value;
239         }
240     }
241 } // class FloatDV
242