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