1 21 package proguard; 22 23 import proguard.classfile.ClassConstants; 24 import proguard.classfile.util.ClassUtil; 25 import proguard.util.ListUtil; 26 27 import java.io.*; 28 import java.util.*; 29 import java.net.URL ; 30 31 32 38 public class ConfigurationParser 39 { 40 private WordReader reader; 41 private String nextWord; 42 private String lastComments; 43 44 45 48 public ConfigurationParser(String [] args) throws IOException 49 { 50 this(args, null); 51 } 52 53 54 58 public ConfigurationParser(String [] args, 59 File baseDir) throws IOException 60 { 61 reader = new ArgumentWordReader(args, baseDir); 62 63 readNextWord(); 64 } 65 66 67 70 public ConfigurationParser(File file) throws IOException 71 { 72 reader = new FileWordReader(file); 73 74 readNextWord(); 75 } 76 77 78 81 public ConfigurationParser(URL url) throws IOException 82 { 83 reader = new FileWordReader(url); 84 85 readNextWord(); 86 } 87 88 89 96 public void parse(Configuration configuration) 97 throws ParseException, IOException 98 { 99 while (nextWord != null) 100 { 101 lastComments = reader.lastComments(); 102 103 if (ConfigurationConstants.AT_DIRECTIVE .startsWith(nextWord) || 105 ConfigurationConstants.INCLUDE_DIRECTIVE .startsWith(nextWord)) configuration.lastModified = parseIncludeArgument(configuration.lastModified); 106 else if (ConfigurationConstants.BASE_DIRECTORY_DIRECTIVE .startsWith(nextWord)) parseBaseDirectoryArgument(); 107 108 else if (ConfigurationConstants.INJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, false); 110 else if (ConfigurationConstants.OUTJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, true); 111 else if (ConfigurationConstants.LIBRARYJARS_OPTION .startsWith(nextWord)) configuration.libraryJars = parseClassPathArgument(configuration.libraryJars, false); 112 else if (ConfigurationConstants.RESOURCEJARS_OPTION .startsWith(nextWord)) throw new ParseException("The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input"); 113 else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(false); 114 else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION.startsWith(nextWord)) configuration.skipNonPublicLibraryClassMembers = parseNoArgument(false); 115 else if (ConfigurationConstants.TARGET_OPTION .startsWith(nextWord)) configuration.targetClassVersion = parseClassVersion(); 116 else if (ConfigurationConstants.FORCE_PROCESSING_OPTION .startsWith(nextWord)) configuration.lastModified = parseNoArgument(Long.MAX_VALUE); 117 118 else if (ConfigurationConstants.KEEP_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, true, false, false); 119 else if (ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, false, false, false); 120 else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, false, true, false); 121 else if (ConfigurationConstants.KEEP_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, true, false, true); 122 else if (ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, false, false, true); 123 else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepSpecificationArguments(configuration.keep, false, true, true); 124 else if (ConfigurationConstants.PRINT_SEEDS_OPTION .startsWith(nextWord)) configuration.printSeeds = parseOptionalFile(); 125 126 else if (ConfigurationConstants.DONT_SHRINK_OPTION .startsWith(nextWord)) configuration.shrink = parseNoArgument(false); 127 else if (ConfigurationConstants.PRINT_USAGE_OPTION .startsWith(nextWord)) configuration.printUsage = parseOptionalFile(); 128 else if (ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION .startsWith(nextWord)) configuration.whyAreYouKeeping = parseClassSpecificationArguments(configuration.whyAreYouKeeping); 129 130 else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION .startsWith(nextWord)) configuration.optimize = parseNoArgument(false); 131 else if (ConfigurationConstants.OPTIMIZATION_PASSES .startsWith(nextWord)) configuration.optimizationPasses = parseIntegerArgument(); 132 else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION .startsWith(nextWord)) configuration.assumeNoSideEffects = parseClassSpecificationArguments(configuration.assumeNoSideEffects); 133 else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION .startsWith(nextWord)) configuration.allowAccessModification = parseNoArgument(true); 134 135 else if (ConfigurationConstants.DONT_OBFUSCATE_OPTION .startsWith(nextWord)) configuration.obfuscate = parseNoArgument(false); 136 else if (ConfigurationConstants.PRINT_MAPPING_OPTION .startsWith(nextWord)) configuration.printMapping = parseOptionalFile(); 137 else if (ConfigurationConstants.APPLY_MAPPING_OPTION .startsWith(nextWord)) configuration.applyMapping = parseFile(); 138 else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION .startsWith(nextWord)) configuration.obfuscationDictionary = parseFile(); 139 else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.overloadAggressively = parseNoArgument(true); 140 else if (ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.useUniqueClassMemberNames = parseNoArgument(true); 141 else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION .startsWith(nextWord)) configuration.useMixedCaseClassNames = parseNoArgument(false); 142 else if (ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION .startsWith(nextWord)) configuration.flattenPackageHierarchy = ClassUtil.internalClassName(parseOptionalArgument()); 143 else if (ConfigurationConstants.REPACKAGE_CLASSES_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument()); 144 else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument()); 145 else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION .startsWith(nextWord)) configuration.keepAttributes = parseCommaSeparatedList("attribute name", true, true, false, true, false, configuration.keepAttributes); 146 else if (ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION .startsWith(nextWord)) configuration.newSourceFileAttribute = parseOptionalArgument(); 147 else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION .startsWith(nextWord)) configuration.adaptResourceFileNames = parseCommaSeparatedList("resource file name", true, true, false, false, false, configuration.adaptResourceFileNames); 148 else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION .startsWith(nextWord)) configuration.adaptResourceFileContents = parseCommaSeparatedList("resource file name", true, true, false, false, false, configuration.adaptResourceFileContents); 149 150 else if (ConfigurationConstants.DONT_PREVERIFY_OPTION .startsWith(nextWord)) configuration.preverify = parseNoArgument(false); 151 else if (ConfigurationConstants.MICRO_EDITION_OPTION .startsWith(nextWord)) configuration.microEdition = parseNoArgument(true); 152 153 else if (ConfigurationConstants.VERBOSE_OPTION .startsWith(nextWord)) configuration.verbose = parseNoArgument(true); 154 else if (ConfigurationConstants.DONT_NOTE_OPTION .startsWith(nextWord)) configuration.note = parseNoArgument(false); 155 else if (ConfigurationConstants.DONT_WARN_OPTION .startsWith(nextWord)) configuration.warn = parseNoArgument(false); 156 else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION .startsWith(nextWord)) configuration.ignoreWarnings = parseNoArgument(true); 157 else if (ConfigurationConstants.PRINT_CONFIGURATION_OPTION .startsWith(nextWord)) configuration.printConfiguration = parseOptionalFile(); 158 else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalFile(); 159 else 160 { 161 throw new ParseException("Unknown option " + reader.locationDescription()); 162 } 163 } 164 } 165 166 167 168 172 public void close() throws IOException 173 { 174 if (reader != null) 175 { 176 reader.close(); 177 } 178 } 179 180 181 private long parseIncludeArgument(long lastModified) throws ParseException, IOException 182 { 183 readNextWord("configuration file name"); 185 186 File file = file(nextWord); 187 reader.includeWordReader(new FileWordReader(file)); 188 189 readNextWord(); 190 191 return Math.max(lastModified, file.lastModified()); 192 } 193 194 195 private void parseBaseDirectoryArgument() throws ParseException, IOException 196 { 197 readNextWord("base directory name"); 199 200 reader.setBaseDir(file(nextWord)); 201 202 readNextWord(); 203 } 204 205 206 private ClassPath parseClassPathArgument(ClassPath classPath, 207 boolean isOutput) 208 throws ParseException, IOException 209 { 210 if (classPath == null) 212 { 213 classPath = new ClassPath(); 214 } 215 216 while (true) 217 { 218 readNextWord("jar or directory name"); 220 221 ClassPathEntry entry = new ClassPathEntry(file(nextWord), isOutput); 223 224 readNextWord(); 226 227 if (!configurationEnd() && 229 ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord)) 230 { 231 String [] filters = new String [5]; 233 234 int counter = 0; 235 do 236 { 237 filters[counter++] = 239 ListUtil.commaSeparatedString( 240 parseCommaSeparatedList("filter", true, 241 false, true, false, true, null)); 242 } 243 while (counter < filters.length && 244 ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)); 245 246 if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord)) 248 { 249 throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + 250 "' or '" + ConfigurationConstants.SEPARATOR_KEYWORD + 251 "', or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + 252 "' before " + reader.locationDescription()); 253 } 254 255 entry.setFilter(filters[--counter]); 257 if (counter > 0) 258 { 259 entry.setJarFilter(filters[--counter]); 260 if (counter > 0) 261 { 262 entry.setWarFilter(filters[--counter]); 263 if (counter > 0) 264 { 265 entry.setEarFilter(filters[--counter]); 266 if (counter > 0) 267 { 268 entry.setZipFilter(filters[--counter]); 269 } 270 } 271 } 272 } 273 274 readNextWord(); 276 } 277 278 classPath.add(entry); 280 281 if (configurationEnd()) 282 { 283 return classPath; 284 } 285 286 if (!nextWord.equals(ConfigurationConstants.JAR_SEPARATOR_KEYWORD)) 287 { 288 throw new ParseException("Expecting class path separator '" + ConfigurationConstants.JAR_SEPARATOR_KEYWORD + 289 "' before " + reader.locationDescription()); 290 } 291 } 292 } 293 294 295 private int parseClassVersion() 296 throws ParseException, IOException 297 { 298 readNextWord("java version"); 300 301 int classVersion = ClassUtil.internalClassVersion(nextWord); 302 if (classVersion == 0) 303 { 304 throw new ParseException("Unsupported java version " + reader.locationDescription()); 305 } 306 307 readNextWord(); 308 309 return classVersion; 310 } 311 312 313 private int parseIntegerArgument() 314 throws ParseException, IOException 315 { 316 try 317 { 318 readNextWord("integer"); 320 321 int integer = Integer.parseInt(nextWord); 322 323 readNextWord(); 324 325 return integer; 326 } 327 catch (NumberFormatException e) 328 { 329 throw new ParseException("Expecting integer argument instead of '" + nextWord + 330 "' before " + reader.locationDescription()); 331 } 332 } 333 334 335 private File parseFile() 336 throws ParseException, IOException 337 { 338 readNextWord("file name"); 340 341 File file = file(nextWord); 343 344 readNextWord(); 345 346 return file; 347 } 348 349 350 private File parseOptionalFile() 351 throws ParseException, IOException 352 { 353 readNextWord(); 355 356 if (configurationEnd()) 358 { 359 return new File(""); 360 } 361 362 File file = file(nextWord); 364 365 readNextWord(); 366 367 return file; 368 } 369 370 371 private String parseOptionalArgument() throws IOException 372 { 373 readNextWord(); 375 376 if (configurationEnd()) 378 { 379 return ""; 380 } 381 382 String fileName = nextWord; 383 384 readNextWord(); 385 386 return fileName; 387 } 388 389 390 private boolean parseNoArgument(boolean value) throws IOException 391 { 392 readNextWord(); 393 394 return value; 395 } 396 397 398 private long parseNoArgument(long value) throws IOException 399 { 400 readNextWord(); 401 402 return value; 403 } 404 405 406 private List parseKeepSpecificationArguments(List keepSpecifications, 407 boolean markClasses, 408 boolean markConditionally, 409 boolean allowShrinking) 410 throws ParseException, IOException 411 { 412 if (keepSpecifications == null) 414 { 415 keepSpecifications = new ArrayList(); 416 } 417 418 boolean allowOptimization = false; 420 boolean allowObfuscation = false; 421 422 while (true) 424 { 425 readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + 426 "' or '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'", true); 427 428 if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord)) 429 { 430 break; 432 } 433 434 readNextWord("keyword '" + 435 ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION + "', '" + 436 ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION + "', or '" + 437 ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION + "'"); 438 439 if (ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION .startsWith(nextWord)) 440 { 441 allowShrinking = true; 442 } 443 else if (ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION.startsWith(nextWord)) 444 { 445 allowOptimization = true; 446 } 447 else if (ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION .startsWith(nextWord)) 448 { 449 allowObfuscation = true; 450 } 451 else 452 { 453 throw new ParseException("Expecting keyword '" + 454 ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION + "', '" + 455 ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION + "', or '" + 456 ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION + "' before " + 457 reader.locationDescription()); 458 } 459 } 460 461 ClassSpecification classSpecification = 463 parseClassSpecificationArguments(); 464 465 keepSpecifications.add(new KeepSpecification(markClasses, 467 markConditionally, 468 allowShrinking, 469 allowOptimization, 470 allowObfuscation, 471 classSpecification)); 472 473 return keepSpecifications; 474 } 475 476 477 private List parseClassSpecificationArguments(List classSpecifications) 478 throws ParseException, IOException 479 { 480 if (classSpecifications == null) 482 { 483 classSpecifications = new ArrayList(); 484 } 485 486 readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + 488 "' or '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'", true); 489 490 classSpecifications.add(parseClassSpecificationArguments()); 491 492 return classSpecifications; 493 } 494 495 496 private ClassSpecification parseClassSpecificationArguments() 497 throws ParseException, IOException 498 { 499 String annotationType = null; 501 502 int requiredSetClassAccessFlags = 0; 504 int requiredUnsetClassAccessFlags = 0; 505 506 while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord)) 508 { 509 if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord)) 511 { 512 annotationType = 513 ClassUtil.internalType( 514 ListUtil.commaSeparatedString( 515 parseCommaSeparatedList("annotation type", 516 true, false, false, true, false, null))); 517 518 continue; 519 } 520 521 String strippedWord = nextWord.startsWith(ConfigurationConstants.NEGATOR_KEYWORD) ? 523 nextWord.substring(1) : 524 nextWord; 525 526 int accessFlag = 528 strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : 529 strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : 530 strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE : 531 strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : 532 unknownAccessFlag(); 533 if (strippedWord == nextWord) 534 { 535 requiredSetClassAccessFlags |= accessFlag; 536 } 537 else 538 { 539 requiredUnsetClassAccessFlags |= accessFlag; 540 } 541 542 543 if ((requiredSetClassAccessFlags & 544 requiredUnsetClassAccessFlags) != 0) 545 { 546 throw new ParseException("Conflicting class access modifiers for '" + strippedWord + 547 "' before " + reader.locationDescription()); 548 } 549 550 if (ClassConstants.EXTERNAL_ACC_INTERFACE.equals(strippedWord)) 551 { 552 break; 554 } 555 556 readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + 557 "' or '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'"); 558 } 559 560 String externalClassName = 562 ListUtil.commaSeparatedString( 563 parseCommaSeparatedList("class name or interface name", 564 true, false, false, true, false, null)); 565 566 String className = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalClassName) ? 569 null : 570 ClassUtil.internalClassName(externalClassName); 571 572 String extendsAnnotationType = null; 574 String extendsClassName = null; 575 576 if (!configurationEnd()) 577 { 578 if (ConfigurationConstants.IMPLEMENTS_KEYWORD.equals(nextWord) || 580 ConfigurationConstants.EXTENDS_KEYWORD.equals(nextWord)) 581 { 582 readNextWord("class name or interface name", true); 583 584 if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord)) 586 { 587 extendsAnnotationType = 588 ClassUtil.internalType( 589 ListUtil.commaSeparatedString( 590 parseCommaSeparatedList("annotation type", 591 true, false, false, true, false, null))); 592 } 593 594 String externalExtendsClassName = 595 ListUtil.commaSeparatedString( 596 parseCommaSeparatedList("class name or interface name", 597 false, false, false, true, false, null)); 598 599 extendsClassName = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalExtendsClassName) ? 600 null : 601 ClassUtil.internalClassName(externalExtendsClassName); 602 } 603 } 604 605 ClassSpecification classSpecification = 607 new ClassSpecification(lastComments, 608 requiredSetClassAccessFlags, 609 requiredUnsetClassAccessFlags, 610 annotationType, 611 className, 612 extendsAnnotationType, 613 extendsClassName); 614 615 616 if (!configurationEnd()) 618 { 619 if (!ConfigurationConstants.OPEN_KEYWORD.equals(nextWord)) 621 { 622 throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_KEYWORD + 623 "' at " + reader.locationDescription()); 624 } 625 626 while (true) 628 { 629 readNextWord("class member description" + 630 " or closing '" + ConfigurationConstants.CLOSE_KEYWORD + "'", true); 631 632 if (nextWord.equals(ConfigurationConstants.CLOSE_KEYWORD)) 633 { 634 readNextWord(); 636 637 break; 638 } 639 640 parseMemberSpecificationArguments(externalClassName, 641 classSpecification); 642 } 643 } 644 645 return classSpecification; 646 } 647 648 649 private void parseMemberSpecificationArguments(String externalClassName, 650 ClassSpecification classSpecification) 651 throws ParseException, IOException 652 { 653 String annotationType = null; 655 656 int requiredSetMemberAccessFlags = 0; 658 int requiredUnsetMemberAccessFlags = 0; 659 660 while (!configurationEnd(true)) 661 { 662 if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord)) 664 { 665 annotationType = 666 ClassUtil.internalType( 667 ListUtil.commaSeparatedString( 668 parseCommaSeparatedList("annotation type", 669 true, false, false, true, false, null))); 670 671 continue; 672 } 673 674 String strippedWord = nextWord.startsWith("!") ? 675 nextWord.substring(1) : 676 nextWord; 677 678 int accessFlag = 680 strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : 681 strippedWord.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE : 682 strippedWord.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED : 683 strippedWord.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC : 684 strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : 685 strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : 686 strippedWord.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : 687 strippedWord.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : 688 strippedWord.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : 689 strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : 690 strippedWord.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : 691 0; 692 if (accessFlag == 0) 693 { 694 break; 696 } 697 698 if (strippedWord == nextWord) 699 { 700 requiredSetMemberAccessFlags |= accessFlag; 701 } 702 else 703 { 704 requiredUnsetMemberAccessFlags |= accessFlag; 705 } 706 707 if ((requiredSetMemberAccessFlags & 710 requiredUnsetMemberAccessFlags) != 0) 711 { 712 throw new ParseException("Conflicting class member access modifiers for " + 713 reader.locationDescription()); 714 } 715 716 readNextWord("class member description"); 717 } 718 719 721 if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord) || 723 ConfigurationConstants.ANY_FIELD_KEYWORD .equals(nextWord) || 724 ConfigurationConstants.ANY_METHOD_KEYWORD .equals(nextWord)) 725 { 726 if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord)) 728 { 729 checkFieldAccessFlags(requiredSetMemberAccessFlags, 730 requiredUnsetMemberAccessFlags); 731 checkMethodAccessFlags(requiredSetMemberAccessFlags, 732 requiredUnsetMemberAccessFlags); 733 734 classSpecification.addField( 735 new MemberSpecification(requiredSetMemberAccessFlags, 736 requiredUnsetMemberAccessFlags, 737 annotationType, 738 null, 739 null)); 740 classSpecification.addMethod( 741 new MemberSpecification(requiredSetMemberAccessFlags, 742 requiredUnsetMemberAccessFlags, 743 annotationType, 744 null, 745 null)); 746 } 747 else if (ConfigurationConstants.ANY_FIELD_KEYWORD.equals(nextWord)) 748 { 749 checkFieldAccessFlags(requiredSetMemberAccessFlags, 750 requiredUnsetMemberAccessFlags); 751 752 classSpecification.addField( 753 new MemberSpecification(requiredSetMemberAccessFlags, 754 requiredUnsetMemberAccessFlags, 755 annotationType, 756 null, 757 null)); 758 } 759 else if (ConfigurationConstants.ANY_METHOD_KEYWORD.equals(nextWord)) 760 { 761 checkMethodAccessFlags(requiredSetMemberAccessFlags, 762 requiredUnsetMemberAccessFlags); 763 764 classSpecification.addMethod( 765 new MemberSpecification(requiredSetMemberAccessFlags, 766 requiredUnsetMemberAccessFlags, 767 annotationType, 768 null, 769 null)); 770 } 771 772 readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); 774 775 if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) 776 { 777 throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + 778 "' before " + reader.locationDescription()); 779 } 780 } 781 else 782 { 783 checkJavaIdentifier("java type"); 785 String type = nextWord; 786 787 readNextWord("class member name"); 788 String name = nextWord; 789 790 if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(name)) 792 { 793 if (!(type.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) || 796 type.equals(externalClassName) || 797 type.equals(ClassUtil.externalShortClassName(externalClassName)))) 798 { 799 throw new ParseException("Expecting type and name " + 800 "instead of just '" + type + 801 "' before " + reader.locationDescription()); 802 } 803 804 type = ClassConstants.EXTERNAL_TYPE_VOID; 806 name = ClassConstants.INTERNAL_METHOD_NAME_INIT; 807 } 808 else 809 { 810 checkJavaIdentifier("class member name"); 813 814 readNextWord("opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + 817 "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); 818 } 819 820 if (ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) 822 { 823 checkFieldAccessFlags(requiredSetMemberAccessFlags, 825 requiredUnsetMemberAccessFlags); 826 827 String descriptor = ClassUtil.internalType(type); 829 830 classSpecification.addField( 832 new MemberSpecification(requiredSetMemberAccessFlags, 833 requiredUnsetMemberAccessFlags, 834 annotationType, 835 name, 836 descriptor)); 837 } 838 else if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord)) 839 { 840 checkMethodAccessFlags(requiredSetMemberAccessFlags, 842 requiredUnsetMemberAccessFlags); 843 844 String descriptor = 846 ClassUtil.internalMethodDescriptor(type, 847 parseCommaSeparatedList("argument", true, true, true, true, false, null)); 848 849 if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord)) 850 { 851 throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + 852 "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + 853 "' before " + reader.locationDescription()); 854 } 855 856 readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); 858 859 if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) 860 { 861 throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + 862 "' before " + reader.locationDescription()); 863 } 864 865 classSpecification.addMethod( 867 new MemberSpecification(requiredSetMemberAccessFlags, 868 requiredUnsetMemberAccessFlags, 869 annotationType, 870 name, 871 descriptor)); 872 } 873 else 874 { 875 throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + 877 "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + 878 "' before " + reader.locationDescription()); 879 } 880 } 881 } 882 883 884 889 private List parseCommaSeparatedList(String expectedDescription, 890 boolean readFirstWord, 891 boolean allowEmptyList, 892 boolean expectClosingParenthesis, 893 boolean checkJavaIdentifiers, 894 boolean replaceSystemProperties, 895 List list) 896 throws ParseException, IOException 897 { 898 if (list == null) 899 { 900 list = new ArrayList(); 901 } 902 903 if (readFirstWord) 904 { 905 if (expectClosingParenthesis || !allowEmptyList) 906 { 907 readNextWord(expectedDescription); 909 } 910 else 911 { 912 readNextWord(); 914 915 if (configurationEnd() || 917 nextWord.equals(ConfigurationConstants.ANY_ATTRIBUTE_KEYWORD)) 918 { 919 return list; 920 } 921 } 922 } 923 924 while (true) 925 { 926 if (expectClosingParenthesis && 927 list.size() == 0 && 928 (ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord) || 929 ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord))) 930 { 931 break; 932 } 933 934 if (checkJavaIdentifiers) 935 { 936 checkJavaIdentifier("java type"); 937 } 938 939 if (replaceSystemProperties) 940 { 941 nextWord = replaceSystemProperties(nextWord); 942 } 943 944 list.add(nextWord); 945 946 if (expectClosingParenthesis) 947 { 948 readNextWord("separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + 950 "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + 951 "'"); 952 } 953 else 954 { 955 readNextWord(); 957 } 958 959 if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord)) 960 { 961 break; 962 } 963 964 readNextWord(expectedDescription); 966 } 967 968 return list; 969 } 970 971 972 975 private int unknownAccessFlag() throws ParseException 976 { 977 throw new ParseException("Unexpected keyword " + reader.locationDescription()); 978 } 979 980 981 984 private File file(String word) throws ParseException 985 { 986 String fileName = replaceSystemProperties(word); 987 File file = new File(fileName); 988 989 if (!file.isAbsolute()) 991 { 992 file = new File(reader.getBaseDir(), fileName); 993 } 994 995 try 997 { 998 file = file.getCanonicalFile(); 999 } 1000 catch (IOException ex) 1001 { 1002 } 1003 1004 return file; 1005 } 1006 1007 1008 1012 private String replaceSystemProperties(String word) throws ParseException 1013 { 1014 int fromIndex = 0; 1015 while (true) 1016 { 1017 fromIndex = word.indexOf(ConfigurationConstants.OPEN_SYSTEM_PROPERTY, fromIndex); 1018 if (fromIndex < 0) 1019 { 1020 break; 1021 } 1022 1023 int toIndex = word.indexOf(ConfigurationConstants.CLOSE_SYSTEM_PROPERTY, fromIndex+1); 1024 if (toIndex < 0) 1025 { 1026 throw new ParseException("Expecting closing '" + ConfigurationConstants.CLOSE_SYSTEM_PROPERTY + 1027 "' after opening '" + ConfigurationConstants.OPEN_SYSTEM_PROPERTY + 1028 "' in " + reader.locationDescription()); 1029 } 1030 1031 String propertyName = word.substring(fromIndex+1, toIndex); 1032 String propertyValue = System.getProperty(propertyName); 1033 if (propertyValue == null) 1034 { 1035 throw new ParseException("Value of system property '" + propertyName + 1036 "' is undefined in " + reader.locationDescription()); 1037 } 1038 1039 word = word.substring(0, fromIndex) + 1040 propertyValue + 1041 word.substring(toIndex+1); 1042 } 1043 1044 return word; 1045 } 1046 1047 1048 1052 private void readNextWord(String expectedDescription) 1053 throws ParseException, IOException 1054 { 1055 readNextWord(expectedDescription, false); 1056 } 1057 1058 1059 1063 private void readNextWord(String expectedDescription, 1064 boolean expectingAtCharacter) 1065 throws ParseException, IOException 1066 { 1067 readNextWord(); 1068 if (configurationEnd(expectingAtCharacter)) 1069 { 1070 throw new ParseException("Expecting " + expectedDescription + 1071 " before " + reader.locationDescription()); 1072 } 1073 } 1074 1075 1076 1079 private void readNextWord() throws IOException 1080 { 1081 nextWord = reader.nextWord(); 1082 } 1083 1084 1085 1088 private boolean configurationEnd() 1089 { 1090 return configurationEnd(false); 1091 } 1092 1093 1094 1097 private boolean configurationEnd(boolean expectingAtCharacter) 1098 { 1099 return nextWord == null || 1100 nextWord.startsWith(ConfigurationConstants.OPTION_PREFIX) || 1101 (!expectingAtCharacter && 1102 nextWord.equals(ConfigurationConstants.AT_DIRECTIVE)); 1103 } 1104 1105 1106 1110 private void checkJavaIdentifier(String expectedDescription) 1111 throws ParseException 1112 { 1113 if (!isJavaIdentifier(nextWord)) 1114 { 1115 throw new ParseException("Expecting " + expectedDescription + 1116 " before " + reader.locationDescription()); 1117 } 1118 } 1119 1120 1121 1125 private boolean isJavaIdentifier(String aWord) 1126 { 1127 for (int index = 0; index < aWord.length(); index++) 1128 { 1129 char c = aWord.charAt(index); 1130 if (!(Character.isJavaIdentifierPart(c) || 1131 c == '.' || 1132 c == '[' || 1133 c == ']' || 1134 c == '<' || 1135 c == '>' || 1136 c == '-' || 1137 c == '!' || 1138 c == '*' || 1139 c == '?' || 1140 c == '%')) 1141 { 1142 return false; 1143 } 1144 } 1145 1146 return true; 1147 } 1148 1149 1150 1154 private void checkFieldAccessFlags(int requiredSetMemberAccessFlags, 1155 int requiredUnsetMemberAccessFlags) 1156 throws ParseException 1157 { 1158 if (((requiredSetMemberAccessFlags | 1159 requiredUnsetMemberAccessFlags) & 1160 ~ClassConstants.VALID_INTERNAL_ACC_FIELD) != 0) 1161 { 1162 throw new ParseException("Invalid method access modifier for field before " + 1163 reader.locationDescription()); 1164 } 1165 } 1166 1167 1168 1172 private void checkMethodAccessFlags(int requiredSetMemberAccessFlags, 1173 int requiredUnsetMemberAccessFlags) 1174 throws ParseException 1175 { 1176 if (((requiredSetMemberAccessFlags | 1177 requiredUnsetMemberAccessFlags) & 1178 ~ClassConstants.VALID_INTERNAL_ACC_METHOD) != 0) 1179 { 1180 throw new ParseException("Invalid field access modifier for method before " + 1181 reader.locationDescription()); 1182 } 1183 } 1184 1185 1186 1189 public static void main(String [] args) 1190 { 1191 try 1192 { 1193 ConfigurationParser parser = new ConfigurationParser(args); 1194 1195 try 1196 { 1197 parser.parse(new Configuration()); 1198 } 1199 catch (ParseException ex) 1200 { 1201 ex.printStackTrace(); 1202 } 1203 finally 1204 { 1205 parser.close(); 1206 } 1207 } 1208 catch (IOException ex) 1209 { 1210 ex.printStackTrace(); 1211 } 1212 } 1213} 1214 | Popular Tags |