001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.dv.xs;
019:
020: import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
021: import org.apache.xerces.impl.dv.ValidationContext;
022: import org.apache.xerces.xs.datatypes.XSFloat;
023:
024: /**
025: * Represent the schema type "float"
026: *
027: * @xerces.internal
028: *
029: * @author Neeraj Bajaj, Sun Microsystems, inc.
030: * @author Sandy Gao, IBM
031: *
032: * @version $Id: FloatDV.java 572095 2007-09-02 18:32:43Z mrglavas $
033: */
034: public class FloatDV extends TypeValidator {
035:
036: public short getAllowedFacets() {
037: return (XSSimpleTypeDecl.FACET_PATTERN
038: | XSSimpleTypeDecl.FACET_WHITESPACE
039: | XSSimpleTypeDecl.FACET_ENUMERATION
040: | XSSimpleTypeDecl.FACET_MAXINCLUSIVE
041: | XSSimpleTypeDecl.FACET_MININCLUSIVE
042: | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE);
043: }//getAllowedFacets()
044:
045: //convert a String to Float form, we have to take care of cases specified in spec like INF, -INF and NaN
046: public Object getActualValue(String content,
047: ValidationContext context)
048: throws InvalidDatatypeValueException {
049: try {
050: return new XFloat(content);
051: } catch (NumberFormatException ex) {
052: throw new InvalidDatatypeValueException(
053: "cvc-datatype-valid.1.2.1", new Object[] { content,
054: "float" });
055: }
056: }//getActualValue()
057:
058: // Can't call Float#compareTo method, because it's introduced in jdk 1.2
059: public int compare(Object value1, Object value2) {
060: return ((XFloat) value1).compareTo((XFloat) value2);
061: }//compare()
062:
063: //distinguishes between identity and equality for float datatype
064: //0.0 is equal but not identical to -0.0
065: public boolean isIdentical(Object value1, Object value2) {
066: if (value2 instanceof XFloat) {
067: return ((XFloat) value1).isIdentical((XFloat) value2);
068: }
069: return false;
070: }//isIdentical()
071:
072: private static final class XFloat implements XSFloat {
073:
074: private final float value;
075:
076: public XFloat(String s) throws NumberFormatException {
077: if (DoubleDV.isPossibleFP(s)) {
078: value = Float.parseFloat(s);
079: } else if (s.equals("INF")) {
080: value = Float.POSITIVE_INFINITY;
081: } else if (s.equals("-INF")) {
082: value = Float.NEGATIVE_INFINITY;
083: } else if (s.equals("NaN")) {
084: value = Float.NaN;
085: } else {
086: throw new NumberFormatException(s);
087: }
088: }
089:
090: public boolean equals(Object val) {
091: if (val == this )
092: return true;
093:
094: if (!(val instanceof XFloat))
095: return false;
096: XFloat oval = (XFloat) val;
097:
098: // NOTE: we don't distinguish 0.0 from -0.0
099: if (value == oval.value)
100: return true;
101:
102: if (value != value && oval.value != oval.value)
103: return true;
104:
105: return false;
106: }
107:
108: public int hashCode() {
109: // This check is necessary because floatToIntBits(+0) != floatToIntBits(-0)
110: return (value == 0f) ? 0 : Float.floatToIntBits(value);
111: }
112:
113: // NOTE: 0.0 is equal but not identical to -0.0
114: public boolean isIdentical(XFloat val) {
115: if (val == this ) {
116: return true;
117: }
118:
119: if (value == val.value) {
120: return (value != 0.0f || (Float.floatToIntBits(value) == Float
121: .floatToIntBits(val.value)));
122: }
123:
124: if (value != value && val.value != val.value)
125: return true;
126:
127: return false;
128: }
129:
130: private int compareTo(XFloat val) {
131: float oval = val.value;
132:
133: // this < other
134: if (value < oval)
135: return -1;
136: // this > other
137: if (value > oval)
138: return 1;
139: // this == other
140: // NOTE: we don't distinguish 0.0 from -0.0
141: if (value == oval)
142: return 0;
143:
144: // one of the 2 values or both is/are NaN(s)
145:
146: if (value != value) {
147: // this = NaN = other
148: if (oval != oval)
149: return 0;
150: // this is NaN <> other
151: return INDETERMINATE;
152: }
153:
154: // other is NaN <> this
155: return INDETERMINATE;
156: }
157:
158: private String canonical;
159:
160: public synchronized String toString() {
161: if (canonical == null) {
162: if (value == Float.POSITIVE_INFINITY)
163: canonical = "INF";
164: else if (value == Float.NEGATIVE_INFINITY)
165: canonical = "-INF";
166: else if (value != value)
167: canonical = "NaN";
168: // NOTE: we don't distinguish 0.0 from -0.0
169: else if (value == 0)
170: canonical = "0.0E1";
171: else {
172: // REVISIT: use the java algorithm for now, because we
173: // don't know what to output for 1.1f (which is no
174: // actually 1.1)
175: canonical = Float.toString(value);
176: // if it contains 'E', then it should be a valid schema
177: // canonical representation
178: if (canonical.indexOf('E') == -1) {
179: int len = canonical.length();
180: // at most 3 longer: E, -, 9
181: char[] chars = new char[len + 3];
182: canonical.getChars(0, len, chars, 0);
183: // expected decimal point position
184: int edp = chars[0] == '-' ? 2 : 1;
185: // for non-zero integer part
186: if (value >= 1 || value <= -1) {
187: // decimal point position
188: int dp = canonical.indexOf('.');
189: // move the digits: ddd.d --> d.ddd
190: for (int i = dp; i > edp; i--) {
191: chars[i] = chars[i - 1];
192: }
193: chars[edp] = '.';
194: // trim trailing zeros: d00.0 --> d.000 --> d.
195: while (chars[len - 1] == '0')
196: len--;
197: // add the last zero if necessary: d. --> d.0
198: if (chars[len - 1] == '.')
199: len++;
200: // append E: d.dd --> d.ddE
201: chars[len++] = 'E';
202: // how far we shifted the decimal point
203: int shift = dp - edp;
204: // append the exponent --> d.ddEd
205: // the exponent is at most 7
206: chars[len++] = (char) (shift + '0');
207: } else {
208: // non-zero digit point
209: int nzp = edp + 1;
210: // skip zeros: 0.003
211: while (chars[nzp] == '0')
212: nzp++;
213: // put the first non-zero digit to the left of '.'
214: chars[edp - 1] = chars[nzp];
215: chars[edp] = '.';
216: // move other digits (non-zero) to the right of '.'
217: for (int i = nzp + 1, j = edp + 1; i < len; i++, j++)
218: chars[j] = chars[i];
219: // adjust the length
220: len -= nzp - edp;
221: // append 0 if nessary: 0.03 --> 3. --> 3.0
222: if (len == edp + 1)
223: chars[len++] = '0';
224: // append E-: d.dd --> d.ddE-
225: chars[len++] = 'E';
226: chars[len++] = '-';
227: // how far we shifted the decimal point
228: int shift = nzp - edp;
229: // append the exponent --> d.ddEd
230: // the exponent is at most 3
231: chars[len++] = (char) (shift + '0');
232: }
233: canonical = new String(chars, 0, len);
234: }
235: }
236: }
237: return canonical;
238: }
239:
240: public float getValue() {
241: return value;
242: }
243: }
244: } // class FloatDV
|