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