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 }