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