1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 2004 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 package com.sun.org.apache.xerces.internal.impl.dv.xs; 21 22 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; 23 import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext; 24 25 /** 26 * Validator for <precisionDecimal> datatype (W3C Schema 1.1) 27 * 28 * @xerces.experimental 29 * 30 * @author Ankit Pasricha, IBM 31 * 32 */ 33 class PrecisionDecimalDV extends TypeValidator { 34 35 static class XPrecisionDecimal { 36 37 // sign: 0 for absent; 1 for positive values; -1 for negative values (except in case of INF, -INF) 38 int sign = 1; 39 // total digits. >= 1 40 int totalDigits = 0; 41 // integer digits when sign != 0 42 int intDigits = 0; 43 // fraction digits when sign != 0 44 int fracDigits = 0; 45 //precision 46 //int precision = 0; 47 // the string representing the integer part 48 String ivalue = ""; 49 // the string representing the fraction part 50 String fvalue = ""; 51 52 int pvalue = 0; 53 54 55 XPrecisionDecimal(String content) throws NumberFormatException { 56 if(content.equals("NaN")) { 57 ivalue = content; 58 sign = 0; 59 } 60 if(content.equals("+INF") || content.equals("INF") || content.equals("-INF")) { 61 ivalue = content.charAt(0) == '+' ? content.substring(1) : content; 62 return; 63 } 64 initD(content); 65 } 66 67 void initD(String content) throws NumberFormatException { 68 int len = content.length(); 69 if (len == 0) 70 throw new NumberFormatException(); 71 72 // these 4 variables are used to indicate where the integre/fraction 73 // parts start/end. 74 int intStart = 0, intEnd = 0, fracStart = 0, fracEnd = 0; 75 76 // Deal with leading sign symbol if present 77 if (content.charAt(0) == '+') { 78 // skip '+', so intStart should be 1 79 intStart = 1; 80 } 81 else if (content.charAt(0) == '-') { 82 intStart = 1; 83 sign = -1; 84 } 85 86 // skip leading zeroes in integer part 87 int actualIntStart = intStart; 88 while (actualIntStart < len && content.charAt(actualIntStart) == '0') { 89 actualIntStart++; 90 } 91 92 // Find the ending position of the integer part 93 for (intEnd = actualIntStart; intEnd < len && TypeValidator.isDigit(content.charAt(intEnd)); intEnd++); 94 95 // Not reached the end yet 96 if (intEnd < len) { 97 // the remaining part is not ".DDD" or "EDDD" or "eDDD", error 98 if (content.charAt(intEnd) != '.' && content.charAt(intEnd) != 'E' && content.charAt(intEnd) != 'e') 99 throw new NumberFormatException(); 100 101 if(content.charAt(intEnd) == '.') { 102 // fraction part starts after '.', and ends at the end of the input 103 fracStart = intEnd + 1; 104 105 // find location of E or e (if present) 106 // Find the ending position of the fracion part 107 for (fracEnd = fracStart; 108 fracEnd < len && TypeValidator.isDigit(content.charAt(fracEnd)); 109 fracEnd++); 110 } 111 else { 112 pvalue = Integer.parseInt(content.substring(intEnd + 1, len)); 113 } 114 } 115 116 // no integer part, no fraction part, error. 117 if (intStart == intEnd && fracStart == fracEnd) 118 throw new NumberFormatException(); 119 120 // ignore trailing zeroes in fraction part 121 /*while (fracEnd > fracStart && content.charAt(fracEnd-1) == '0') { 122 fracEnd--; 123 }*/ 124 125 // check whether there is non-digit characters in the fraction part 126 for (int fracPos = fracStart; fracPos < fracEnd; fracPos++) { 127 if (!TypeValidator.isDigit(content.charAt(fracPos))) 128 throw new NumberFormatException(); 129 } 130 131 intDigits = intEnd - actualIntStart; 132 fracDigits = fracEnd - fracStart; 133 134 if (intDigits > 0) { 135 ivalue = content.substring(actualIntStart, intEnd); 136 } 137 138 if (fracDigits > 0) { 139 fvalue = content.substring(fracStart, fracEnd); 140 if(fracEnd < len) { 141 pvalue = Integer.parseInt(content.substring(fracEnd + 1, len)); 142 } 143 } 144 totalDigits = intDigits + fracDigits; 145 } 146 147 148 public boolean equals(Object val) { 149 if (val == this) 150 return true; 151 152 if (!(val instanceof XPrecisionDecimal)) 153 return false; 154 XPrecisionDecimal oval = (XPrecisionDecimal)val; 155 156 return this.compareTo(oval) == EQUAL; 157 } 158 159 /** 160 * @return 161 */ 162 private int compareFractionalPart(XPrecisionDecimal oval) { 163 if(fvalue.equals(oval.fvalue)) 164 return EQUAL; 165 166 StringBuffer temp1 = new StringBuffer(fvalue); 167 StringBuffer temp2 = new StringBuffer(oval.fvalue); 168 169 truncateTrailingZeros(temp1, temp2); 170 return temp1.toString().compareTo(temp2.toString()); 171 } 172 173 private void truncateTrailingZeros(StringBuffer fValue, StringBuffer otherFValue) { 174 for(int i = fValue.length() - 1;i >= 0; i--) 175 if(fValue.charAt(i) == '0') 176 fValue.deleteCharAt(i); 177 else 178 break; 179 180 for(int i = otherFValue.length() - 1;i >= 0; i--) 181 if(otherFValue.charAt(i) == '0') 182 otherFValue.deleteCharAt(i); 183 else 184 break; 185 } 186 187 public int compareTo(XPrecisionDecimal val) { 188 189 // seen NaN 190 if(sign == 0) 191 return INDETERMINATE; 192 193 //INF is greater than everything and equal to itself 194 if(ivalue.equals("INF") || val.ivalue.equals("INF")) { 195 if(ivalue.equals(val.ivalue)) 196 return EQUAL; 197 else if(ivalue.equals("INF")) 198 return GREATER_THAN; 199 return LESS_THAN; 200 } 201 202 //-INF is smaller than everything and equal itself 203 if(ivalue.equals("-INF") || val.ivalue.equals("-INF")) { 204 if(ivalue.equals(val.ivalue)) 205 return EQUAL; 206 else if(ivalue.equals("-INF")) 207 return LESS_THAN; 208 return GREATER_THAN; 209 } 210 211 if (sign != val.sign) 212 return sign > val.sign ? GREATER_THAN : LESS_THAN; 213 214 return sign * compare(val); 215 } 216 217 // To enable comparison - the exponent part of the decimal will be limited 218 // to the max value of int. 219 private int compare(XPrecisionDecimal val) { 220 221 if(pvalue != 0 || val.pvalue != 0) { 222 if(pvalue == val.pvalue) 223 return intComp(val); 224 else { 225 226 if(intDigits + pvalue != val.intDigits + val.pvalue) 227 return intDigits + pvalue > val.intDigits + val.pvalue ? GREATER_THAN : LESS_THAN; 228 229 //otherwise the 2 combined values are the same 230 if(pvalue > val.pvalue) { 231 int expDiff = pvalue - val.pvalue; 232 StringBuffer buffer = new StringBuffer(ivalue); 233 StringBuffer fbuffer = new StringBuffer(fvalue); 234 for(int i = 0;i < expDiff; i++) { 235 if(i < fracDigits) { 236 buffer.append(fvalue.charAt(i)); 237 fbuffer.deleteCharAt(i); 238 } 239 else 240 buffer.append('0'); 241 } 242 return compareDecimal(buffer.toString(), val.ivalue, fbuffer.toString(), val.fvalue); 243 } 244 else { 245 int expDiff = val.pvalue - pvalue; 246 StringBuffer buffer = new StringBuffer(val.ivalue); 247 StringBuffer fbuffer = new StringBuffer(val.fvalue); 248 for(int i = 0;i < expDiff; i++) { 249 if(i < val.fracDigits) { 250 buffer.append(val.fvalue.charAt(i)); 251 fbuffer.deleteCharAt(i); 252 } 253 else 254 buffer.append('0'); 255 } 256 return compareDecimal(ivalue, buffer.toString(), fvalue, fbuffer.toString()); 257 } 258 } 259 } 260 else { 261 return intComp(val); 262 } 263 } 264 265 /** 266 * @param val 267 * @return 268 */ 269 private int intComp(XPrecisionDecimal val) { 270 if (intDigits != val.intDigits) 271 return intDigits > val.intDigits ? GREATER_THAN : LESS_THAN; 272 273 return compareDecimal(ivalue, val.ivalue, fvalue, val.fvalue); 274 } 275 276 /** 277 * @param val 278 * @return 279 */ 280 private int compareDecimal(String iValue, String fValue, String otherIValue, String otherFValue) { 281 int ret = iValue.compareTo(otherIValue); 282 if (ret != 0) 283 return ret > 0 ? GREATER_THAN : LESS_THAN; 284 285 if(fValue.equals(otherFValue)) 286 return EQUAL; 287 288 StringBuffer temp1=new StringBuffer(fValue); 289 StringBuffer temp2=new StringBuffer(otherFValue); 290 291 truncateTrailingZeros(temp1, temp2); 292 ret = temp1.toString().compareTo(temp2.toString()); 293 return ret == 0 ? EQUAL : (ret > 0 ? GREATER_THAN : LESS_THAN); 294 } 295 296 private String canonical; 297 298 public synchronized String toString() { 299 if (canonical == null) { 300 makeCanonical(); 301 } 302 return canonical; 303 } 304 305 private void makeCanonical() { 306 // REVISIT: to be determined by working group 307 canonical = "TBD by Working Group"; 308 } 309 310 /** 311 * @param decimal 312 * @return 313 */ 314 public boolean isIdentical(XPrecisionDecimal decimal) { 315 if(ivalue.equals(decimal.ivalue) && (ivalue.equals("INF") || ivalue.equals("-INF") || ivalue.equals("NaN"))) 316 return true; 317 318 if(sign == decimal.sign && intDigits == decimal.intDigits && fracDigits == decimal.fracDigits && pvalue == decimal.pvalue 319 && ivalue.equals(decimal.ivalue) && fvalue.equals(decimal.fvalue)) 320 return true; 321 return false; 322 } 323 324 } 325 /* (non-Javadoc) 326 * @see com.sun.org.apache.xerces.internal.impl.dv.xs.TypeValidator#getAllowedFacets() 327 */ 328 public short getAllowedFacets() { 329 return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE | XSSimpleTypeDecl.FACET_TOTALDIGITS | XSSimpleTypeDecl.FACET_FRACTIONDIGITS); 330 } 331 332 /* (non-Javadoc) 333 * @see com.sun.org.apache.xerces.internal.impl.dv.xs.TypeValidator#getActualValue(java.lang.String, com.sun.org.apache.xerces.internal.impl.dv.ValidationContext) 334 */ 335 public Object getActualValue(String content, ValidationContext context) 336 throws InvalidDatatypeValueException { 337 try { 338 return new XPrecisionDecimal(content); 339 } catch (NumberFormatException nfe) { 340 throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "precisionDecimal"}); 341 } 342 } 343 344 public int compare(Object value1, Object value2) { 345 return ((XPrecisionDecimal)value1).compareTo((XPrecisionDecimal)value2); 346 } 347 348 public int getFractionDigits(Object value) { 349 return ((XPrecisionDecimal)value).fracDigits; 350 } 351 352 public int getTotalDigits(Object value) { 353 return ((XPrecisionDecimal)value).totalDigits; 354 } 355 356 public boolean isIdentical(Object value1, Object value2) { 357 if(!(value2 instanceof XPrecisionDecimal) || !(value1 instanceof XPrecisionDecimal)) 358 return false; 359 return ((XPrecisionDecimal)value1).isIdentical((XPrecisionDecimal)value2); 360 } 361 }