1 /* TimeType.java -- 2 Copyright (C) 2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package gnu.xml.validation.datatype; 39 40 import java.util.TimeZone; 41 import javax.xml.XMLConstants; 42 import javax.xml.namespace.QName; 43 import org.relaxng.datatype.DatatypeException; 44 import org.relaxng.datatype.ValidationContext; 45 46 /** 47 * The XML Schema time type. 48 * 49 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 50 */ 51 final class TimeType 52 extends AtomicSimpleType 53 { 54 55 static class Time 56 implements Comparable 57 { 58 int minutes; 59 float seconds; 60 hashCode()61 public int hashCode() 62 { 63 return minutes * 31 + new Float(seconds).hashCode(); 64 } 65 equals(Object other)66 public boolean equals(Object other) 67 { 68 if (other instanceof Time) 69 { 70 Time time = (Time) other; 71 return time.minutes == minutes && time.seconds == seconds; 72 } 73 return false; 74 } 75 compareTo(Object other)76 public int compareTo(Object other) 77 { 78 if (other instanceof Time) 79 { 80 Time time = (Time) other; 81 if (time.minutes != minutes) 82 return minutes - time.minutes; 83 if (time.seconds == seconds) 84 return 0; 85 return (seconds < time.seconds) ? -1 : 1; 86 } 87 return 0; 88 } 89 90 } 91 92 static final int[] CONSTRAINING_FACETS = { 93 Facet.PATTERN, 94 Facet.ENUMERATION, 95 Facet.WHITESPACE, 96 Facet.MAX_INCLUSIVE, 97 Facet.MAX_EXCLUSIVE, 98 Facet.MIN_INCLUSIVE, 99 Facet.MIN_EXCLUSIVE 100 }; 101 TimeType()102 TimeType() 103 { 104 super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "time"), 105 TypeLibrary.ANY_SIMPLE_TYPE); 106 } 107 getConstrainingFacets()108 public int[] getConstrainingFacets() 109 { 110 return CONSTRAINING_FACETS; 111 } 112 checkValid(String value, ValidationContext context)113 public void checkValid(String value, ValidationContext context) 114 throws DatatypeException 115 { 116 super.checkValid(value, context); 117 int len = value.length(); 118 int state = 3; 119 int start = 0; 120 for (int i = 0; i < len; i++) 121 { 122 char c = value.charAt(i); 123 if (c == '-' && state == 0) 124 { 125 start++; 126 continue; 127 } 128 if (c >= 0x30 && c <= 0x39) 129 continue; 130 switch (state) 131 { 132 case 3: // hour 133 if (c == ':') 134 { 135 if (i - start != 2) 136 throw new DatatypeException(i, "invalid time value"); 137 state = 4; 138 start = i + 1; 139 continue; 140 } 141 break; 142 case 4: // minute 143 if (c == ':') 144 { 145 if (i - start != 2) 146 throw new DatatypeException(i, "invalid time value"); 147 state = 5; 148 start = i + 1; 149 continue; 150 } 151 break; 152 case 5: // second 153 if (c == '.') 154 { 155 if (i - start != 2) 156 throw new DatatypeException(i, "invalid time value"); 157 state = 6; 158 start = i + 1; 159 continue; 160 } 161 else if (c == ' ') 162 { 163 if (i - start != 2) 164 throw new DatatypeException(i, "invalid time value"); 165 state = 7; 166 start = i + 1; 167 continue; 168 } 169 break; 170 case 6: // second fraction 171 if (c == ' ') 172 { 173 state = 7; 174 start = i + 1; 175 continue; 176 } 177 break; 178 case 7: // timezone 1 179 if (start == i) 180 { 181 if (c == '+' || c == '-') 182 continue; 183 else if (c == 'Z') 184 { 185 state = 9; 186 start = i + 1; 187 continue; 188 } 189 } 190 if (c == ':') 191 { 192 if (i - start != 2) 193 throw new DatatypeException(i, "invalid time value"); 194 state = 8; 195 start = i + 1; 196 continue; 197 } 198 break; 199 } 200 throw new DatatypeException(i, "invalid time value"); 201 } 202 switch (state) 203 { 204 case 5: // second 205 if (len - start != 2) 206 throw new DatatypeException(len, "invalid time value"); 207 break; 208 case 6: // second fraction 209 break; 210 case 8: // timezone 2 211 if (len - start != 2) 212 throw new DatatypeException(len, "invalid time value"); 213 break; 214 case 9: // post Z 215 break; 216 default: 217 throw new DatatypeException(len, "invalid time value"); 218 } 219 } 220 createValue(String value, ValidationContext context)221 public Object createValue(String value, ValidationContext context) { 222 int len = value.length(); 223 int state = 3; 224 int start = 0; 225 Time time = new Time(); 226 try 227 { 228 for (int i = 0; i < len; i++) 229 { 230 char c = value.charAt(i); 231 if (c >= 0x30 && c <= 0x39) 232 continue; 233 switch (state) 234 { 235 case 3: // hour 236 if (c == ':') 237 { 238 time.minutes = 239 Integer.parseInt(value.substring(start, i)) * 60; 240 state = 4; 241 start = i + 1; 242 continue; 243 } 244 break; 245 case 4: // minute 246 if (c == ':') 247 { 248 time.minutes += 249 Integer.parseInt(value.substring(start, i)); 250 state = 5; 251 start = i + 1; 252 continue; 253 } 254 break; 255 case 5: // second 256 if (c == ' ') 257 { 258 time.seconds = 259 Float.parseFloat(value.substring(start, i)); 260 state = 7; 261 start = i + 1; 262 continue; 263 } 264 break; 265 } 266 } 267 // end of input 268 if (len - start > 0 && state == 7) 269 { 270 // Timezone 271 String timezone = value.substring(len - start); 272 int i = timezone.indexOf(':'); 273 if (i == -1) 274 { 275 if ("Z".equals(timezone)) 276 timezone = "UTC"; 277 TimeZone tz = TimeZone.getTimeZone(timezone); 278 if (tz == null) 279 return null; 280 time.minutes += tz.getRawOffset(); 281 } 282 else 283 { 284 String tzh = timezone.substring(0, i); 285 String tzm = timezone.substring(i + 1); 286 int offset = Integer.parseInt(tzh) * 60; 287 if (offset < 0) 288 offset -= Integer.parseInt(tzm); 289 else 290 offset += Integer.parseInt(tzm); 291 time.minutes += offset; 292 } 293 } 294 return time; 295 } 296 catch (NumberFormatException e) 297 { 298 return null; 299 } 300 } 301 302 } 303