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