1 28 package org.jvyamlb; 29 30 import java.io.FileInputStream ; 31 import java.io.InputStream ; 32 33 import java.util.Calendar ; 34 import java.util.HashMap ; 35 import java.util.HashSet ; 36 import java.util.Iterator ; 37 import java.util.List ; 38 import java.util.Map ; 39 import java.util.Set ; 40 41 import java.util.regex.Matcher ; 42 import java.util.regex.Pattern ; 43 44 import org.jvyamlb.nodes.Node; 45 46 import org.jvyamlb.util.Base64Coder; 47 48 import org.jruby.util.ByteList; 49 50 53 public class SafeConstructorImpl extends BaseConstructorImpl { 54 private final static Map yamlConstructors = new HashMap (); 55 private final static Map yamlMultiConstructors = new HashMap (); 56 private final static Map yamlMultiRegexps = new HashMap (); 57 public YamlConstructor getYamlConstructor(final Object key) { 58 YamlConstructor mine = (YamlConstructor)yamlConstructors.get(key); 59 if(mine == null) { 60 mine = super.getYamlConstructor(key); 61 } 62 return mine; 63 } 64 65 public YamlMultiConstructor getYamlMultiConstructor(final Object key) { 66 YamlMultiConstructor mine = (YamlMultiConstructor)yamlMultiConstructors.get(key); 67 if(mine == null) { 68 mine = super.getYamlMultiConstructor(key); 69 } 70 return mine; 71 } 72 73 public Pattern getYamlMultiRegexp(final Object key) { 74 Pattern mine = (Pattern )yamlMultiRegexps.get(key); 75 if(mine == null) { 76 mine = super.getYamlMultiRegexp(key); 77 } 78 return mine; 79 } 80 81 public Set getYamlMultiRegexps() { 82 final Set all = new HashSet (super.getYamlMultiRegexps()); 83 all.addAll(yamlMultiRegexps.keySet()); 84 return all; 85 } 86 87 public static void addConstructor(final String tag, final YamlConstructor ctor) { 88 yamlConstructors.put(tag,ctor); 89 } 90 91 public static void addMultiConstructor(final String tagPrefix, final YamlMultiConstructor ctor) { 92 yamlMultiConstructors.put(tagPrefix,ctor); 93 yamlMultiRegexps.put(tagPrefix,Pattern.compile("^"+tagPrefix)); 94 } 95 96 public SafeConstructorImpl(final Composer composer) { 97 super(composer); 98 } 99 100 private static ByteList into(String v) { 101 return new ByteList(v.getBytes(),false); 102 } 103 104 private final static Map BOOL_VALUES = new HashMap (); 105 static { 106 BOOL_VALUES.put(into("yes"),Boolean.TRUE); 107 BOOL_VALUES.put(into("Yes"),Boolean.TRUE); 108 BOOL_VALUES.put(into("YES"),Boolean.TRUE); 109 BOOL_VALUES.put(into("no"),Boolean.FALSE); 110 BOOL_VALUES.put(into("No"),Boolean.FALSE); 111 BOOL_VALUES.put(into("NO"),Boolean.FALSE); 112 BOOL_VALUES.put(into("true"),Boolean.TRUE); 113 BOOL_VALUES.put(into("True"),Boolean.TRUE); 114 BOOL_VALUES.put(into("TRUE"),Boolean.TRUE); 115 BOOL_VALUES.put(into("false"),Boolean.FALSE); 116 BOOL_VALUES.put(into("False"),Boolean.FALSE); 117 BOOL_VALUES.put(into("FALSE"),Boolean.FALSE); 118 BOOL_VALUES.put(into("on"),Boolean.TRUE); 119 BOOL_VALUES.put(into("On"),Boolean.TRUE); 120 BOOL_VALUES.put(into("ON"),Boolean.TRUE); 121 BOOL_VALUES.put(into("off"),Boolean.FALSE); 122 BOOL_VALUES.put(into("Off"),Boolean.FALSE); 123 BOOL_VALUES.put(into("OFF"),Boolean.FALSE); 124 } 125 126 public static Object constructYamlNull(final Constructor ctor, final Node node) { 127 return null; 128 } 129 130 public static Object constructYamlBool(final Constructor ctor, final Node node) { 131 final Object val = ctor.constructScalar(node); 132 return BOOL_VALUES.get(val); 133 } 134 135 public static Object constructYamlOmap(final Constructor ctor, final Node node) { 136 return ctor.constructPairs(node); 137 } 138 139 public static Object constructYamlPairs(final Constructor ctor, final Node node) { 140 return constructYamlOmap(ctor,node); 141 } 142 143 public static Object constructYamlSet(final Constructor ctor, final Node node) { 144 return ((Map )ctor.constructMapping(node)).keySet(); 145 } 146 147 public static Object constructYamlStr(final Constructor ctor, final Node node) { 148 final ByteList value = (ByteList)ctor.constructScalar(node); 149 return value.length() == 0 ? (ByteList)null : value; 150 } 151 152 public static Object constructYamlSeq(final Constructor ctor, final Node node) { 153 return ctor.constructSequence(node); 154 } 155 156 public static Object constructYamlMap(final Constructor ctor, final Node node) { 157 return ctor.constructMapping(node); 158 } 159 160 public static Object constructUndefined(final Constructor ctor, final Node node) { 161 throw new ConstructorException(null,"could not determine a constructor for the tag " + node.getTag(),null); 162 } 163 164 private final static Pattern TIMESTAMP_REGEXP = Pattern.compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$"); 165 private final static Pattern YMD_REGEXP = Pattern.compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$"); 166 public static Object constructYamlTimestamp(final Constructor ctor, final Node node) { 167 Matcher match = YMD_REGEXP.matcher(node.getValue().toString()); 168 if(match.matches()) { 169 final String year_s = match.group(1); 170 final String month_s = match.group(2); 171 final String day_s = match.group(3); 172 final Calendar cal = Calendar.getInstance(); 173 cal.clear(); 174 if(year_s != null) { 175 cal.set(Calendar.YEAR,Integer.parseInt(year_s)); 176 } 177 if(month_s != null) { 178 cal.set(Calendar.MONTH,Integer.parseInt(month_s)-1); } 180 if(day_s != null) { 181 cal.set(Calendar.DAY_OF_MONTH,Integer.parseInt(day_s)); 182 } 183 return cal.getTime(); 184 } 185 match = TIMESTAMP_REGEXP.matcher(node.getValue().toString()); 186 if(!match.matches()) { 187 return ctor.constructPrivateType(node); 188 } 189 final String year_s = match.group(1); 190 final String month_s = match.group(2); 191 final String day_s = match.group(3); 192 final String hour_s = match.group(4); 193 final String min_s = match.group(5); 194 final String sec_s = match.group(6); 195 final String fract_s = match.group(7); 196 final String utc = match.group(8); 197 final String timezoneh_s = match.group(9); 198 final String timezonem_s = match.group(10); 199 200 int usec = 0; 201 if(fract_s != null) { 202 usec = Integer.parseInt(fract_s); 203 if(usec != 0) { 204 while(10*usec < 1000) { 205 usec *= 10; 206 } 207 } 208 } 209 final Calendar cal = Calendar.getInstance(); 210 cal.clear(); 211 if("Z".equalsIgnoreCase(utc)) { 212 cal.setTimeZone(java.util.TimeZone.getTimeZone("GMT")); 213 } else { 214 if(timezoneh_s != null || timezonem_s != null) { 215 int zone = 0; 216 int sign = +1; 217 if(timezoneh_s != null) { 218 if(timezoneh_s.startsWith("-")) { 219 sign = -1; 220 } 221 zone += Integer.parseInt(timezoneh_s.substring(1))*3600000; 222 } 223 if(timezonem_s != null) { 224 zone += Integer.parseInt(timezonem_s)*60000; 225 } 226 cal.set(Calendar.ZONE_OFFSET,sign*zone); 227 } 228 } 229 if(year_s != null) { 230 cal.set(Calendar.YEAR,Integer.parseInt(year_s)); 231 } 232 if(month_s != null) { 233 cal.set(Calendar.MONTH,Integer.parseInt(month_s)-1); } 235 if(day_s != null) { 236 cal.set(Calendar.DAY_OF_MONTH,Integer.parseInt(day_s)); 237 } 238 if(hour_s != null) { 239 cal.set(Calendar.HOUR_OF_DAY,Integer.parseInt(hour_s)); 240 } 241 if(min_s != null) { 242 cal.set(Calendar.MINUTE,Integer.parseInt(min_s)); 243 } 244 if(sec_s != null) { 245 cal.set(Calendar.SECOND,Integer.parseInt(sec_s)); 246 } 247 cal.set(Calendar.MILLISECOND,usec); 248 249 return cal.getTime(); 250 } 251 252 public static Object constructYamlInt(final Constructor ctor, final Node node) { 253 String value = ctor.constructScalar(node).toString().replaceAll("_",""); 254 int sign = +1; 255 char first = value.charAt(0); 256 if(first == '-') { 257 sign = -1; 258 value = value.substring(1); 259 } else if(first == '+') { 260 value = value.substring(1); 261 } 262 int base = 10; 263 if(value.equals("0")) { 264 return new Long (0); 265 } else if(value.startsWith("0b")) { 266 value = value.substring(2); 267 base = 2; 268 } else if(value.startsWith("0x")) { 269 value = value.substring(2); 270 base = 16; 271 } else if(value.startsWith("0")) { 272 value = value.substring(1); 273 base = 8; 274 } else if(value.indexOf(':') != -1) { 275 final String [] digits = value.split(":"); 276 int bes = 1; 277 int val = 0; 278 for(int i=0,j=digits.length;i<j;i++) { 279 val += (Long.parseLong(digits[(j-i)-1])*bes); 280 bes *= 60; 281 } 282 return new Integer (sign*val); 283 } else { 284 return new Long (sign * Long.parseLong(value)); 285 } 286 return new Long (sign * Long.parseLong(value,base)); 287 } 288 289 private final static Double INF_VALUE_POS = new Double (Double.POSITIVE_INFINITY); 290 private final static Double INF_VALUE_NEG = new Double (Double.NEGATIVE_INFINITY); 291 private final static Double NAN_VALUE = new Double (Double.NaN); 292 293 public static Object constructYamlFloat(final Constructor ctor, final Node node) { 294 String value = ctor.constructScalar(node).toString().replaceAll("_",""); 295 int sign = +1; 296 char first = value.charAt(0); 297 if(first == '-') { 298 sign = -1; 299 value = value.substring(1); 300 } else if(first == '+') { 301 value = value.substring(1); 302 } 303 final String valLower = value.toLowerCase(); 304 if(valLower.equals(".inf")) { 305 return sign == -1 ? INF_VALUE_NEG : INF_VALUE_POS; 306 } else if(valLower.equals(".nan")) { 307 return NAN_VALUE; 308 } else if(value.indexOf(':') != -1) { 309 final String [] digits = value.split(":"); 310 int bes = 1; 311 double val = 0.0; 312 for(int i=0,j=digits.length;i<j;i++) { 313 val += (Double.parseDouble(digits[(j-i)-1])*bes); 314 bes *= 60; 315 } 316 return new Double (sign*val); 317 } else { 318 return Double.valueOf(value); 319 } 320 } 321 322 public static Object constructYamlBinary(final Constructor ctor, final Node node) { 323 final String [] values = ctor.constructScalar(node).toString().split("[\n\u0085]|(?:\r[^\n])"); 324 final StringBuffer vals = new StringBuffer (); 325 for(int i=0,j=values.length;i<j;i++) { 326 vals.append(values[i].trim()); 327 } 328 return Base64Coder.decode(ByteList.plain(vals)); 329 } 330 331 public static Object constructSpecializedSequence(final Constructor ctor, final String pref, final Node node) { 332 List outp = null; 333 try { 334 final Class seqClass = Class.forName(pref); 335 outp = (List )seqClass.newInstance(); 336 } catch(final Exception e) { 337 throw new YAMLException("Can't construct a sequence from class " + pref + ": " + e.toString()); 338 } 339 outp.addAll((List )ctor.constructSequence(node)); 340 return outp; 341 } 342 343 public static Object constructSpecializedMap(final Constructor ctor, final String pref, final Node node) { 344 Map outp = null; 345 try { 346 final Class mapClass = Class.forName(pref); 347 outp = (Map )mapClass.newInstance(); 348 } catch(final Exception e) { 349 throw new YAMLException("Can't construct a mapping from class " + pref + ": " + e.toString()); 350 } 351 outp.putAll((Map )ctor.constructMapping(node)); 352 return outp; 353 } 354 355 private static Object fixValue(final Object inp, final Class outp) { 356 if(inp == null) { 357 return null; 358 } 359 final Class inClass = inp.getClass(); 360 if(outp.isAssignableFrom(inClass)) { 361 return inp; 362 } 363 if(inClass == Long .class && (outp == Integer .class || outp == Integer.TYPE)) { 364 return new Integer (((Long )inp).intValue()); 365 } 366 if(inClass == Long .class && (outp == Short .class || outp == Short.TYPE)) { 367 return new Short ((short)((Long )inp).intValue()); 368 } 369 if(inClass == Long .class && (outp == Character .class || outp == Character.TYPE)) { 370 return new Character ((char)((Long )inp).intValue()); 371 } 372 if(inClass == Double .class && (outp == Float .class || outp == Float.TYPE)) { 373 return new Float (((Double )inp).floatValue()); 374 } 375 return inp; 376 } 377 378 public static Object constructJava(final Constructor ctor, final String pref, final Node node) { 379 Object outp = null; 380 try { 381 final Class cl = Class.forName(pref); 382 outp = cl.newInstance(); 383 final Map values = (Map )ctor.constructMapping(node); 384 java.lang.reflect.Method [] ems = cl.getMethods(); 385 for(final Iterator iter = values.keySet().iterator();iter.hasNext();) { 386 final Object key = iter.next(); 387 final Object value = values.get(key); 388 final String keyName = key.toString(); 389 final String mName = "set" + Character.toUpperCase(keyName.charAt(0)) + keyName.substring(1); 390 for(int i=0,j=ems.length;i<j;i++) { 391 if(ems[i].getName().equals(mName) && ems[i].getParameterTypes().length == 1) { 392 ems[i].invoke(outp, new Object []{fixValue(value, ems[i].getParameterTypes()[0])}); 393 break; 394 } 395 } 396 } 397 } catch(final Exception e) { 398 throw new YAMLException("Can't construct a java object from class " + pref + ": " + e.toString()); 399 } 400 return outp; 401 } 402 403 static { 404 BaseConstructorImpl.addConstructor("tag:yaml.org,2002:null",new YamlConstructor() { 405 public Object call(final Constructor self, final Node node) { 406 return constructYamlNull(self,node); 407 } 408 }); 409 addConstructor("tag:yaml.org,2002:bool",new YamlConstructor() { 410 public Object call(final Constructor self, final Node node) { 411 return constructYamlBool(self,node); 412 } 413 }); 414 addConstructor("tag:yaml.org,2002:omap",new YamlConstructor() { 415 public Object call(final Constructor self, final Node node) { 416 return constructYamlOmap(self,node); 417 } 418 }); 419 addConstructor("tag:yaml.org,2002:pairs",new YamlConstructor() { 420 public Object call(final Constructor self, final Node node) { 421 return constructYamlPairs(self,node); 422 } 423 }); 424 addConstructor("tag:yaml.org,2002:set",new YamlConstructor() { 425 public Object call(final Constructor self, final Node node) { 426 return constructYamlSet(self,node); 427 } 428 }); 429 addConstructor("tag:yaml.org,2002:int",new YamlConstructor() { 430 public Object call(final Constructor self, final Node node) { 431 return constructYamlInt(self,node); 432 } 433 }); 434 addConstructor("tag:yaml.org,2002:float",new YamlConstructor() { 435 public Object call(final Constructor self, final Node node) { 436 return constructYamlFloat(self,node); 437 } 438 }); 439 addConstructor("tag:yaml.org,2002:timestamp",new YamlConstructor() { 440 public Object call(final Constructor self, final Node node) { 441 return constructYamlTimestamp(self,node); 442 } 443 }); 444 addConstructor("tag:yaml.org,2002:timestamp#ymd",new YamlConstructor() { 445 public Object call(final Constructor self, final Node node) { 446 return constructYamlTimestamp(self,node); 447 } 448 }); 449 addConstructor("tag:yaml.org,2002:str",new YamlConstructor() { 450 public Object call(final Constructor self, final Node node) { 451 return constructYamlStr(self,node); 452 } 453 }); 454 addConstructor("tag:yaml.org,2002:binary",new YamlConstructor() { 455 public Object call(final Constructor self, final Node node) { 456 return constructYamlBinary(self,node); 457 } 458 }); 459 addConstructor("tag:yaml.org,2002:seq",new YamlConstructor() { 460 public Object call(final Constructor self, final Node node) { 461 return constructYamlSeq(self,node); 462 } 463 }); 464 addConstructor("tag:yaml.org,2002:map",new YamlConstructor() { 465 public Object call(final Constructor self, final Node node) { 466 return constructYamlMap(self,node); 467 } 468 }); 469 addConstructor(null,new YamlConstructor() { 470 public Object call(final Constructor self, final Node node) { 471 return self.constructPrivateType(node); 472 } 473 }); 474 475 addMultiConstructor("tag:yaml.org,2002:seq:",new YamlMultiConstructor() { 476 public Object call(final Constructor self, final String pref, final Node node) { 477 return constructSpecializedSequence(self,pref,node); 478 } 479 }); 480 addMultiConstructor("tag:yaml.org,2002:map:",new YamlMultiConstructor() { 481 public Object call(final Constructor self, final String pref, final Node node) { 482 return constructSpecializedMap(self,pref,node); 483 } 484 }); 485 addMultiConstructor("!java/object:",new YamlMultiConstructor() { 486 public Object call(final Constructor self, final String pref, final Node node) { 487 return constructJava(self,pref,node); 488 } 489 }); 490 } 491 492 public static void main(final String [] args) throws Exception { 493 final String filename = args[0]; 494 System.out.println("Reading of file: \"" + filename + "\""); 495 496 final ByteList input = new ByteList(1024); 497 final InputStream reader = new FileInputStream (filename); 498 byte[] buff = new byte[1024]; 499 int read = 0; 500 while(true) { 501 read = reader.read(buff); 502 input.append(buff,0,read); 503 if(read < 1024) { 504 break; 505 } 506 } 507 reader.close(); 508 final long before = System.currentTimeMillis(); 509 for(int i=0;i<1;i++) { 510 final Constructor ctor = new SafeConstructorImpl(new ComposerImpl(new ParserImpl(new ScannerImpl(input)),new ResolverImpl())); 511 for(final Iterator iter = ctor.eachDocument();iter.hasNext();) { 512 iter.next(); 513 } 515 } 516 final long after = System.currentTimeMillis(); 517 final long time = after-before; 518 final double timeS = (after-before)/1000.0; 519 System.out.println("Walking through the nodes for the file: " + filename + " took " + time + "ms, or " + timeS + " seconds"); 520 } 521 } | Popular Tags |