001    /*
002     * Copyright (c) 2006 Henri Sivonen
003     *
004     * Permission is hereby granted, free of charge, to any person obtaining a 
005     * copy of this software and associated documentation files (the "Software"), 
006     * to deal in the Software without restriction, including without limitation 
007     * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
008     * and/or sell copies of the Software, and to permit persons to whom the 
009     * Software is furnished to do so, subject to the following conditions:
010     *
011     * The above copyright notice and this permission notice shall be included in 
012     * all copies or substantial portions of the Software.
013     *
014     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
015     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
016     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
017     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
018     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
019     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
020     * DEALINGS IN THE SOFTWARE.
021     */
022    
023    package org.whattf.datatype;
024    
025    import org.relaxng.datatype.Datatype;
026    import org.relaxng.datatype.DatatypeException;
027    import org.relaxng.datatype.DatatypeStreamingValidator;
028    import org.relaxng.datatype.ValidationContext;
029    
030    /**
031     * Common superclass for HTML5 datatypes. Implements all methods of the 
032     * <code>Datatype</code> interface and leaves a new <code>checkValid</code> for 
033     * subclasses to implement.
034     * 
035     * @version $Id: AbstractDatatype.java,v 1.7 2006/11/26 14:22:54 hsivonen Exp $
036     * @author hsivonen
037     */
038    abstract class AbstractDatatype implements Datatype {
039    
040        /**
041         * Mask for ASCII case folding.
042         */
043        private static final int CASE_MASK = (1 << 5);
044    
045        /**
046         * Constructor
047         */
048        AbstractDatatype() {
049            super();
050        }
051    
052        /**
053         * Calls <code>checkValid(CharSequence literal)</code>.
054         * @param literal the value
055         * @param context the validation context (ignored by subclasses)
056         * @return <code>true</code> if valid and <code>false</code> if not
057         * @see org.relaxng.datatype.Datatype#isValid(java.lang.String, org.relaxng.datatype.ValidationContext)
058         */
059        public final boolean isValid(String literal, ValidationContext context) {
060            try {
061                checkValid(literal);
062            } catch (DatatypeException e) {
063                return false;
064            }
065            return true;
066        }
067    
068        /**
069         * Delegates to <code>checkValid(CharSequence literal)</code>.
070         * @param literal the value
071         * @param context the validation context (ignored by subclasses)
072         * @throws DatatypeException if the literal does not conform to the datatype definition
073         * @see org.relaxng.datatype.Datatype#checkValid(java.lang.String, org.relaxng.datatype.ValidationContext)
074         */
075        public final void checkValid(String literal, ValidationContext context) throws DatatypeException {
076            checkValid(literal);
077        }
078    
079        public abstract void checkValid(CharSequence literal) throws DatatypeException;
080        
081        /**
082         * Merely returns a <code>DatatypeStreamingValidatorImpl</code>.
083         * @param context the validation context (ignored by subclasses)
084         * @return An unoptimized <code>DatatypeStreamingValidator</code>
085         * @see org.relaxng.datatype.Datatype#createStreamingValidator(org.relaxng.datatype.ValidationContext)
086         */
087        public DatatypeStreamingValidator createStreamingValidator(
088                ValidationContext context) {
089            return new DatatypeStreamingValidatorImpl(this);
090        }
091    
092        /**
093         * Implements strict string equality semantics by returning <code>literal</code> 
094         * itself.
095         * @param literal the value (get returned)
096         * @param context ignored
097         * @return the <code>literal</code> that was passed in
098         * @see org.relaxng.datatype.Datatype#createValue(java.lang.String, org.relaxng.datatype.ValidationContext)
099         */
100        public final Object createValue(String literal, ValidationContext context) {
101            return literal;
102        }
103    
104        /**
105         * Implements strict stirng equality semantics by performing a standard 
106         * <code>equals</code> check on the arguments.
107         * @param value1 an object returned by <code>createValue</code>
108         * @param value2 another object returned by <code>createValue</code>
109         * @return <code>true</code> if the values are equal, <code>false</code> otherwise
110         * @see org.relaxng.datatype.Datatype#sameValue(java.lang.Object, java.lang.Object)
111         */
112        public final boolean sameValue(Object value1, Object value2) {
113            if (value1 == null) {
114                return (value2 == null);
115            }
116            return value1.equals(value2);
117        }
118    
119        /**
120         * Implements strict stirng equality semantics by returning the 
121         * <code>java.lang.Object</code>-level <code>hashCode</code> of 
122         * the object.
123         * @param value an object returned by <code>createValue</code>
124         * @return the hash code
125         * @see org.relaxng.datatype.Datatype#valueHashCode(java.lang.Object)
126         */
127        public final int valueHashCode(Object value) {
128            return value.hashCode();
129        }
130    
131        /**
132         * Always returns <code>Datatype.ID_TYPE_NULL</code>. (Overridden by subclasses 
133         * that have a different ID-type.)
134         * @return <code>Datatype.ID_TYPE_NULL</code>
135         * @see org.relaxng.datatype.Datatype#getIdType()
136         */
137        public int getIdType() {
138            return Datatype.ID_TYPE_NULL;
139        }
140    
141        /**
142         * Always returns <code>false</code>
143         * @return <code>false</code>
144         * @see org.relaxng.datatype.Datatype#isContextDependent()
145         */
146        public final boolean isContextDependent() {
147            return false;
148        }
149    
150        /**
151         * Checks if a UTF-16 code unit represents a whitespace character (U+0020, 
152         * U+0009, U+000D or U+000A).
153         * @param c the code unit
154         * @return <code>true</code> if whitespace, <code>false</code> otherwise
155         */
156        protected final boolean isWhitespace(char c) {
157            return c == ' ' || c == '\t' || c == '\n' || c == '\r';
158        }
159    
160        /**
161         * If the argument is an upper case ASCII letter, returns the letter in 
162         * lower case. Otherwise returns the argument.
163         * @param c a UTF-16 code unit
164         * @return upper case ASCII lower cased
165         */
166        protected final char toAsciiLowerCase(char c) {
167            if (c >= 'A' && c <= 'Z') {
168                return (char) (c | CASE_MASK);
169            } else {
170               return c;
171            }
172        }
173        
174        protected final String toAsciiLowerCase(String str) {
175            char[] buf = str.toCharArray();
176            for (int i = 0; i < buf.length; i++) {
177                buf[i] = toAsciiLowerCase(buf[i]);
178            }
179            return new String(buf);
180        }
181    }