Compare commits

...

298 Commits

Author SHA1 Message Date
hoenicke e5c8e18a43 Updated String type to Java 6/7. 11 years ago
hoenicke 33504d1840 Small bug fix 11 years ago
hoenicke 7a96e31c81 Labelled Blocks 12 years ago
hoenicke 0277d99ebb Removed absolute paths 12 years ago
hoenicke accfa1271e New way to handle catch blocks, still needs finetuning 12 years ago
hoenicke 744346bbcb Added eclipse configuration 12 years ago
hoenicke 3c76f52d03 Fix more Warnings 12 years ago
hoenicke 5815ab3a08 Fix Warnings 12 years ago
hoenicke 977e4a6e8d Added accessor method getCondition to IfThenElseBlock 18 years ago
asal 0526241d2f bugfix 1626107 18 years ago
asal 2610837e4e decompile output: added "python" style and line length variable 18 years ago
asal 08ca574741 test string comparison locale must iso-8859-1, bytewise comparison 18 years ago
hoenicke a69e8b35b6 Fixed png Files 18 years ago
hoenicke 39775ca4ee Information about subversion 18 years ago
hoenicke f7d5e15584 * src/net/sf/jode/flow/TransformConstructor.java: 19 years ago
hoenicke 000cbe01e8 Check for NullPointer in SyntheticAnalyzer. Based on 19 years ago
hoenicke 4ff081adef Changed enum to enumeration to make it compile with Java 5 19 years ago
hoenicke 183db2f66c Removed old outdated hints to change URL. The old URL scheme doesn't work anymore, because sourceforge disallows outgoing connections from the web server. 20 years ago
hoenicke 4ec17554de Integrated changes from 1.2->1.3 of index.php 20 years ago
hoenicke 7a700a7a5b Jode logo looks now better 20 years ago
hoenicke 9e663e0b65 HTP logo now certified by M. Moeller :) 20 years ago
hoenicke 7442ded059 Produce web pages with htp now. 20 years ago
hoenicke 487a4b49d9 Some copyright/documentation updates 20 years ago
hoenicke 033d9d57e5 Checked in LGPL License file 20 years ago
hoenicke ec129979e1 * build.xml: replace execon with apply. 20 years ago
hoenicke ae5ffbf3f8 Set copyright to LGPL for package type 20 years ago
hoenicke bf472df5c0 Handle jdk1.4 class$ methods. 21 years ago
hoenicke 338feb1f61 * src/net/sf/jode/jvm/SyntheticAnalyzer.java (checkGetClass): 21 years ago
seeksthemoon 2872b22195 Added MANIFEST.MF to be able to create executable jar-file. The 21 years ago
seeksthemoon c53a8d1acf Added new MenuItem to save a decompiled file. Main window now will be 21 years ago
hoenicke 0c1d7a4b7c Made HTML/4.0 conform; minor updates 22 years ago
hoenicke 66dc0880ab Fixed a bug spotted by Eider Oliveira 22 years ago
hoenicke 48d511532d New option keep-alive. With this option jode won't stop after an error 22 years ago
hoenicke d6462acefc Moved addHeader.pl to scripts. 22 years ago
hoenicke f43b317ae8 Set copyright to LGPL for packages util,bytecode,jvm,expr,flow and decompiler. 22 years ago
hoenicke 375a002248 Don't check for a maximum version anymore. Sun changes it with every 23 years ago
hoenicke b33f6d1045 Fixed link to collections.jar 23 years ago
hoenicke c11b2426df Handle empty blocks used for "while(true) {}" 23 years ago
hoenicke d7567a6b06 Added syntax for IdentifierMatcher. 23 years ago
hoenicke 06f647eb1c Added info about SerializePreserver. 23 years ago
hoenicke c0bd096c0d Updated link to dmoz directory. 23 years ago
hoenicke d04992725b Fixed major/minor naming. Allow minor to be bigger than 45 for newer java 23 years ago
hoenicke d3f133999f HTML view 23 years ago
hoenicke 25339761a8 Added a-logo 23 years ago
hoenicke 0243eb4f23 Copied documentation from Jode-1.1 23 years ago
hoenicke 9e5dca11ad Added new script to convert php to html. 23 years ago
hoenicke d5a0591d1f Javadoc updates. 23 years ago
hoenicke 2d1bb14f08 Added javadoc overview. 23 years ago
hoenicke 14b4dd94f8 Added test cases. 23 years ago
hoenicke 7714d5d503 Documentation updates. 23 years ago
hoenicke 6acf9d8d7a More Documentation updates. 23 years ago
hoenicke dab92b2d4d Added configuration file. 23 years ago
hoenicke 4352b285ab Documentation updates (INSTALL, javadoc). 23 years ago
hoenicke 1ce57d3614 build.xml: Search lib directory for all jar files and put them in classpath 23 years ago
hoenicke 804d4f7912 Cleaning up 23 years ago
hoenicke 743e08ea39 Cleaning up. 23 years ago
hoenicke 31ebef4f9c Changed compilation procedure to ant. 23 years ago
hoenicke a2006f63d4 Fixed import of non collection java.util classes. 23 years ago
hoenicke f2d8663e9f * jode/AssertError.java: removed, all uses are now replaced 23 years ago
hoenicke e78e8b0472 Applied more patches from Jode-1.1 branch 23 years ago
hoenicke 676e21257f Applied more patches from Jode-1.1 branch. 23 years ago
hoenicke c30ac484c5 Applied changes from the Jode-1.1 tree. 23 years ago
hoenicke 9f97289a90 Updated to viewcvs.cgi 23 years ago
hoenicke 472188e7ff Added description how to run automake/autoconf. 23 years ago
hoenicke 14943a8451 Changed mail address to jode-commit list. 24 years ago
hoenicke 9cbbe3b6ea Check in gif and xcf as binary. 24 years ago
hoenicke 51ad83c9c9 Polishing up syncmail. 24 years ago
hoenicke 2ae9fec86a Changed format of commit messages. 24 years ago
hoenicke 5a22174883 Changed syncmail script to only print urls. 24 years ago
hoenicke e3e58de150 fixed typo. 24 years ago
hoenicke 389f642dd5 Trying to send cvs commit messages. 24 years ago
hoenicke 342283c03a added syncmail. 24 years ago
hoenicke 9470aef606 Method scoped classes can look like inner classes. Try to distinguish by 24 years ago
hoenicke 03a84b8f4f Some fixes. 24 years ago
hoenicke 31b99cc4f0 First update, not complete... 24 years ago
hoenicke 8c85a88d39 Minor fixes. 24 years ago
hoenicke 854a466d67 Copy options from childBP, when replacing childBP with this break point. 24 years ago
hoenicke 0e32c28865 Moved getDefaultValue to TypeSignature 24 years ago
hoenicke 00448cfcbc Added a missing load() 24 years ago
hoenicke 8f00154e64 add new sanity check to ReturnBlock. 24 years ago
hoenicke 712f5d03dd Insert a jump to end-of-method after a valued return, since try-catch analysis 24 years ago
hoenicke b14a4f5e86 Merged checkAccess() and checkStaticAccess(), since they are very similar and 24 years ago
hoenicke e4b704ca70 Updated links to dmoz.org 24 years ago
hoenicke 571bb071fe Initial release 24 years ago
hoenicke 1a0fc97111 Added some information about the different passes. 24 years ago
hoenicke 4a63627c87 Big updates: bytecode instruction interface, new types for the decompiler, 24 years ago
hoenicke 5e6af53990 * ConstantInstruction.java,IncInstruction.java,ReferenceInstruction.java,SlotInstruction.java,TypeDimensionInstruction.java,TypeInstruction.java: Class and Constructors no longer public. 24 years ago
hoenicke ca386721b2 Use the ClassPath to list all classes. 24 years ago
hoenicke af97d8da6d Remove ampersands (I thought they were used to underline characters). 24 years ago
hoenicke 7ff611fe09 Removed obfuscator directory since it currently doesn't compile. 24 years ago
hoenicke bde4f7f48c Added a nice ClassPathDialog. 24 years ago
hoenicke e154dfdc1b Changed version code, to accept version 46.0 (jdk 1.2) 24 years ago
hoenicke 0b2f10fddf beautification 24 years ago
hoenicke bf597fea43 toString: close tabbed print writer to flush it 24 years ago
hoenicke aca625aa34 Added functionality to flush() and close() 24 years ago
hoenicke 34081d2e06 Fixed calculation of SerialVersionUID 24 years ago
hoenicke 96ef935ccc Allow the additional parameter for constructor wrappers occur at every place 24 years ago
hoenicke 46f4102cec Reading of LocalVariableTable entries fixed. 24 years ago
hoenicke ff73414ef3 reworked comment. 24 years ago
hoenicke b99c87a98d mergeModifiers: Merge the right modifiers for innerclasses attributes. 24 years ago
hoenicke f85c46fd44 TODO list updated 24 years ago
hoenicke 39d1fbb31b New scripts directory. 24 years ago
hoenicke 3378492cd3 New bytecode interface, no .java.in files anymore 24 years ago
hoenicke a34a837696 The package description. 24 years ago
hoenicke b53430f5c5 Adapted to new bytecode package. 24 years ago
hoenicke 723088e8be New bytecode interface: 24 years ago
hoenicke 9c9de3b561 Put menu in head line, added feedback page, small updates. 24 years ago
hoenicke 076911a762 final static fields must always be initialized, so output a null 24 years ago
hoenicke 826a7ec101 Searching collection classes in package gnu.java.util.collections 24 years ago
hoenicke edc69e287a Updated web pages. 24 years ago
hoenicke 7a3d90542b Handle INVOKESPECIAL, where the class expression isn't this. 24 years ago
hoenicke 60889790b5 Remove most modifiers from static constructors, since java syntax 24 years ago
hoenicke 058eb11e6a Import classes from unnamed packages correctly 24 years ago
hoenicke de5d631370 Fixed a status message 24 years ago
hoenicke f8fa155236 Added a nicely looking border around the applet. 24 years ago
hoenicke 76430344f3 Fallback to jar if unzip is missing for class detection. 24 years ago
hoenicke ae980c0e34 Pretty option fixed. 24 years ago
hoenicke eedb8fadf5 Header of decompiled files adjusted for SourceForge 24 years ago
hoenicke d20847b1a3 Initial revision 24 years ago
root 55f208a167 initial checkin 24 years ago
root bd2e71821b initial checkin 24 years ago
jochen 92878b6692 Line breaking added. 24 years ago
jochen b8e6d80e8c fixed a bug in long shifts 24 years ago
jochen 5f8d149b5e Makefile optimized 25 years ago
jochen 7628ebc073 Makefile optimized 25 years ago
jochen dfd56173e8 Use new Decompiler interface, with progress bar 25 years ago
jochen 2bc051bee9 ConstantAnalyzer: Fixed a bug (but it is much slower now). 25 years ago
jochen 6ea8124cad (Package)?Identifier: Handle unified packages. 25 years ago
jochen 7fc1ab0b1e FlowBlock: Handle nops. 25 years ago
jochen d79c1f7b8b ConstOperator.isOne was wrong 25 years ago
jochen 9ce95e120a New Decompiler/ProgressListener interface 25 years ago
jochen c24a2b7133 bug fix in ClassInfo extraClasses 25 years ago
jochen 0966dfcefe Y2K update (copyright ;-) 25 years ago
jochen 3aa4b59217 documentation update 25 years ago
jochen 1e661ada97 distribute shell scripts 25 years ago
jochen 8481f0f500 Changed files for new release 25 years ago
jochen 7c03c14e23 ConstOperator.isOne(type) added and used. 25 years ago
jochen e959a929a9 LocalVarOperator now fillDeclarableis itself. 25 years ago
jochen 22166d2741 NEWS now contains a more detailed history 25 years ago
jochen 926792e1be lots of .in changes 25 years ago
jochen 41c16a1deb cleanup, made faster 25 years ago
jochen 5782f56f04 removed doubled keywords 25 years ago
jochen 8e5d50568d check for keyword conflicts, mainly for (--pretty and java.lang.Class) 25 years ago
jochen 7eb76796d2 jode.Decompiler moved to jode.decompiler.Options 25 years ago
jochen 49aa106080 fixed a typo in usage 25 years ago
jochen 915439b1ff Decompiler, JodeApplet and JodeWindow moved into decompile package 25 years ago
jochen c5b840847b added dropInfo 25 years ago
jochen 47b22fdb21 added dropInfo 25 years ago
jochen 74f161a417 Decompiler, JodeApplet and JodeWindow moved into decompile package 25 years ago
jochen 19f4c534d4 jode.in updated to new package hierarchy 25 years ago
jochen 23d5d05fe3 added bluesky 25 years ago
jochen 80e2a7916c fixed some bugs for method scoped classes 25 years ago
jochen 761e734973 getFieldIndex returns -1, if it can't find field. 25 years ago
jochen b2783d0d69 NEWS updated. 25 years ago
jochen 8fc12f679e OuterValues added 25 years ago
jochen 38a01116c1 OuterValues added 25 years ago
jochen 62ca43d74f OuterValues added 25 years ago
jochen 2ad9965256 some new .in files added 25 years ago
jochen ec5fc0d1b9 made arrows black 25 years ago
jochen f7fced3615 Some more tests for method scoped and anonymous classes 25 years ago
jochen b06f5a9c12 fixed some typos 25 years ago
jochen 3ef0de7514 SearchPath.pathSeparatorChar -> altPathSeparatorChar 25 years ago
jochen 43a2e1ccfa ACCESSCONSTRUCTOR added. 25 years ago
jochen e00cff956c InvokeOperator has new constructor syntax 25 years ago
jochen 75f42b3167 ConstOperator.getValue() returns Object not String. 25 years ago
jochen 6885078d96 InvokeOperator has new constructor syntax 25 years ago
jochen cab4f7495d Changed the header 25 years ago
jochen d8e2746780 getInnerClassAnalyzer and initialize added 25 years ago
jochen 0270969c56 SearchPath.pathSeparatorChar -> altPathSeparatorChar 25 years ago
jochen 80d71addd4 SearchPath.pathSeparatorChar -> altPathSeparatorChar 25 years ago
jochen 7c2b66dc21 preserving serializable classes 25 years ago
jochen cc4c5ac156 renamed to jode.jos 25 years ago
jochen 49eb9190e3 move modules into separate package 25 years ago
jochen f8384e9928 move modules into separate package 25 years ago
jochen 8f32e39421 put html files into distribution 25 years ago
jochen 0d3cdeee1e added lots of file to configure.in 25 years ago
jochen c51eff9430 Added the files for the logo 25 years ago
jochen cf5477df8a Big update of jode documentation 25 years ago
jochen 7e6a592c69 add a missing semicolon for jdk 1.2 25 years ago
jochen 4e9f556534 add a missing import for jdk 1.2 25 years ago
jochen 52ac9a783e burst version to 1.0.92 25 years ago
jochen 6afd4abd28 changed dependency generation 25 years ago
jochen a23cab6985 *** empty log message *** 25 years ago
jochen 81b43965eb changed dependency generation. 25 years ago
jochen 6a7b61f3c4 changed dependency generation. 25 years ago
jochen 8eab046f28 changed version to inofficial. 25 years ago
jochen 744fd53156 some comments 25 years ago
jochen 853a315167 bug fix when lvt is broken 25 years ago
jochen 74001822d7 simplified parameter handling. 25 years ago
jochen 12d8d27cdd fixed a bug with long options: --pretty had code 'h' as had help 25 years ago
jochen ff298fb733 version set to 1.0.91 25 years ago
jochen 567209f324 added cast if necessary. 25 years ago
jochen 2402d437c1 printType called with type.getHint() 25 years ago
jochen 28514944da added some comments 25 years ago
jochen 6acf478de4 added a comment 25 years ago
jochen 9da2bae535 simple bug fix: super is Object not null for classes loaded from reflection 25 years ago
jochen 75cc1c2c9d Remove jode.test package 25 years ago
jochen 15e5e76033 swingui: class list toggable between class hierarchy and package hierarchy 25 years ago
jochen 74acab5ec7 fix a bug if destination is directory 25 years ago
jochen ae9c23f5ec use implementation specific opcode as border opcode instead of xxxunknownxxx 25 years ago
jochen 2108dbbaa2 Don't load fields and methods any more, they take too much space. 25 years ago
jochen 6092fcd5ef remove debugging message 25 years ago
jochen cdd5662578 print stacktrace to stderr 25 years ago
jochen 52c6c30277 made start and end instruction determination more robust 25 years ago
jochen 52c24788fe some small changes 25 years ago
jochen 20700d69ba added hashCode 25 years ago
jochen 3ee902a629 a minor optimization 25 years ago
jochen 4e007feb53 Use TypeSignature instead of Type 25 years ago
jochen f4d9bae9f6 allow script reading from stdin 25 years ago
jochen 054a4eeccb remove Type import 25 years ago
jochen eff1cbfc99 added copyright header 25 years ago
jochen 10f0a467df Use TypeSignature instead of jode.type.Type 25 years ago
jochen c41a61b4a3 JSR handling reworked 25 years ago
jochen e88bfb332d added copyright header 25 years ago
jochen c77119dd31 allow .java.in extension 25 years ago
jochen 55bb13e768 Some JSR tests 25 years ago
jochen d9e7c2b803 fixed some bugs 25 years ago
jochen d54f47c0a2 optimized checkTypeSig 25 years ago
jochen 4104af6d61 some speed improvements 25 years ago
jochen 6fea2e3540 check for cygpath and give java a correct classpath under windows 25 years ago
jochen 17986f6c3f check for cygpath and give java a correct classpath under windows 25 years ago
jochen 43a8e3ea9d create listener set on demand to save memory 25 years ago
jochen 4b8022a00e rename exception attributes 25 years ago
jochen 1cfa18f43c use UnifiyHash 25 years ago
jochen fccee54533 remove softreference import 25 years ago
jochen afc996f5e0 removed commented code 25 years ago
jochen efc2f0f662 Type.java.in added 25 years ago
jochen fd99e8bf69 oops, previous code did not even compile 25 years ago
jochen d9f8ffd373 fixed a bug 25 years ago
jochen 6eb8ea7f59 added ConstantRuntimeEnvironment.java.in 25 years ago
jochen e52d921afc simplified Interpreter even more 25 years ago
jochen 2b972a10ae added getClass() 25 years ago
jochen ed15fe5b9a commented this interface 25 years ago
jochen f504348712 Interpreter reworked and simplified 25 years ago
jochen b15a674928 New type handling (again, there were some problems in previous code) 25 years ago
jochen 9d59b9ced1 a finally block is handled like a no return block in mapStackToLocal 25 years ago
jochen 97bf664ac8 Adjust exception range when appending instructions. 25 years ago
jochen ad5a9f0194 fixed a bug in SynchronizedBlock. 25 years ago
jochen 8e6f442ee5 isOfType should return true on (class, interface) 25 years ago
jochen e598216b97 removed debugging output 25 years ago
jochen f483a1d87e obfuscator script for the RemovePopExample.j class 25 years ago
jochen a3c6698ccc Example for the remove pop analyzer 25 years ago
jochen 4d643e9cbf simple program to count how many opcodes a package has and how much 25 years ago
jochen 02522b5cef instructions collectionified 25 years ago
jochen 67e5bf4656 finally blocks reworked. 25 years ago
jochen 7c1859a4df remove predecessor of dest in removeJumps 25 years ago
jochen b462a21ed6 bug fix for exceptionLocal == null case 25 years ago
jochen c2ec44a43b instructions collectionified 25 years ago
jochen c3ead8b084 instructions now collectionified 25 years ago
jochen dcd5686bc2 added UnifyHash 25 years ago
jochen 996fc49dbd collection interface for instructions. 25 years ago
jochen ddbf2c969a fixed a bug for old swing package 25 years ago
jochen 22ca8fd79d fixed a stupid bug 25 years ago
jochen cb159304d8 added the dasm_to_java.perl script. 25 years ago
jochen 6a30f5c91d a small comment improvement 25 years ago
jochen 2f04c0e0cb obfuscator scripting implemented 25 years ago
jochen f7be2d00d5 make dependencies more relative 25 years ago
jochen d524b1f2a8 Using the autoconfigured @COLLECTIONS@ imports. 25 years ago
jochen 6786a3fa35 using the autoconfigured @COLLECTIONS@ imports. 25 years ago
jochen 48d5c63aec open class file as binary 25 years ago
jochen dd3b440b9b move chmod 755 to AC_OUTPUT 25 years ago
jochen d7311d1091 remove autoconf part 25 years ago
jochen 48fb8a75b3 ConstructorOperator removed, InvokeOperator handles it all. 25 years ago
jochen e4337a16a7 ConstructorOperator removed, InvokeOperator handles it all. 25 years ago
jochen 1a153a2529 print anonymous class name 25 years ago
jochen 9a042f80c8 ConstructorOperator removed, InvokeOperator handles it all. 25 years ago
jochen ea7bac2872 Startet to write something that may make sense. 25 years ago
jochen ec599fb69b New perl script to build dependencies out of java class files. 25 years ago
jochen 12ca9d7b09 fixed some small things 25 years ago
jochen 6a189d2a66 added javacWithDeps, to calculate dependencies 25 years ago
jochen d2eaf84869 updated, so that emacs can compile in build directory 25 years ago
jochen 5b3fb0a36b fixed some AWT10 things 25 years ago
jochen ba4e13803b use appendBlock instead of sequentialT1 25 years ago
jochen d4b15f7b44 use member functions to access Instruction fields 25 years ago
jochen 8d4691f8b0 mergeKill added (which doesn't combine the locals) 25 years ago
jochen f4d9aff1da clear removed entries in backing array 25 years ago
jochen 00edbfd0df fillInGenSet now takes Collection instead Set as parameter 25 years ago
jochen 0f38b5d122 use member functions to access Instruction fields 25 years ago
jochen f301603e87 use member functions to access Instruction fields 25 years ago
jochen 4280f1d6ce moved class->typesignature methods into bytecode package 25 years ago
jochen 9dd47c5ea7 made constructor package local. 25 years ago
jochen 900205e713 use member functions to access Instruction fields 25 years ago
jochen 2ecb19a3d9 imports cleaned up 25 years ago
jochen 56464880ac Cleaned up the bytecode module: 25 years ago
jochen 75df7ec7f2 merged changes from stable tree 25 years ago
jochen 0a8b2be671 moved html files into doc directory 25 years ago
jochen 5a7713ae1a added automake/autoconf files for automatically building. 25 years ago
jochen a41bef2994 removed redundant call 25 years ago
jochen 38d78b49bf new set, that will merge locals with same slot on insertion 25 years ago
jochen 8db70be1a7 fillInGenSet now takes Set, not VariableSet 25 years ago
jochen ec1e63532c gen/kill set rework in FlowBlock, successors now private 25 years ago
jochen efdfcbf7bc Use gnu.getopt package to parse the options. 25 years ago
jochen aace74ecc2 setDebugging now returns result. 25 years ago
jochen 6e053f676e ClassAnalyzer now handles OPTION_IMMEDIATE flag 25 years ago
jochen cb2026eac7 handle OPTION_IMMEDIATE flag 25 years ago
jochen 4eac3b281e simplify also successing flow blocks on simplify() 25 years ago
jochen 81cac56337 some bug fixes 25 years ago
jochen e0f4124830 ignore class files 25 years ago
  1. 14
      CVSROOT/checkoutlist
  2. 15
      CVSROOT/commitinfo
  3. 11
      CVSROOT/config
  4. 1
      CVSROOT/cvsignore
  5. 24
      CVSROOT/cvswrappers
  6. 21
      CVSROOT/editinfo
  7. 27
      CVSROOT/loginfo
  8. 1
      CVSROOT/modules
  9. 12
      CVSROOT/notify
  10. 13
      CVSROOT/rcsinfo
  11. 206
      CVSROOT/syncmail
  12. 20
      CVSROOT/taginfo
  13. 21
      CVSROOT/verifymsg
  14. 7
      jode/.classpath
  15. 9
      jode/.cvsignore
  16. 17
      jode/.project
  17. 353
      jode/.settings/org.eclipse.jdt.core.prefs
  18. 4
      jode/.settings/org.eclipse.jdt.ui.prefs
  19. 3
      jode/.settings/org.eclipse.ltk.core.refactoring.prefs
  20. 1
      jode/AUTHORS
  21. 504
      jode/COPYING.LESSER
  22. 504
      jode/COPYING.LGPL
  23. 563
      jode/ChangeLog
  24. 23
      jode/INSTALL
  25. 3
      jode/MANIFEST.MF
  26. 36
      jode/NEWS
  27. 90
      jode/README
  28. 5
      jode/THANKS
  29. 56
      jode/TODO
  30. 2
      jode/bin/.cvsignore
  31. 5
      jode/bin/Makefile.am
  32. 19
      jode/bin/jode.bat.in
  33. 14
      jode/bin/jode.in
  34. 380
      jode/build.xml
  35. 28
      jode/config.props
  36. 58
      jode/create.sh
  37. 3
      jode/doc/.cvsignore
  38. 25
      jode/doc/applet.htp
  39. 69
      jode/doc/bluesky.htp
  40. 711
      jode/doc/dasm_to_java.perl
  41. 39
      jode/doc/download.htp
  42. 90
      jode/doc/faq.htp
  43. 106
      jode/doc/favicon.xpm
  44. 11
      jode/doc/feedback.htp
  45. 13
      jode/doc/footer.inc
  46. BIN
      jode/doc/gimp/arrow.gif
  47. BIN
      jode/doc/gimp/bytecode.gif
  48. 9
      jode/doc/gimp/bytecode.txt
  49. BIN
      jode/doc/gimp/flow.gif
  50. BIN
      jode/doc/gimp/jode-logo.xcf
  51. BIN
      jode/doc/gimp/statement.gif
  52. 9
      jode/doc/gimp/statement.txt
  53. 42
      jode/doc/gimp/vects.fig
  54. 63
      jode/doc/header.inc
  55. 20
      jode/doc/history.htp
  56. 52
      jode/doc/htp.def
  57. 74
      jode/doc/index.htp
  58. BIN
      jode/doc/jode-logo.png
  59. 67
      jode/doc/jode.htt
  60. 21
      jode/doc/license.htp
  61. 75
      jode/doc/links.htp
  62. 47
      jode/doc/menu.inc
  63. 84
      jode/doc/myproject.jos
  64. BIN
      jode/doc/poweredbyhtp.png
  65. 62
      jode/doc/technical.texi
  66. 250
      jode/doc/usage.htp
  67. BIN
      jode/doc/w3c_ab.png
  68. 39
      jode/jode-applet.html
  69. 14
      jode/jode-obfuscator.html
  70. 96
      jode/jode-unix.html
  71. 49
      jode/jode-useapplet.html
  72. 62
      jode/jode-win.html
  73. 124
      jode/jode.html
  74. 282
      jode/jode/Decompiler.java
  75. 46
      jode/jode/JodeApplet.java
  76. 201
      jode/jode/bytecode/BinaryInfo.java
  77. 1127
      jode/jode/bytecode/BytecodeInfo.java
  78. 771
      jode/jode/bytecode/ClassInfo.java
  79. 194
      jode/jode/bytecode/FieldInfo.java
  80. 257
      jode/jode/bytecode/GrowableConstantPool.java
  81. 29
      jode/jode/bytecode/Handler.java
  82. 492
      jode/jode/bytecode/Instruction.java
  83. 29
      jode/jode/bytecode/LineNumber.java
  84. 225
      jode/jode/bytecode/MethodInfo.java
  85. 92
      jode/jode/bytecode/Reference.java
  86. 506
      jode/jode/bytecode/SearchPath.java
  87. 513
      jode/jode/decompiler/ClassAnalyzer.java
  88. 120
      jode/jode/decompiler/DeadCodeAnalysis.java
  89. 45
      jode/jode/decompiler/LocalVarEntry.java
  90. 79
      jode/jode/decompiler/LocalVariableRangeList.java
  91. 44
      jode/jode/decompiler/LocalVariableTable.java
  92. 1031
      jode/jode/decompiler/MethodAnalyzer.java
  93. 389
      jode/jode/decompiler/Opcodes.java
  94. 27
      jode/jode/decompiler/OuterValueListener.java
  95. 340
      jode/jode/decompiler/TabbedPrintWriter.java
  96. 61
      jode/jode/expr/ArrayStoreOperator.java
  97. 333
      jode/jode/expr/ConstructorOperator.java
  98. 221
      jode/jode/expr/GetFieldOperator.java
  99. 111
      jode/jode/expr/IfThenElseOperator.java
  100. 741
      jode/jode/expr/InvokeOperator.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,14 @@
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
syncmail

@ -0,0 +1,15 @@
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

@ -0,0 +1,11 @@
# Set this to "no" if pserver shouldn't check system users/passwords
#SystemAuth=no
# Set `PreservePermissions' to `yes' to save file status information
# in the repository.
#PreservePermissions=no
# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top
# level of the new working directory when using the `cvs checkout'
# command.
#TopLevelAdmin=no

@ -0,0 +1,24 @@
# This file affects handling of files based on their names.
#
# The -t/-f options allow one to treat directories of files
# as a single file, or to transform a file in other ways on
# its way in and out of CVS.
#
# The -m option specifies whether CVS attempts to merge files.
#
# The -k option specifies keyword expansion (e.g. -kb for binary).
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
# -k expansion mode value: b, o, kkv, &c
#
# and value is a single-quote delimited value.
# For example:
*.gif -k 'b'
*.xcf -k 'b'

@ -0,0 +1,21 @@
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

@ -0,0 +1,27 @@
# The "loginfo" file controls where "cvs commit" log information
# is sent. The first entry on a line is a regular expression which must match
# the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is a filter
# program that should expect log information on its standard input.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
# You may specify a format string as part of the
# filter. The string is composed of a `%' followed
# by a single format character, or followed by a set of format
# characters surrounded by `{' and `}' as separators. The format
# characters are:
#
# s = file name
# V = old version number (pre-checkin)
# v = new version number (post-checkin)
#
# For example:
#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
DEFAULT $CVSROOT/CVSROOT/syncmail %{sVv} jode-commit@lists.sourceforge.net

@ -0,0 +1 @@
jode jode

@ -0,0 +1,12 @@
# The "notify" file controls where notifications from watches set by
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
# a regular expression which is tested against the directory that the
# change is being made to, relative to the $CVSROOT. If it matches,
# then the remainder of the line is a filter program that should contain
# one occurrence of %s for the user to notify, and information on its
# standard input.
#
# "ALL" or "DEFAULT" can be used in place of the regular expression.
#
# For example:
#ALL mail %s -s "CVS notification"

@ -0,0 +1,13 @@
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, then the remainder of the
# line is the name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

@ -0,0 +1,206 @@
#! /usr/bin/python
# -*- Python -*-
"""Complicated notification for CVS checkins.
This script is used to provide email notifications of changes to the CVS
repository. These email changes will include context diffs of the changes.
Really big diffs will be trimmed.
This script is run from a CVS loginfo file (see $CVSROOT/CVSROOT/loginfo). To
set this up, create a loginfo entry that looks something like this:
mymodule /path/to/this/script %%s some-email-addr@your.domain
In this example, whenever a checkin that matches `mymodule' is made, this
script is invoked, which will generate the diff containing email, and send it
to some-email-addr@your.domain.
Note: This module used to also do repository synchronizations via
rsync-over-ssh, but since the repository has been moved to SourceForge,
this is no longer necessary. The syncing functionality has been ripped
out in the 3.0, which simplifies it considerably. Access the 2.x versions
to refer to this functionality. Because of this, the script is misnamed.
It no longer makes sense to run this script from the command line. Doing so
will only print out this usage information.
Usage:
%(PROGRAM)s [options] <%%S> email-addr [email-addr ...]
Where options is:
--cvsroot=<path>
Use <path> as the environment variable CVSROOT. Otherwise this
variable must exist in the environment.
--help
-h
Print this text.
<%%S>
CVS %%s loginfo expansion. When invoked by CVS, this will be a single
string containing the directory the checkin is being made in, relative
to $CVSROOT, followed by the list of files that are changing. If the
%%s in the loginfo file is %%{sVv}, context diffs for each of the
modified files are included in any email messages that are generated.
email-addrs
At least one email address.
"""
import os
import sys
import string
import time
import getopt
# Notification command
MAILCMD = '/bin/mail -s "%(SUBJECT)s" %(PEOPLE)s 2>&1 > /dev/null'
# Diff trimming stuff
DIFF_HEAD_LINES = 20
DIFF_TAIL_LINES = 20
DIFF_TRUNCATE_IF_LARGER = 1000
PROGRAM = sys.argv[0]
def usage(code, msg=''):
print __doc__ % globals()
if msg:
print msg
sys.exit(code)
def calculate_diff(filespec):
try:
file, oldrev, newrev = string.split(filespec, ',')
except ValueError:
# No diff to report
return '***** Bogus filespec: %s' % filespec
if oldrev == 'NONE':
try:
if os.path.exists(file):
fp = open(file)
else:
update_cmd = 'cvs -fn update -r %s -p %s' % (newrev, file)
fp = os.popen(update_cmd)
lines = fp.readlines()
fp.close()
lines.insert(0, '--- NEW FILE ---\n')
except IOError, e:
lines = ['***** Error reading new file: ',
str(e), '\n***** file: ', file, ' cwd: ', os.getcwd()]
elif newrev == 'NONE':
lines = ['--- %s DELETED ---\n' % file]
else:
# This /has/ to happen in the background, otherwise we'll run into CVS
# lock contention. What a crock.
diffcmd = '/usr/bin/cvs -f diff -kk -C 2 -r %s -r %s %s' % (
oldrev, newrev, file)
fp = os.popen(diffcmd)
lines = fp.readlines()
sts = fp.close()
# ignore the error code, it always seems to be 1 :(
## if sts:
## return 'Error code %d occurred during diff\n' % (sts >> 8)
if len(lines) > DIFF_TRUNCATE_IF_LARGER:
removedlines = len(lines) - DIFF_HEAD_LINES - DIFF_TAIL_LINES
del lines[DIFF_HEAD_LINES:-DIFF_TAIL_LINES]
lines.insert(DIFF_HEAD_LINES,
'[...%d lines suppressed...]\n' % removedlines)
return string.join(lines, '')
def calculate_url(dir, filespec):
try:
file, oldrev, newrev = string.split(filespec, ',')
except ValueError:
# No diff to report
return '***** Bogus filespec: %s' % filespec
if oldrev == 'NONE':
lines = [ 'http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jode/%s/%s?rev=%s' % (dir, file, newrev) ]
elif newrev == 'NONE':
lines = [ 'DELETED: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jode/%s/%s?rev=%s' % (dir, file, oldrev) ]
else:
lines = [ 'http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jode/%s/%s.diff?r1=%s&r2=%s&diff_format=u' % (dir, file, oldrev, newrev) ]
return string.join(lines, '')
def blast_mail(mailcmd, dir, filestodiff):
## cannot wait for child process or that will cause parent to retain cvs
## lock for too long. Urg!
#if not os.fork():
# in the child
# give up the lock you cvs thang!
time.sleep(2)
fp = os.popen(mailcmd, 'w')
fp.write(sys.stdin.read())
fp.write('\n')
# append the cvsweb urls if available
fp.write('CVSWeb URLs:\n');
for file in filestodiff:
# fp.write(calculate_diff(file))
fp.write(calculate_url(dir, file))
fp.write('\n')
fp.close()
## doesn't matter what code we return, it isn't waited on
# os._exit(0)
# scan args for options
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], 'h', ['cvsroot=', 'help'])
except getopt.error, msg:
usage(1, msg)
# parse the options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt == '--cvsroot':
os.environ['CVSROOT'] = arg
# What follows is the specification containing the files that were
# modified. The argument actually must be split, with the first component
# containing the directory the checkin is being made in, relative to
# $CVSROOT, followed by the list of files that are changing.
if not args:
usage(1, 'No CVS module specified')
specs = string.split(args[0])
changedfiles = [ specs[0] ];
for filespec in specs[1:]:
try:
file, oldrev, newrev = string.split(filespec, ',')
changedfiles.append(file)
except ValueError:
changedfiles.append(filespec)
SUBJECT = string.join(changedfiles, ' ')
del args[0]
# The remaining args should be the email addresses
if not args:
usage(1, 'No recipients specified')
# Now do the mail command
PEOPLE = string.join(args)
mailcmd = MAILCMD % vars()
if specs == ['-', 'Imported', 'sources']:
return
if specs[-3:] == ['-', 'New', 'directory']:
del specs[-3:]
blast_mail(mailcmd, specs[0], specs[1:])
if __name__ == '__main__':
main()
sys.exit(0)

@ -0,0 +1,20 @@
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

@ -0,0 +1,21 @@
# The "verifymsg" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="net/sf/jode/obfuscator/modules/LocalOptimizer.java|net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java|net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java" kind="src" output="build" path="src"/>
<classpathentry kind="lib" path="lib/java-getopt-1.0.8.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="build"/>
</classpath>

@ -0,0 +1,9 @@
Makefile
Makefile.in
configure
config.log
config.cache
config.status
stamp-h
libtool
aclocal.m4

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>jode</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

@ -0,0 +1,353 @@
#Thu Mar 01 23:39:18 CET 2012
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.4
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.3
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=80
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=mixed
org.eclipse.jdt.core.formatter.tabulation.size=8
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true

@ -0,0 +1,4 @@
#Thu Mar 01 22:21:28 CET 2012
eclipse.preferences.version=1
formatter_profile=org.eclipse.jdt.ui.default.sun_profile
formatter_settings_version=12

@ -0,0 +1,3 @@
#Thu Mar 01 22:15:48 CET 2012
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

@ -0,0 +1 @@
Jochen Hoenicke <Jochen.Hoenicke@Informatik.Uni-Oldenburg.DE>

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

@ -0,0 +1,563 @@
2005-10-14 Jochen Hoenicke <jochen@gnu.org>
* src/net/sf/jode/flow/TransformConstructor.java:
(lookForConstructorCall) Check for isStatic before setting
outer $this reference
(reported by Andreas Salathé, bug #1306688)
2005-09-13 Jochen Hoenicke <jochen@gnu.org>
Check for NullPointer in SyntheticAnalyzer. Based on
patch suggessted by Peter Klauser (klp at users.sf.net).
* src/net/sf/jode/jvm/SyntheticAnalyzer.java:
(checkStaticAccess): Check refField for null pointer.
(checkAccess): Likewise.
2004-08-06 Jochen Hoenicke <hoenicke@marge.Informatik.Uni-Oldenburg.DE>
* src/net/sf/jode/bytecode/BinaryInfo.java (ACC_*): added
constants describing modifier attributes.
* src/net/sf/jode/bytecode/BasicBlockReader.java
(convertHandlers): remove empty handlers.
(readCode): merge adjacent try-blocks (splitted by javac-1.4
return rule).
* src/net/sf/jode/bytecode/FieldInfo.java (syntheticFlag):
removed, use modifier and ACC_SYNTHETIC (new in java 5) instead.
Changed all usages. When writing it currently writes out both
old and new synthetic format.
(getSignature): New method to return full generic signature.
* src/net/sf/jode/bytecode/MethodInfo.java
(syntheticFlag, getSignature): likewise.
* src/net/sf/jode/bytecode/ClassInfo.java (getSignature):
New method to return full generic signature.
* src/net/sf/jode/decompiler/MethodAnalyzer.java (skipWriting):
Skip java 5 bridge methods.
* src/net/sf/jode/expr/InvokeOperator.java (getClassAnalyzer):
Check for null callee.
* src/net/sf/jode/expr/FlowBlock.java (analyze): New order for
T1,T2 analysis: Do not do T1 analysis when the block has more
than one real successor and the next block can be easily merged.
See comment for more information.
2004-08-05 Jochen Hoenicke <hoenicke@marge.Informatik.Uni-Oldenburg.DE>
* build.xml: replace execon with apply.
* src/net/sf/jode/bytecode/ClassInfo.java (readAttributes):
read in signature attribute (not yet published, though).
* src/net/sf/jode/bytecode/MethodInfo.java (readAttributes):
likewise.
* src/net/sf/jode/bytecode/FieldInfo.java (readAttributes):
likewise.
* src/net/sf/jode/bytecode/ClassInfo.java (mergeModifiers):
only check the traditional modifiers for equality.
* src/net/sf/jode/bytecode/ConstantPool.java (getConstant):
Support for CLASS constants (jdk1.5) added.
* src/net/sf/jode/bytecode/BasicBlockReader.java (readCode):
opc_ldc, opc_ldc_w: Support for CLASS constants added.
* src/net/sf/jode/decompiler/Opcodes.java (addOpcode):
likewise.
* src/net/sf/jode/expr/InvokeOperator.java
(simplifyStringBuffer, simplifyString):
Also handle StringBuilder (jdk1.5).
* src/net/sf/jode/type/Type.java (tStringBuilder): new field.
* src/net/sf/jode/swingui/Main.java (main): handle debug
options.
2004-01-31 Jochen Hoenicke <hoenicke@informatik.uni-oldenburg.de>
* src/net/sf/jode/jvm/SyntheticAnalyzer.java (checkGetClass):
Handle jdk1.4 class$ methods.
* src/net/sf/jode/jvm/RuntimeEnvironment.java: Fixed some javadocs.
* src/net/sf/jode/flow/CompleteSynchronized.java: likewise.
* src/net/sf/jode/flow/CreateExpression.java: likewise.
* src/net/sf/jode/flow/CreateIfThenElseOperator.java: likewise.
Added changes (except obfuscator changes) from jode-1.1 tree up to
2001-07-08
* src/net/sf/jode/bytecode/ClassInfo.java (deprecatedFlag): Added
flag for deprecated classes. Stuart Ballard noticed that this was
missing.
(readAttribute): Read deprecated attribute.
(prepareWriting): Prepare deprecated attribute.
(writeKnownAttributes): Write deprecated attribute.
(isDeprected): New function.
(setDeprecated): Likewise.
* src/net/sf/jode/bytecode/BasicBlockReader.java (readCode): Fix
the exception handlers that javac 1.4 produces: I simply shorten
the start/end interval, so that the catcher is not in the end
interval.
* src/net/sf/jode/flow/CreateAssignExpression.java
(createAssignOp): Bug fix: Check whether store is already a
op-assign and break out.
* src/net/sf/jode/expr/StoreInstruction.java (isOpAssign): New
function to check whether this is an op-assign.
* src/net/sf/jode/flow/CatchBlock.java (combineLocal): Added more
checks if LocalStoreOperator is of the right form.
* net/sf/jode/flow/TransformConstructors.java (Constructor): Ignore
OuterValues for static constructor.
* src/net/sf/jode/expr/CompareToIntOperator.java (dumpExpression):
Added a missing breakOp.
2004-01-22 Jochen Hoenicke <hoenicke@informatik.uni-oldenburg.de>
* net/sf/jode/jvm/CodeVerifier.java (modelEffect): Allow assigning
fields in an uninitialized class as some synthetic code does this.
2003-06-11 Mark Morschhäuser <mark.morschhaeuser@firemail.de>
* net/sf/jode/decompiler/Main.java: New MenuItem to save a decompiled file.
* net/sf/jode/decompiler/Main.java: Main-window will be centered on startup
* build.xml:
(release): Added MANIFEST.MF to target and enabled compressed jar-file
* MANIFEST.MF: Added this file to be able to create an executable jar-file
2002-06-11 Jochen Hoenicke <jochen@gnu.org>
* net/sf/jode/decompiler/Main.java: New option keep-alive. With
this option jode won't stop after an error but will continue with
the next class.
Patch suggested by Francis Devereux, francis at hc.eclipse.co.uk
2002-02-25 Jochen Hoenicke <jochen@gnu.org>
* jode/bytecode/ClassInfo.java.in (read): Don't check for a
maximum version anymore. Sun changes it with every release without
changing the bytecode format.
2002-02-15 Jochen Hoenicke <jochen@gnu.org>
* net/sf/jode/bytecode/BasicBlockReader.java: handle empty loops.
(IS_NULL): new constant to tag empty blocks.
(markReachableBlocks): check for empty loops.
(convertBlock): Handle empty blocks.
(convert): Handle IS_NULL.
* net/sf/jode/decompiler/MethodAnalyzer.java:
(analyzeCode): handle empty blocks.
2001-08-14 Jochen Hoenicke <jochen@gnu.org>
* build.xml: test is default.
(release-javadoc): New target.
(release-src): Get from dir test only source files.
(doc-javadoc): More parameters for nicer docu.
2001-08-12 Jochen Hoenicke <jochen@gnu.org>
* net/sf/jode/bytecode/TypeSignature.java:
(getArgumentSize): Renamed to ...
(getParameterSize): ... this. Changed all callers.
(skipType): Made private.
* net/sf/jode/jvm/CodeVerifier.java:
(initInfo): Use TypeSignature.getParameterTypes instead of skipType.
* net/sf/jode/jvm/SyntheticAnalyzer.java:
(checkGetClass): Be more lenient with the types, they are already
checked by the CodeVerifier. This is to support jdk-1.4.
* net/sf/jode/expr/InvokeOperator.java
(dumpExpression): Fixed the check for null outerExpr.
* net/sf/jode/flow/FlowBlock.java:
(checkConsistent): Allow lastModified in a finally block.
* net/sf/jode/flow/TransformExceptionHandlers.java: Reworked exception
handlers again. This time checked with javac 1.3, javac 1.1 and
jikes.
(checkTryCatchOrder): New method that was previously part of
analyze.
(analyze): Use checkTryCatchOrder. Don't merge try and catch flow
blocks anymore, leave it to the analyzeXXX methods.
(mergeTryCatch): New method.
(analyzeCatchBlock): Get catchFlow as parameter. Call
mergeTryCatch.
(transformSubroutine): Handle POP-only subroutines.
(removeJSR): Don't do special case for catchBlock any more. This
is because catchFlow isn't yet merged when this method is called.
(checkAndRemoveJSR): Likewise.
(checkAndRemoveMonitorExit): Likewise. Merge subroutine only if
we are the only predecessor.
(analyzeSynchronized): Get catchFlow as parameter. Call
mergeTryCatch.
(mergeFinallyBlocks): New method, calls mergeTryCatch and does the
common part of mergeFinally and mergeSpecialFinally.
(analyzeFinally): Simplified, after checking and removing JSR, it
does immediately analyze and transform subroutine to get the
finallyBlock. Then it throws away the catchFlow and calls
mergeFinallyBlocks.
(analyzeSpecialFinally): Simplified, after checking it only handles
the jumps in the try part and then call mergeFinallyBlocks.
2001-08-08 Jochen Hoenicke <jochen@gnu.org>
More Documentation updates.
* build.xml: Release rules.
* scripts/jcpp.pl: Don't make backups of original.
* net/sf/jode/bytecode/BasicBlocks.java (setBlocks): Check that
successors are inside method.
* net/sf/jode/bytecode/Block.java (getStackHeight): New Method.
* net/sf/jode/bytecode/ClassPath.java (Location): public class to
model a component of the class path. Previously it was Path.
(ClassPath): New constructors added that take Location objects.
* net/sf/jode/bytecode/ConstantPool.java (getClassName): Cache
constants.
* net/sf/jode/bytecode/GrowableConstantPool.java: Made public.
(grow): Check that not too many constants are added.
(reserveLongConstants): Removed (not used).
(copyConstant): Removed (not used).
* net/sf/jode/jvm/NewObject.java: Made package protected.
* net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java:
Big updates (almost rewrote from scratch). Still doesn't compile.
2001-08-05 Jochen Hoenicke <jochen@gnu.org>
Documentation updates (INSTALL, javadoc).
Added JUnit Test cases.
* build.xml: Big update.
* net/sf/jode/bytecode/BasicBlock.java:
(updateMaxStackLocals): new method to calculate maxStack and
maxLocals.
(setBlocks): fixed calculation of handlers, call updateMaxLocals.
* net/sf/jode/bytecode/BasicBlockReader.java:
(maxLocals, maxStack): new fields.
(readCode): read maxStack/Locals into private fields.
(convert): check that maxStack/Locals match what we calculate.
* net/sf/jode/bytecode/BinaryInfo.java:
(getKnownAttributeCount): renamed to...
(getAttributeCount): ... this, and also count internal attributes.
Made it protected.
(readAttribute): made protected.
(drop): made protected.
(prepareAttributes): made protected.
(writeKnownAttributes): removed.
(writeAttributes): made protected, use getAttributeCount.
Changed policy: it doesn't call writeKnownAttribute, but instead
it expects sub classes to override this method.
(getAttributeSize): made protected, subclasses should override it.
Changed all subclasses to new policy.
* net/sf/jode/bytecode/Block.java:
(lineNr): Removed, it wasn't used.
(pop,push): Removed, replaced by ...
(maxpop,maxpush,delta): ... these, with slightly changed semantics.
(stackHeight): New variable.
(Block): Default Constructor doesn't initialize fields now.
(getCatchers): Renamed to ...
(getHandlers): ... this, changed all callers.
(initCode): Calculate maxpop, maxpush, delta correctly.
(getStackPopPush): Changed accordingly to new fields.
(setCode): Removed debugging output for illegal contents.
* net/sf/jode/bytecode/Classes.java: Reworked handling of inner
classes.
(innerClasses): Field mustn't be null anymore when loaded.
(setName): Update class in classpath.
* net/sf/jode/bytecode/ClassPath.java:
(renameClassInfo): new function, should only used by ClassInfo.
* net/sf/jode/bytecode/ConstantPool.java: made public.
(getUTF8,getRef,getClassType,getClassName): Don't allow the 0 index.
(iterateClassNames): New method.
* net/sf/jode/decompiler/Main.java:
(decompileClass): Catch ClassFormatExceptions and decompile
remaining classes.
* net/sf/jode/obfuscator/ClassIdentifier.java:
Updated handling of inner/extra classes to new ClassInfo behaviour.
(initSuperClasses): Load DECLARATION of super classes.
* net/sf/jode/obfuscator/PackageIdentifier.java:
Replace deprecated methods of ClassInfo with corresponding classpath
calls.
(loadMatchingClasses): Initialize packages loaded on demand if we
are initialize.
* net/sf/jode/obfuscator/modules/ConstantAnalyzer.java:
Now extends SimpleAnalyzer.
(canonizeIfaceRef): Removed; it is now inherited.
(canonizeRef): likewise.
Big updates to handle jsr correctly.
(handleOpcode): Moved method to BlockInfo.
* net/sf/jode/obfuscator/modules/SimpleAnalyzer.java:
(canonizeIfaceRef): New method, copied from ConstantAnalyzer.
(canonizeRef): call canonizeIfaceRef for interfaces.
* net/sf/jode/util/UnifyHash.java
(iterateHashCode): iterator now supports remove().
(remove): New method.
2001-07-30 Jochen Hoenicke <jochen@gnu.org>
Changed compilation procedure to ant.
2001-07-30 Jochen Hoenicke <jochen@gnu.org>
* jode/bytecode/BasicBlockReader.java: Fixed import of non
collection java.util classes.
* jode/bytecode/BasicBlockWriter.java: likewise.
2001-07-28 Jochen Hoenicke <jochen@gnu.org>
* jode/AssertError.java: removed, all uses are now replaced
by java.lang.InternalError.
* jode/Makefile.am: removed AssertError.java
* jode/bytecode/ClassInfo.java: reworked handling of inner
classes.
(extraClasses): removed, they are calculated automatically.
(hasInnerClassesAttr): new variable.
(readInnerClassesAttribute): Mark all classes in the constant
pool as having OUTERCLASS info filled. Don't handle extraClasses
specially.
(prepareWriting): Change for automatically generating outer
class info.
(getKnownAttributes): dito.
(writeKnownAttributes): dito.
(getExtraClasses): removed.
(setExtraClasses): removed.
* jode/bytecode/ClassAnalyzer.java (conflicts): load or guess
declarations of info before getting inner classes.
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp):
Set options correctly.
* jode/expr/InvokeOperator.java (getMethodInfo): load or guess
declarations before accessing methods.
* jode/flow/FlowBlock.java (resolveSomeJumps): When creating a
if-then-else move the jump from the then branch to the if, before
restarting analysis.
(doT1): handle the case when lastModified.jump is null. Throw
statements have no jump now.
* jode/jvm/SyntheticAnalyzer (checkAccess): Fix the detection for
PUTDUPSTATIC/FIELD.
* jode/type/ClassType.java (getCastHelper): More checks when
cast is not needed: interfaces and null pointer.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
* jode/decompiler/Decompiler.java (decompile): removed
setClassPath call. ClassInfo.forName() is no longer used.
* jode/decompiler/Main.java (decompile): likewise.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patches from 2001-05-26 of Jode 1.1 tree:
* configure.in: Set version to 1.1.
* jode/swingui/Main.java (main): Also use bootclasspath if no
classpath given.
* jode/decompiler/MethodAnalyzer.java (skipWriting): Don't skip
empty constructor that have a throws clause.
* configure.in: Determine whether jdk1.1 resp. jdk1.2. Call jcpp
in config.status.
* jode/expr/Expression.java (makeInitializer): Now takes the
type of the initialization. Changed all callers.
* jode/expr/ConstantArrayOperator.java (makeInitializer): Check
that type is our array type, otherwise we can't omit new Array[].
* jode/decompiler/LocalInfo.java (markFinal): Don't check that
only one write is present. If two writes are in an then and an
else branch of an if, the local can still be final.
* jode/type/ArrayType.java (getSubType): Handle array of integer
types correctly: byte[] is something completely different than
int[].
(getSuperType): Likewise.
* jode/expr/FieldOperator.java (getFieldInfo): New function.
(needsCast): A cast is also needed if the field is private or
package scope and the current type can't access the field.
* jode/expr/InvokeOperator.java (getMethodInfo): New function.
(needsCast): A cast is also needed if the method is private or
package scope and the current type can't access the method.
* jode/expr/ArrayStoreOperator.java (dumpExpression): Check if a
cast of the array expression is needed.
* jode/expr/TransformConstructors.java
(transformFieldInitializers): Don't allow moving method invocations
that throw a checked exception.
* jode/bytecode/MethodInfo.java (readAttribute): Read Exceptions
attribute even when not all attributes should be read. They are
needed by TransformConstructors, see above.
* jode/decompiler/TabbedPrintWriter.java (saveOps): Don't allow
line breaks in not completed expressions since implicit parentheses
would destroy the syntax. No need to put line break option on stack.
(restoreOps): Adapted Stack format.
* jode/decompiler/ClassAnalyzer.java (dumpDeclaration): Moved
Code from dumpSource here. Don't put a line break after closing
brace.
(dumpSource): call dumpDeclaration and add a line break.
(dumpBlock): Moved dropInfo(ATTRIBS) here.
* jode/decompiler/ClassAnalyzer.java (STRICTFP): New Constant.
(isStrictFP): New function.
(initialize): Set strictfp modifier if a constructor has it set.
(dumpSource): Handle strictfp modifier.
* jode/decompiler/MethodAnalyzer.java (STRICTFP): New Constant.
(isStrictFP): New function.
(dumpSource): Handle strictfp modifier.
* jode/jvm/SyntheticAnalyzer.java (checkAccess): Check for a
special putfield access, where the set value is returned. Allow
the modifier of field/method to be protected and the class to be
a superclass.
(checkStaticAccess): Likewise.
(ACCESSDUPPUTFIELD): New Constant.
(ACCESSDUPPUTSTATIC): New Constant.
* jode/expr/InvokeOperator.java (simplifyAccess): Handle new
synthetics.
* jode/flow/SpecialBlock.java (removePop): Remove pop also for
non void store instructions.
* jode/decompiler/MethodAnalyzer.java (skipWriting): Also skip
the new synthetics.
* jode/decompiler/Main.java (main): Call System.exit() after
everything was compiled.
* jode/flow/TransformExceptionHandlers.java (removeJSR):
Renamed back from removeBadJSR (see patch from 2001-02-04). The
checkAndRemove* functions mustn't change the successors while they
iterate over them. Instead of removing good jsr they mark them as
good and removeJSR will finally remove them.
(checkAndRemoveJSR): See above.
(checkAndRemoveMonitorExit): See above.
* jode/flow/JsrBlock.java (good): New variable, see above.
(setGood): New method.
(isGood): New method.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-05-08 of Jode 1.1 tree:
* jode/jvm/CodeVerifier.java (doVerify): Don't check for
uninitialized objects in local or stack slots on backwards jump or
exception blocks. Sun's jdk also doesn't check it, and I never
understood why it is necessary. But see JVM Spec 4.9.4.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-05-02 of Jode 1.1 tree:
* jode/obfuscator/modules/ConstantAnalyzer.java (handleOpcode):
Added divide by zero checks for opc_irem and opc_lrem.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patches from 2001-02-27 of Jode 1.1 tree:
* acinclude.m4 (JODE_CHECK_CLASS): Changed "test -e" to "-f" since
-e is not supported on all architectures (Solaris) and -f is more
correct anyway.
Reported by Erik Modén.
* jode/swingui/Main.java (AreaWriter): Convert all kinds of
line breaks (CR+LF, CR, LF) to a LF character, which a JTextArea
understands.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-02-04 of Jode 1.1 tree:
* jode/expr/IfThenElseOperator.java (simplify): Allow in the class$
simplification the then and else part to be swapped.
* jode/type/ClassType.java (keywords): Added the package
and import keywords.
* jode/flow/TransformExceptionHandlers.java:
(getPredecessor): New function.
(getMonitorExitSlot): New function.
(skipFinExitChain): New function.
(removeJSR): Replaced by ...
(removeBadJSR): ... this.
(checkAndRemoveJSR): Use the new functions. Much simpler and
handles nested synchronized blocks. It now traces the whole JSR
and monitorexit chain before a jump to the first entry via
skipFinExitChain, then checks and remove the first JSR
resp. monitorexit. JSR jumps are simply ignored now.
(checkAndRemoveMonitorExit): likewise.
* jode/flow/StructuredBlock.java (prependBlock): New function.
* jode/flow/CatchBlock.java (makeDeclaration): Generate name
of dummyLocal, since nobody else will generate it.
* jode/bytecode/BasicBlockReader.java (readCode): Remove bogus
exceptionHandlers, whose catchers just throw the exception again.
This kind of entries are inserted by an obfuscator and would break
JODE.
* jode/util/UnifyHash.java (iterateHashCode): Call cleanUp,
to clean unneeded references.
* jode/flow/TransformConstructors.java (transformOneField):
Changed to private. Take field number as parameter. Check that
expression doesn't contain a FieldOperator for a later field of
the same class or a PutFieldOperator. Changed all callers.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-02-01 of Jode 1.1 tree:
* jode/jvm/CodeVerifier.java (Type.mergeType): If array elem
types can't be merged, return tObject as common super type.
* jode/type/ArrayType.java (getGeneralizedType): If array elem
type can't be intersected, return tObject as common super type.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from Jode 1.1 tree:
* jode/expr/Expression.java (updateParentTypes): Call setType,
instead of merging the types. Other childs want to know about the
type change as well.
* jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit,
but no changes.
* jode/expr/InvokeOperator.java (dumpExpression): Always print
the ThisOperator if a field is from a parent class of an outer
class is used. And always qualify the this operator if not
innermost.
2001-07-14 Jochen Hoenicke <jochen@gnu.org>
Applied patches from the Jode 1.1 tree:
* jode/decompiler/TabbedPrintWriter.java: Better gnu style handling:
(openBraceClass) (closeBraceClass)
(openBraceNoIndent) (closeBraceNoIndent): new functions.
(closeBraceNoSpace): Removed.
* jode/decompiler/TabbedPrintWriter.java (GNU_SPACING): new constant.
(printOptionalSpace): Print space for GNU_SPACING.
* jode/decompiler/Options.java (setOptions): changed gnu style
to include GNU_SPACING.
* jode/decompiler/ClassAnalyzer.java (dumpSource): Use
open/closeBraceClass.
* jode/decompiler/MethodAnalyzer.java (dumpSource): Use
open/closeBraceNoIndent. Call printOptionalSpace.
* jode/decompiler/InvokeOperator.java (dumpExpression):
Call printOptionalSpace, use open/closeBraceClass for inner
classes.
* jode/decompiler/UnaryOperator.java (dumpExpression): Call
printOptionalSpace.
Added pascal style from Rolf Howarth <rolf@squarebox.co.uk>
* jode/decompiler/Decompiler.java (setOption): detect pascal option.
* jode/decompiler/TabbedPrintWriter.java (BRACE_FLUSH_LEFT):
new constant.
(openBrace, openBraceContinue, closeBrace, closeBraceNoSpace,
closeBraceContinue): handle flush left.
* jode/type/NullType.java (intersection): Removed, since the
version in ReferenceType is more correct. Before
tNull.isOfType(tRange(X,tNull)) returned false, which lead to
incorrect behaviour in InvokeOperator.needsCast.
* jode/decompiler/FieldAnalyzer.java (dumpSource): Removed the
"= null" hack for final fields; it was not correct, since the
field could be initialized in a constructor.
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp):
Simplified the code, copy options always from child.
* jode/expr/InvokeOperator.java (isGetClass): Allow the method to
be declared inside an outer class: We simply check if we can get
the method analyzer.
(simplify): handle unifyParam.
* jode/expr/PopOperator.java (getBreakPenalty): return penalty of
inner expression. (dumpExpression): Call dumpExpression of
subexpression immediately without priority.

@ -0,0 +1,23 @@
Before installing, make sure you have at least version 1.1 of the java
developement kit installed. If you want to run this program you only
need the java runtime environment. Version 1.1 is quite old, I
recommend using Java 2 (jdk1.2 or above). You need perl if you want
to compile a 1.1 version.
This package was designed to use the ANT from the jakarta.apache.org
tools. I assume you have installed it correctly.
Take some time to edit config.props. There are a few options you need
to take care of. (Unfortunately ant can't test for executables).
Now you are ready to invoke ant. There are many possible targets, here
are the most useful ones:
all builds class files and documentation.
build builds class files only (autodetects java version).
build-1.1 builds JDK1.1 class files.
doc builds documentation.
dist creates all release files.
test does some self tests. You need to have junit installed for this.
clean cleans everything that doesn't belong to the source distribution.
cvsclean cleans everything that doesn't belong into the cvs repository.

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: net.sf.jode.swingui.Main
Created-By: SeeksTheMoon

@ -0,0 +1,36 @@
New in 1.2
* New bytecode interface
* Faster and better flow analyzation
New in 1.1
* break long lines
* handle most of javac v8 constructs (jdk 1.3)
* bug fixes
New in 1.0.93
* anonymous and inner class decompilation reworked.
* replaced a bash specific construct in acinclude.m4
* fixed a funny bug: string += "1" was decompiled as string++
* main class of decompiler is now jode.decompiler.Main
* fixed a bug in ConstantAnalyzer (obfuscator) (produced wrong code)
* fixed more bugs in obfuscator
* better memory usage in decompiler
* fixed a bug in decompiler (couldn't handle nop instruction)
* web pages updated.
New in 1.0.92
* option --pretty works again
* web pages updated
* swingui can show class hierarchie
* KeywordRenamer added to obfuscator.
New in 1.0.91:
* first version using configure. Jode can now be almost automatically
build, see INSTALL for instructions.
* the decompiler can handler inner and anoymous classes.
* you now need the gnu getopt package.
* you need JDK 1.2 or alternatively the swing and collection packages
for 1.1

@ -0,0 +1,90 @@
JODE (Java Optimize and Decompile Environment)
JODE is a java package containing a decompiler and an optimizer for
java. This package is freely available under the GNU General Public
License.
The decompiler reads in class files and produces something similar to
the original java file. Of course this can't be perfect: There is no
way to produce the comments or the names of local variables (except
when the java files were compiled with `-g') and there are often more
ways to write the same thing. However, jode does its job quite well.
The optimizer transforms class files in various ways with
can be controlled by a script file.
Please note that most software licenses forbid to decompile class
files. Use this decompiler only, if you have legal rights to
decompile the class (e.g. on your own code).
The features of the decompilers are:
* Systematic flow analysis, that can decompile every java code
without the need of goto (which doesn't exists in java).
* Type deduction, that can guess the type of local variables, even if
it is an interface type that doesn't occur in the bytecode.
* Handling of inner and anonymous classes.
* Different indentation styles available.
* It can decompile itself (194 classes) without a single error.
* It can decrypt strings on the fly, that were encrypted by an obfuscator.
Known bugs of the decompiler:
- Some jdk1.3 synthetic access functions aren't understood. The
produced source contains access$xxx functions, but it still compiles.
- There may be other bugs, that cause Exceptions or invalid code.
If you have such a problems don't hesitate to issue a bug report.
Please include the <code>class</code> file if possible.
Limitations:
- If not all dependent classes can be found, the verifier (which is
run before decompilation starts) may exit with a type error. You
can decompile it with --verify=off, but take the warning serious,
that the types may be incorrect. There's sometimes no way to guess
the right type, if you don't have access the full class hierarchie.
But if you don't have the dependent classes, you can't compile the
code again, anyway, so why do you want to decompile it?
- There may be situations, where jode doesn't understand complex
expressions. In this case many ugly temporary variables are used,
but the code should still be compileable. This does especially
happen when you compile with `-O' flag and javac has inlined some
methods.
The features of the obfuscator are:
* Modular design, you can plug the obfuscation transformation you need
together via the script file.
* Strong analysis, that optimizes away fields, expressions that are
known to be constant (and reverts the flow obfuscation of Zelix
Klassmaster)
* Can also be used as Optimizer, without any obfuscation at all, it
will preserve the local variable table and line number table.
* Many different renaming options, you can also simply add your own.
PRELIMINARIES:
See INSTALL for installation instructions.
USAGE:
First set the classpath. It should contain the jar file jode-1.1.jar,
the gnu getopt package and the sun collection package for 1.1. For
the swingui program you also need swing in you classpath.
You can then decompile a class file with:
java jode.decompiler.Main --classpath program.jar,libfoo.jar org.package.Class
or a complete package with
java jode.decompiler.Main --classpath libfoo.jar program.jar
For a graphical user interface based on swing try:
java jode.swingui.Main --classpath jarfile1.jar
The obfuscator/deobfuscator can be run with a script:
java jode.obfuscator.Main obfuscation.jos
See the web documents for more information about the script syntax.

@ -0,0 +1,5 @@
Joe Bronkema <joseph.d.bronkema at lmco.com>
Rolf Howarth <rolf at squarebox.co.uk> for pascal indentaton style.
Erik Modén <Erik.Moden at emw.ericsson.se>
Martin Schmitz <m.schmitz at e-sign.com> for finding many bugs in the obfuscator.
zzzeek <classic at io.com>

@ -1,28 +1,64 @@
This is a list of features, that would be nice to have:
Decompiler:
- deinline inlined methods.
- BUG: public final static null fields aren't initialized (leads to compile error)
- outline inlined methods.
- remove string decrypt method.
- remove synthetic methods if and only if all calls to them are resolved.
- rename keywords to safe names.
~ handle try catch more thouroughly/safely.
~ decompile jode.jvm.Interpreter (hand optimized bytecode)
Obfuscator:
- read options from a script.
- flow obfuscation/optimization.
- warn about Class.forName and list occurences.
- Detect Class.forName() calls with constant parameters and rename
these constants. Detect class$ methods with constant parameters.
Warn about all other occurences of Class.forName()
- work around Class.forName, by creating a new version using a hash
table that maps md5 sums of old names to obfuscated names.
This should be put into the constant analyzer. The simple
analyzer should only do the warnings.
- Transforming the class hierarchy, e.g. combining two totally
unrelated classes together into one class or make some class
to implement some interfaces, that it previously didn't.
- Doing flow obfuscation, i.e. do some tests, that one knows to
succeed always, and jump to funny position if the test fails.
The tests should use undecidable properties, so that a
deobfuscator cannot remove them again.
DeObfuscator:
- generate nice names:
- classes: derive name from super.
- fields: derive name from type.
- give synthetic methods the right attribute and name (e.g. class$)
- detect inner classes and give suitable names.
- Deobfuscator should detect inner/anonymous classes and mark them
as such. It should be possible with the renaming table to mark
inner classes as well. Inner classes are easy to detect; there
constructor has a special form. And the information is very
useful for the decompiler.
This should be done with some generalize interface similar to (or
instead of) Transformer
- Deobfuscator should generate nicer names. This should be a
special Renamer. The renamer should analyze short methods and
call them getXXX, isXXX, setXXX if apropriate, detect synthetic
methods and similar. Class names should be derived from super
class or interface (e.g. Enumeration), fields should be derived
from their type, maybe also from their assignments.
One can build more renamer, each handles some special cases and
calls the next one, if it can't handle an identifier.
User Interface:
- make a nice user interface:
- list classnames: toggable between class hierarchie/package hierarchie.
~ list classnames: toggable between class hierarchie/package hierarchie.
- list fields/method of selected class.
- show decompilation of selected method.
- show usage of method/fields.
- syntax highlighting, hyper links etc.
(look at java.swing.JEditorPane or at Java Insight)
- as a first approximation use HTML code and a JHTMLPane
- visual obfuscation/deobfuscation (like klassmaster?, better?)
Internal:
- clean up package hierarchy, esp. expr, flow and decompiler.
- move to net.sf.jode package.
- make the class names more precise, e.g. StructuredBlock is Statement,
FlowBlock is BasicBlock.

@ -0,0 +1,2 @@
Makefile
Makefile.in

@ -0,0 +1,5 @@
## Input file for automake to generate the Makefile.in used by configure
bin_SCRIPTS = jode
EXTRA_DIST = jode.bat.in jode.in

@ -0,0 +1,19 @@
; Use this batch file to make invoking the decompiler easier.
; Please edit this file and insert correct directories where needed.
;
; Usage: jode dec [decompiler options]
; jode swi [swingui options]
; jode obf [obfuscator options]
; Since the decompiler is the most important program you can omit `dec':
; jode [decompiler options]
set CLASSPATH=jode-@VERSION@-1.2.jar;%CLASSPATH%
set PROGGY=default
if %1 == swi set PROGGY=swingui
if %1 == obf set PROGGY=obfuscator
if %1 == dec set PROGGY=decompiler
if NOT %PROGGY% == default shift
if %PROGGY% == default set PROGGY=decompiler
java jode.%PROGGY%.Main %1 %2 %3 %4 %5 %6 %7 %8 %9

@ -0,0 +1,14 @@
#!@SHELL@
prefix=@prefix@
case $1 in
[Ss]wi*) CLAZZ=jode.swingui.Main; shift ;;
[Dd]ec*) CLAZZ=jode.decompiler.Main; shift ;;
[Oo]bf*) CLAZZ=jode.obfuscator.Main; shift ;;
*) CLAZZ=jode.decompiler.Main ;;
esac
CP=`echo $CLASSPATH | sed s/:/,/`
CLASSPATH=@datadir@/jode-@VERSION@.jar:@CLASSPATH@ \
@JAVA@ $CLAZZ --classpath $CP $*

@ -0,0 +1,380 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Jakarta-Ant build file for jode, Copyright (C) 1999-2004 Jochen Hoenicke.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
-->
<!DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "project.dtd">
<project name="jode" default="test" basedir=".">
<!-- set global properties for this build -->
<property name="version" value="1.90-CVS"/>
<property name="build" value="${basedir}/build"/>
<property name="props" value="${basedir}/props"/>
<property name="doc" value="${basedir}/doc"/>
<property name="lib" value="${basedir}/lib"/>
<property name="src" value="${basedir}/src"/>
<property name="release" value="${basedir}/release"/>
<property name="distdir" value="${release}/jode-${version}"/>
<property name="scripts" value="${basedir}/scripts"/>
<property name="api.doc" value="${doc}/api"/>
<property name="test" value="${basedir}/test"/>
<property name="test.src" value="${test}/src"/>
<property name="test.build" value="${test}/build"/>
<property name="test.log" value="${test}/log"/>
<property name="jcpp" value="${scripts}/jcpp.pl"/>
<property name="versionfile" value="${src}/jode/GlobalOptions.java"/>
<property file="config.props"/>
<path id="project.classpath">
<pathelement path="${classpath}"/>
<fileset dir="lib" includes="*.jar"/>
</path>
<!-- ********* General targets ******* -->
<!-- compiles jode and creates its javadoc-files -->
<target name="all" depends="build,doc"/>
<!-- clean all -->
<target name="clean" depends="clean-jcpp,clean-build,clean-doc,clean-test"/>
<target name="cvsclean" depends="clean,clean-html,clean-release"/>
<!-- ********* jcpp targets ******* -->
<target name="check-jcpp" unless="perl.present">
<fail message="need perl to configure for JDK 1.1"/>
</target>
<target name="run-jcpp" depends="check-packages,check-jcpp">
<apply dir="." executable="perl" parallel="true">
<arg file="${jcpp}"/>
<arg value="-DJDK11"/>
<arg value="-DCOLLECTIONS=${collections.package}"/>
<arg value="-DCOLLECTIONEXTRA=${collections.package}"/>
<arg value="-DJAVAX_SWING=${swing.package}"/>
<fileset dir="${src}" includes="**/*.java"/>
</apply>
</target>
<target name="clean-jcpp" if="perl.present">
<apply dir="." executable="perl" parallel="true">
<arg file="${jcpp}"/>
<arg value="-DJDK12"/>
<arg value="-DCOLLECTIONS=java.util"/>
<arg value="-DCOLLECTIONEXTRA=java.lang"/>
<arg value="-DJAVAX_SWING=javax.swing"/>
<fileset dir="${src}" includes="**/*.java"/>
</apply>
</target>
<!-- ********* Check Environment ******* -->
<target name="check-jdk" unless="jdk1.1.forced">
<available property="jdk1.2+" classname="java.lang.ThreadLocal" />
<available property="jdk1.3+" classname="java.lang.StrictMath" />
</target>
<target name="fail-getopt" unless="getopt.present">
<fail message="Package gnu.getopt not found!"/>
</target>
<target name="check-getopt">
<available property="getopt.present"
classname="gnu.getopt.Getopt"
classpathref="project.classpath" />
<antcall target="fail-getopt"/>
</target>
<target name="check-packages">
<available property="collections.package"
value="gnu.java.util.collections"
classname="gnu.java.util.collections.Set"
classpathref="project.classpath" />
<available property="collections.package"
value="org.gnu.java.util.collections"
classname="org.gnu.java.util.collections.Set"
classpathref="project.classpath" />
<available property="collections.package"
value="com.sun.java.util.collections"
classname="com.sun.java.util.collections.Set"
classpathref="project.classpath" />
<available property="swing.package" value="com.sun.java.swing"
classname="com.sun.java.swing.JFrame"
classpathref="project.classpath" />
<available property="swing.package" value="javax.swing"
classname="javax.swing.JFrame"
classpathref="project.classpath" />
</target>
<!-- ********* Build targets ******* -->
<target name="preconfig" depends="check-jdk,check-getopt,preconfig.11"/>
<target name="preconfig.11" unless="jdk1.2+">
<antcall target="run-jcpp"/>
</target>
<target name="preconfig.12" if="jdk1.2+">
<antcall target="clean-jcpp"/>
</target>
<target name="build-1.1">
<antcall target="build">
<param name="jdk1.1.forced" value="on"/>
</antcall>
</target>
<target name="build" depends="check-jdk,preconfig">
<mkdir dir="${build}"/>
<javac srcdir="${src}"
destdir="${build}"
debug="true"
classpathref="project.classpath"
deprecation="on">
<exclude name="net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java"/>
<exclude name="net/sf/jode/obfuscator/modules/LocalOptimizer.java"/>
<exclude name="net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java"/>
<!--
<exclude name="net/sf/jode/bytecode/*Subroutine*" />
-->
</javac>
</target>
<!-- clean the class files -->
<target name="clean-build">
<delete dir="${build}"/>
</target>
<!-- ********* Create Release files ******* -->
<target name="release" depends="release-bin,release-bin11,release-src,release-javadoc"/>
<target name="release-bindist" depends="build">
<jar jarfile="${distdir}/jode.jar" compress="true" manifest="${basedir}/MANIFEST.MF">
<fileset dir="${build}" includes="**/*.class"/>
<fileset dir="${props}" includes="**/*.properties"/>
</jar>
<copy todir="${distdir}">
<fileset dir="${lib}">
<include name="*getopt*.jar" />
<include name="*collection*.jar" unless="jdk1.2+" />
</fileset>
<fileset dir="${basedir}"
includes="AUTHORS,COPYING,NEWS,README,THANKS,TODO">
<include name="doc/*.html" />
<include name="doc/*.gif" />
<include name="doc/*.jos" />
<include name="doc/*.perl" />
</fileset>
</copy>
</target>
<target name="release-bin" depends="doc-html">
<antcall target="clean"/>
<mkdir dir="${release}"/>
<mkdir dir="${distdir}"/>
<antcall target="release-bindist"/>
<jar jarfile="${release}/jode-${version}.jar"
basedir="${release}" includes="jode-${version}/**"/>
<delete dir="${distdir}"/>
<antcall target="clean"/>
</target>
<target name="release-bin11" depends="doc-html">
<antcall target="clean"/>
<mkdir dir="${release}"/>
<mkdir dir="${distdir}"/>
<antcall target="release-bindist">
<param name="jdk1.1.forced" value="on"/>
</antcall>
<jar jarfile="${release}/jode-${version}-JDK1.1.jar"
basedir="${release}" includes="jode-${version}/**"/>
<delete dir="${distdir}"/>
<antcall target="clean"/>
</target>
<target name="release-src" depends="doc-html">
<antcall target="clean"/>
<mkdir dir="${release}"/>
<mkdir dir="${distdir}"/>
<copy todir="${distdir}">
<fileset dir="${basedir}"
includes="AUTHORS,COPYING,INSTALL,NEWS,README,THANKS,TODO,ChangeLog">
<include name="build.xml,config.props,project*.dtd"/>
<include name="doc/**"/>
<include name="scripts/**"/>
<include name="src/**"/>
<include name="test/*.java"/>
<include name="test/*.j"/>
<include name="test/src/**"/>
<include name="props/**"/>
<include name="lib/**"/>
</fileset>
</copy>
<jar jarfile="${release}/jode-${version}-src.jar"
basedir="${release}" includes="jode-${version}/**"/>
<delete dir="${distdir}"/>
</target>
<target name="release-javadoc">
<antcall target="doc-javadoc"/>
<mkdir dir="${release}"/>
<jar jarfile="${release}/jode-${version}-API.jar"
basedir="${doc}" includes="api/**"/>
<antcall target="clean-doc"/>
</target>
<target name="clean-release">
<delete dir="${release}"/>
</target>
<!-- ********* Javadoc targets ********** -->
<target name="doc" depends="doc-javadoc,doc-html"/>
<target name="doc-html" if="htp.present">
<apply executable="htp" dir="${doc}" dest="${doc}" parallel="false" relative="yes">
<arg value="-NODEPEND" />
<srcfile />
<targetfile />
<fileset dir="${doc}" includes="*.htp"/>
<mapper type="glob" from="*.htp" to="*.html"/>
</apply>
</target>
<target name="doc-javadoc">
<tstamp>
<format property="date" pattern="MMM d, yyyy"/>
</tstamp>
<mkdir dir="${api.doc}"/>
<javadoc packagenames="net.sf.jode.*"
windowtitle="Jode ${version} API Specification"
header='&lt;b&gt;&lt;a href="http://jode.sourceforge.net/"&gt;Jode&lt;/a&gt; ${version}&lt;/b&gt;&lt;br&gt;&lt;font size="-2"&gt;Build ${date}&lt;/font&gt;'
overview="${src}/net/sf/jode/overview.html"
bottom='Copyright &amp;copy; 1998-2004 by Jochen Hoenicke.'
sourcepath="${src}"
destdir="${api.doc}"
use="yes">
<link offline="${javadoc.offline}"
href="${javadoc.href}"
packagelistLoc="${javadoc.packagelistLoc}"/>
</javadoc>
</target>
<target name="clean-doc">
<delete dir="${api.doc}"/>
</target>
<target name="clean-html">
<delete>
<fileset dir="${doc}" includes="*.html"/>
</delete>
</target>
<!-- ********* test targets ************* -->
<target name="build-test" depends="build">
<mkdir dir="${test.build}"/>
<javac srcdir="${test.src}"
destdir="${test.build}"
debug="true"
classpathref="project.classpath"
classpath="${build}"
deprecation="on">
</javac>
</target>
<target name="test" depends="build-test">
<mkdir dir="${test.log}"/>
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement path="${test.build}"/>
<pathelement path="${build}"/>
<path refid="project.classpath"/>
</classpath>
<formatter type="plain" />
<batchtest fork="no" todir="${test.log}">
<fileset dir="${test.src}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
</target>
<target name="test-cvs" depends="build-test">
<mkdir dir="${test.log}"/>
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement path="${test.build}"/>
<pathelement path="${build}"/>
<fileset dir="lib" includes="*.jar"/>
<fileset dir="/usr/local/ant/lib" includes="*.jar"/>
</classpath>
<formatter type="plain" />
<batchtest fork="no" todir="${test.log}">
<fileset dir="${test.src}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
</target>
<target name="clean-test">
<delete dir="${test.build}"/>
<delete dir="${test.log}"/>
</target>
<!-- ********* version targets ************* -->
<target name="setversion" if="version">
<echo message="updating version in ${versionfile} ..."/>
<exec executable="perl">
<arg value="-i"/>
<arg value="-pe"/>
<arg value='s/(String\s*version\s*=\s*")[^"]*/$1${version}/' />
<arg value="${versionfile}"/>
</exec>
</target>
<target name="commit" depends="setversion,test-cvs" if="version">
<antcall target="cvsclean"/>
<echo message="---------------------------------------------------"/>
<echo message=' Commiting new Jode version: ${version} !!!'/>
<echo message="==================================================="/>
<!--
search the old version information and replace it with the new version
we will search the $(mainclass) for 'String VERSION = "..."' and
replace the contents of the String with the new version.
-->
<!-- commit the new $(VERSIONFILE) to the CVS
<echo message="commiting updated file to CVS..."/>
<cvs command='ci -m"new version ${version}" ${versionfile}'/>
-->
<!-- commit the new $(VERSIONFILE) to the CVS
<echo message="tagging files in CVS..."/>
<property
<cvs command="tag ${cvstag}"/>
-->
<echo message="...done!"/>
<echo message="---------------------------------------------------"/>
</target>
</project>

@ -0,0 +1,28 @@
# Do you have online access for generating javadoc?
# If not, where are your local files.
javadoc.offline=false
javadoc.packagelistLoc=
javadoc.href=http://java.sun.com/products/jdk/1.2/docs/api/
#javadoc.href=file:/usr/doc/inet/java/jdk1.2/docs/api
#javadoc.offline=true
#javadoc.packagelistLoc=/usr/doc/inet/java/jdk1.2/docs/api
# Is Perl installed on your system?
#
# perl is needed to reconfigure Jode for JDK-1.1. If you haven't
# installed it you can only configure for JDK-1.2 and you should
# comment out the next line.
#
# perl is also used for things that are relevant for the maintainer.
#
# Remove the next line if perl is not installed.
perl.present=true
# Is HTP installed on your system?
#
# htp is needed to generate html files from htp files.
# see http://htp.sourceforge.net/
#
# Remove the next line if either htp is not installed.
htp.present=true

@ -0,0 +1,58 @@
#!/bin/sh
create_jar() {
jar -xvf $HOME/java/jars/getopt.jar
rm -rf META-INF
jar -cvf ../jode-1.0.92-$1.jar AUTHORS COPYING README INSTALL NEWS doc/*.{html,jos,perl,gif} `find jode -name \*.class` gnu
rm -rf gnu
}
create_first() {
# first 1.1 version.
tar -xvzf jode-1.0.92.tar.gz
cd jode-1.0.92
CLASSPATH=$HOME/java/jars/getopt.jar:/usr/local/1.1collections/lib/collections.jar:/usr/local/swing-1.1/swingall.jar \
./configure --with-java=/usr/lib/java --with-jikes=/home/jochen/bin
make
create_jar 1.1
cd ..
rm -rf jode-1.0.92
}
create_second() {
# now 1.2 version.
tar -xvzf jode-1.0.92.tar.gz
cd jode-1.0.92
find -name \*.java -o -name \*.java.in | xargs jcpp -DJDK12
CLASSPATH=$HOME/java/jars/getopt.jar \
./configure --with-java=/usr/local/jdk1.2 --with-jikes=/home/jochen/bin
make
create_jar 1.2
cd ..
rm -rf jode-1.0.92
}
create_applet() {
cat <<EOF >jode-applet.jos
# JODE Optimizer Script
strip = "unreach","source","lnt","lvt","inner"
load = new WildCard { value = "jode" },
new WildCard { value = "gnu" }
preserve = new WildCard { value = "jode.JodeApplet.<init>.()V" }
renamer = new StrongRenamer {
charsetStart = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
charsetPart = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$"
charsetPackage = "abcdefghijklmnopqrstuvwxyz"
charsetClass = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
analyzer = new ConstantAnalyzer
post = new LocalOptimizer, new RemovePopAnalyzer
EOF
CLASSPATH=jode-1.0.92-1.1.jar:$CLASSPATH java jode.obfuscator.Main \
--cp jode-1.0.92-1.1.jar --dest jode-applet.jar jode-applet.jos
}
#create_first
#create_second
create_applet

@ -0,0 +1,3 @@
Makefile
Makefile.in
*.html

@ -0,0 +1,25 @@
<section title="The <i>JODE</i> Applet">
<p>Please be patience, loading the applet may take some time.</p>
<center>
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400>
<param name=pagecolor value="ffffff">
<param name=classpath value="http://jode.sourceforge.net/plasma.jar">
<param name=class value="PlasmaApplet">
<p>Sorry you need a java enabled browser to test a java applet ;-)</p>
<p>Don't read the rest, it only contains information about the applet.</p>
</applet>
</center><br>
<p> Press the start button to decompile <a
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's
Plasma applet</a> (and give the decompiler some time to download the
jar file). </p>
<p>You may change the classpath to point to a zip or jar file of your
choice. Unfortunately, your browser will most likely forbid URL's that
aren't located on jode.sourceforge.net.
Save probably doesn't work, because it is forbidden by your browser.</p>
</section>

@ -0,0 +1,69 @@
<section title="Wish List">
<p>This section contains features that I think would be great to have,
but are also very hard to implement. </p>
<p>Currently this are all my own ideas. But if you send me an idea
for an interesting feature, I will add it to this list.</p>
<h2><i>Out</i>line inlined methods</h2>
<p>If java gets called with `<code>-O</code>' switch, it inlines methods,
that are private, final, or static and contain no loops. When
decompiling this it sometimes produces really ugly code. The right
way to solve this would be to <i>out</i>line the code again. This is
possible but requires to find the inlined method. </p>
<p>The name `outline' was suggested by <a
href="http://www.informatik.uni-oldenburg.de/~mw">Michael</a>.
</p>
<h2>Better names of local variables</h2>
<p>The local variable naming is very stupid. Even with pretty it just
names the variable after the type with a unifying number appended. A
method containing very much objects of the same type looks very
ugly. </p>
<p>My plan is looking at the assignments. If we have locals in
assignments</p>
<pre>
int l_1 = array.length
String l_2 = object.getName()
</pre>
<p>we could name them "length" and "name". If we
have assignments:</p>
<pre>
MenuItem local_1 = new MenuItem("Open");
MenuItem local_2 = new MenuItem("Save");
</pre>
<p>good names would be <code>miOpen</code> and <code>miSave</code>. </p>
<p>It is currently possible to assign a <i>(hint name,type)</i> pair
to a local. If the type matches, the local will be named after
<i>hint name</i>. This could be extended by giving them several
weighted hints and constructing the name in an intelligent way. </p>
<h2>Better deobfuscation features</h2>
<p>First there should be a good Renamer: Methods that simply
return a field value should be renamed to get<i>FieldName</i>.
Fields should be named after their type, maybe also by assignments
(see section about local variable names).</p>
<p>The deobfuscator should detect inner and anonymous variables,
synthetic methods and so on, and rename them accordingly.</p>
<h2>Handling of Class.forName in obfuscator</h2>
<p>The obfuscator should detect Class.forName constructs (and
similarly for methods and fields) and if their parameters are constant
it should change the parameter according to the rename function. </p>
<h2>Merging javadoc comments</h2>
<p>It would be nice if the decompiler could merge the javadoc comments
into the class file. More and more people use javadoc to comment the
public api of their java classes. It shouldn't be too difficult to
copy them back into the java code. </p>
<p>This doesn't need to be built into the decompiler. A script that takes
the javadoc pages and the decompiled code can easily merge them.</p>
</section>

@ -0,0 +1,711 @@
use strict;
my (@tstack, @vstack);
my $incindent = 4;
my $instr_addr;
my (%instr, %next_instr, %prev_instr);
@tstack = ();
@vstack = ();
sub print_stack {
my ($type, $value);
while (@tstack and @vstack) {
$type = shift @tstack;
$value = shift @vstack;
print STDERR "($type) $value, ";
}
if (@tstack) {
print STDERR "TSTACK to big : @tstack ";
} elsif (@vstack) {
print STDERR "VSTACK to big : @vstack ";
}
@tstack = ();
@vstack = ();
}
sub print_code {
my ($indent, $code, $addr) = @_;
#print " "x$indent, $code, (defined addr)?"/* $addr */":"", "\n";
print " "x$indent, $code, "\n";
}
sub dump_program {
my $addr;
foreach $addr (sort { $a <=> $b } keys %instr) {
print_code (0, "$addr $instr{$addr}");
}
return 1
}
sub convert_value($$$) {
my ($value, $oldtype, $newtype) = @_;
return "$value" if ($oldtype eq $newtype);
return "$value" if ($oldtype =~ /\*/ or $newtype =~ /\*/);
return "$value" if ($oldtype eq "boolean" && $newtype eq "int");
if ($oldtype eq "int" && $newtype eq "boolean") {
$value =~ s/1/true/g;
$value =~ s/0/false/g;
$value =~ s/\&/\&\&/g;
$value =~ s/\|/\|\|/g;
return $value;
}
return $value; # "/*warn: conv: $oldtype => $newtype*/ $value";
}
sub get_type ($) {
my $type;
$_ = $_[0];
SWITCH: {
/^b$/ && ($type = "byte",last);
/^c$/ && ($type = "char",last);
/^s$/ && ($type = "short",last);
/^i$/ && ($type = "int",last);
/^l$/ && ($type = "long",last);
/^f$/ && ($type = "float",last);
/^d$/ && ($type = "double",last);
/^a$/ && ($type = "*",last);
die "internal error in get_type";
}
return $type;
}
sub pop_value_type ($) {
if (not @tstack || not @vstack) {
die "Stack is empty??";
}
my $result = "";
my $want_type = $_[0];
my $act_type = pop @tstack;
my $value = pop @vstack;
warn "want_type not defined"
if (not defined $want_type);
warn "act_type not defined"
if (not defined $act_type);
$result = convert_value($value, $act_type, $want_type);
return ($result, $act_type);
}
sub pop_value($) {
@_ = pop_value_type($_[0]);
return $_[0];
}
sub parse_type($) {
$_[0] =~ /^\#\d+\s+ <Class
\s+(\S+) # type
>\s*$/x or die "Wrong field parameter `$_[0]'";
return $1;
}
sub parse_field($) {
$_[0] =~ /^\#\d+\s+ <Field
\s+(\S+) # type
\s+([^\[>]+) # name
((?:\[\])*) # [][]... belongs to type
>\s*$/x or die "Wrong field parameter `$_[0]'";
return $1.$3, $2;
}
sub parse_special($) {
$_[0] =~ /\#\d+\s+<Method
\s+([^\(\s]+) # method
\s*\(([^\)]*)\) # params
>\s*$/x or die "Wrong method parameter `$_[0]'";
my ($method, $params) = ($1,$2);
my @params = split /,\s*/, $params;
return $method, @params;
}
sub parse_method($) {
$_[0] =~ /\#\d+\s+<Method
\s+(\S+) # type
\s+([^\(\s]+) # method
\s*\(([^\)]*)\) # params
>\s*$/x or die "Wrong method parameter `$_[0]'";
my ($type, $method, $params) = ($1, $2,$3);
my @params = split /,\s*/, $params;
return $type, $method, @params;
}
sub classify($$) {
my $class = $_[0] . ".";
$class = "" if $class eq "this.";
return $class.$_[1];
}
sub new_instr($) {
if (defined ($instr{$instr_addr})) {
$instr{$instr_addr} .= "\n/*warn: multiple*/\n".$_[0];
} else {
$instr{$instr_addr} = $_[0];
}
# print STDERR "$instr_addr: $instr{$instr_addr}\n";
}
sub new_assign($$) {
my ($var, $value) = @_;
if (@vstack) {
if (("$value" eq "($var + 1)") &&
($vstack[-1] eq "$var")) {
$vstack[-1] = "$var++";
} else {
warn("`$var = $value' in expression, while vstack");
}
} else {
new_instr("$var = $value;");
}
}
sub combine_if_block {
my ($addr, $end) = @_;
$instr{$addr} =~ /if (\(.*\)) goto (\d+);/ or return;
my ($cond, $dest) = ($1, $2);
COMBINE:
while (1) {
my $if;
# First combine ifs with the same dest addr, that is ors.
my @conds = ($cond);
for ($if = $next_instr{$addr}; $if < $end; $if = $next_instr{$addr}) {
$instr{$if} =~ /if (\(.*\)) goto ($dest);/ or last;
push @conds, $1;
#remove unnecessary ifs (hope there are no goto's)
$next_instr{$addr} = $next_instr{$if};
$prev_instr{$next_instr{$if}}= $addr;
delete $instr{$if};
delete $prev_instr{$if};
delete $next_instr{$if};
}
if (@conds > 1) {
# combine conditions with or and reset the list
$cond = join " || ", @conds;
$cond = "($cond)";
}
last COMBINE if ($if >= $end || $instr{$if} !~ /^if/);
# Now try if we can combine all further ifs until the destination (that is and)
combine_if_block($if, $dest)
unless ($next_instr{$if} == $dest);
last COMBINE if ($next_instr{$if} != $dest);
# This is an and
$instr{$if} =~ /if (\(.*\)) goto (\d+);/;
$cond = "(!$cond && $1)";
$dest = $2;
$next_instr{$addr} = $next_instr{$if};
$prev_instr{$next_instr{$if}}= $addr;
delete $instr{$if};
delete $prev_instr{$if};
delete $next_instr{$if};
}
# Okay, we are stuck here, build the combined if.
$instr{$addr} = "if $cond goto $dest;";
}
sub simplify_instructions {
my ($addr, $end) = @_;
ADDR:
for (; $addr < $end; $addr = $next_instr{$addr}) {
combine_if_block($addr, $end)
if $instr{$addr} =~ /^if /;
while ( $instr{$addr} =~
/^(.*)new (java\.lang\.)?StringBuffer\((\).append\(.*)+\).toString\(\)(.*)$/ ) {
my ($first, $middle, $last) = ($1,$3,$4);
$middle =~ s/\).append\(/\+/g;
$middle =~ s/^\+//;
$instr{$addr} = $first.$middle.$last;
}
while ( $instr{$addr} =~ s/([A-Za-z_\$][A-Za-z_\$0-9]*) = \(\1 \+ 1\)/$1++/) {
}
}
}
# The parameters:
# start first instruction to decode
# end last instruction to decode + 1
# next instruction where control flows after this block
# (usually end but may be bigger)
# break instruction where a break would bring us to
# indent The indentation of this block
sub print_stmtlist ($$$$$) {
my ($start, $end, $next, $break, $indent) = @_;
my $addr;
$addr = $start;
ADDR:
while ($addr < $end) {
(dump_program && die "Addresses out of range: $addr") if (not defined $next_instr{$addr});
$_ = $instr{$addr};
/^goto (\d+);$/ && do {
my $dest = $1;
if ($dest == $break) {
print_code($indent, "break $dest;", $addr);
$addr = $next_instr{$addr};
next ADDR;
}
my $begin = $next_instr{$addr};
if ($instr{$dest} =~ /^if\s\((.*)\)\sgoto\s$begin/) {
# This is a while-loop
print_code($indent, "while ($1) {", $addr);
print_stmtlist($begin, $dest, $dest, $dest, $indent+$incindent);
print_code($indent, "}");
$addr = $next_instr{$dest};
next ADDR;
}
};
/^if \((.*)\) goto (\d+);/ && do {
my $cond = $1;
my $next_after_if = $2;
if ($next_after_if > $addr &&
($next_after_if <= $end || $next_after_if == $next)) {
# This seems to be an if.
print_code($indent, "if (!($cond)) {", $addr);
# endthen is the last instruction in then block + 1
my $endthen = ($next_after_if > $end) ? $end : $next_after_if;
my $prev = $prev_instr{$endthen};
if ($instr{$prev} =~ /^goto\s(.*);/ &&
$1 > $endthen && ($1 <= $end || $1 == $next)) {
$next_after_if = $1;
my $endelse = $1;
if ($endelse > $end) {
$endelse = $end;
}
# there is an else part
print_stmtlist ($next_instr{$addr}, $prev,
$next_after_if, $break, $indent+$incindent);
print_code($indent, "} else {");
print_stmtlist ($endthen, $endelse,
$next_after_if, $break, $indent+$incindent);
$addr = $endelse;
} else {
# no else-part
print_stmtlist ($next_instr{$addr}, $endthen,
$next_after_if, $break, $indent+$incindent);
$addr = $endthen;
}
print_code($indent, "}");
next ADDR;
}
if ($next_after_if == $break) {
# This is an if () break;
print_code($indent, "if ($cond) break;", $addr);
$addr = $next_instr{$addr};
next ADDR;
}
};
/^case ((.|\n)*)$/ && do {
my $default;
my $cond = "NONE";
my @lines = split "\n", $1;
$_ = shift @lines;
/^\((.*)\)$/ and $cond = $1;
(shift @lines) =~ /^default: goto (\d+);/ and $default = $1;
my $next_after_switch = $default;
if ($instr{$prev_instr{$default}} =~ /^goto\s(\d+);/ and
$1 > $default) {
$next_after_switch = $1;
}
print_code ($indent, "switch ($cond) {", $addr);
my %cases = ($default => "default");
foreach (@lines) {
(/^(\d+): goto (\d+);$/ and $cases{$2} = "case $1")
or warn ("ILLEGAL case : `$_'");
my $casepos = $1;
if ($casepos > $next_after_switch) {
if ($instr{$prev_instr{$1}} =~ /^goto\s(\d+);/ and
$1 > $casepos) {
$next_after_switch = $1;
} else {
$next_after_switch = $casepos;
}
}
}
$next_after_switch = $end
if ($next_after_switch > $end && $next_after_switch != $next);
my $endswitch = ($next_after_switch > $end) ? $end : $next_after_switch;
#print STDERR "Addr: $addr, labels: `",
# (join ":", keys %cases ), "', default: $default, end: $next_after_switch\n";
$addr = $next_instr{$addr};
foreach $_ (sort { $a <=> $b } keys %cases) {
my $next_case = $_;
if ($instr{$prev_instr{$next_case}} eq
"goto $next_after_switch;") {
print_stmtlist($addr, $prev_instr{$next_case},
$next_after_switch, $next_after_switch,
$indent+$incindent);
print_code($indent+$incindent, "break;");
} else {
print_stmtlist($addr, $next_case,
$next_case, $next_after_switch,
$indent+$incindent);
}
print_code($indent, $cases{$next_case}.":");
$addr = $next_case;
}
print_stmtlist($addr, $endswitch,
$endswitch, $next_after_switch,
$indent+$incindent);
print_code($indent, "}");
$addr = $endswitch;
next ADDR;
};
print_code($indent, $_, $addr);
$addr = $next_instr{$addr};
}
}
my %locals = ();
my $addr;
LINE: while (<>) {
chomp;
(/^\s*(\d+)\s+(.*)$/ and $addr = $1, $_ = $2) or do {
warn "Line `$_' ist not formatted correctly\n";
next LINE;
};
if (not @vstack) {
if (defined ($instr_addr)) {
new_instr("/*warn: missing instruction!*/")
if (not defined $instr{$instr_addr});
$next_instr{$instr_addr} = $addr;
$prev_instr{$addr} = $instr_addr;
} else {
$prev_instr{$addr} = -1;
}
$instr_addr = $addr;
}
INSTR:
{
/^([ilfda])load[\s_]+(\d+)\s*$/ && do {
push @tstack, get_type($1);
my $local;
if ($2 == 0) {
$local = "this";
} else {
$local = "local_$2";
}
push @vstack, $local;
last INSTR;
};
/^([bcsilfda])aload\s*$/ && do {
my $warn = "";
my $index = pop_value("int");
my ($array, $atype) = pop_value_type(get_type($1)."[]");
my $type = $atype;
($atype =~ /(.*)\[\]/ and $type = $1) or
$warn = "/*warn: `$atype' not an array*/ ";
push @tstack, $type;
push @vstack, "$warn$array"."[$index]";
last INSTR;
};
(/^[bs](i)push\s+(-?\d+)\s*$/ ||
/^([ilfda])const[\s_]+([m\-]?[\d.Ee\+\-]+|null)\s*$/) && do {
push @tstack, get_type($1);
push @vstack, ($2 eq "m1") ? -1 : $2;
last INSTR;
};
/ldc[12]?_?w?\s+\#\d+\s+\<(\S+)\s+([^\>]+)\>/ && do {
push @tstack, $1;
push @vstack, $2;
last INSTR;
};
/^([ilfda])store[\s_]+(\d+)\s*$/ && do {
my $local;
my ($value, $type) = pop_value_type(get_type($1));
if ($2 == 0) {
$local = "this";
} else {
$local = "local_$2";
if (not defined $locals{$2}) {
$locals{$2} = $type;
$local = "$type $local";
} else {
$local = convert_value($local, $type, $locals{$2});
}
}
new_assign($local, $value);
last INSTR;
};
/^([bcsilfda])astore\s*$/ && do {
my ($value, $type) = pop_value_type(get_type($1));
my $index = pop_value("int");
my ($array, $atype) = pop_value_type(get_type($1)."[]");
($atype =~ /(.*)\[\]/ and $atype = $1) or
$atype = "`$atype' not an array*/\n\t";
new_assign("$array"."[$index]",
convert_value("$value", $type, $atype));
last INSTR;
};
/^new\s+(.*)\s*/ && do {
my ($type) = parse_type($1);
push @tstack, $type;
push @vstack, "new $type";
last INSTR;
};
/^newarray\s+(\S+)\s*$/ && do {
my $arrtype = $1;
my $value = pop_value("int");
push @tstack, $arrtype."[]";
push @vstack, "new ".$arrtype."[$value]";
last INSTR;
};
/^getfield\s+(.*)$/ && do {
my ($type, $field) = parse_field($1);
my $class = pop_value("*") . ".";
$class = "" if $class eq "this.";
push @tstack, $type;
push @vstack, "$class$field";
last INSTR;
};
/^getstatic\s+(.*)$/ && do {
my ($type, $field) = parse_field($1);
push @tstack, $type;
my $class="FIXME.";
push @vstack, "$class$field";
last INSTR;
};
/^putfield\s+(.*)$/ && do {
my ($dtype, $field) = parse_field($1);
my $value = pop_value($dtype);
$field = classify(pop_value("*"), $field);
new_assign($field, $value);
last INSTR;
};
/^goto\s+(\d+)\s*$/ && do {
new_instr("goto $1;");
last INSTR;
};
/^tableswitch\s+(\d+)\s+to\s+(\d+): default=(\d+)\s*$/ && do {
my $from = $1;
my $to = $2;
my $default = $3;
my $num;
my $casestmt = "case (" . pop_value("int") . ")\n";
$casestmt .= "default: goto $default;\n";
for $num ($from .. $to) {
$_ = <>;
if ( $_ =~ /\s+$num:\s*(\d+)/ ) {
$casestmt .= "$num: goto $1;\n";
} else {
warn "unknown case: `$_' at $.";
}
}
new_instr($casestmt);
last INSTR;
};
/^lookupswitch\s+(\d+):\s+default=(\d+)\s*$/ && do {
my $anz = $1;
my $default = $2;
my $num;
my $casestmt = "case (" . pop_value("int") . ")\n";
$casestmt .= "default: goto $default;\n";
for $num (1 .. $anz) {
$_ = <>;
if ( $_ =~ /\s+(\d+):\s*(\d+)/ ) {
$casestmt .= "$1: goto $2;\n";
} else {
$casestmt .= "error in case";
}
}
new_instr($casestmt);
last INSTR;
};
/^invokespecial\s+(.*)$/ && do {
my ($method, @paramtypes) = parse_special ($1);
my @params=();
# Constructoraufruf! Wenn alles glatt laeuft...
while (@paramtypes) {
my $ptype = pop @paramtypes;
my $value = pop_value($ptype);
unshift @params, $value;
}
my ($new_class, $class_type) = pop_value_type ("*");
$method = $new_class;
my $call = "$method(" . join (", ", @params) . ")";
if ($vstack[-1] eq $new_class) {
$vstack[-1] = "$call";
} else {
new_instr("$call;");
}
last INSTR;
};
/^invoke(virtual|static)\s+(.*)$/ && do {
my ($type, $method, @paramtypes) = parse_method ($2);
my @params=();
while (@paramtypes) {
my $ptype = pop @paramtypes;
my $value = pop_value($ptype);
unshift @params, $value;
}
my ($class, $class_type) = ($1 eq "virtual")? pop_value_type ("*") : "FIXME";
$method = classify($class, $method);
my $call = "$method(" . join (", ", @params) . ")";
if ($type eq "void") {
new_instr("$call;");
} else {
push @tstack, $type;
push @vstack, $call;
}
last INSTR;
};
/^return\s*$/ && do {
new_instr("return;");
last INSTR;
};
/^pop\s*$/ && do {
unless (@vstack) {
print STDERR "pop: Stack is empty at $addr";
}
new_instr(pop(@vstack).";");
pop @tstack;
last INSTR;
};
/^dup\s*$/ && do {
push @tstack, $tstack[-1];
push @vstack, $vstack[-1];
last INSTR;
};
/^dup2\s*$/ && do {
push @tstack, $tstack[-2];
push @vstack, $vstack[-2];
push @tstack, $tstack[-2];
push @vstack, $vstack[-2];
last INSTR;
};
/^dup_x([12])\s*$/ && do {
splice @tstack, -1-$1, 0, $tstack[-1];
splice @vstack, -1-$1, 0, $vstack[-1];
last INSTR;
};
/^([ilfd])neg\s*$/ && do {
my $type = get_type($1);
my $op1 = pop_value($type);
push @tstack, $type;
push @vstack, "-$op1";
last INSTR;
};
/^([ilfd])(add|sub|mul|div|rem|and|or|xor|shl|shr)\s*$/ && do {
my $type = get_type($1);
my $op2 = pop_value($type);
my $op1 = pop_value($type);
my $op;
for ($2) {
/add/ && ($op="+", last);
/sub/ && ($op="-", last);
/mul/ && ($op="*", last);
/div/ && ($op="/", last);
/rem/ && ($op="%", last);
/and/ && ($op="&", last);
/or/ && ($op="|", last);
/xor/ && ($op="^", last);
/shl/ && ($op="<<", last);
/shr/ && ($op=">>", last);
}
push @tstack, $type;
push @vstack, "($op1 $op $op2)";
last INSTR;
};
/^iinc\s+(\d+)\s+(-?\d+)\s*$/ && do {
my $value = $2;
my $local;
if ($1 == 0) {
$local = "this";
} else {
$local = "local_$1";
}
new_instr(convert_value("$local", "int", $locals{$1}).
(($2 == 1)? "++;" : " += $2;"));
last INSTR;
};
/^([bcifld])2([bcifld])\s*$/ && do {
my $value = pop_value(get_type($1));
my $type = get_type($2);
push @tstack, $type;
push @vstack, "($type) $value";
last INSTR;
};
/^([lfd])cmp([lg]?)\s*$/ && do {
my $type = get_type($1);
my $op2 = pop_value($type);
my $op1 = pop_value($type);
push @tstack, "int";
push @vstack, "($op1 <=>$2 $op2)";
last INSTR;
};
/^if(eq|lt|le|ne|gt|ge)\s+(\d+)\s*$/ && do {
my $op;
my $dest = $2;
for ($1) {
/eq/ && ($op="==", last);
/lt/ && ($op="<", last);
/le/ && ($op="<=", last);
/ne/ && ($op="!=", last);
/gt/ && ($op=">", last);
/ge/ && ($op=">=", last);
}
my $op1 = pop_value("int");
new_instr("if ($op1 $op 0) goto $dest;");
last INSTR;
};
/^if_icmp(eq|lt|le|ne|gt|ge)\s+(\d+)\s*$/ && do {
my $op;
my $dest = $2;
for ($1) {
/eq/ && ($op="==", last);
/lt/ && ($op="<", last);
/le/ && ($op="<=", last);
/ne/ && ($op="!=", last);
/gt/ && ($op=">", last);
/ge/ && ($op=">=", last);
}
my $op2 = pop_value("int");
my $op1 = pop_value("int");
new_instr("if ($op1 $op $op2) goto $dest;");
last INSTR;
};
/^if(null|nonnull)\s+(\d+)\s*$/ && do {
my $dest = $2;
my $op;
for ($1) {
/notnull/ && ($op="!=", last);
/null/ && ($op="==", last);
}
my $op1 = pop_value("*");
new_instr("if ($op1 $op null) goto $dest;");
last INSTR;
};
do {
print STDERR "Stack: ";
&print_stack;
print STDERR "\nUnknown Instruction: `$_'\n\t";
};
}
}
$addr++;
$next_instr{$instr_addr} = $addr;
simplify_instructions (0, $addr);
print_stmtlist(0, $addr, $addr, $addr, 2*$incindent);

@ -0,0 +1,39 @@
<section title="Download">
<p>Jode is available in the <sflink
href="project/showfiles.php">download area</a> in source or binary
form. For compiling the source code, you need several other packages,
check the <a href="links.html">links page</a>. You need a unix like
environment for compilation.</p>
<p>The simplest way to get it, especially for non unix users, is in
precompiled form, though. There are two jar archives in the download
area:</P>
<ul> <li>jode-1.1-JDK1.1.jar is for JDK&nbsp;1.1. If you want to use
the swing interface, you have to download swing separately, all other
packages are already included in the archive. </li>
<li>jode-1.1.jar is for JDK&nbsp;1.2 or better. It should run
without any other package.</li> </ul>
</section>
<section title="Subversion Repository">
<p>You can get the latest sources from the <a
href="http://sourceforge.net/svn/?group_id=3790">SVN repository</a>.
Follow the instruction on that page; use
<code>/svnroot/jode/trunk/jode</code> as last part of the URL. If you
want to checkout a specific version you can checkout the URL
<code>.../svnroot/jode/tags/xxx/jode</code>:</p>
<ul>
<li><code>../jode/tags/jode_1_0_93/jode</code>: checks out the version 1.0.93</li>
<li><code>../jode/branches/branch_1_1/jode</code>: checks out the latest version in the
1.1 series.</li> </ul>
<p>To build the sources from latest SVN change to the main directory and invoke ant.</p>
<p>To build the 1.1 versions of jode change to the main directory and run
<pre>aclocal && automake -a && autoconf</pre>
<p>Afterwards follow the instruction in the INSTALL file. </p>
</section>

@ -0,0 +1,90 @@
<section title="FAQ - Frequently Asked Questions">
This is a list of some questions that pop up from time to time.
</section>
<section title="Decompiler issues">
<h3>Does Jode support Java 5?</h3>
<p>It does not support generics/vararg method or the new for loop at
the moment. It produces readable code and I think it may even compile
again. But it is not compatible as the generics and varargs
information is not included.</p>
<h3>Jode crashes with ExceptionHandler order failed</h3>
<p>Try jode-1.1.2pre1 or the latest CVS version. If it still does not
work rewrite <code>jode.flow.TransformExceptionHandlers</code> and
send me the fix :) </p>
<p>Since Java 1.4 the format for finally and synchronized blocks
changed again. It was always a very difficult task to reconstruct
<code>finally</code> blocks correctly and the code is huge and very
hard to maintain. With Java 5 it gets even worse.</p>
<h3>The decompiler crashes with a VerifyException, what can I do?</h3>
<p>The class isn't verifiable, probably because there is not enough
information about used classes. See the question about the
classpath.</p>
<p>This could also be caused by malicious bytecode, or because there
is a bug in Jode's verifier, or because Sun decided to change the
definition of correct bytecode, again.</p>
<h3>What should be included in the classpath?</h3>
<p>Jode needs to know the full class hierarchie to guess the types.
This includes not only the classes in the program, but also the
libraries used by the java program, even the Java runtime library.
You should set the classpath to include all these classes.</p>
<p>If you don't specify the classpath on the command line, Jode uses
the same as your Java Virtual Machine.</p>
<p>As last resort, if Jode can't find a class in the classpath it uses
reflection to ask the Virtual Machine. This works quite well, but
loading classes can have side effects, e.g. when AWT classes are
loaded, an AWT thread is created, even though Jode doesn't need
it.</p>
<h3>Why doesn't Jode decompile my inner class
<code>MyClass$Inner.class</code>?</h3>
<p>You should decompile the outermost class (<code>MyClass</code> in
this case). The produced code contains the inner class. </p>
</section>
<section title="Obfuscator issues">
<h3>What should be included in the classpath?</h3>
<p>The program, all libraries, the Java runtime library. Don't omit a
library even when you don't want to obfuscate it.</p>
<h3>What should I preserve</h3>
<p>The most common mistake is to preserve a class. In most cases this
is not what you want. This only makes sure the class won't be
renamed, it doesn't prevent it from being stripped. Instead you
should preserve methods and constructors. The constructor is just a
method with the special name <tt>&lt;init&gt;</tt>. </p>
<p> Another common mistake is to omit the type
signature, e.g. to preserve <tt>Class.main</tt> instead of
<tt>Class.main.([Ljava/lang/String;)V</tt>. That doesn't work. If
you don't want to care about the format of the type signature use a
wildcard as in <tt>Class.main.*</tt>. </p>
<h3>What is a type signature</h3>
<p>The type signature is a machine readable representation of a java
type that is used all over in java bytecode. The JDK ships a command
named <tt>javap</tt>. With <tt>java -s</tt> you can lists the fields
and methods of a class with their type signatures.</p>
<p> If you are interested in the format of type signatures read the
Java Virtual Machine Specification, Chapter 4.3 Descriptors</p>
</section>

@ -0,0 +1,106 @@
/* XPM */
static char * favicon_xpm[] = {
"16 16 87 1",
" c None",
". c #C2C2C2",
"+ c #A1A1A1",
"@ c #BBBBBB",
"# c #D9D9D9",
"$ c #BABABA",
"% c #C1C1C1",
"& c #ECECEC",
"* c #A7A7A7",
"= c #636363",
"- c #989898",
"; c #C3C3C3",
"> c #C5C5C5",
", c #A6A6A6",
"' c #747474",
") c #646464",
"! c #6D6D6D",
"~ c #8C8C8C",
"{ c #ABABAB",
"] c #A5A5A5",
"^ c #787878",
"/ c #A8A8A8",
"( c #606060",
"_ c #FFFFFF",
": c #626262",
"< c #7A7A7A",
"[ c #FEFEFE",
"} c #949494",
"| c #535353",
"1 c #919191",
"2 c #F0F0F0",
"3 c #5B5B5B",
"4 c #B3B3B3",
"5 c #5A5A5A",
"6 c #3E3E3E",
"7 c #4C4C4C",
"8 c #666666",
"9 c #616161",
"0 c #939393",
"a c #F8F8F8",
"b c #1C1C1C",
"c c #999999",
"d c #DFDFDF",
"e c #0D0D0D",
"f c #B1B1B1",
"g c #343434",
"h c #5D5D5D",
"i c #676767",
"j c #6F6F6F",
"k c #9E9E9E",
"l c #4F4F4F",
"m c #F7F7F7",
"n c #1B1B1B",
"o c #E7E7E7",
"p c #1D1D1D",
"q c #7C7C7C",
"r c #9B9B9B",
"s c #525252",
"t c #EFEFEF",
"u c #9C9C9C",
"v c #434343",
"w c #414141",
"x c #3D3D3D",
"y c #3F3F3F",
"z c #BFBFBF",
"A c #3A3A3A",
"B c #686868",
"C c #6B6B6B",
"D c #C4C4C4",
"E c #F4F4F4",
"F c #FAFAFA",
"G c #D7D7D7",
"H c #AFAFAF",
"I c #828282",
"J c #737373",
"K c #818181",
"L c #DEDEDE",
"M c #E9E9E9",
"N c #696969",
"O c #9F9F9F",
"P c #A2A2A2",
"Q c #717171",
"R c #B4B4B4",
"S c #E8E8E8",
"T c #898989",
"U c #767676",
"V c #DBDBDB",
" ",
" ",
" ",
" ",
" .++@ #$%& ",
"*=-;>,')!~{]^)/ ",
"(_:<[}|123:42567",
"8_,90=abc|defg*h",
"i_jklfmnj1opq(r=",
"9sgtugvuwxyzwAB:",
"}CDEFGHIJK{L[MNO",
" #PQCKRd S@TiUV ",
" ",
" ",
" ",
" "};

@ -0,0 +1,11 @@
<section title="Feedback">
<p>You can report bugs to the <?php sflink("bugs/")?>bug forum</a>. </p>
<p>You can contact me by email via <a
href="http://sourceforge.net/sendmessage.php?touser=18252">hoenicke at
users.sourceforge.net</a>. Please mention <i>jode</i> in the
subject.</p>
<p>There is a mailing list. Check <a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">this page</a> for subscription informations.</p>
</section>

@ -0,0 +1,13 @@
<TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
<TR>
<TD align="center"><SPAN class=footer>
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 29-May-2002,
Copyright &copy; 1998-2002 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,9 @@
21 iconst_4
22 iand
23 ifne 30
26 iconst_0
27 goto 31
30 iconst_1
31 ireturn

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,9 @@
while (i>0) {
if (a[i] > max)
max = a[i];
if (a[i] == 0)
break;
i++;
}

@ -0,0 +1,42 @@
#FIG 3.2
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
1800 4725 2700 4725 2700 5400 1800 5400 1800 4725
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
2475 4275 3375 4275 3375 3600 2475 3600 2475 4275
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
2475 2475 3375 2475 3375 3150 2475 3150 2475 2475
2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 1
2475 3825
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
2475 5850 3375 5850 3375 6525 2475 6525 2475 5850
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 3
1 1 2.00 60.00 120.00
3600 5400 2925 5625 2925 5850
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 3
1 1 2.00 60.00 120.00
2925 4275 2250 4500 2250 4725
2 2 0 1 0 7 100 0 -1 0.000 0 0 7 0 0 5
3150 4725 4050 4725 4050 5400 3150 5400 3150 4725
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 2
1 1 2.00 60.00 120.00
2925 3150 2925 3600
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 5
1 1 2.00 60.00 120.00
2250 5400 2250 5625 1350 5625 1350 3825 2475 3825
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 3
1 1 2.00 60.00 120.00
2925 4275 3600 4500 3600 4725
2 1 0 1 0 7 100 0 -1 0.000 0 0 7 1 0 5
1 1 2.00 60.00 120.00
3600 5400 3600 5625 4275 5625 4275 3825 3375 3825
2 1 0 1 0 0 100 0 20 0.000 0 0 7 0 0 8
10800 2250 9675 3375 9675 2700 8325 2700 8325 1800 9675 1800
9675 1125 10800 2250

@ -0,0 +1,63 @@
<?php
if (! $extension) {
$extension = "php";
}
$version="1.1";
function selflink($link) {
global $extension;
echo "<a href=\"./";
if ($link != "index") {
if (ereg("#", $link)) {
$link = ereg_replace("#", ".$extension#", $link);
} else {
$link .= ".$extension";
}
echo "$link";
}
echo "\">";
}
function sflink($link) {
echo "<a href=\"http://sourceforge.net/$link?group_id=3790\">";
}
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2001-05-29">
<meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL">
<style type="text/css">
<!--
body { color:#000000; background-color: #FFFFFF; }
.nav { font-family: Helvetica, Arial, sans-serif; font-weight: bold;
color:#000000; background-color: #EEEEF8; }
.footer { color:#FFFFFF; background-color: #737B9C; }
.boldlink { font-weight:bold; text-decoration: none; color:#FFFFFF; }
//-->
</style>
</head>
<body text="#000000" bgcolor="#FFFFFF">
<table cellpadding=4 cellspacing=1 width="100%"
><tr
><td align="left"
><img src="jode-logo.gif" alt="JODE" width=286 height=110
></td
><td align="right"
>Powered by <a href="http://sourceforge.net"><img
src="http://sourceforge.net/sflogo.php?group_id=3790&amp;type=1"
border=0 width=88 height=31 alt="SourceForge"></a><br
>Best viewed with <a
href="http://www.anybrowser.org/campaign/"><img
src="a-logo.gif" border=0 width=88 height=31 alt="Any
Browser"></a><br
></td
></tr
></table>
<?php require("menu.inc"); ?>

@ -0,0 +1,20 @@
<section title="History">
<p>Someday I found <code>guavad</code>, a disassembler for java byte
code (it does similar things like <code>javap&nbsp;-c</code>). I used
it on a class file, and found that it was possible to reconstruct the
original java code. First I did it by hand on some small routines,
but I soon realized that it was a rather stupid task. So I wrote a
small <a href="dasm_to_java.perl"><code>perl</code> script</a> that
did this process automatically. At the end of the next day I had my
first working decompiler.</p>
<p>Now while the <code>perl</code> script is working, it is not easy
to use. You have to decompile the code first with a disassembler, cut
out the code of a single method, and run the perl script on it. I
decided to get the bytecode directly out of the class files and do
this all automatically. I decided to write it in <code>java</code>
now, because it suited best.</p>
<p>Just for the records: the java code is now more than 50 times
bigger than the original perl script and is still growing.</p>
</section>

@ -0,0 +1,52 @@
<opt quiet>
<file template="jode.htt">
<set version="1.1">
<set sfgroup="3790">
<def name="sflink" option="href">
<a href="http://sourceforge.net/${href}?group_id=${sfgroup}">
</def>
<def name="entry" option="name type href">
<if type="sflink">
<sflink href="$href"><use name></a>
<else>
<if _htpfile_out="${href}.html">
<use name>
<elseif $href="index">
<a href="."><use name></a>
<else>
<a href="${href}.html"><use name></a>
</if>
</if>
</def>
<block name=menu>
<entry name="<B>Home</B>" href="index">
<entry type=sflink name="Project page" href="project/">
<entry name="Applet" href="applet">
<entry name="Download" href="download">
<entry name="FAQ" href="faq">
<entry name="Feedback" href="feedback">
<entry name="Documentation" href="usage">
<entry name="License" href="license">
<entry name="History" href="history">
<entry name="Links" href="links">
<entry name="Blue Sky" href="bluesky">
</block>
<blockdef name=section option="title">
<if not sect_ctr><set sect_ctr="0" global></if>
<inc sect_ctr global>
<set title${sect_ctr}="$title" global>
<block name=section${sect_ctr} global expand>
<use block noexpand>
</block>
</blockdef>
<block name=everything>
<set i=1>
<while section$i>
<h1><use title$i></h1>
<use section$i>
<inc i>
</while>
</block>

@ -0,0 +1,74 @@
<section title="Introduction">
<P><i>JODE</i> is a java package containing a decompiler and an
optimizer for java. This package is <a href="license.html">freely
available</a> under the GNU GPL. The bytecode package and the core
decompiler is now under GNU Lesser General Public License, so you can
integrate it in your project.</p>
<P>The decompiler reads in <tt>class</tt> files and produces something
similar to the original <tt>java</tt> file. Of course this can't be
perfect: There is no way to produce the comments or the names of local
variables (except when compiled with debuging) and there are often
more ways to write the same thing. However, <i>JODE</i> does its job quite
well, so you should give it a try and <a href="applet.html">start the
applet</a>.</P>
<P>The optimizer transforms <tt>class</tt> files in various ways with
can be controlled by a script file. It supports the following
operations:</p>
<ul>
<li>Renaming class, method, field and local names to shorter,
obfuscated, or unique names or according to a given translation
table</li>
<li>Removing debugging information</li>
<li>Removing dead code (classes, fields, methods) and constant
fields</li>
<li>Optimizing local variable allocation</li>
</ul>
</section>
<section title="News">
<ul>
<li><i>JODE</i> 1.1.1 is out. With support for javac v8 (jdk 1.3). </li>
<li>The license changed to LGPL for the bytecode interface and decompiler.</li>
</ul>
</section>
<section title="Known Bugs">
<p>The current version has problems try/catch/finally code produced
by java 1.4 compiler. You may try the latest CVS version or pre-release
instead.</p>
<p>Some jdk1.3 synthetic access functions aren't understood. The
produced source contains access$xxx functions, but it still compiles.</p>
<p>There may be other bugs, that cause Exceptions or invalid code.
If you have such a problems don't hesitate to issue a bug report.
Please include the <code>class</code> file if possible.</p>
</section>
<section title="Limits">
<p>If not all dependent classes can be found, the verifier (which is
run before decompilation starts) may exit with a type error. You
can decompile it with <tt>--verify=off</tt>, but take the warning
serious, that types may be incorrect. There's sometimes no way to
guess the right type, if you don't have access the full class
hierarchie.<br>
This is not a bug in the verifier: java will complain the same way,
if it is run with bytecode verification turned on. And if you don't
have the dependent classes, you can't compile the code again.</p>
<p>There may be situations, where the code doesn't understand complex
expressions. In this case many ugly temporary variables are used, but
the code should still be compileable. This does especially happen
when you compile with <tt>`-O'</tt> flag and javac has inlined some
methods. </p>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

@ -0,0 +1,67 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="date" content="2001-05-29">
<meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL">
<style type="text/css">
<!--
body { color:#000000; background-color: #FFFFFF; }
.nav { font-family: Helvetica, Arial, sans-serif; font-weight: bold;
color:#000000; background-color: #EEEEF8; }
.footer { color:#FFFFFF; background-color: #737B9C; }
.boldlink { font-weight:bold; text-decoration: none; color:#FFFFFF; }
//-->
</style>
</head>
<body text="#000000" bgcolor="#FFFFFF">
<table cellpadding=4 cellspacing=1 width="100%"
><tr
><td align="left"
><img src="jode-logo.png" alt="JODE"
></td
><td align="right"
>Powered by <a href="http://sourceforge.net"><img
src="http://sourceforge.net/sflogo.php?group_id=3790&amp;type=1"
border=0 width=88 height=31 alt="SourceForge"></a><br
>HTML coding <a href="http://htp.sourceforge.net"><img
src="poweredbyhtp.png" border=0 alt="Powered by htp"></a><br
>Best viewed with <a
href="http://www.anybrowser.org/campaign/"><img
src="w3c_ab.png" border=0 alt="Any Browser"></a><br
></td
></tr
></table>
<table cellspacing=0 cellpadding=3 border=0 bgcolor="#EEEEF8" class="nav">
<tr><td class="nav">
<use menu>
</td></tr>
</table><br>
<use everything>
<if _htpfile_out="index.html">
<set pageref="">
<else>
<set pageref="$_htpfile_out">
</if>
<TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
<TR>
<TD align="center"><SPAN class=footer>
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on <file date>,
Copyright &copy; 1998-2004 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/$pageref">http://jode.sourceforge.net/<use pageref></a></SPAN>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -0,0 +1,21 @@
<section title="License">
<p><i>JODE</i> is Copyright &copy; 1998-2004 by Jochen Hoenicke. <br><br>
<p>This program is free software; you can redistribute it and/or modify
it under the terms of the <a
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public
License</a> as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.</p>
<p>You can redistribute some of the packages under the
terms of the of the <a
href="http://www.gnu.org/copyleft/lesser.html">GNU Lesser General
Public License</a> as published by the Free Software Foundation. See
the copyright headers in the source code.</p>
<p>This program is distributed in the hope that it will be useful,
but <b>without any warranty</b>; without even the implied warranty of
<b>merchantability</b> or <b>fitness for a particular purpose</b>. See the
GNU General Public License for more details.</p>
</section>

@ -0,0 +1,75 @@
<section title="<i>JODE</i> Links">
<h3>Other decompilers</h3>
<ul>
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Development_Tools/Translators/Decompilers_and_Disassemblers/">The Open Directory list</a></li>
<li>A list of decompilers can be found at <a href="http://www.meurrens.org/ip-Links/Java/CodeEngineering/#tocDecompilersToJava">Marc Meurren's list</a>
</li>
<li>A very fast decompiler is <a
href="http://www.geocities.com/SiliconValley/Bridge/8617/jad.html">jad</a>
written in C++. It doesn't come with source code though, and misses
some features <i>JODE</i> has ;-)</li> <li><a
href="http://www.javaworld.com/javaworld/jw-07-1997/jw-07-decompilers.html">A
comparison of three decompilers</a> (but not <i>JODE</i>) was done by Dave
Dyer.
</ul>
<h3>Other obfuscators</h3>
<ul>
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Development_Tools/Obfuscators/">The Open Directory list</a></li>
<li><a href="http://www.sbktech.org/hashjava_old.html">Hashjava</a> is another free obfuscator. It is no longer maintained, though, since its successor was commercialized.</li>
<li><a href="http://www.zelix.com/klassmaster/index.html">Zelix
Klassmaster</a> does a very good flow optimization and also decrypts
strings. But <i>JODE</i>'s deobfuscator can undo both.</li>
<li><a href="http://www.cs.arizona.edu/~collberg/Research/">Christian S. Collberg</a> has some really interesting papers about non reversible obfuscations.</li>
</ul>
<h3>Graphical User Interface</h3>
<ul>
<li><i>JODE</i> is used by the <a
href="http://jedit.standmed.com/plugins/JavaInsight">JavaInsight plugin</a> for
<a href="http://jedit.sourceforge.net/">jEdit</a>.</li>
</ul>
<h3>Software Directories</h3>
<ul>
<li>Get everything and anything for Linux at the
<a href="http://www.linux-directory.com" target="_top"
><IMG SRC="http://www.linux-directory.com/button_88x31.gif"
WIDTH=88 HEIGHT=31 BORDER=0 ALT="Linux Directory"></a>.
</li>
<li>A great place for developing free software is
<a href="http://sourceforge.net"><img
src="http://sourceforge.net/sflogo.php?group_id=3790&type=1"
border=0 width=88 height=31 alt="SourceForge"></a>
</li>
</ul>
<h3>Miscellanous packages needed to run JODE</h3>
<dl>
<dt>CYGWIN (unix tools for win95/NT)</dt>
<dd>
<a href="http://sourceware.cygnus.com/cygwin/">http://sourceware.cygnus.com/cygwin/</a>
</dd>
<dt>JDK 1.1:</dt>
<dd>
<a href="http://java.sun.com/products/jdk/1.1/">http://java.sun.com/products/jdk/1.1/</a>
</dd>
<dt><a name="swing">Swing for JDK 1.1:</a><dt>
<dd>
<a href="http://java.sun.com/products/jfc/index.html#download-swing">http://java.sun.com/products/jfc/index.html#download-swing</a>
</dd>
<dt>JDK 1.2:</dt>
<dd>
<a href="http://java.sun.com/products/jdk/1.2/">http://java.sun.com/products/jdk/1.2/</a>
</dd>
<dt><a name="getopt">Getopt</a>:</dt>
<dd>
<a href="http://www.urbanophile.com/arenn/hacking/download.html#getopt">http://www.urbanophile.com/arenn/hacking/download.html#getopt</a>
</dd>
<dt><a name="collections">Collection Classes</a>:</dt>
<dd>I have written a small script that puts the collection classes
from the <a href="http://www.classpath.org">GNU Classpath Project</a>
into its own package (<code>gnu.java.util.collections</code>). This
script is now part of GNU classpath. For your convenience I have put a
precompiled <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.jar">jar
file</a> on this server.
</dd>
</dl>
</section>

@ -0,0 +1,47 @@
<?php
$menu =
array("<B>Home</B>" , "selflink", "index",
"Project page" , "sflink", "project/",
"Applet" , "selflink", "applet",
"Download" , "selflink", "download",
"FAQ" , "selflink", "faq",
"Feedback" , "selflink", "feedback",
"Documentation", "selflink", "usage",
"License" , "selflink", "license",
"History" , "selflink", "history",
"Links" , "selflink", "links",
"Blue Sky" , "selflink", "bluesky");
?>
<table cellspacing=0 cellpadding=3 border=0 bgcolor="#EEEEF8" class="nav">
<tr><td class="nav">
<?php
reset($menu);
$self = ereg_replace("^.*/", "", $PHP_SELF);
while (list($dummy, $name) = each($menu)) {
list($dummy, $type) = each($menu);
list($dummy, $link) = each($menu);
$name = ereg_replace(" ", "&nbsp;", $name);
if ($type == "selflink") {
if ($self == "$link.$extension") {
echo "$name";
} else {
selflink($link);
echo "$name</a>";
}
} else if ($type == "sflink") {
sflink($link);
echo "$name</a>";
} else if ($type == "-") {
echo "<br>\n";
continue;
} else if ($type == "link") {
echo "<a href=\"$link\">$name</a>";
}
if (current($menu)) {
echo " |\n";
}
}
?>
</td></tr>
</table><br>

@ -0,0 +1,84 @@
# This is a sample script file to obfuscate my project
# The class path should include everything that is needed to run the
# project. Don't forget the java base classes (rt.jar or classes.zip).
classpath = "c:\\jdk1.2\\jre\\lib\\rt.jar","d:\\project\\java"
# The jar, zip file or directory in which the obfuscated class files
# should be written.
dest = "obfuscated.zip"
# Write the reverse translation table to translat.tbl. With the help of
# this table you can later undo the renaming.
revtable = "translat.tbl"
strip = "unreach","lvt","inner"
# this variable will tell, which classes and packages should be included
# in the obfuscated.jar package.
load = new WildCard { value = "org.myorg.myproject" },
new WildCard { value = "org.myorg.mylib*" },
new WildCard { value = "org.otherorg.shortlib" }
# this variable will tell, which classes and packages must not be
# renamed.
preserve = new WildCard { value = "org.myorg.ApplicationClass.main.*" },
new WildCard { value = "org.myorg.AppletClass.<init>.()V" },
new WildCard { value = "org.resources.BundleClass*.<init>.()V" },
new MultiIdentifierMatcher {
and = new WildCard { value = "org.myorg.publiclib.*" },
new ModifierMatcher { access = "PUBLIC" }
}
# There are different renamers currently. This is just an example that
# produces very good obfuscated code, that is still valid bytecode.
renamer = new StrongRenamer {
charsetStart = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
charsetPart = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789_$"
charsetPackage = "abcdefghijklmnopqrstuvwxyz"
charsetClass = "abcdefghijklmnopqrstuvwxyz"
}
# The constant analyzer does a great job to remove constant fields and
# deadcode. E.g. if you obfuscate the decompiler applet it will
# remove the whole debugging code, since the applet doesn't need it.
analyzer = new ConstantAnalyzer
# The LocalOptimizer will reorder local variables to use fewer slots.
# It may still have some bugs, so remove it if your applet doesn't
# work (and send me the class).
# The RemovePopAnalyzer will remove instructions that were optimized
# away by the ConstantAnalyzer and LocalOptimizer.
post = new LocalOptimizer, new RemovePopAnalyzer
################################################################
# The syntax for load and preserve is as follows
################################################################
#
# preserve ::= <list of IdentifierMatcher>
# // preserves everything that is matched by
# // at least one identifier matcher.
#
# IdentifierMatcher ::=
# MultiIdentifierMatcher { and = <list of IdentifierMatcher> }
# |
# MultiIdentifierMatcher { or = <list of IdentifierMatcher> }
# |
# WildCard { value = "<wildcard>" }
# |
# ModifierMatcher { access = "<AccessSpec>"
# [access = "<AccessSpec>" ...]
# modifier = "<ModifierSpec>"
# [modifier = "<ModifierSpec>" ...]
# // identifier must fulfill all constraints
# }
# |
# SerializedPreserver
#
# AccessSpec ::=
# <optional "<" or ">"> (PUBLIC|PROTECTED|PACKAGE|PRIVATE)
#
# ModifierSpec ::=
# <optional "!" (not)> (ABSTRACT|FINAL|INTERFACE|NATIVE|STATIC
# |STRICT|SYNCHRONIZED|TRANSIENT|VOLATILE)
#

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -215,3 +215,65 @@ Zu betrachtende 32bit Typen:
(I,S,B,Z)
(I,S,B,cS,cB)
@node Highlevel analysis, Technical Info, Solving unknown stack-ops, Technical Info
@section Highlevel analysis
@cindex passes
@section The passes
JODE works in three passes:
@subsection Pass 1: Initialize
In the initialize pass the methods, fields and inner classes are read in
and the inner classes are recursively initialized. In this pass the
complexity of the class is calculated. Anonymous and method scoped
classes aren't even considered yet.
@subsection Pass 2: Analyze
The analyze pass is the real decompilation pass: The code of the methods
is transformed into flow blocks and merged to one flow block as
described in a previous section. The in/out analysis for the local
variables is completed, and the locals are merged as necessary. The
parameter 0 for non static method is marked as ThisOperator in this
pass.
The constructors are analyzed first. If they initialize synthetic
fields, this is taken as clear sign that this are outer value
parameters. So afterwards, these synthetic fields know their value.
Then the methods are analyzed. Each method remembers the anonymous
classes it creates for Pass 3, but these classes are not yet
initialized. Inner classes aren't analyzed yet, either.
@subsection Pass 3: Analyze Inner
As the name of this pass makes clear the inner classes are initialized
in this pass, i.e. first Pass 2 and 3 are invoked for the inner classes.
After that the method scoped classes are analyzed: For each constructor
it is first check if one surrounding method knows about it. If not, a
new class analyzer is created for the method scoped class and Pass 1--3
are invoked. Every surrounding method is then told about this new class
analyzer.
After this pass, every anonymous constructor is analyzed, so we know
which constructor parameters can be outer values. The constructor
transformation may force some other outer values, though. It is also
known, in which method a method scoped class must be declared.
@subsection Pass 4: Make Declarations
The last pass begins with transforming the constructors of a class. Now
the outer values are fixed and the constructor parameters and synthetic
fields are told their values.
After that every method determines where to declare local variables and
method scoped classes. Local variables are declared as final if a
method scoped class uses it as outer value. The name of local
variables is guessed now.
This pass is done recursively for inner and method scoped classes.

@ -0,0 +1,250 @@
<if we_want_a_menu>
<p>On this page:<br>
<a href="#decompiler">Decompiler</a><br>
&nbsp;&nbsp;&nbsp;<a href="#cmdline">Command&nbsp;Line</a><br>
&nbsp;&nbsp;&nbsp;<a href="#awt">AWT&nbsp;Interface</a><br>
&nbsp;&nbsp;&nbsp;<a href="#swing">Swing&nbsp;Interface</a><br>
&nbsp;&nbsp;&nbsp;<a href="#java">Java&nbsp;Interface</a><br>
<a href="#optimizer">Obfuscator</a><br>
</p>
</if>
<section title="Using the Decompiler">
<p>After you have <a href="download.html">downloaded</a> the jar archive
put it into your <tt>CLASSPATH</tt>. The package
<tt>swingall.jar</tt> is also needed if you are using JDK 1.1.</p>
<ul><li>Under Windows you have to start a MSDOS session and type
something like:
<pre>
set CLASSPATH=C:\download\jode-<use version>.jar;C:\swing\swingall.jar
</pre>
<li>Under Unix you start a shell and type (for bourne shell):
<pre>export CLASSPATH=/tmp/jode-<use version>.jar:/usr/local/swing/swingall.jar</pre>
or for csh:
<pre>setenv CLASSPATH /tmp/jode-<use version>.jar:/usr/local/swing/swingall.jar</pre>
</ul>
<br>
There is also a batch file for windows and a script file for unix,
that you can use. You can extract it with the following command:
<pre>
jar -xvf jode-<use version>".jar bin/jode.bat <i>resp.</i> bin/jode
</pre>
Edit the file to adapt it to your paths and put it to a convenient location.
</section>
<section title="Command Line Interface">
The most powerful way to start <I>JODE</I>'s decompiler is the command
line interface. Some people don't like long command lines; they
should go to the next section. <br>
Start the class <tt>jode.decompiler.Main</tt> with the options. The
following command will give a complete list of the available commands:
<pre>java jode.decompiler.Main --help</pre>
If you want to decompile a jar package you can do it this way:
<pre>java jode.decompiler.Main --dest srcdir program.jar</pre>
If you have installed the batch file/script, you can use it like this:
<pre>jode --dest srcdir program.jar</pre>
<h3><a name="awt">AWT Interface</a></h3>
The AWT Interface looks exactly like the <a href="applet.html">
applet</a>. In fact the applet uses the AWT Interface. You start it
after setting the <tt>CLASSPATH</tt> (see <a
href="#decompiler">above</a>), with
<pre>java jode.decompiler.Window</pre>
In the classpath line you can enter a number of jar files, zip files
and directories separated by comma(<tt>,</tt>). Then enter the
dot(<tt>.</tt>) separated name of the class you want to decompile.
Press the <code>start</code> button and the decompiled class should
appear. You can save it via the <code>save</code> button.
<h3><a name="swing">Swing Interface</a></h3>
For the swing interface you need java version 1.2 or the separately
available swing package (see <a href="links.html#swing">link
page</a>. You can invoke it with the following command (JDK1.2 only):
<pre>
java -jar jode-<use version>.jar classes.jar
</pre>
or if you have set the classpath (see above)
<pre>
java jode.swingui.Main classes.jar
<i>resp.</i> jode swi classes.jar
</pre>
<p>The swing interface will show the package hierarchie of all classes
in the classpath on the left side. You can now select a class and the
decompiled code will appear on the right side. Via the menu, you may
change the classpath or switch between package hierarchie tree and
class inheritence tree.</p>
<p>The swing interface is very useful to browse through class files if
you don't have the source code. You can also use it to trace bugs in
library code. It is not meant to generate <tt>java</tt> files and so
you won't find a save option there.</p>
<h3><a name="java">Java Interface</a></h3>
<p>If you want to integrate <i>JODE</i> into your own java program,
you can use the <a
href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jode/jode/jode/decompiler/Decompiler.java?rev=jode_1_1&amp;content-type=text/vnd.viewcvs-markup"
><code>jode.decompiler.Decompiler</code></a>
class. Note that the LGPL allows dynamic linking as long as you don't change
Jode itself. Please tell me if you use <i>JODE</i> in this way.</p>
<p>You should ship <code>jode-1.1-embedded.jar</code> with your program. This jar file is
available in the <sflink href="project/showfiles.php">download area</a>.
It works only under JDK&nbsp;1.2 and above.</p>
</section>
<section title="Using the Obfuscator">
<p>To use the obfuscator you should first create a script file, say <a
href="myproject.jos"><tt>myproject.jos</tt></a>. Then you can invoke the
obfuscator with:</p>
<pre>
java jode.obfuscator.Main myproject.jos
</pre>
<p>The script file should contain the following options: </p>
<p>First select the classpath. You should include everything in the
classpath that you need to run your application. This also includes
the system class files (Sun puts them into <code>classes.zip</code> or
<code>rt.jar</code>))</p>
<pre>
classpath = "c:\\jdk1.2\\jre\\lib\\rt.jar","d:\\project\\java",
"ftp://www.myorg.org/pub/classlib.jar"
</pre>
<p>Specify where you want the obfuscated classes to go. I recommend
to write them directly into a zip file, but you can also give a
directory.</p>
<pre>
dest = "obfuscated.zip"
</pre>
<p>You can make <i>JODE</i> write its translation table. This table
can be used later to undo the name obfuscation, or you can look there
to decrypt exceptions you may get.</p>
<pre>
revtable = "translat.tbl"
</pre>
<p>Select what you want to strip. There are several
possibilities, which can be separated by comma(<tt>,</tt>):</p>
<dl>
<dt>unreach</dt>
<dd>strip unreachable methods and classes.</dd>
<dt>source</dt>
<dd>remove the name of the java file (exceptions will get unreadable).</dd>
<dt>lnt</dt>
<dd>remove the line number table (exceptions will get unreadable).</dd>
<dt>lvt</dt>
<dd>remove the local variable table (debugging doesn't work).</dd>
<dt>inner</dt>
<dd>strip inner class info (reflection doesn't work correctly).</dd>
</dl>
<pre>
strip = "unreach","lvt","inner"
</pre>
<p>Select the packages and classes you want to obfuscate. You should
only include libraries, that you don't ship separately. If you give a
package, all classes and subpackages are loaded. You can also use
<code>*</code> as wild card, that matches everything (including dots).
</p>
<pre>
load = new WildCard { value = "org.myorg.myproject" },
new WildCard { value = "org.myorg.mylib*" },
new WildCard { value = "org.otherorg.shortlib" }
</pre>
<p>Select the methods and classes you want to preserve. This is
the <tt>main</tt> method for applications and the default constructor
<tt>&lt;init&gt;.()V</tt> for applets, resource bundles and other classes
that you load manually at runtime. <br>
You have to give the method
name and the type signature to identify your method. <tt>javap
-s</tt> will show you the type signatures for your classes, but you
may also use <tt>*</tt>, to select all methods with that name.
If you have serializable classes and want to preserve their serialized
form you can use the <tt>SerializePreserver</tt>. </p>
<pre>
preserve = new SerializePreserver,
new WildCard { value = "org.myorg.ApplicationClass.main.*" },
new WildCard { value = "org.myorg.AppletClass.&lt;init&gt;.()V" },
new WildCard { value = "org.resources.Bundle*.&lt;init&gt;.()V" },
</pre>
<p>If you want to obfuscate (or just shorten) the identifier you can
specify a renamer. There are currently following renamer
available</p>
<dl><dt>StrongRenamer</dt>
<dd>Renames to the shortest possible name. You can give a charset
that should be used. It uses the same name as much as possible.</dd>
<dt>UniqueRenamer</dt>
<dd>Renames to unique identifier of the form <tt>xxx123</tt>. Useful
to reduce name conflicts, before you decompile an obfuscated package.</dd>
<dt>NameSwapper</dt>
<dd>This renamer just swaps the names. This is a funny obfuscation
option that is not very strong, but very confusing.</dd>
<dt>KeywordRenamer</dt>
<dd>Renames identifiers to keyword. You can give your own list of
keywords as parameters. Resulting code is not decompilable directly,
<b>but it is <i>not</i> legal bytecode either</b>. Some paranoid
web browsers refuse to run applets containing keywords as identifiers
(and they are completely within the Java VM spec).</dd>
</dl>
<pre>
renamer = new StrongRenamer
</pre>
<p>You can also create a renaming table with the same format as the
table written by revtable. The entries in the table get precedence
over renamer. Entries not in the table will get renamed by the
renamer.</p>
<pre>
table = "translat.tbl"
</pre>
<p>Now you can select the analyzer. The purpose of the
analyzer is to mark all reachable methods, find out which methods
needs to get the same name (overloading), and which method names
mustn't change (overload of library methods, e.g. <tt>nextElement</tt>
for <tt>Enumeration</tt>s). There are currently two analyzers.
</p>
<dl><dt>SimpleAnalyzer</dt>
<dd>Straight forward analyzer. It is fast and will remove dead code
on method basis.</dd>
<dd><dt>ConstantAnalyzer</dt>
<dd>Strong analyzer that will determine, which fields and instructions
have constant values. It will remove dead code on instruction basis
and replace constant instruction with a load of the constant, or
remove them completely.<br> This analyzer is especially useful to
revert the flow obfuscation of some other obfuscators.</dd>
</dl>
<pre>
analyzer = new ConstantAnalyzer
</pre>
<p>Pre- and Post transformers transform the bytecode before
resp. after the Analyzer runs. Using this default should be okay.
You may remove the LocalOptimizer, though, if you have problems.</p>
<p>In the future I may add some new post transformers, that do string
encryption, flow obfuscation and similar things. If you want to write
your own Transformers please contact me, since the next version will
change the bytecode interface.</p>
<pre>
post = new LocalOptimizer, new RemovePopAnalyzer
</pre>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -1,39 +0,0 @@
<html>
<head>
<title>Jode Test Applet</title>
</head>
<body>
<a href="../index.html">Home</a> <a href="jode.html">Up</a>
<h1>Test Applet</h1>
<applet code="jode/JodeApplet.class" archive="jode_cls.zip" width=640 height=400>
<param name=classpath
value="http://www.informatik.uni-oldenburg.de/~delwi/jode/jode_cls.zip">
<param name=class value="jode.JodeApplet">
</applet><br><br>
Press the start button to decompile this applet. You may change the
class path and class name to point to a class file of your choice.
But note that most browsers doesn't allow loading files from a
different server.<br><br>
Save probably doesn't work, because it is forbidden by the browser.<br><br>
You may give multiple entries in the class path field separated by a
comma. The components may be local or remote zip or jar files or
directories. Note that browsers forbid accesses to different hosts or
local files that are not in a subdirectory of the applet
directory.<br><br>
BTW: If you just want to read the source, you may <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode">browse it
online</a> <code>:-)</code><br><br>
You can download this, look <a href="jode-useapplet.html">here</a> for
a description.
</body>
</html>

@ -1,14 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Using the obfuscator</title>
</head>
<body>
The obfuscator currently takes a lot of options (I plan to use an
extra file containing the options). You should therefore create a
script (or batch file under Windows) that invokes the obfuscator.<br>
</body>

@ -1,96 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Using the decompiler under Unix</title>
</head>
<body>
<a href="../index.html">Home</a> <a href="jode.html">Up</a> <br>
<h1>Step by Step</h1>
You need java version 1.1 or higher. In the following description I
assume you have the JDK 1.1, residing in <code>/usr/lib/java</code>.
For other installations you have to adopt the paths. Also I use the
bourne shell syntax.
<ol>
<li> Set the classpath. It should include the jode_cls.zip as well as
the directory where the class files you want to decompile resides.
You can also specify a zip file instead of a directory. It is
also a good idea to include the zip resp. jar file containing the
basic <code>java.*</code> class files.
<pre>
export CLASSPATH=$HOME/jode_cls.zip:$HOME/download:/usr/lib/java/lib/classes.zip
</pre>
</li>
<li> Now you can start the graphical interface as following (Note the
case of the parameter)
<pre>
java jode.JodeWindow
</pre>
</li>
<li> The classpath field should already contain the classpath you set
above. The class field contains <code>jode.JodeWindow</code> and
you may push start immediately to decompile this class.
</li>
<li> If you want to decompile your own <code>.class</code> file, enter
the name of the file without <code>.class</code> extension and
push the start button. Change the class path if it doesn't point
to the right directory.
</li>
<li> After decompiling, you can save the file using the save button.
</li>
</ol>
<h1>Packaged classes</h1>
If the class file belongs to a package (like jode.JodeWindow) you
have to give the full qualified class name (the package names
separated by a dot followed by the class name). The class path should
point to the directory containing the package sub directories in this
case. <br><br>
<h1>Command line utility</h1>
There is also a command line utility which is much more powerful, but
also more difficult to use. You can start it (after setting the
classpath) with
<pre>
java jode.Decompiler
</pre>
and get a list of the supported parameters. To decompile the whole
decompiler you can use these magic lines:
<pre>
mkdir src
CLASSPATH=jode_cls.zip java jode.Decompiler --dest src \
`unzip -v jode_cls.zip|grep .class|cut -c59-|sed s/.class//|sed s?/?.?g`
</pre>
<h1>Obfuscator</h1>
So you want to protect your classes from decompiling? Well that is
your choice. You may use my obfuscator. The class files are
decompileable again (except when using -strong option, but this is
reversable by obfuscating again), but at least the information about
the names of identifiers are completely lost. <br><br>
The obfuscator is quite difficult to use (this is why I hided this
section here) and there is only a short description of the command
line parameters:
<pre>
CLASSPATH=jode_cls.zip java jode.Obfuscator
</pre>
As a hint, to obfuscate the obfuscator use the following command line:
<pre>
CLASSPATH=jode_cls.zip java jode.Obfuscator \
-cp jode_cls.zip:/usr/lib/java/lib/classes.zip -d obfuscated.zip \
-weak -revtable translate.tbl -swaporder \
-preserve jode.Obfuscator.main jode
</pre>
The options <code>-unique</code> and <code>-table</code> can be
helpful to deobfuscate obfuscated code.
</body>

@ -1,49 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Using the decompiler as applet (locally)</title>
</head>
<body>
<a href="../index.html">Home</a> <a href="jode.html">Up</a> <br>
<h1>Step by Step</h1>
If you want to use the applet version you need a recent Internet
Explorer or Netscape which supports java 1.1. You can also use the
appletviewer of the java development kit.
<ol>
<li> Copy <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode/jode-applet.html"
>jode-applet.html</a> into a local directory.
</li>
<li> Copy <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode/jode_cls.zip"
>jode_cls.zip</a> to the <b>same</b> directory.
</li>
<li> Copy the <code>.class</code> file or <code>zip</code> file, you
want to decompile, to that directory.
</li>
<li> Load the html file into Netscape or Internet Explorer.
</li>
<li> Set the classpath simply to `<code>.</code>' (without quotes).
You may also specify a zip or jar file here. Note that applet and
class files must be in the same directory due to security policy. <br>
You can also change the default classpath in the html file.
</li>
<li> Enter the name of the class without <code>.class</code>
extension.
</li>
<li> Press start button in applet. </li>
<li> Press save button to save the decompiled code. </li>
</ol>
<h1>Packaged classes</h1>
If the class file belongs to a package (like jode.JodeWindow) you
have to give the full qualified class name (the package names
separated by a dot followed by the class name). The class path should
point to the directory containing the package sub directories in this
case.
</body>

@ -1,62 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Using the decompiler under Windows</title>
</head>
<body>
<a href="../index.html">Home</a> <a href="jode.html">Up</a> <br>
<h1>Step by Step</h1>
You need java version 1.1 or higher. I suggest using the Sun JDK or
JRE 1.1 or 1.2. In the following description I assume Sun JDK 1.2,
for other virtual machines the paths and the name of the java
interpreter (<code>c:\jdk1.2\java</code>) may differ. <br><br>
<ol>
<li> Set the classpath. It should include the jode_cls.zip as well as
the directory where the class files you want to decompile resides.
You can also specify a zip file instead of a directory. It is
also a good Idea to include the zip resp. jar file containing the
basic <code>java.*</code> class files.
<pre>
set CLASSPATH=c:\temp\jode_cls.zip;c:\temp;c:\jdk1.2\jre\lib\rt.jar
</pre>
</li>
<li> Now you can start the graphical interface as following (Note the
case of the parameter)
<pre>
c:\jdk1.2\java jode.JodeWindow
</pre>
</li>
<li> The classpath field should already contain the classpath you set
above. The class field contains <code>jode.JodeWindow</code> and
you may push start immediately to decompile this class.
</li>
<li> If you want to decompile your own <code>.class</code> file, enter
the name of the file without <code>.class</code> extension and
push the start button. Change the class path if it doesn't point
to the right directory.
</li>
<li> After decompiling, you can save the file using the save button.
</li>
</ol>
<h1>Packaged classes</h1>
If the class file belongs to a package (like jode.JodeWindow) you
have to give the full qualified class name (the package names
separated by a dot followed by the class name). The class path should
point to the directory containing the package sub directories in this
case. <br><br>
<h1>Command line utility</h1>
There is also a command line utility which is much more powerful, but
also more difficult to use. You can start it (after setting the
classpath) with
<pre>
c:\jdk1.2\java jode.Decompiler
</pre>
and get a list of the supported parameters.
</body>

@ -1,124 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title> JOchens' java-DEcompiler (JODE) </title>
<meta name="description" content="The home page of jode, my Java decompiler.">
<meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompile, decompiler,
java-decompiler, reverse engineering, free, GPL">
<meta name="robots" content="index">
<meta name="robots" content="nofollow">
<meta name="date" content="1999-03-08">
</head>
<body>
<a href="../index.html">Home</a>
<h2>What is it?</h2>
<P>This is a decompiler for java I have written in my spare time. It
takes class-files as input and produces something similar to the
original java-File. Of course this can't be perfect: There is no way
to produce the comments or the names of local variables (except when
compiled with <code>-g</code>) and there are often more ways to write
the same thing. But it does its job quite well.</P>
<h2>Quick Test</h2>
I have now an applet interface to the decompiler.
<a href="jode-applet.html">Check it out</a>.
<h2>How to get it</h2>
<P>You can donwload the files in zip form.
The <a href="jode_src.zip">sources</a> contain only the
<code>java</code> files, the <a href="jode_cls.zip">classes</a>
contain only the <code>class</code> files. </p>
<p>I also have a <a href="jode.tar.gz">tar.gz file</a> containing only
the <code>RCS</code> directories. This is the form I maintain the
project, but you probably need unix and a few tools to use them.</p>
<p>There are also some <a href="snapshot/">snapshots</a> that have new
features like inner and anonymous classes. </p>
<p><a href=".">Click here</a> to browse the files online.
</p>
<h2>How to use it</h2>
<p>I have some simple step by step pages. There are three
possibilities:
<ul>
<li> <a href="jode-useapplet.html"> Using the applet version</a>.
This can make problem due to java's security policy, but is the
simplest way and works on most platforms.
</li>
<li> If you use Windows, you should look on <a
href="jode-win.html">this page</a>.</li>
<li> Unix users should look on <a href="jode-unix.html">this page</a>.
</ul>
<h2>Known bugs</h2>
<p>There may be situations, where the code doesn't understand complex
expressions. In this many ugly temporary variables are used, but the
code should still be compileable. This does especially happen when
you compile with `-O' flag and javac has inlined some methods. </p>
<p>Sometimes this program may exit with an <code>Exception</code> or
produce incorrect code. Most time the code can't be compiled, so that
it can be easily spotted. If you have one of these problems (except
those that occur on some of the <code>jode.test</code> files, I would
be very interested in a bug report (including the <code>class</code>
file, if possible).</p>
<p>Sometimes it generates some <code>GOTO</code> expression and
labels. This can't be compiled, but shouldn't happen any more with
javac or jikes.</p>
<p>It doesn't handle inner and anonymous classes, yet. You can
decompile them separately, though (use `<code>+$</code>' switch under
jikes), but there is a bug in javac, so that a final variable is twice
initialized. If you encounter this problem just remove the doubled
line by hand. </p>
<p><b>New!</b> The latest <a href="snapshot">snapshot</a> can handle
inner and anonymous classes.</p>
<h2>Why did I wrote it?</h2>
<p>Someday I found <code>guavad</code>, a disassembler for java byte
code (it does similar things like <code>javap&nbsp;-c</code>). I used
it on a class file, and found that it was possible to reconstruct the
original java code. First I did it by hand on some small routines,
but I soon realized that it was a rather stupid task, and that I could
write a <a href="../perl/dasm_to_java.perl"><code>perl</code> script</a>
that does the same. At the end of the next day I had a working
decompiler.</p>
<p>Now while it was working, it was not easy to use. You had to
decompile the code first with a disassembler, cut the method, you
wanted to decompile and then run the perl script on it. So I decided
to get some information of the class files and do this all
automatically. I decided to write it in <code>java</code> now,
because it suited best.</p>
<p>Just for the records: the java code is now more than 50 times
bigger than the original perl script and is still growing.</p>
<h2>License</h2>
<p>This code is under GNU GPL. That basically means, that you can copy
or modify this code, as long as you put all your modification under
the GPL again. <A HREF="http://www.gnu.org/copyleft/gpl.html"> Look
here for the complete license</a>.</p>
<hr>
<p><A HREF="mailto:Jochen.Hoenicke@Informatik.Uni-Oldenburg.DE">
http://www.informatik.uni-oldenburg.de/~delwi/jode/jode.html</A>, last
updated on <em>17-Jun-1999</em>.</p>
</body>
</html>

@ -1,282 +0,0 @@
/* Decompiler Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
import java.io.*;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.bytecode.InnerClassInfo;
import jode.decompiler.*;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;
public class Decompiler {
public final static int TAB_SIZE_MASK = 0x0f;
public final static int BRACE_AT_EOL = 0x10;
public final static int SUN_STYLE = 0x14;
public final static int GNU_STYLE = 0x02;
public static final int OPTION_LVT = 0x0001;
public static final int OPTION_INNER = 0x0002;
public static final int OPTION_ANON = 0x0004;
public static final int OPTION_PUSH = 0x0008;
public static final int OPTION_PRETTY = 0x0010;
public static final int OPTION_DECRYPT = 0x0020;
public static final int OPTION_ONETIME = 0x0040;
public static final int OPTION_IMMEDIATE = 0x0080;
public static final int OPTION_VERIFY = 0x0100;
public static final int OPTION_CONTRAFO = 0x0200;
public static int options =
OPTION_LVT | OPTION_INNER | OPTION_ANON |
OPTION_DECRYPT | OPTION_VERIFY | OPTION_CONTRAFO;
public static final String[] optionNames = {
"lvt", "inner", "anonymous", "push",
"pretty", "decrypt", "onetime", "immediate",
"verify", "contrafo"
};
public static int outputStyle = SUN_STYLE;
public static void usage() {
PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version);
err.print("use: jode [-v]"
+"[--cp <classpath>][--dest <destdir>]"
+"[--import <pkglimit> <clslimit>]");
for (int i=0; i < optionNames.length; i++)
err.print("[--[no]"+optionNames[i]+"]");
err.println("[--debug=...] class1 [class2 ...]");
err.println("\t-v "+
"be verbose (multiple times means more verbose).");
err.println("\t--cp <classpath> "+
"search for classes in specified classpath.");
err.println("\t "+
"The paths should be separated by ','.");
err.println("\t--dest <destdir> "+
"write decompiled files to disk into directory destdir.");
err.println("\t--style {sun|gnu}"+
" specifies indentation style");
err.println("\t--import <pkglimit> <clslimit>");
err.println("\t "+
"import classes used more than clslimit times");
err.println("\t "+
"and packages with more then pkglimit used classes");
err.println("\t--[no]inner "+
"[don't] decompile inner classes.");
err.println("\t--[no]anonymous "+
"[don't] decompile anonymous classes.");
err.println("\t--[no]contrafo "+
"[don't] transform constructors of inner classes.");
err.println("\t--[no]lvt "+
"[don't] use the local variable table.");
err.println("\t--[no]pretty "+
"[don't] use `pretty' names for local variables.");
err.println("\t--[no]push "+
"[replace] PUSH instructions [with compilable code].");
err.println("\t--[no]decrypt "+
"[don't] try to decrypt encrypted strings.");
err.println("\t--[no]onetime "+
"[don't] remove locals, that are used only one time.");
err.println("\t--[no]immediate "+
"[don't] output source immediately with wrong import.");
err.println("\t--[no]verify "+
"[don't] verify code before decompiling it.");
err.println("Debugging options, mainly used to debug this decompiler:");
err.println("\t--debug=... "+
"use --debug=help for more information.");
}
public static boolean skipClass(ClassInfo clazz) {
InnerClassInfo[] outers = clazz.getOuterClasses();
if (outers != null) {
if (outers[0].outer == null) {
return ((Decompiler.options & Decompiler.OPTION_ANON) != 0);
} else {
return ((Decompiler.options & Decompiler.OPTION_INNER) != 0);
}
}
return false;
}
public static void main(String[] params) {
int i;
String classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar);
File destDir = null;
ZipOutputStream destZip = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;;
GlobalOptions.err.println(GlobalOptions.copyright);
for (i=0; i<params.length && params[i].startsWith("-"); i++) {
if (params[i].equals("-v"))
GlobalOptions.verboseLevel++;
else if (params[i].equals("--dest"))
destDir = new File(params[++i]);
else if (params[i].startsWith("--debug")) {
String flags;
if (params[i].startsWith("--debug=")) {
flags = params[i].substring(8);
} else if (params[i].length() != 7) {
usage();
return;
} else {
flags = params[++i];
}
GlobalOptions.setDebugging(flags);
} else if (params[i].equals("--style")) {
String style = params[++i];
if (style.equals("sun"))
outputStyle = SUN_STYLE;
else if (style.equals("gnu"))
outputStyle = GNU_STYLE;
else {
GlobalOptions.err.println("Unknown style: "+style);
usage();
return;
}
} else if (params[i].equals("--import")) {
importPackageLimit = Integer.parseInt(params[++i]);
importClassLimit = Integer.parseInt(params[++i]);
} else if (params[i].equals("--cp")) {
classPath = params[++i];
} else if (params[i].equals("--")) {
i++;
break;
} else {
if (params[i].startsWith("--")) {
boolean negated = false;
String optionName = params[i].substring(2);
if (optionName.startsWith("no")) {
optionName = optionName.substring(2);
negated = true;
}
int index = -1;
for (int j=0; j < optionNames.length; j++) {
if (optionNames[j].startsWith(optionName)) {
if (optionNames[j].equals(optionName)) {
index = j;
break;
}
if (index == -1) {
index = j;
} else {
index = -2;
break;
}
}
}
if (index >= 0) {
if (negated)
options &= ~(1<< index);
else
options |= 1 << index;
continue;
}
}
if (!params[i].startsWith("-h") && !params[i].equals("--help"))
GlobalOptions.err.println("Unknown option: "+params[i]);
usage();
return;
}
}
if (i == params.length) {
usage();
return;
}
ClassInfo.setClassPath(classPath);
ImportHandler imports = new ImportHandler(importPackageLimit,
importClassLimit);
TabbedPrintWriter writer = null;
if (destDir == null)
writer = new TabbedPrintWriter(System.out, imports);
else if (destDir.getName().endsWith(".zip")) {
try {
destZip = new ZipOutputStream(new FileOutputStream(destDir));
} catch (IOException ex) {
GlobalOptions.err.println("Can't open zip file "+destDir);
ex.printStackTrace(GlobalOptions.err);
return;
}
writer = new TabbedPrintWriter(new BufferedOutputStream(destZip),
imports, false);
}
for (; i< params.length; i++) {
try {
ClassInfo clazz;
try {
clazz = ClassInfo.forName(params[i]);
} catch (IllegalArgumentException ex) {
GlobalOptions.err.println
("`"+params[i]+"' is not a class name");
continue;
}
if (skipClass(clazz))
continue;
String filename =
params[i].replace('.', File.separatorChar)+".java";
if (destZip != null) {
writer.flush();
destZip.putNextEntry(new ZipEntry(filename));
} else if (destDir != null) {
File file = new File (destDir, filename);
File directory = new File(file.getParent());
if (!directory.exists() && !directory.mkdirs()) {
GlobalOptions.err.println
("Could not create directory "
+ directory.getPath() + ", check permissions.");
}
writer = new TabbedPrintWriter
(new BufferedOutputStream(new FileOutputStream(file)),
imports, false);
}
GlobalOptions.err.println(params[i]);
ClassAnalyzer clazzAna = new ClassAnalyzer(clazz, imports);
clazzAna.dumpJavaFile(writer);
if (destZip != null) {
writer.flush();
destZip.closeEntry();
} else if (destDir != null)
writer.close();
/* Now is a good time to clean up */
System.gc();
} catch (IOException ex) {
GlobalOptions.err.println
("Can't write source of "+params[i]+".");
GlobalOptions.err.println("Check the permissions.");
ex.printStackTrace(GlobalOptions.err);
}
}
if (destZip != null) {
try {
destZip.close();
} catch (IOException ex) {
GlobalOptions.err.println("Can't close Zipfile");
ex.printStackTrace(GlobalOptions.err);
}
}
}
}

@ -1,46 +0,0 @@
/* JodeApplet Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class JodeApplet extends Applet {
JodeWindow jodeWin = new JodeWindow(this);
///#ifdef AWT10
/// public boolean action(Event e, Object arg) {
/// jodeWin.action(e);
/// return true;
/// }
///#endif
public void init() {
String cp = getParameter("classpath");
if (cp != null)
jodeWin.setClasspath(cp);
String cls = getParameter("class");
if (cls != null)
jodeWin.setClass(cls);
setFont(new Font("dialog", Font.PLAIN, 10));
}
}

@ -1,201 +0,0 @@
/* BinaryInfo Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.io.*;
import jode.util.SimpleMap;
///#ifdef JDK12
///import java.util.Map;
///import java.util.Iterator;
///#else
import jode.util.Map;
import jode.util.Iterator;
///#endif
/**
*
* @author Jochen Hoenicke
*/
public class BinaryInfo {
public static final int HIERARCHY = 0x01;
public static final int FIELDS = 0x02;
public static final int METHODS = 0x04;
public static final int CONSTANTS = 0x08;
public static final int ALL_ATTRIBUTES = 0x10;
public static final int INNERCLASSES = 0x20;
public static final int OUTERCLASSES = 0x40;
public static final int FULLINFO = 0xff;
private Map unknownAttributes = new SimpleMap();
protected void skipAttributes(DataInputStream input) throws IOException {
int count = input.readUnsignedShort();
for (int i=0; i< count; i++) {
input.readUnsignedShort(); // the name index
long length = input.readInt();
while (length > 0) {
long skipped = input.skip(length);
if (skipped == 0)
throw new EOFException("Can't skip. EOF?");
length -= skipped;
}
}
}
protected int getKnownAttributeCount() {
return 0;
}
protected void readAttribute(String name, int length,
ConstantPool constantPool,
DataInputStream input,
int howMuch) throws IOException {
byte[] data = new byte[length];
input.readFully(data);
if ((howMuch & ALL_ATTRIBUTES) != 0)
unknownAttributes.put(name, data);
}
static class ConstrainedInputStream extends FilterInputStream {
int length;
public ConstrainedInputStream(int attrLength, InputStream input) {
super(input);
length = attrLength;
}
public int read() throws IOException {
if (length > 0) {
int data = super.read();
length--;
return data;
}
throw new EOFException();
}
public int read(byte[] b, int off, int len) throws IOException {
if (length < len) {
len = length;
}
if (len == 0)
return -1;
int count = super.read(b, off, len);
length -= count;
return count;
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
public long skip(long count) throws IOException {
if (length < count) {
count = length;
}
count = super.skip(count);
length -= (int) count;
return count;
}
public void skipRemaining() throws IOException {
while (length > 0) {
int skipped = (int) skip(length);
if (skipped == 0)
throw new EOFException();
length -= skipped;
}
}
}
protected void readAttributes(ConstantPool constantPool,
DataInputStream input,
int howMuch) throws IOException {
int count = input.readUnsignedShort();
unknownAttributes.clear();
for (int i=0; i< count; i++) {
String attrName =
constantPool.getUTF8(input.readUnsignedShort());
final int attrLength = input.readInt();
ConstrainedInputStream constrInput =
new ConstrainedInputStream(attrLength, input);
readAttribute(attrName, attrLength,
constantPool, new DataInputStream(constrInput),
howMuch);
constrInput.skipRemaining();
}
}
protected void prepareAttributes(GrowableConstantPool gcp) {
Iterator i = unknownAttributes.keySet().iterator();
while (i.hasNext())
gcp.putUTF8((String) i.next());
}
protected void writeKnownAttributes
(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
}
protected void writeAttributes
(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
int count = unknownAttributes.size() + getKnownAttributeCount();
output.writeShort(count);
writeKnownAttributes(constantPool, output);
Iterator i = unknownAttributes.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
String name = (String) e.getKey();
byte[] data = (byte[]) e.getValue();
output.writeShort(constantPool.putUTF8(name));
output.writeInt(data.length);
output.write(data);
}
}
public int getAttributeSize() {
int size = 2; /* attribute count */
Iterator i = unknownAttributes.values().iterator();
while (i.hasNext())
size += 2 + 4 + ((byte[]) i.next()).length;
return size;
}
public byte[] findAttribute(String name) {
return (byte[]) unknownAttributes.get(name);
}
public Iterator getAttributes() {
return unknownAttributes.values().iterator();
}
public void setAttribute(String name, byte[] content) {
unknownAttributes.put(name, content);
}
public byte[] removeAttribute(String name) {
return (byte[]) unknownAttributes.remove(name);
}
public void removeAllAttributes() {
unknownAttributes.clear();
}
}

File diff suppressed because it is too large Load Diff

@ -1,771 +0,0 @@
/* ClassInfo Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import jode.GlobalOptions;
import jode.type.Type;
import java.io.*;
import java.util.*;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///#endif
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* This class does represent a class similar to java.lang.Class. You
* can get the super class and the interfaces.
*
* The main difference to java.lang.Class is, that the objects are builded
* from a stream containing the .class file, and that it uses the
* <code>Type</code> to represent types instead of Class itself.
*
* @author Jochen Hoenicke
*/
public class ClassInfo extends BinaryInfo {
private static SearchPath classpath;
///#ifdef JDK12
/// private static final Map classes = new HashMap();
/// private static final ReferenceQueue queue = new ReferenceQueue();
///#else
private static final Hashtable classes = new Hashtable();
///#endif
private int status = 0;
private boolean modified = false;
private int modifiers = -1;
private String name;
private ClassInfo superclass;
private ClassInfo[] interfaces;
private FieldInfo[] fields;
private MethodInfo[] methods;
private InnerClassInfo[] outerClasses;
private InnerClassInfo[] innerClasses;
private InnerClassInfo[] extraClasses;
private String sourceFile;
public final static ClassInfo javaLangObject = forName("java.lang.Object");
public static void setClassPath(String path) {
classpath = new SearchPath(path);
///#ifdef JDK12
/// java.lang.ref.Reference died;
/// while ((died = queue.poll()) != null) {
/// classes.values().remove(died);
/// }
/// Iterator i = classes.values().iterator();
/// while (i.hasNext()) {
/// ClassInfo ci = (ClassInfo) ((WeakReference)i.next()).get();
/// if (ci == null) {
/// i.remove();
/// continue;
/// }
///#else
Enumeration enum = classes.elements();
while (enum.hasMoreElements()) {
ClassInfo ci = (ClassInfo) enum.nextElement();
///#endif
ci.status = 0;
ci.superclass = null;
ci.fields = null;
ci.interfaces = null;
ci.methods = null;
ci.removeAllAttributes();
}
}
public static boolean exists(String name) {
return classpath.exists(name.replace('.', '/') + ".class");
}
public static boolean isPackage(String name) {
return classpath.isDirectory(name.replace('.', '/'));
}
public static Enumeration getClassesAndPackages(final String packageName) {
final Enumeration enum =
classpath.listFiles(packageName.replace('.','/'));
return new Enumeration() {
public boolean hasMoreElements() {
return enum.hasMoreElements();
}
public Object nextElement() {
String name = (String) enum.nextElement();
if (!name.endsWith(".class"))
// This is a package
return name;
return name.substring(0, name.length()-6);
}
};
}
public static ClassInfo forName(String name) {
if (name == null
|| name.indexOf(';') != -1
|| name.indexOf('[') != -1
|| name.indexOf('/') != -1)
throw new IllegalArgumentException("Illegal class name: "+name);
///#ifdef JDK12
/// java.lang.ref.Reference died;
/// while ((died = queue.poll()) != null) {
/// classes.values().remove(died);
/// }
/// WeakReference ref = (WeakReference) classes.get(name);
/// ClassInfo clazz = (ref == null) ? null : (ClassInfo) ref.get();
///#else
ClassInfo clazz = (ClassInfo) classes.get(name);
///#endif
if (clazz == null) {
clazz = new ClassInfo(name);
///#ifdef JDK12
/// classes.put(name, new WeakReference(clazz, queue));
///#else
classes.put(name, clazz);
///#endif
}
return clazz;
}
private ClassInfo(String name) {
this.name = name;
}
protected void readAttribute(String name, int length,
ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("SourceFile")) {
if (length != 2)
throw new ClassFormatException("SourceFile attribute"
+ " has wrong length");
sourceFile = cp.getUTF8(input.readUnsignedShort());
} else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0
&& name.equals("InnerClasses")) {
int count = input.readUnsignedShort();
int innerCount = 0, outerCount = 0, extraCount = 0;
InnerClassInfo[] innerClassInfo = new InnerClassInfo[count];
for (int i=0; i< count; i++) {
int innerIndex = input.readUnsignedShort();
int outerIndex = input.readUnsignedShort();
int nameIndex = input.readUnsignedShort();
String inner = cp.getClassName(innerIndex);
String outer =
outerIndex != 0 ? cp.getClassName(outerIndex) : null;
String innername =
nameIndex != 0 ? cp.getUTF8(nameIndex) : null;
int access = input.readUnsignedShort();
if (innername != null && innername.length() == 0)
innername = null;
InnerClassInfo ici = new InnerClassInfo
(inner, outer, innername, access);
if (outer != null && outer.equals(getName())
&& innername != null)
innerClassInfo[innerCount++] = ici;
else
innerClassInfo[count - (++extraCount)] = ici;
}
{
String lastOuterName = getName();
for (int i = count - extraCount; i < count; i++) {
InnerClassInfo ici = innerClassInfo[i];
if (ici.inner.equals(lastOuterName)) {
for (int j = i; j > count - extraCount; j--)
innerClassInfo[j] = innerClassInfo[j-1];
innerClassInfo[count-extraCount] = ici;
extraCount--;
outerCount++;
lastOuterName = ici.outer;
}
}
}
if (innerCount > 0) {
innerClasses = new InnerClassInfo[innerCount];
System.arraycopy(innerClassInfo, 0,
innerClasses, 0, innerCount);
} else
innerClasses = null;
if (outerCount > 0) {
outerClasses = new InnerClassInfo[outerCount];
System.arraycopy(innerClassInfo, innerCount,
outerClasses, 0, outerCount);
} else
outerClasses = null;
if (extraCount > 0) {
extraClasses = new InnerClassInfo[extraCount];
System.arraycopy(innerClassInfo, innerCount + outerCount,
extraClasses, 0, extraCount);
} else
extraClasses = null;
if (length != 2 + 8 * count)
throw new ClassFormatException
("InnerClasses attribute has wrong length");
} else
super.readAttribute(name, length, cp, input, howMuch);
}
public void read(DataInputStream input, int howMuch) throws IOException {
/* header */
if (input.readInt() != 0xcafebabe)
throw new ClassFormatException("Wrong magic");
if (input.readUnsignedShort() > 3)
throw new ClassFormatException("Wrong minor");
if (input.readUnsignedShort() != 45)
throw new ClassFormatException("Wrong major");
/* constant pool */
ConstantPool cpool = new ConstantPool();
cpool.read(input);
/* always read modifiers, name, super, ifaces */
{
modifiers = input.readUnsignedShort();
String className = cpool.getClassName(input.readUnsignedShort());
if (!name.equals(className))
throw new ClassFormatException("wrong name " + className);
String superName = cpool.getClassName(input.readUnsignedShort());
superclass = superName != null ? ClassInfo.forName(superName) : null;
int count = input.readUnsignedShort();
interfaces = new ClassInfo[count];
for (int i=0; i< count; i++) {
interfaces[i] = ClassInfo.forName
(cpool.getClassName(input.readUnsignedShort()));
}
status |= HIERARCHY;
}
/* fields */
if ((howMuch & FIELDS) != 0) {
int count = input.readUnsignedShort();
fields = new FieldInfo[count];
for (int i=0; i< count; i++) {
fields[i] = new FieldInfo(this);
fields[i].read(cpool, input, howMuch);
}
} else {
byte[] skipBuf = new byte[6];
int count = input.readUnsignedShort();
for (int i=0; i< count; i++) {
input.readFully(skipBuf); // modifier, name, type
skipAttributes(input);
}
}
/* methods */
if ((howMuch & METHODS) != 0) {
int count = input.readUnsignedShort();
methods = new MethodInfo[count];
for (int i=0; i< count; i++) {
methods[i] = new MethodInfo(this);
methods[i].read(cpool, input, howMuch);
}
} else {
byte[] skipBuf = new byte[6];
int count = input.readUnsignedShort();
for (int i=0; i< count; i++) {
input.readFully(skipBuf); // modifier, name, type
skipAttributes(input);
}
}
/* attributes */
readAttributes(cpool, input, howMuch);
}
public void reserveSmallConstants(GrowableConstantPool gcp) {
for (int i=0; i < fields.length; i++)
fields[i].reserveSmallConstants(gcp);
for (int i=0; i < methods.length; i++)
methods[i].reserveSmallConstants(gcp);
}
public void prepareWriting(GrowableConstantPool gcp) {
gcp.putClassName(name);
gcp.putClassName(superclass.getName());
for (int i=0; i < interfaces.length; i++)
gcp.putClassName(interfaces[i].getName());
for (int i=0; i < fields.length; i++)
fields[i].prepareWriting(gcp);
for (int i=0; i < methods.length; i++)
methods[i].prepareWriting(gcp);
if (sourceFile != null) {
gcp.putUTF8("SourceFile");
gcp.putUTF8(sourceFile);
}
if (outerClasses != null || innerClasses != null
|| extraClasses != null) {
gcp.putUTF8("InnerClasses");
int outerCount = outerClasses != null ? outerClasses.length : 0;
for (int i=outerCount; i-- > 0;) {
gcp.putClassName(outerClasses[i].inner);
if (outerClasses[i].outer != null)
gcp.putClassName(outerClasses[i].outer);
if (outerClasses[i].name != null)
gcp.putUTF8(outerClasses[i].name);
}
int innerCount = innerClasses != null ? innerClasses.length : 0;
for (int i=0; i< innerCount; i++) {
gcp.putClassName(innerClasses[i].inner);
if (innerClasses[i].outer != null)
gcp.putClassName(innerClasses[i].outer);
if (innerClasses[i].name != null)
gcp.putUTF8(innerClasses[i].name);
}
int extraCount = extraClasses != null ? extraClasses.length : 0;
for (int i=0; i< extraCount; i++) {
gcp.putClassName(extraClasses[i].inner);
if (extraClasses[i].outer != null)
gcp.putClassName(extraClasses[i].outer);
if (extraClasses[i].name != null)
gcp.putUTF8(extraClasses[i].name);
}
}
prepareAttributes(gcp);
}
protected int getKnownAttributeCount() {
int count = 0;
if (sourceFile != null)
count++;
if (innerClasses != null || outerClasses != null
|| extraClasses != null)
count++;
return count;
}
public void writeKnownAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
if (sourceFile != null) {
output.writeShort(gcp.putUTF8("SourceFile"));
output.writeInt(2);
output.writeShort(gcp.putUTF8(sourceFile));
}
if (outerClasses != null || innerClasses != null
|| extraClasses != null) {
output.writeShort(gcp.putUTF8("InnerClasses"));
int outerCount = (outerClasses != null) ? outerClasses.length : 0;
int innerCount = (innerClasses != null) ? innerClasses.length : 0;
int extraCount = (extraClasses != null) ? extraClasses.length : 0;
int count = outerCount + innerCount + extraCount;
output.writeInt(2 + count * 8);
output.writeShort(count);
for (int i=outerCount; i-- > 0; ) {
output.writeShort(gcp.putClassName(outerClasses[i].inner));
output.writeShort(outerClasses[i].outer != null ?
gcp.putClassName(outerClasses[i].outer) : 0);
output.writeShort(outerClasses[i].name != null ?
gcp.putUTF8(outerClasses[i].name) : 0);
output.writeShort(outerClasses[i].modifiers);
}
for (int i=0; i< innerCount; i++) {
output.writeShort(gcp.putClassName(innerClasses[i].inner));
output.writeShort(innerClasses[i].outer != null ?
gcp.putClassName(innerClasses[i].outer) : 0);
output.writeShort(innerClasses[i].name != null ?
gcp.putUTF8(innerClasses[i].name) : 0);
output.writeShort(innerClasses[i].modifiers);
}
for (int i=0; i< extraCount; i++) {
output.writeShort(gcp.putClassName(extraClasses[i].inner));
output.writeShort(extraClasses[i].outer != null ?
gcp.putClassName(extraClasses[i].outer) : 0);
output.writeShort(extraClasses[i].name != null ?
gcp.putUTF8(extraClasses[i].name) : 0);
output.writeShort(extraClasses[i].modifiers);
}
}
}
public void write(DataOutputStream out) throws IOException {
GrowableConstantPool gcp = new GrowableConstantPool();
reserveSmallConstants(gcp);
prepareWriting(gcp);
out.writeInt(0xcafebabe);
out.writeShort(3);
out.writeShort(45);
gcp.write(out);
out.writeShort(modifiers);
out.writeShort(gcp.putClassName(name));
out.writeShort(gcp.putClassName(superclass.getName()));
out.writeShort(interfaces.length);
for (int i=0; i < interfaces.length; i++)
out.writeShort(gcp.putClassName(interfaces[i].getName()));
out.writeShort(fields.length);
for (int i=0; i < fields.length; i++)
fields[i].write(gcp, out);
out.writeShort(methods.length);
for (int i=0; i < methods.length; i++)
methods[i].write(gcp, out);
writeAttributes(gcp, out);
}
public void loadInfoReflection(Class clazz, int howMuch)
throws SecurityException {
if ((howMuch & HIERARCHY) != 0) {
modifiers = clazz.getModifiers();
if (clazz.getSuperclass() == null)
superclass = null;
else
superclass = ClassInfo.forName
(clazz.getSuperclass().getName());
Class[] ifaces = clazz.getInterfaces();
interfaces = new ClassInfo[ifaces.length];
for (int i=0; i<ifaces.length; i++)
interfaces[i] = ClassInfo.forName(ifaces[i].getName());
status |= HIERARCHY;
}
if ((howMuch & FIELDS) != 0 && fields == null) {
Field[] fs;
try {
fs = clazz.getDeclaredFields();
} catch (SecurityException ex) {
fs = clazz.getFields();
GlobalOptions.err.println
("Could only get public fields of class "
+ name + ".");
}
fields = new FieldInfo[fs.length];
for (int i = fs.length; --i >= 0; ) {
String type = Type.getSignature(fs[i].getType());
fields[i] = new FieldInfo
(this, fs[i].getName(), type, fs[i].getModifiers());
}
}
if ((howMuch & METHODS) != 0 && methods == null) {
Method[] ms;
try {
ms = clazz.getDeclaredMethods();
} catch (SecurityException ex) {
ms = clazz.getMethods();
GlobalOptions.err.println
("Could only get public methods of class "
+ name + ".");
}
methods = new MethodInfo[ms.length];
for (int i = ms.length; --i >= 0; ) {
String type = Type.getSignature
(ms[i].getParameterTypes(), ms[i].getReturnType());
methods[i] = new MethodInfo
(this, ms[i].getName(), type, ms[i].getModifiers());
}
}
if ((howMuch & INNERCLASSES) != 0 && innerClasses == null) {
Class[] is;
try {
is = clazz.getDeclaredClasses();
} catch (SecurityException ex) {
is = clazz.getClasses();
GlobalOptions.err.println
("Could only get public methods of class "
+ name + ".");
}
if (is.length > 0) {
innerClasses = new InnerClassInfo[is.length];
for (int i = is.length; --i >= 0; ) {
String inner = is[i].getName();
int dollar = inner.lastIndexOf('$');
String name = inner.substring(dollar+1);
innerClasses[i] = new InnerClassInfo
(inner, getName(), name, is[i].getModifiers());
}
}
}
if ((howMuch & OUTERCLASSES) != 0 && outerClasses == null) {
int count = 0;
Class declarer = clazz.getDeclaringClass();
while (declarer != null) {
count++;
declarer = declarer.getDeclaringClass();
}
if (count > 0) {
outerClasses = new InnerClassInfo[count];
Class current = clazz;
for (int i = 0; i < count; i++) {
declarer = current.getDeclaringClass();
String name = current.getName();
int dollar = name.lastIndexOf('$');
outerClasses[i] = new InnerClassInfo
(name, declarer.getName(),
name.substring(dollar+1), current.getModifiers());
current = declarer;
}
}
}
status |= howMuch;
}
public void loadInfo(int howMuch) {
if ((status & howMuch) == howMuch)
return;
if (modified) {
System.err.println("Allocating info 0x"
+ Integer.toHexString(howMuch)
+ " (status 0x" + Integer.toHexString(status)
+ ") in class " + this);
Thread.dumpStack();
return;
}
try {
DataInputStream input =
new DataInputStream(classpath.getFile(name.replace('.', '/')
+ ".class"));
read(input, howMuch);
status |= howMuch;
} catch (IOException ex) {
String message = ex.getMessage();
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY
|INNERCLASSES|OUTERCLASSES)) != 0) {
GlobalOptions.err.println
("Can't read class " + name + ".");
ex.printStackTrace(GlobalOptions.err);
throw new NoClassDefFoundError(name);
}
// Try getting the info through the reflection interface
// instead.
Class clazz = null;
try {
clazz = Class.forName(name);
} catch (ClassNotFoundException ex2) {
} catch (NoClassDefFoundError ex2) {
}
try {
if (clazz != null) {
loadInfoReflection(clazz, howMuch);
return;
}
} catch (SecurityException ex2) {
GlobalOptions.err.println
(ex2+" while collecting info about class " + name + ".");
}
// Give a warning and ``guess'' the hierarchie, methods etc.
GlobalOptions.err.println
("Can't read class " + name + ", types may be incorrect. ("
+ ex.getClass().getName()
+ (message != null ? ": " + message : "") + ")");
if ((howMuch & HIERARCHY) != 0) {
modifiers = Modifier.PUBLIC;
if (name.equals("java.lang.Object"))
superclass = null;
else
superclass = javaLangObject;
interfaces = new ClassInfo[0];
}
if ((howMuch & METHODS) != 0)
methods = new MethodInfo[0];
if ((howMuch & FIELDS) != 0)
fields = new FieldInfo[0];
status |= howMuch;
}
}
public String getName() {
return name;
}
public String getJavaName() {
/* Don't load attributes for class names not containing a
* dollar sign.
*/
if (name.indexOf('$') == -1)
return getName();
if (getOuterClasses() != null) {
int last = outerClasses.length-1;
StringBuffer sb =
new StringBuffer(outerClasses[last].outer != null
? outerClasses[last].outer : "METHOD");
for (int i=last; i >= 0; i--)
sb.append(".").append(outerClasses[i].name != null
? outerClasses[i].name : "ANONYMOUS");
return sb.toString();
}
return getName();
}
public ClassInfo getSuperclass() {
if ((status & HIERARCHY) == 0)
loadInfo(HIERARCHY);
return superclass;
}
public ClassInfo[] getInterfaces() {
if ((status & HIERARCHY) == 0)
loadInfo(HIERARCHY);
return interfaces;
}
public int getModifiers() {
if ((status & HIERARCHY) == 0)
loadInfo(HIERARCHY);
return modifiers;
}
public boolean isInterface() {
return Modifier.isInterface(getModifiers());
}
public FieldInfo findField(String name, String typeSig) {
if ((status & FIELDS) == 0)
loadInfo(FIELDS);
for (int i=0; i< methods.length; i++)
if (fields[i].getName().equals(name)
&& fields[i].getType().equals(typeSig))
return fields[i];
return null;
}
public MethodInfo findMethod(String name, String typeSig) {
if ((status & METHODS) == 0)
loadInfo(METHODS);
for (int i=0; i< methods.length; i++)
if (methods[i].getName().equals(name)
&& methods[i].getType().equals(typeSig))
return methods[i];
return null;
}
public MethodInfo[] getMethods() {
if ((status & METHODS) == 0)
loadInfo(METHODS);
return methods;
}
public FieldInfo[] getFields() {
if ((status & FIELDS) == 0)
loadInfo(FIELDS);
return fields;
}
public InnerClassInfo[] getOuterClasses() {
if ((status & OUTERCLASSES) == 0)
loadInfo(OUTERCLASSES);
return outerClasses;
}
public InnerClassInfo[] getInnerClasses() {
if ((status & INNERCLASSES) == 0)
loadInfo(INNERCLASSES);
return innerClasses;
}
public InnerClassInfo[] getExtraClasses() {
if ((status & INNERCLASSES) == 0)
loadInfo(INNERCLASSES);
return extraClasses;
}
public String getSourceFile() {
return sourceFile;
}
public void setName(String newName) {
name = newName;
modified = true;
}
public void setSuperclass(ClassInfo newSuper) {
superclass = newSuper;
modified = true;
}
public void setInterfaces(ClassInfo[] newIfaces) {
interfaces = newIfaces;
modified = true;
}
public void setModifiers(int newModifiers) {
modifiers = newModifiers;
modified = true;
}
public void setMethods(MethodInfo[] mi) {
methods = mi;
modified = true;
}
public void setFields(FieldInfo[] fi) {
fields = fi;
modified = true;
}
public void setOuterClasses(InnerClassInfo[] oc) {
outerClasses = oc;
modified = true;
}
public void setInnerClasses(InnerClassInfo[] ic) {
innerClasses = ic;
modified = true;
}
public void setExtraClasses(InnerClassInfo[] ec) {
extraClasses = ec;
modified = true;
}
public void setSourceFile(String newSource) {
sourceFile = newSource;
modified = true;
}
public boolean superClassOf(ClassInfo son) {
while (son != this && son != null) {
son = son.getSuperclass();
}
return son == this;
}
public boolean implementedBy(ClassInfo clazz) {
while (clazz != this && clazz != null) {
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i< ifaces.length; i++) {
if (implementedBy(ifaces[i]))
return true;
}
clazz = clazz.getSuperclass();
}
return clazz == this;
}
public String toString() {
return name;
}
}

@ -1,194 +0,0 @@
/* FieldInfo Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.io.*;
import java.lang.reflect.Modifier;
public class FieldInfo extends BinaryInfo {
ClassInfo clazzInfo;
int modifier;
String name;
String typeSig;
Object constant;
boolean syntheticFlag;
boolean deprecatedFlag;
public FieldInfo(ClassInfo ci) {
this.clazzInfo = ci;
}
public FieldInfo(ClassInfo ci, String name, String typeSig, int modifier) {
this.clazzInfo = ci;
this.name = name;
this.typeSig = typeSig;
this.modifier = modifier;
}
protected void readAttribute(String name, int length,
ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("ConstantValue")) {
if (length != 2)
throw new ClassFormatException("ConstantValue attribute"
+ " has wrong length");
int index = input.readUnsignedShort();
constant = cp.getConstant(index);
} else if (name.equals("Synthetic")) {
syntheticFlag = true;
if (length != 0)
throw new ClassFormatException
("Synthetic attribute has wrong length");
} else if (name.equals("Deprecated")) {
deprecatedFlag = true;
if (length != 0)
throw new ClassFormatException
("Deprecated attribute has wrong length");
} else
super.readAttribute(name, length, cp, input, howMuch);
}
public void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort());
typeSig = constantPool.getUTF8(input.readUnsignedShort());
readAttributes(constantPool, input, howMuch);
}
public void reserveSmallConstants(GrowableConstantPool gcp) {
}
public void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name);
gcp.putUTF8(typeSig);
if (constant != null) {
gcp.putUTF8("ConstantValue");
if (typeSig.charAt(0) == 'J' || typeSig.charAt(0) == 'D')
gcp.putLongConstant(constant);
else
gcp.putConstant(constant);
}
if (syntheticFlag)
gcp.putUTF8("Synthetic");
if (deprecatedFlag)
gcp.putUTF8("Deprecated");
prepareAttributes(gcp);
}
protected int getKnownAttributeCount() {
int count = 0;
if (constant != null)
count++;
if (syntheticFlag)
count++;
if (deprecatedFlag)
count++;
return count;
}
public void writeKnownAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
if (constant != null) {
output.writeShort(gcp.putUTF8("ConstantValue"));
output.writeInt(2);
int index;
if (typeSig.charAt(0) == 'J'
|| typeSig.charAt(0) == 'D')
index = gcp.putLongConstant(constant);
else
index = gcp.putConstant(constant);
output.writeShort(index);
}
if (syntheticFlag) {
output.writeShort(gcp.putUTF8("Synthetic"));
output.writeInt(0);
}
if (deprecatedFlag) {
output.writeShort(gcp.putUTF8("Deprecated"));
output.writeInt(0);
}
}
public void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name));
output.writeShort(constantPool.putUTF8(typeSig));
writeAttributes(constantPool, output);
}
public String getName() {
return name;
}
public String getType() {
return typeSig;
}
public int getModifiers() {
return modifier;
}
public boolean isSynthetic() {
return syntheticFlag;
}
public boolean isDeprecated() {
return deprecatedFlag;
}
public Object getConstant() {
return constant;
}
public void setName(String newName) {
name = newName;
}
public void setType(String newType) {
typeSig = newType;
}
public void setModifiers(int newModifier) {
modifier = newModifier;
}
public void setSynthetic(boolean flag) {
syntheticFlag = flag;
}
public void setDeprecated(boolean flag) {
deprecatedFlag = flag;
}
public void setConstant(Object newConstant) {
constant = newConstant;
}
public String toString() {
return "Field "+Modifier.toString(modifier)+" "+
typeSig+" "+name;
}
}

@ -1,257 +0,0 @@
/* GrowableConstantPool Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.io.*;
import jode.type.Type;
import java.util.Hashtable;
/**
* This class represent a constant pool, where new constants can be added to.
*
* @author Jochen Hoenicke
*/
public class GrowableConstantPool extends ConstantPool {
Hashtable entryToIndex = new Hashtable();
boolean written;
public GrowableConstantPool () {
count = 1;
tags = new int[128];
indices1 = new int[128];
indices2 = new int[128];
constants = new Object[128];
written = false;
}
public final void grow(int wantedSize) {
if (written)
throw new IllegalStateException("adding to written ConstantPool");
if (tags.length < wantedSize) {
int newSize = Math.max(tags.length*2, wantedSize);
int[] tmpints = new int[newSize];
System.arraycopy(tags, 0, tmpints, 0, count);
tags = tmpints;
tmpints = new int[newSize];
System.arraycopy(indices1, 0, tmpints, 0, count);
indices1 = tmpints;
tmpints = new int[newSize];
System.arraycopy(indices2, 0, tmpints, 0, count);
indices2 = tmpints;
Object[] tmpobjs = new Object[newSize];
System.arraycopy(constants, 0, tmpobjs, 0, count);
constants = tmpobjs;
}
}
int putConstant(int tag, Object constant) {
String key = "" + (char)tag + constant;
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
return index.intValue();
int newIndex = count;
grow(count + 1);
tags[newIndex] = tag;
constants[newIndex] = constant;
entryToIndex.put(key, new Integer(newIndex));
count++;
return newIndex;
}
int putLongConstant(int tag, Object constant) {
String key = "" + (char)tag + constant;
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
return index.intValue();
int newIndex = count;
grow(count + 2);
tags[newIndex] = tag;
tags[newIndex+1] = -tag;
constants[newIndex] = constant;
entryToIndex.put(key, new Integer(newIndex));
count += 2;
return newIndex;
}
int putIndexed(String key, int tag, int index1, int index2) {
Integer indexObj = (Integer) entryToIndex.get(key);
if (indexObj != null) {
/* Maybe this was a reserved, but not filled entry */
int index = indexObj.intValue();
indices1[index] = index1;
indices2[index] = index2;
return index;
}
grow(count+1);
tags[count] = tag;
indices1[count] = index1;
indices2[count] = index2;
entryToIndex.put(key, new Integer(count));
return count++;
}
public final int putUTF8(String utf) {
return putConstant(UTF8, utf);
}
public int putClassName(String name) {
name = name.replace('.','/');
return putIndexed(""+(char) CLASS + name,
CLASS, putUTF8(name), 0);
}
public int putClassType(String name) {
if (name.charAt(0) == 'L')
name = name.substring(1, name.length()-1);
return putIndexed(""+(char) CLASS + name,
CLASS, putUTF8(name), 0);
}
public int putRef(int tag, Reference ref) {
String className = ref.getClazz();
String typeSig = ref.getType();
String nameAndType = ref.getName() + "/" + typeSig;
int classIndex = putClassType(className);
int nameIndex = putUTF8(ref.getName());
int typeIndex = putUTF8(typeSig);
int nameTypeIndex = putIndexed("" + (char) NAMEANDTYPE + nameAndType,
NAMEANDTYPE, nameIndex, typeIndex);
return putIndexed("" + (char)tag + className + "/" + nameAndType,
tag, classIndex, nameTypeIndex);
}
/**
* Puts a constant into this constant pool
* @param c the constant, must be of type
* Integer, Long, Float, Double or String
* @return the index into the pool of this constant.
*/
public int putConstant(Object c) {
if (c instanceof String) {
return putIndexed("" + (char) STRING + c,
STRING, putUTF8((String) c), 0);
} else {
int tag;
if (c instanceof Integer)
tag = INTEGER;
else if (c instanceof Float)
tag = FLOAT;
else
throw new IllegalArgumentException
("illegal constant " + c + " of type: " + c.getClass());
return putConstant(tag, c);
}
}
/**
* Puts a constant into this constant pool
* @param c the constant, must be of type
* Integer, Long, Float, Double or String
* @return the index into the pool of this constant.
*/
public int putLongConstant(Object c) {
int tag;
if (c instanceof Long)
tag = LONG;
else if (c instanceof Double)
tag = DOUBLE;
else
throw new IllegalArgumentException
("illegal long constant " + c + " of type: " + c.getClass());
return putLongConstant(tag, c);
}
/**
* Reserve an entry in this constant pool for a constant (for ldc).
* @param c the constant, must be of type
* Integer, Long, Float, Double or String
* @return the reserved index into the pool of this constant.
*/
public int reserveConstant(Object c) {
if (c instanceof String) {
return putIndexed("" + (char)STRING + c,
STRING, -1, 0);
} else {
return putConstant(c);
}
}
/**
* Reserve an entry in this constant pool for a constant (for ldc).
* @param c the constant, must be of type
* Integer, Long, Float, Double or String
* @return the reserved index into the pool of this constant.
*/
public int reserveLongConstant(Object c) {
return putLongConstant(c);
}
public int copyConstant(ConstantPool cp, int index)
throws ClassFormatException {
return putConstant(cp.getConstant(index));
}
public void write(DataOutputStream stream)
throws IOException {
written = true;
stream.writeShort(count);
for (int i=1; i< count; i++) {
int tag = tags[i];
stream.writeByte(tag);
switch (tag) {
case CLASS:
stream.writeShort(indices1[i]);
break;
case FIELDREF:
case METHODREF:
case INTERFACEMETHODREF:
stream.writeShort(indices1[i]);
stream.writeShort(indices2[i]);
break;
case STRING:
stream.writeShort(indices1[i]);
break;
case INTEGER:
stream.writeInt(((Integer)constants[i]).intValue());
break;
case FLOAT:
stream.writeFloat(((Float)constants[i]).floatValue());
break;
case LONG:
stream.writeLong(((Long)constants[i]).longValue());
i++;
break;
case DOUBLE:
stream.writeDouble(((Double)constants[i]).doubleValue());
i++;
break;
case NAMEANDTYPE:
stream.writeShort(indices1[i]);
stream.writeShort(indices2[i]);
break;
case UTF8:
stream.writeUTF((String)constants[i]);
break;
default:
throw new ClassFormatException("unknown constant tag");
}
}
}
}

@ -1,29 +0,0 @@
/* Handler Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
/**
* A simple class containing the info about an exception handler
*/
public class Handler {
public Instruction start, end, catcher;
public String type;
}

@ -1,492 +0,0 @@
/* Instruction Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.util.Vector;
import java.util.Enumeration;
import jode.type.Type;
import jode.type.MethodType;
/**
* This class represents an instruction in the byte code.
*
* For simplicity currently most fields are public. You shouldn't change
* many of them, though.
*/
public class Instruction implements Opcodes{
public BytecodeInfo codeinfo;
/**
* The opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre>
*/
public int opcode;
/**
* If this opcode uses a local this gives the slot. This info is
* used when swapping locals.
*/
public int localSlot = -1;
/**
* Optional object data for this opcode. This is mostly used for
* method/field/class references, but also for a value array
* in a lookupswitch.
*/
public Object objData;
/**
* Optional integer data for this opcode. There are various uses
* for this.
*/
public int intData;
/**
* The address of this opcode.
*/
public int addr;
/**
* The length of this opcode. You shouldn't touch it, nor rely on
* it, since the length of some opcodes may change automagically
* (e.g. when changing localSlot iload_0 <-> iload 5)
*/
public int length;
/**
* If this is true, the instruction will never flow into the nextByAddr.
*/
public boolean alwaysJumps = false;
/**
* The successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null is equivalent to an empty array.
*/
public Instruction[] succs;
/**
* The predecessors of this opcode, orthogonal to the succs array.
* This must be null or a non empty array.
*/
public Instruction[] preds;
/**
* The next instruction in code order.
*/
public Instruction nextByAddr;
/**
* The previous instruction in code order, useful when changing
* the order.
*/
public Instruction prevByAddr;
/**
* You can use this field to add some info to each instruction.
* After using, you must set it to null again.
*/
public Object tmpInfo;
public Instruction(BytecodeInfo ci) {
this.codeinfo = ci;
}
public void addPredecessor(Instruction pred) {
if (preds == null) {
preds = new Instruction[] { pred };
return;
}
int predsLength = preds.length;
Instruction[] newPreds = new Instruction[predsLength+1];
System.arraycopy(preds, 0, newPreds, 0, predsLength);
newPreds[predsLength] = pred;
preds = newPreds;
}
public void removePredecessor(Instruction pred) {
/* Hopefully it doesn't matter if this is slow */
int predLength = preds.length;
if (predLength == 1) {
if (preds[0] != pred)
throw new jode.AssertError
("removing not existing predecessor");
preds = null;
} else {
Instruction[] newPreds = new Instruction[predLength-1];
int j;
for (j = 0; preds[j] != pred; j++)
newPreds[j] = preds[j];
System.arraycopy(preds, j+1, newPreds, j, predLength - j - 1);
preds = newPreds;
}
}
public Instruction insertInstruction() {
Instruction newInstr = new Instruction(codeinfo);
newInstr.addr = addr;
newInstr.prevByAddr = prevByAddr;
if (prevByAddr != null)
prevByAddr.nextByAddr = newInstr;
else
codeinfo.firstInstr = newInstr;
newInstr.nextByAddr = this;
prevByAddr = newInstr;
/* promote the predecessors to newInstr */
if (preds != null) {
for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++)
if (preds[j].succs[i] == this)
preds[j].succs[i] = newInstr;
newInstr.preds = preds;
preds = null;
}
return newInstr;
}
public Instruction appendInstruction() {
Instruction newInstr = new Instruction(codeinfo);
newInstr.addr = addr;
newInstr.nextByAddr = nextByAddr;
if (nextByAddr != null)
nextByAddr.prevByAddr = newInstr;
newInstr.prevByAddr = this;
nextByAddr = newInstr;
return newInstr;
}
/**
* Removes this instruction (as if it would be replaced by a nop).
*/
public void removeInstruction() {
/* remove from chained list */
if (prevByAddr != null)
prevByAddr.nextByAddr = nextByAddr;
else
codeinfo.firstInstr = nextByAddr;
if (nextByAddr != null)
nextByAddr.prevByAddr = prevByAddr;
/* remove predecessors of successors */
if (succs != null) {
for (int i=0; i < succs.length; i++)
succs[i].removePredecessor(this);
succs = null;
}
Instruction alternative = nextByAddr != null ? nextByAddr : prevByAddr;
/* remove the predecessors to alternative */
if (preds != null) {
for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++)
if (preds[j].succs[i] == this)
preds[j].succs[i] = alternative;
if (alternative.preds == null)
alternative.preds = preds;
else {
Instruction[] newPreds
= new Instruction[alternative.preds.length + preds.length];
System.arraycopy(preds, 0, newPreds, 0, preds.length);
System.arraycopy(alternative.preds, 0, newPreds, preds.length,
alternative.preds.length);
alternative.preds = newPreds;
}
preds = null;
}
/* adjust exception handlers */
Handler[] handlers = codeinfo.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].start == this)
handlers[i].start = nextByAddr;
if (handlers[i].end == this)
handlers[i].end = prevByAddr;
if (handlers[i].catcher == this)
handlers[i].catcher = nextByAddr;
if (handlers[i].start == null
|| handlers[i].end == null
|| handlers[i].end.nextByAddr == handlers[i].start) {
/* Remove the handler.
* This is very seldom, so we can make it slow */
Handler[] newHandlers = new Handler[handlers.length - 1];
System.arraycopy(handlers, 0, newHandlers, 0, i);
System.arraycopy(handlers, i+1, newHandlers, i,
handlers.length - (i+1));
handlers = newHandlers;
codeinfo.setExceptionHandlers(newHandlers);
i--;
}
}
/* adjust local variable table and line number table */
LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
if (lvt != null) {
for (int i=0; i< lvt.length; i++) {
if (lvt[i].start == this)
lvt[i].start = nextByAddr;
if (lvt[i].end == this)
lvt[i].end = prevByAddr;
if (lvt[i].start == null
|| lvt[i].end == null
|| lvt[i].end.nextByAddr == lvt[i].start) {
/* Remove the local variable info.
* This is very seldom, so we can make it slow */
LocalVariableInfo[] newLVT =
new LocalVariableInfo[lvt.length - 1];
System.arraycopy(lvt, 0, newLVT, 0, i);
System.arraycopy(lvt, i+1, newLVT, i,
newLVT.length - i);
lvt = newLVT;
codeinfo.setLocalVariableTable(newLVT);
i--;
}
}
}
LineNumber[] lnt = codeinfo.getLineNumberTable();
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this)
lnt[i].start = nextByAddr;
if (lnt[i].start == null
|| (i+1 < lnt.length && lnt[i].start == lnt[i+1].start)) {
/* Remove the line number.
* This is very seldom, so we can make it slow */
LineNumber[] newLNT =
new LineNumber[lnt.length - 1];
System.arraycopy(lnt, 0, newLNT, 0, i);
System.arraycopy(lnt, i+1, newLNT, i,
newLNT.length - i);
lnt = newLNT;
codeinfo.setLineNumberTable(newLNT);
i--;
}
}
}
}
/**
* This returns the number of stack entries this instruction
* pushes and pops from the stack. The result fills the given
* array.
*
* @param poppush an array of two ints. The first element will
* get the number of pops, the second the number of pushes.
*/
public void getStackPopPush(int[] poppush)
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
{
byte delta = stackDelta[opcode];
if (delta < 0x40) {
poppush[0] = delta & 7;
poppush[1] = delta >> 3;
} else {
switch (opcode) {
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface: {
Reference ref = (Reference) objData;
MethodType mt = (MethodType) Type.tType(ref.getType());
poppush[1] = mt.getReturnType().stackSize();
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
for (int i = mt.getParameterTypes().length-1; i >= 0; i--)
poppush[0] += mt.getParameterTypes()[i].stackSize();
break;
}
case opc_putfield:
case opc_putstatic: {
Reference ref = (Reference) objData;
poppush[1] = 0;
poppush[0] = Type.tType(ref.getType()).stackSize();
if (opcode == opc_putfield)
poppush[0]++;
break;
}
case opc_getstatic:
case opc_getfield: {
Reference ref = (Reference) objData;
poppush[1] = Type.tType(ref.getType()).stackSize();
poppush[0] = opcode == opc_getfield ? 1 : 0;
break;
}
case opc_multianewarray: {
poppush[1] = 1;
poppush[0] = prevByAddr.intData;
break;
}
default:
throw new jode.AssertError("Unknown Opcode: "+opcode);
}
}
}
public Instruction findMatchingPop() {
int poppush[] = new int[2];
getStackPopPush(poppush);
int count = poppush[1];
Instruction instr = this;
while (true) {
if (instr.succs != null || instr.alwaysJumps)
return null;
instr = instr.nextByAddr;
if (instr.preds != null)
return null;
instr.getStackPopPush(poppush);
if (count == poppush[0])
return instr;
count += poppush[1] - poppush[0];
}
}
public Instruction findMatchingPush() {
int count = 0;
Instruction instr = this;
int poppush[] = new int[2];
while (true) {
if (instr.preds != null)
return null;
instr = instr.prevByAddr;
if (instr == null || instr.succs != null || instr.alwaysJumps)
return null;
instr.getStackPopPush(poppush);
if (count < poppush[1]) {
return count == 0 ? instr : null;
}
count += poppush[0] - poppush[1];
}
}
public String getDescription() {
StringBuffer result = new StringBuffer(String.valueOf(addr))
.append('_').append(Integer.toHexString(hashCode()))
.append(": ").append(opcodeString[opcode]);
switch (opcode) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
case opc_ret:
result.append(" ").append(localSlot);
break;
case opc_iinc:
result.append(" ").append(localSlot).append(" ").append(intData);
break;
case opc_ldc: case opc_ldc2_w:
case opc_getstatic: case opc_getfield:
case opc_putstatic: case opc_putfield:
case opc_invokespecial: case opc_invokestatic: case opc_invokevirtual:
case opc_new:
case opc_checkcast:
case opc_instanceof:
result.append(" ").append(objData);
break;
case opc_anewarray:
case opc_newarray:
result.append(" ").append(((String)objData).substring(1));
break;
case opc_multianewarray:
case opc_invokeinterface:
result.append(" ").append(objData).append(" ").append(intData);
break;
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull:
case opc_goto:
case opc_jsr:
result.append(" ").append(succs[0].addr);
break;
}
return result.toString();
}
public String toString() {
return ""+addr+"_"+Integer.toHexString(hashCode());
}
public final static byte[] stackDelta;
static {
stackDelta = new byte[202];
for (int i=0; i < 202; i++) {
stackDelta[i] = (byte) "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010".charAt(i);
}
}
/* stackDelta contains \100 if stack count of opcode is variable
* \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise
* The above values are extracted from following list with:
* perl -ne'/"(.*)"/ and print $1'
*
* "\000" // nop
* "\010\010\010\010\010\010\010\010" // aconst_null, iconst_m?[0-5]
* "\020\020\010\010\010\020\020" // [lfd]const_[0-2]
* "\010\010\010\010\020" // sipush bipush ldcx
* "\010\020\010\020\010" // [ilfda]load
* "\010\010\010\010"
* "\020\020\020\020"
* "\010\010\010\010"
* "\020\020\020\020"
* "\010\010\010\010"
* "\012\022\012\022\012\012\012\012" // [ilfdabcs]aload
* "\001\002\001\002\001" // [ilfda]store
* "\001\001\001\001"
* "\002\002\002\002"
* "\001\001\001\001"
* "\002\002\002\002"
* "\001\001\001\001"
* "\003\004\003\004\003\003\003\003" // [ilfdabcs]astore
* "\001\002" // pop
* "\021\032\043\042\053\064" // dup2?(_x[12])?
* "\022" // swap
* "\012\024\012\024" // [ilfd]add
* "\012\024\012\024" // [ilfd]sub
* "\012\024\012\024" // [ilfd]mul
* "\012\024\012\024" // [ilfd]div
* "\012\024\012\024" // [ilfd]rem
* "\011\022\011\022" // [ilfd]neg
* "\012\023\012\023\012\023" // [il]u?sh[lr]
* "\012\024\012\024\012\024" // [il](and|or|xor)
* "\000" // opc_iinc
* "\021\011\021" // i2[lfd]
* "\012\012\022" // l2[ifd]
* "\011\021\021" // f2[ild]
* "\012\022\012" // d2[ilf]
* "\011\011\011" // i2[bcs]
* "\014\012\012\014\014" // [lfd]cmp.?
* "\001\001\001\001\001\001" // if..
* "\002\002\002\002\002\002" // if_icmp..
* "\002\002" // if_acmp..
* "\000\010\000\001\001" // goto,jsr,ret, .*switch
* "\001\002\001\002\001\000" // [ilfda]?return
* "\100\100\100\100" // (get/put)(static|field)
* "\100\100\100\100" // invoke.*
* "\177\010\011\011\011" // 186 - 190
* "\001\011\011\001\001" // 191 - 195
* "\177\100\001\001" // 196 - 199
* "\000\010" // goto_w, jsr_w
*/
}

@ -1,29 +0,0 @@
/* LineNumber Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
/**
* A simple class containing the info of the LineNumberTable
*/
public class LineNumber {
public Instruction start;
public int linenr;
}

@ -1,225 +0,0 @@
/* MethodInfo Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.io.*;
import java.lang.reflect.Modifier;
public class MethodInfo extends BinaryInfo {
ClassInfo clazzInfo;
int modifier;
String name;
String typeSig;
BytecodeInfo bytecode;
String[] exceptions;
boolean syntheticFlag;
boolean deprecatedFlag;
public MethodInfo(ClassInfo ci) {
clazzInfo = ci;
}
public MethodInfo(ClassInfo ci,
String name, String typeSig, int modifier) {
this.clazzInfo = ci;
this.name = name;
this.typeSig = typeSig;
this.modifier = modifier;
}
protected void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("Code")) {
bytecode = new BytecodeInfo(this);
bytecode.read(cp, input);
} else if ((howMuch & ALL_ATTRIBUTES) != 0
&& name.equals("Exceptions")) {
int count = input.readUnsignedShort();
exceptions = new String[count];
for (int i=0; i< count; i++)
exceptions[i] = cp.getClassName(input.readUnsignedShort());
if (length != 2 * (count + 1))
throw new ClassFormatException
("Exceptions attribute has wrong length");
} else if (name.equals("Synthetic")) {
syntheticFlag = true;
if (length != 0)
throw new ClassFormatException
("Synthetic attribute has wrong length");
} else if (name.equals("Deprecated")) {
deprecatedFlag = true;
if (length != 0)
throw new ClassFormatException
("Deprecated attribute has wrong length");
} else
super.readAttribute(name, length, cp, input, howMuch);
}
public void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort());
typeSig = constantPool.getUTF8(input.readUnsignedShort());
readAttributes(constantPool, input, howMuch);
}
public void reserveSmallConstants(GrowableConstantPool gcp) {
if (bytecode != null)
bytecode.reserveSmallConstants(gcp);
}
public void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name);
gcp.putUTF8(typeSig);
if (bytecode != null) {
gcp.putUTF8("Code");
bytecode.prepareWriting(gcp);
}
if (exceptions != null) {
gcp.putUTF8("Exceptions");
for (int i=0; i< exceptions.length; i++)
gcp.putClassName(exceptions[i]);
}
if (syntheticFlag)
gcp.putUTF8("Synthetic");
if (deprecatedFlag)
gcp.putUTF8("Deprecated");
prepareAttributes(gcp);
}
protected int getKnownAttributeCount() {
int count = 0;
if (bytecode != null)
count++;
if (exceptions != null)
count++;
if (syntheticFlag)
count++;
if (deprecatedFlag)
count++;
return count;
}
public void writeKnownAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
if (bytecode != null) {
output.writeShort(gcp.putUTF8("Code"));
output.writeInt(bytecode.getSize());
bytecode.write(gcp, output);
}
if (exceptions != null) {
int count = exceptions.length;
output.writeShort(gcp.putUTF8("Exceptions"));
output.writeInt(2 + count * 2);
output.writeShort(count);
for (int i=0; i< count; i++)
output.writeShort(gcp.putClassName(exceptions[i]));
}
if (syntheticFlag) {
output.writeShort(gcp.putUTF8("Synthetic"));
output.writeInt(0);
}
if (deprecatedFlag) {
output.writeShort(gcp.putUTF8("Deprecated"));
output.writeInt(0);
}
}
public void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name));
output.writeShort(constantPool.putUTF8(typeSig));
writeAttributes(constantPool, output);
}
public ClassInfo getClazzInfo() {
return clazzInfo;
}
public String getName() {
return name;
}
public String getType() {
return typeSig;
}
public int getModifiers() {
return modifier;
}
public boolean isStatic() {
return Modifier.isStatic(modifier);
}
public boolean isSynthetic() {
return syntheticFlag;
}
public boolean isDeprecated() {
return deprecatedFlag;
}
public BytecodeInfo getBytecode() {
return bytecode;
}
public String[] getExceptions() {
return exceptions;
}
public void setName(String newName) {
name = newName;
}
public void setType(String newType) {
typeSig = newType;
}
public void setModifiers(int newModifier) {
modifier = newModifier;
}
public void setSynthetic(boolean flag) {
syntheticFlag = flag;
}
public void setDeprecated(boolean flag) {
deprecatedFlag = flag;
}
public void setBytecode(BytecodeInfo newBytecode) {
bytecode = newBytecode;
}
public void setExceptions(String[] newExceptions) {
exceptions = newExceptions;
}
public String toString() {
return "Method "+Modifier.toString(modifier)+" "+
typeSig + " " + clazzInfo.getName() + "."+ name;
}
}

@ -1,92 +0,0 @@
/* Reference Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///#endif
import java.util.*;
/**
* This class represents a field or method reference.
*/
public class Reference {
/**
* The reference string. This is the class name, the member name and
* the member type, all separated by a space.
*/
private final String sig;
/**
* The position of the first and second space in the reference
* string.
*/
private final int firstSpace, secondSpace;
///#ifdef JDK12
/// private static final Map references = new HashMap();
///#else
private static final Hashtable references = new Hashtable();
///#endif
public static Reference getReference(String className,
String name, String type) {
String sig = className+" "+name+" "+type;
///#ifdef JDK12
/// WeakReference ref = (WeakReference) references.get(sig);
/// Reference reference = (ref == null) ? null : (Reference) ref.get();
///#else
Reference reference = (Reference) references.get(sig);
///#endif
if (reference == null) {
sig = sig.intern();
int firstSpace = className.length();
int secondSpace = firstSpace + name.length() + 1;
reference = new Reference(sig, firstSpace, secondSpace);
///#ifdef JDK12
/// references.put(sig, new WeakReference(reference));
///#else
references.put(sig, reference);
///#endif
}
return reference;
}
private Reference(String sig, int first, int second) {
this.sig = sig;
this.firstSpace = first;
this.secondSpace = second;
}
public String getClazz() {
return sig.substring(0, firstSpace);
}
public String getName() {
return sig.substring(firstSpace + 1, secondSpace);
}
public String getType() {
return sig.substring(secondSpace + 1);
}
public String toString() {
return sig;
}
}

@ -1,506 +0,0 @@
/* SearchPath Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import java.io.*;
import java.net.*;
import java.util.zip.*;
import java.util.*;
import jode.GlobalOptions;
/**
* This class represents a path of multiple directories and/or zip files,
* where we can search for file names.
*
* @author Jochen Hoenicke
*/
public class SearchPath {
/**
* We need a different pathSeparatorChar, since ':' (used for most
* UNIX System, is used a protocol separator in URLs.
*/
public static final char pathSeparatorChar = ',';
URL[] bases;
byte[][] urlzips;
File[] dirs;
ZipFile[] zips;
String[] zipDirs;
Hashtable[] zipEntries;
private static void addEntry(Hashtable entries, String name) {
String dir = "";
int pathsep = name.lastIndexOf("/");
if (pathsep != -1) {
dir = name.substring(0, pathsep);
name = name.substring(pathsep+1);
}
Vector dirContent = (Vector) entries.get(dir);
if (dirContent == null) {
dirContent = new Vector();
entries.put(dir, dirContent);
if (dir != "")
addEntry(entries, dir);
}
dirContent.addElement(name);
}
private void fillZipEntries(int nr) {
Enumeration zipEnum = zips[nr].entries();
zipEntries[nr] = new Hashtable();
while (zipEnum.hasMoreElements()) {
ZipEntry ze = (ZipEntry) zipEnum.nextElement();
String name = ze.getName();
// if (name.charAt(0) == '/')
// name = name.substring(1);
if (zipDirs[nr] != null) {
if (!name.startsWith(zipDirs[nr]))
continue;
name = name.substring(zipDirs[nr].length());
}
if (!ze.isDirectory() && name.endsWith(".class"))
addEntry(zipEntries[nr], name);
}
}
private void readURLZip(int nr, URLConnection conn) {
int length = conn.getContentLength();
if (length <= 0)
// Give a approximation if length is unknown
length = 10240;
else
// Increase the length by one, so we hopefully don't need
// to grow the array later (we need a little overshot to
// know when the end is reached).
length++;
urlzips[nr] = new byte[length];
try {
InputStream is = conn.getInputStream();
int pos = 0;
for (;;) {
// This is ugly, is.available() may return zero even
// if there are more bytes.
int avail = Math.max(is.available(), 1);
if (pos + is.available() > urlzips[nr].length) {
// grow the byte array.
byte[] newarr = new byte
[Math.max(2*urlzips[nr].length, pos + is.available())];
System.arraycopy(urlzips[nr], 0, newarr, 0, pos);
urlzips[nr] = newarr;
}
int count = is.read(urlzips[nr], pos, urlzips[nr].length-pos);
if (count == -1)
break;
pos += count;
}
if (pos < urlzips[nr].length) {
// shrink the byte array again.
byte[] newarr = new byte[pos];
System.arraycopy(urlzips[nr], 0, newarr, 0, pos);
urlzips[nr] = newarr;
}
} catch (IOException ex) {
GlobalOptions.err.println("IOException while reading "
+"remote zip file "+bases[nr]);
// disable entry
bases[nr] = null;
urlzips[nr] = null;
return;
}
try {
// fill entries into hash table
ZipInputStream zis = new ZipInputStream
(new ByteArrayInputStream(urlzips[nr]));
zipEntries[nr] = new Hashtable();
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
String name = ze.getName();
// if (name.charAt(0) == '/')
// name = name.substring(1);
if (zipDirs[nr] != null) {
if (!name.startsWith(zipDirs[nr]))
continue;
name = name.substring(zipDirs[nr].length());
}
if (!ze.isDirectory() && name.endsWith(".class"))
addEntry(zipEntries[nr], name);
zis.closeEntry();
}
zis.close();
} catch (IOException ex) {
GlobalOptions.err.println("Remote zip file "+bases[nr]
+" is corrupted.");
// disable entry
bases[nr] = null;
urlzips[nr] = null;
zipEntries[nr] = null;
return;
}
}
/**
* Creates a new search path for the given path.
* @param path The path where we should search for files. They
* should be separated by the system dependent pathSeparator. The
* entries may also be zip or jar files.
*/
public SearchPath(String path) {
StringTokenizer tokenizer =
new StringTokenizer(path,
String.valueOf(pathSeparatorChar));
int length = tokenizer.countTokens();
bases = new URL[length];
urlzips = new byte[length][];
dirs = new File[length];
zips = new ZipFile[length];
zipEntries = new Hashtable[length];
zipDirs = new String[length];
for (int i=0; i< length; i++) {
String token = tokenizer.nextToken();
boolean mustBeJar = false;
// We handle jar URL's ourself.
if (token.startsWith("jar:")) {
int index = 0;
do {
index = token.indexOf('!', index);
} while (token.charAt(index+1) != '/');
zipDirs[i] = token.substring(index+2);
if (!zipDirs[i].endsWith("/"))
zipDirs[i] = zipDirs[i] + "/";
token = token.substring(4, index);
mustBeJar = true;
}
int index = token.indexOf(':');
if (index != -1 && index < token.length()-2
&& token.charAt(index+1) == '/'
&& token.charAt(index+2) == '/') {
// This looks like an URL.
try {
bases[i] = new URL(token);
try {
URLConnection connection = bases[i].openConnection();
if (mustBeJar
|| token.endsWith(".zip") || token.endsWith(".jar")
|| connection.getContentType().endsWith("/zip")) {
// This is a zip file. Read it into memory.
readURLZip(i, connection);
}
} catch (IOException ex) {
// ignore
} catch (SecurityException ex) {
GlobalOptions.err.println("Warning: Security exception "
+"while accessing "
+bases[i]+".");
}
} catch (MalformedURLException ex) {
/* disable entry */
bases[i] = null;
dirs[i] = null;
}
} else {
try {
dirs[i] = new File(token);
if (mustBeJar || !dirs[i].isDirectory()) {
try {
zips[i] = new ZipFile(dirs[i]);
} catch (java.io.IOException ex) {
/* disable this entry */
dirs[i] = null;
}
}
} catch (SecurityException ex) {
/* disable this entry */
GlobalOptions.err.println("Warning: SecurityException while"
+ " accessing " + token);
dirs[i] = null;
}
}
}
}
public boolean exists(String filename) {
for (int i=0; i<dirs.length; i++) {
if (zipEntries[i] != null) {
if (zipEntries[i].get(filename) != null)
return true;
String dir = "";
String name = filename;
int index = filename.lastIndexOf('/');
if (index >= 0) {
dir = filename.substring(0, index);
name = filename.substring(index+1);
}
Vector directory = (Vector)zipEntries[i].get(dir);
if (directory != null && directory.contains(name))
return true;
continue;
}
if (bases[i] != null) {
try {
URL url = new URL(bases[i], filename);
URLConnection conn = url.openConnection();
conn.connect();
conn.getInputStream().close();
return true;
} catch (IOException ex) {
/* ignore */
}
continue;
}
if (dirs[i] == null)
continue;
if (zips[i] != null) {
String fullname = zipDirs[i] != null
? zipDirs[i] + filename : filename;
ZipEntry ze = zips[i].getEntry(fullname);
if (ze != null)
return true;
} else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try {
File f = new File(dirs[i], filename);
if (f.exists())
return true;
} catch (SecurityException ex) {
/* ignore and take next element */
}
}
}
return false;
}
/**
* Searches for a file in the search path.
* @param filename the filename. The path components should be separated
* by <code>/</code>.
* @return An InputStream for the file.
*/
public InputStream getFile(String filename) throws IOException {
for (int i=0; i<dirs.length; i++) {
if (urlzips[i] != null) {
ZipInputStream zis = new ZipInputStream
(new ByteArrayInputStream(urlzips[i]));
ZipEntry ze;
String fullname = zipDirs[i] != null
? zipDirs[i] + filename : filename;
while ((ze = zis.getNextEntry()) != null) {
if (ze.getName().equals(fullname)) {
///#ifdef JDK11
// The skip method in jdk1.1.7 ZipInputStream
// is buggy. We return a wrapper that fixes
// this.
return new FilterInputStream(zis) {
private byte[] tmpbuf = new byte[512];
public long skip(long n) throws IOException {
long skipped = 0;
while (n > 0) {
int count = read(tmpbuf, 0,
(int)Math.min(n, 512L));
if (count == -1)
return skipped;
skipped += count;
n -= count;
}
return skipped;
}
};
///#else
/// return zis;
///#endif
}
zis.closeEntry();
}
continue;
}
if (bases[i] != null) {
try {
URL url = new URL(bases[i], filename);
URLConnection conn = url.openConnection();
conn.setAllowUserInteraction(true);
return conn.getInputStream();
} catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException"
+" while accessing "
+bases[i]+filename);
ex.printStackTrace(GlobalOptions.err);
/* ignore and take next element */
} catch (FileNotFoundException ex) {
/* ignore and take next element */
}
continue;
}
if (dirs[i] == null)
continue;
if (zips[i] != null) {
String fullname = zipDirs[i] != null
? zipDirs[i] + filename : filename;
ZipEntry ze = zips[i].getEntry(fullname);
if (ze != null)
return zips[i].getInputStream(ze);
} else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try {
File f = new File(dirs[i], filename);
if (f.exists())
return new FileInputStream(f);
} catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException"
+" while accessing "
+dirs[i]+filename);
/* ignore and take next element */
}
}
}
throw new FileNotFoundException(filename);
}
/**
* Searches for a filename in the search path and tells if it is a
* directory.
* @param filename the filename. The path components should be separated
* by <code>/</code>.
* @return true, if filename exists and is a directory, false otherwise.
*/
public boolean isDirectory(String filename) {
for (int i=0; i<dirs.length; i++) {
if (dirs[i] == null)
continue;
if (zips[i] != null && zipEntries[i] == null)
fillZipEntries(i);
if (zipEntries[i] != null) {
if (zipEntries[i].containsKey(filename))
return true;
} else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try {
File f = new File(dirs[i], filename);
if (f.exists())
return f.isDirectory();
} catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException"
+" while accessing "
+dirs[i]+filename);
}
}
}
return false;
}
/**
* Searches for all files in the given directory.
* @param dirName the directory name. The path components should
* be separated by <code>/</code>.
* @return An enumeration with all files/directories in the given
* directory. */
public Enumeration listFiles(final String dirName) {
return new Enumeration() {
int pathNr;
Enumeration zipEnum;
int fileNr;
String localDirName =
(java.io.File.separatorChar != '/')
? dirName.replace('/', java.io.File.separatorChar)
: dirName;
File currentDir;
String[] files;
public String findNextFile() {
while (true) {
if (zipEnum != null) {
while (zipEnum.hasMoreElements()) {
return (String) zipEnum.nextElement();
}
zipEnum = null;
}
if (files != null) {
while (fileNr < files.length) {
String name = files[fileNr++];
if (name.endsWith(".class")) {
return name;
} else if (name.indexOf(".") == -1) {
/* ignore directories containing a dot.
* they can't be a package directory.
*/
File f = new File(currentDir, name);
if (f.exists() && f.isDirectory())
return name;
}
}
files = null;
}
if (pathNr == dirs.length)
return null;
if (zips[pathNr] != null && zipEntries[pathNr] == null)
fillZipEntries(pathNr);
if (zipEntries[pathNr] != null) {
Vector entries =
(Vector) zipEntries[pathNr].get(dirName);
if (entries != null)
zipEnum = entries.elements();
} else if (dirs[pathNr] != null) {
try {
File f = new File(dirs[pathNr], localDirName);
if (f.exists() && f.isDirectory()) {
currentDir = f;
files = f.list();
}
} catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException"
+" while accessing "
+dirs[pathNr]+localDirName);
/* ignore and take next element */
}
}
pathNr++;
}
}
String nextName;
public boolean hasMoreElements() {
return (nextName != null
|| (nextName = findNextFile()) != null);
}
public Object nextElement() {
if (nextName == null)
return findNextFile();
else {
String result = nextName;
nextName = null;
return result;
}
}
};
}
}

@ -1,513 +0,0 @@
/* ClassAnalyzer Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.GlobalOptions;
import jode.Decompiler;
import jode.type.*;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.MethodInfo;
import jode.bytecode.InnerClassInfo;
import jode.bytecode.ConstantPool;
import jode.expr.Expression;
import jode.expr.ThisOperator;
import jode.expr.ConstructorOperator;
import jode.flow.TransformConstructors;
import jode.flow.StructuredBlock;
import java.util.NoSuchElementException;
import java.util.Vector;
import java.util.Enumeration;
import java.lang.reflect.Modifier;
public class ClassAnalyzer
implements Analyzer, Scope, Declarable, ClassDeclarer
{
ImportHandler imports;
ClassInfo clazz;
ClassDeclarer parent;
String name;
StructuredBlock[] blockInitializers;
FieldAnalyzer[] fields;
MethodAnalyzer[] methods;
ClassAnalyzer[] inners;
int modifiers;
TransformConstructors constrAna;
MethodAnalyzer staticConstructor;
MethodAnalyzer[] constructors;
Expression[] outerValues;
boolean jikesAnonymousInner = false;
Vector ovListeners;
public ClassAnalyzer(ClassDeclarer parent,
ClassInfo clazz, ImportHandler imports,
Expression[] outerValues)
{
clazz.loadInfo(clazz.FULLINFO);
this.parent = parent;
this.clazz = clazz;
this.imports = imports;
this.outerValues = outerValues;
modifiers = clazz.getModifiers();
name = clazz.getName();
if (parent != null) {
InnerClassInfo[] outerInfos = clazz.getOuterClasses();
if (outerInfos[0].outer == null || outerInfos[0].name == null) {
if (parent instanceof ClassAnalyzer)
throw new jode.AssertError
("ClassInfo Attributes are inconsistent: "
+ clazz.getName());
} else {
if (!(parent instanceof ClassAnalyzer)
|| !(((ClassAnalyzer) parent).clazz.getName()
.equals(outerInfos[0].outer))
|| outerInfos[0].name == null)
throw new jode.AssertError
("ClassInfo Attributes are inconsistent: "
+ clazz.getName());
}
name = outerInfos[0].name;
modifiers = outerInfos[0].modifiers;
} else {
name = clazz.getName();
int dot = name.lastIndexOf('.');
if (dot >= 0)
name = name.substring(dot+1);
}
}
public ClassAnalyzer(ClassDeclarer parent,
ClassInfo clazz, ImportHandler imports)
{
this(parent, clazz, imports, null);
}
public ClassAnalyzer(ClassInfo clazz, ImportHandler imports)
{
this(null, clazz, imports);
}
public final boolean isStatic() {
return Modifier.isStatic(modifiers);
}
public FieldAnalyzer getField(String fieldName, Type fieldType) {
for (int i=0; i< fields.length; i++) {
if (fields[i].getName().equals(fieldName)
&& fields[i].getType().equals(fieldType))
return fields[i];
}
throw new NoSuchElementException
("Field "+fieldType+" "+clazz.getName()+"."+fieldName);
}
public MethodAnalyzer getMethod(String methodName, MethodType methodType) {
for (int i=0; i< methods.length; i++) {
if (methods[i].getName().equals(methodName)
&& methods[i].getType().equals(methodType))
return methods[i];
}
return null;
}
public int getModifiers() {
return modifiers;
}
public ClassDeclarer getParent() {
return parent;
}
public void setParent(ClassDeclarer newParent) {
this.parent = newParent;
}
public ClassInfo getClazz() {
return clazz;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Expression[] getOuterValues() {
return outerValues;
}
public void addBlockInitializer(FieldAnalyzer nextField,
StructuredBlock initializer) {
int index = 0;
while (index < fields.length) {
if (fields[index] == nextField)
break;
index++;
}
blockInitializers[index] = initializer;
}
public void addOuterValueListener(OuterValueListener l) {
if (ovListeners == null)
ovListeners = new Vector();
ovListeners.addElement(l);
}
public void shrinkOuterValues(int newCount) {
if (newCount >= outerValues.length)
return;
Expression[] newOuter = new Expression[newCount];
System.arraycopy(outerValues, 0, newOuter, 0, newCount);
outerValues = newOuter;
if (ovListeners != null) {
for (Enumeration enum = ovListeners.elements();
enum.hasMoreElements();)
((OuterValueListener) enum.nextElement()
).shrinkingOuterValues(this, newCount);
}
}
/**
* Jikes gives the outer class reference in an unusual place (as last
* parameter) for anonymous classes that extends an inner (or method
* scope) class. This method tells if this is such a class.
*/
public void setJikesAnonymousInner(boolean value) {
jikesAnonymousInner = value;
}
/**
* Jikes gives the outer class reference in an unusual place (as last
* parameter) for anonymous classes that extends an inner (or method
* scope) class. This method tells if this is such a class.
*/
public boolean isJikesAnonymousInner() {
return jikesAnonymousInner;
}
public void analyze() {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("Class " + clazz.getName());
imports.useClass(clazz);
if (clazz.getSuperclass() != null)
imports.useClass(clazz.getSuperclass());
ClassInfo[] interfaces = clazz.getInterfaces();
for (int j=0; j< interfaces.length; j++)
imports.useClass(interfaces[j]);
FieldInfo[] finfos = clazz.getFields();
MethodInfo[] minfos = clazz.getMethods();
InnerClassInfo[] innerInfos = clazz.getInnerClasses();
if (finfos == null) {
/* This means that the class could not be loaded.
* give up.
*/
return;
}
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0
&& innerInfos != null) {
Expression[] outerThis = new Expression[] {
new ThisOperator(clazz)
};
int innerCount = innerInfos.length;
inners = new ClassAnalyzer[innerCount];
for (int i=0; i < innerCount; i++) {
ClassInfo ci = ClassInfo.forName(innerInfos[i].inner);
inners[i] = new ClassAnalyzer
(this, ci, imports,
Modifier.isStatic(innerInfos[i].modifiers)
? null : outerThis);
}
} else
inners = new ClassAnalyzer[0];
fields = new FieldAnalyzer[finfos.length];
methods = new MethodAnalyzer[minfos.length];
blockInitializers = new StructuredBlock[finfos.length+1];
for (int j=0; j < finfos.length; j++)
fields[j] = new FieldAnalyzer(this, finfos[j], imports);
staticConstructor = null;
java.util.Vector constrVector = new java.util.Vector();
for (int j=0; j < methods.length; j++) {
methods[j] = new MethodAnalyzer(this, minfos[j], imports);
if (methods[j].isConstructor()) {
if (methods[j].isStatic())
staticConstructor = methods[j];
else
constrVector.addElement(methods[j]);
}
}
// First analyze fields
for (int j=0; j < fields.length; j++)
fields[j].analyze();
// now analyze constructors and synthetic fields:
constrAna = null;
constructors = new MethodAnalyzer[constrVector.size()];
if (constructors.length > 0) {
constrVector.copyInto(constructors);
for (int j=0; j< constructors.length; j++)
constructors[j].analyze();
constrAna = new TransformConstructors(this, false, constructors);
constrAna.initSyntheticFields();
}
// Now analyze remaining methods.
for (int j=0; j < methods.length; j++) {
if (methods[j].isStatic() || !methods[j].isConstructor())
methods[j].analyze();
}
}
public void analyzeInnerClasses() {
// Now analyze the inner classes.
for (int j=0; j < inners.length; j++) {
inners[j].analyze();
inners[j].analyzeInnerClasses();
}
// Now analyze the method scoped classes.
for (int j=0; j < methods.length; j++)
methods[j].analyzeInnerClasses();
}
public void makeDeclaration() {
// Finally anlyze the remaining field initializers.
if (constrAna != null)
constrAna.transform();
if (staticConstructor != null) {
new TransformConstructors
(this, true, new MethodAnalyzer[] { staticConstructor })
.transform();
}
for (int j=0; j < fields.length; j++)
fields[j].makeDeclaration();
for (int j=0; j < inners.length; j++)
inners[j].makeDeclaration();
for (int j=0; j < methods.length; j++)
methods[j].makeDeclaration();
}
public void dumpDeclaration(TabbedPrintWriter writer)
throws java.io.IOException
{
dumpSource(writer);
}
public void dumpBlock(TabbedPrintWriter writer) throws java.io.IOException
{
writer.pushScope(this);
boolean needFieldNewLine = false;
boolean needNewLine = false;
for (int i=0; i< fields.length; i++) {
if (blockInitializers[i] != null) {
if (needNewLine)
writer.println("");
blockInitializers[i].dumpSource(writer);
needFieldNewLine = needNewLine = true;
}
if (fields[i].skipWriting())
continue;
if (needFieldNewLine)
writer.println("");
fields[i].dumpSource(writer);
needNewLine = true;
}
if (blockInitializers[fields.length] != null) {
if (needNewLine)
writer.println("");
writer.openBrace();
writer.tab();
blockInitializers[fields.length].dumpSource(writer);
writer.untab();
writer.closeBrace();
needNewLine = true;
}
for (int i=0; i< inners.length; i++) {
if (needNewLine)
writer.println("");
inners[i].dumpSource(writer);
needNewLine = true;
}
for (int i=0; i< methods.length; i++) {
if (methods[i].skipWriting())
continue;
if (needNewLine)
writer.println("");
methods[i].dumpSource(writer);
needNewLine = true;
}
writer.popScope();
}
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException
{
if (fields == null) {
/* This means that the class could not be loaded.
* give up.
*/
return;
}
int modifiedModifiers = modifiers & ~Modifier.SYNCHRONIZED;
if (clazz.isInterface())
modifiedModifiers &= ~Modifier.ABSTRACT;
if (parent instanceof MethodAnalyzer) {
/* method scope classes are implicitly private */
modifiedModifiers &= ~Modifier.PRIVATE;
/* anonymous classes are implicitly final */
if (name == null)
modifiedModifiers &= ~Modifier.FINAL;
}
String modif = Modifier.toString(modifiedModifiers);
if (modif.length() > 0)
writer.print(modif + " ");
/*interface is in modif*/
if (!clazz.isInterface())
writer.print("class ");
writer.println(name);
writer.tab();
ClassInfo superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz != ClassInfo.javaLangObject) {
writer.println("extends " + (writer.getClassString
(superClazz, Scope.CLASSNAME)));
}
ClassInfo[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.print(clazz.isInterface() ? "extends " : "implements ");
for (int i=0; i < interfaces.length; i++) {
if (i > 0)
writer.print(", ");
writer.print(writer.getClassString
(interfaces[i], Scope.CLASSNAME));
}
writer.println("");
}
writer.untab();
writer.openBrace();
writer.tab();
dumpBlock(writer);
writer.untab();
if (parent instanceof MethodAnalyzer) {
/* This is a method scope class */
writer.closeBraceNoSpace();
} else
writer.closeBrace();
}
public void dumpJavaFile(TabbedPrintWriter writer)
throws java.io.IOException {
imports.init(clazz.getName());
LocalInfo.init();
analyze();
analyzeInnerClasses();
makeDeclaration();
imports.dumpHeader(writer);
dumpSource(writer);
}
public boolean isScopeOf(Object obj, int scopeType) {
if (clazz.equals(obj) && scopeType == CLASSSCOPE)
return true;
return false;
}
static int serialnr = 0;
public void makeNameUnique() {
name = name + "_" + serialnr++ + "_";
}
public boolean conflicts(String name, int usageType) {
ClassInfo info = clazz;
while (info != null) {
if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) {
MethodInfo[] minfos = info.getMethods();
for (int i = 0; i< minfos.length; i++)
if (minfos[i].getName().equals(name))
return true;
}
if (usageType == NOSUPERFIELDNAME || usageType == FIELDNAME
|| usageType == AMBIGUOUSNAME) {
FieldInfo[] finfos = info.getFields();
for (int i=0; i < finfos.length; i++) {
if (finfos[i].getName().equals(name))
return true;
}
}
if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) {
InnerClassInfo[] iinfos = info.getInnerClasses();
if (iinfos != null) {
for (int i=0; i < iinfos.length; i++) {
if (iinfos[i].name.equals(name))
return true;
}
}
}
if (usageType == NOSUPERFIELDNAME
|| usageType == NOSUPERMETHODNAME)
return false;
info = info.getSuperclass();
}
return false;
}
/**
* Get the class analyzer for the given class info. This searches
* the method scoped/anonymous classes in this method and all
* outer methods and the outer classes for the class analyzer.
* @param cinfo the classinfo for which the analyzer is searched.
* @return the class analyzer, or null if there is not an outer
* class that equals cinfo, and not a method scope/inner class in
* an outer method.
*/
public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) {
if (cinfo == getClazz())
return this;
if (parent == null)
return null;
return getParent().getClassAnalyzer(cinfo);
}
public void addClassAnalyzer(ClassAnalyzer clazzAna) {
if (parent != null)
parent.addClassAnalyzer(clazzAna);
}
public String toString() {
return getClass().getName()+"["+getClazz()+"]";
}
}

@ -1,120 +0,0 @@
/* DeadCodeAnalysis Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.Instruction;
import jode.bytecode.Handler;
public class DeadCodeAnalysis {
private final static Object reachable = new Integer(1);
private final static Object reachChanged = new Integer(2);
private static void propagateReachability(Instruction firstInstr,
Instruction reachInstr) {
if (reachInstr.tmpInfo != null)
return;
reachInstr.tmpInfo = reachChanged;
boolean changed;
do {
changed = false;
for (Instruction instr = firstInstr;
instr != null; instr = instr.nextByAddr) {
if (instr.tmpInfo == reachChanged) {
changed = true;
instr.tmpInfo = reachable;
if (instr.succs != null)
for (int i=0; i< instr.succs.length; i++)
if (instr.succs[i].tmpInfo == null)
instr.succs[i].tmpInfo = reachChanged;
if (!instr.alwaysJumps && instr.nextByAddr != null)
if (instr.nextByAddr.tmpInfo == null)
instr.nextByAddr.tmpInfo = reachChanged;
/*XXX code after jsr reachable iff ret is reachable...*/
if (instr.opcode == Opcodes.opc_jsr)
if (instr.nextByAddr.tmpInfo == null)
instr.nextByAddr.tmpInfo = reachChanged;
}
}
} while (changed);
}
public static void removeDeadCode(BytecodeInfo code) {
propagateReachability(code.getFirstInstr(), code.getFirstInstr());
Handler[] handlers = code.getExceptionHandlers();
boolean changed;
do {
changed = false;
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher.tmpInfo == null) {
/* check if the try block is somewhere reachable
* and mark the catcher as reachable then.
*/
for (Instruction instr = handlers[i].start;
instr != null; instr = instr.nextByAddr) {
if (instr.tmpInfo != null) {
propagateReachability(code.getFirstInstr(),
handlers[i].catcher);
changed = true;
break;
}
if (instr == handlers[i].end)
break;
}
}
}
} while (changed);
/* Now remove the dead code */
Instruction nextInstr;
for (Instruction instr = code.getFirstInstr();
instr != null; instr = nextInstr) {
nextInstr = instr.nextByAddr;
if (instr.tmpInfo == null) {
instr.removeInstruction();
/* adjust length, since someone may rely on this */
/* first block is always reachable, so prevByAddr != null */
instr.prevByAddr.length += instr.length;
}
}
for (int i=0; i< handlers.length; i++) {
/* A handler is not reachable iff the catcher is not reachable */
if (handlers[i].catcher.tmpInfo == null) {
/* This is very seldom, so we can make it slow */
Handler[] newHandlers = new Handler[handlers.length - 1];
System.arraycopy(handlers, 0, newHandlers, 0, i);
System.arraycopy(handlers, i+1, newHandlers, i,
handlers.length - (i+1));
handlers = newHandlers;
code.setExceptionHandlers(newHandlers);
i--;
} else {
/* This works! */
while (handlers[i].start.tmpInfo == null)
handlers[i].start = handlers[i].start.nextByAddr;
while (handlers[i].end.tmpInfo == null)
handlers[i].end = handlers[i].end.prevByAddr;
}
}
/* clean up tmpInfo */
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr)
instr.tmpInfo = null;
}
}

@ -1,45 +0,0 @@
/* LocalVarEntry Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.type.Type;
public class LocalVarEntry {
String name;
Type type;
int startAddr;
int endAddr;
LocalVarEntry next;
public LocalVarEntry(int s, int e, String n, Type t) {
startAddr = s;
endAddr = e;
name = n;
type = t;
next = null;
}
public String getName() {
return name;
}
public Type getType() {
return type;
}
}

@ -1,79 +0,0 @@
/* LocalVariableRangeList Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.GlobalOptions;
import jode.type.Type;
public class LocalVariableRangeList {
LocalVarEntry list = null;
LocalVariableRangeList() {
}
private void add(LocalVarEntry li) {
LocalVarEntry prev = null;
LocalVarEntry next = list;
while (next != null && next.endAddr < li.startAddr) {
prev = next;
next = next.next;
}
/* prev.endAddr < li.startAddr <= next.endAddr
*/
if (next != null && li.endAddr >= next.startAddr) {
if (next.type.equals(li.type)
&& next.name.equals(li.name)) {
/* Same type, same name and overlapping range.
* This is the same local: extend next to the common
* range and don't add li.
*/
next.startAddr = Math.min(next.startAddr, li.startAddr);
next.endAddr = Math.max(next.endAddr, li.endAddr);
return;
}
GlobalOptions.err.println("warning: non disjoint locals");
}
li.next = next;
if (prev == null)
list = li;
else
prev.next = li;
}
private LocalVarEntry find(int addr) {
LocalVarEntry li = list;
while (li != null && li.endAddr < addr)
li = li.next;
if (li == null || li.startAddr > addr) {
return null;
}
return li;
}
public void addLocal(int startAddr, int endAddr,
String name, Type type) {
LocalVarEntry li = new LocalVarEntry(startAddr,endAddr,name,type);
add (li);
}
public LocalVarEntry getInfo(int addr) {
return find(addr);
}
}

@ -1,44 +0,0 @@
/* LocalVariableTable Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import java.io.*;
import jode.Decompiler;
import jode.type.Type;
import jode.bytecode.LocalVariableInfo;
public class LocalVariableTable {
LocalVariableRangeList[] locals;
public LocalVariableTable(int maxLocals, LocalVariableInfo[] lvt) {
locals = new LocalVariableRangeList[maxLocals];
for (int i=0; i < maxLocals; i++)
locals[i] = new LocalVariableRangeList();
for (int i=0; i<lvt.length; i++)
locals[lvt[i].slot].addLocal(lvt[i].start.addr, lvt[i].end.addr,
lvt[i].name, Type.tType(lvt[i].type));
}
public LocalVarEntry getLocal(int slot, int addr)
throws ArrayIndexOutOfBoundsException
{
return locals[slot].getInfo(addr);
}
}

File diff suppressed because it is too large Load Diff

@ -1,389 +0,0 @@
/* Opcodes Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.type.Type;
import jode.type.IntegerType;
import jode.type.MethodType;
import jode.expr.*;
import jode.flow.*;
import jode.bytecode.*;
import java.io.*;
import java.util.Vector;
/**
* This is an abstract class which creates flow blocks for the
* opcodes in a byte stream.
*/
public abstract class Opcodes implements jode.bytecode.Opcodes {
private final static Type tIntHint
= new IntegerType(IntegerType.IT_I,
IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S);
private final static Type tBoolIntHint
= new IntegerType(IntegerType.IT_I
| IntegerType.IT_Z,
IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S
| IntegerType.IT_Z);
private final static int LOCAL_TYPES = 0;
private final static int ARRAY_TYPES = 1;
private final static int UNARY_TYPES = 2;
private final static int I2BCS_TYPES = 3;
private final static int BIN_TYPES = 4;
private final static int ZBIN_TYPES = 5;
private final static Type types[][] = {
// Local types
{ Type.tBoolUInt, Type.tLong, Type.tFloat, Type.tDouble,
Type.tUObject },
// Array types
{ Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject,
Type.tBoolByte, Type.tChar, Type.tShort },
// ifld2ifld and shl types
{ Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject },
// i2bcs types
{ Type.tByte, Type.tChar, Type.tShort },
// cmp/add/sub/mul/div types
{ tIntHint, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject },
// and/or/xor types
{ tBoolIntHint, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject }
};
private static StructuredBlock createNormal(MethodAnalyzer ma,
Instruction instr,
Expression expr)
{
return new InstructionBlock(expr, new Jump(FlowBlock.NEXT_BY_ADDR));
}
private static StructuredBlock createSpecial(MethodAnalyzer ma,
Instruction instr,
int type,
int stackcount, int param)
{
return new SpecialBlock(type, stackcount, param,
new Jump(FlowBlock.NEXT_BY_ADDR));
}
private static StructuredBlock createGoto(MethodAnalyzer ma,
Instruction instr)
{
return new EmptyBlock(new Jump((FlowBlock)instr.succs[0].tmpInfo));
}
private static StructuredBlock createJsr(MethodAnalyzer ma,
Instruction instr)
{
return new JsrBlock(new Jump((FlowBlock)instr.succs[0].tmpInfo),
new Jump(FlowBlock.NEXT_BY_ADDR));
}
private static StructuredBlock createIfGoto(MethodAnalyzer ma,
Instruction instr,
Expression expr)
{
return new ConditionalBlock
(expr, new Jump((FlowBlock)instr.succs[0].tmpInfo),
new Jump(FlowBlock.NEXT_BY_ADDR));
}
private static StructuredBlock createSwitch(MethodAnalyzer ma,
Instruction instr,
int[] cases, FlowBlock[] dests)
{
return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests);
}
private static StructuredBlock createBlock(MethodAnalyzer ma,
Instruction instr,
StructuredBlock block)
{
return block;
}
private static StructuredBlock createRet(MethodAnalyzer ma,
Instruction instr,
LocalInfo local)
{
return new RetBlock(local);
}
/**
* Read an opcode out of a data input stream containing the bytecode.
* @param addr The current address.
* @param stream The stream containing the java byte code.
* @param ma The Method Analyzer
* (where further information can be get from).
* @return The FlowBlock representing this opcode
* or null if the stream is empty.
* @exception IOException if an read error occured.
* @exception ClassFormatError if an invalid opcode is detected.
*/
public static StructuredBlock readOpcode(Instruction instr,
MethodAnalyzer ma)
throws ClassFormatError
{
int opcode = instr.opcode;
switch (opcode) {
case opc_nop:
return createBlock(ma, instr, new EmptyBlock
(new Jump(FlowBlock.NEXT_BY_ADDR)));
case opc_ldc:
case opc_ldc2_w:
return createNormal (ma, instr, new ConstOperator(instr.objData));
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return createNormal
(ma, instr, new LocalLoadOperator
(types[LOCAL_TYPES][opcode-opc_iload], ma,
ma.getLocalInfo(instr.addr, instr.localSlot)));
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
return createNormal
(ma, instr, new ArrayLoadOperator
(types[ARRAY_TYPES][opcode - opc_iaload]));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return createNormal
(ma, instr, new StoreInstruction
(new LocalStoreOperator
(types[LOCAL_TYPES][opcode-opc_istore],
ma.getLocalInfo(instr.addr+instr.length,instr.localSlot))));
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
return createNormal
(ma, instr, new StoreInstruction
(new ArrayStoreOperator
(types[ARRAY_TYPES][opcode - opc_iastore])));
case opc_pop: case opc_pop2:
return createSpecial
(ma, instr, SpecialBlock.POP, opcode - opc_pop + 1, 0);
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return createSpecial
(ma, instr, SpecialBlock.DUP,
(opcode - opc_dup)/3+1, (opcode - opc_dup)%3);
case opc_swap:
return createSpecial(ma, instr, SpecialBlock.SWAP, 1, 0);
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return createNormal
(ma, instr, new BinaryOperator
(types[BIN_TYPES][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return createNormal
(ma, instr, new UnaryOperator
(types[UNARY_TYPES][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
return createNormal
(ma, instr, new ShiftOperator
(types[UNARY_TYPES][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land:
case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor:
return createNormal
(ma, instr, new BinaryOperator
(types[ZBIN_TYPES][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: {
int value = instr.intData;
int operation = Operator.ADD_OP;
if (value < 0) {
value = -value;
operation = Operator.SUB_OP;
}
LocalInfo li = ma.getLocalInfo(instr.addr, instr.localSlot);
return createNormal
(ma, instr, new IIncOperator
(new LocalStoreOperator(Type.tInt, li),
value, operation + Operator.OPASSIGN_OP));
}
case opc_i2l: case opc_i2f: case opc_i2d:
case opc_l2i: case opc_l2f: case opc_l2d:
case opc_f2i: case opc_f2l: case opc_f2d:
case opc_d2i: case opc_d2l: case opc_d2f: {
int from = (opcode-opc_i2l)/3;
int to = (opcode-opc_i2l)%3;
if (to >= from)
to++;
return createNormal
(ma, instr, new ConvertOperator(types[UNARY_TYPES][from],
types[UNARY_TYPES][to]));
}
case opc_i2b: case opc_i2c: case opc_i2s:
return createNormal
(ma, instr, new ConvertOperator
(types[UNARY_TYPES][0], types[I2BCS_TYPES][opcode-opc_i2b]));
case opc_lcmp:
case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
return createNormal
(ma, instr, new CompareToIntOperator
(types[BIN_TYPES][(opcode-(opc_lcmp-3))/2],
(opcode == opc_fcmpg || opcode == opc_dcmpg)));
case opc_ifeq: case opc_ifne:
return createIfGoto
(ma, instr,
new CompareUnaryOperator
(Type.tBoolInt, opcode - (opc_ifeq-Operator.COMPARE_OP)));
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return createIfGoto
(ma, instr,
new CompareUnaryOperator
(Type.tInt, opcode - (opc_ifeq-Operator.COMPARE_OP)));
case opc_if_icmpeq: case opc_if_icmpne:
return createIfGoto
(ma, instr,
new CompareBinaryOperator
(tBoolIntHint, opcode - (opc_if_icmpeq-Operator.COMPARE_OP)));
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
return createIfGoto
(ma, instr,
new CompareBinaryOperator
(tIntHint, opcode - (opc_if_icmpeq-Operator.COMPARE_OP)));
case opc_if_acmpeq: case opc_if_acmpne:
return createIfGoto
(ma, instr,
new CompareBinaryOperator
(Type.tUObject,
opcode - (opc_if_acmpeq-Operator.COMPARE_OP)));
case opc_goto:
return createGoto(ma, instr);
case opc_jsr:
return createJsr(ma, instr);
case opc_ret:
return createRet
(ma, instr, ma.getLocalInfo(instr.addr, instr.localSlot));
case opc_tableswitch: {
int low = instr.intData;
int[] cases = new int[instr.succs.length-1];
FlowBlock[] dests = new FlowBlock[instr.succs.length];
for (int i=0; i < cases.length; i++) {
cases[i] = i+low;
dests[i] = (FlowBlock) instr.succs[i].tmpInfo;
}
dests[cases.length] = (FlowBlock)instr.succs[cases.length].tmpInfo;
return createSwitch(ma, instr, cases, dests);
}
case opc_lookupswitch: {
int[] cases = (int[]) instr.objData;
FlowBlock[] dests = new FlowBlock[instr.succs.length];
for (int i=0; i < dests.length; i++)
dests[i] = (FlowBlock) instr.succs[i].tmpInfo;
dests[cases.length] = (FlowBlock)instr.succs[cases.length].tmpInfo;
return createSwitch(ma, instr, cases, dests);
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: {
Type retType = Type.tSubType(ma.getReturnType());
return createBlock
(ma, instr, new ReturnBlock(new NopOperator(retType)));
}
case opc_return:
return createBlock
(ma, instr, new EmptyBlock(new Jump(FlowBlock.END_OF_METHOD)));
case opc_getstatic:
case opc_getfield: {
Reference ref = (Reference) instr.objData;
return createNormal
(ma, instr, new GetFieldOperator
(ma, opcode == opc_getstatic, ref));
}
case opc_putstatic:
case opc_putfield: {
Reference ref = (Reference) instr.objData;
return createNormal
(ma, instr, new StoreInstruction
(new PutFieldOperator(ma, opcode == opc_putstatic, ref)));
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic :
case opc_invokeinterface: {
Reference ref = (Reference) instr.objData;
StructuredBlock block = createNormal
(ma, instr, new InvokeOperator
(ma, opcode == opc_invokestatic,
opcode == opc_invokespecial, ref));
return block;
}
case opc_new: {
Type type = Type.tType((String) instr.objData);
ma.useType(type);
return createNormal(ma, instr, new NewOperator(type));
}
case opc_arraylength:
return createNormal
(ma, instr, new ArrayLengthOperator());
case opc_athrow:
return createBlock
(ma, instr,
new ThrowBlock(new NopOperator(Type.tUObject)));
case opc_checkcast: {
Type type = Type.tType((String) instr.objData);
ma.useType(type);
return createNormal
(ma, instr, new CheckCastOperator(type));
}
case opc_instanceof: {
Type type = Type.tType((String) instr.objData);
ma.useType(type);
return createNormal
(ma, instr, new InstanceOfOperator(type));
}
case opc_monitorenter:
return createNormal(ma, instr,
new MonitorEnterOperator());
case opc_monitorexit:
return createNormal(ma, instr,
new MonitorExitOperator());
case opc_multianewarray: {
Type type = Type.tType((String) instr.objData);
ma.useType(type);
int dimension = instr.intData;
return createNormal(ma, instr,
new NewArrayOperator(type, dimension));
}
case opc_ifnull: case opc_ifnonnull:
return createIfGoto
(ma, instr, new CompareUnaryOperator
(Type.tUObject, opcode - (opc_ifnull-Operator.COMPARE_OP)));
default:
throw new jode.AssertError("Invalid opcode "+opcode);
}
}
}

@ -1,27 +0,0 @@
/* OuterValueListener Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
/**
* Interface, that every one should implement who is interested in
* outer value changes.
*/
public interface OuterValueListener {
public void shrinkingOuterValues(ClassAnalyzer clazzAna, int newLength);
}

@ -1,340 +0,0 @@
/* TabbedPrintWriter Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import java.io.*;
import java.util.Stack;
import jode.Decompiler;
import jode.GlobalOptions;
import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo;
import jode.type.*;
public class TabbedPrintWriter {
boolean atbol;
int indentsize;
int currentIndent = 0;
String indentStr = "";
PrintWriter pw;
ImportHandler imports;
Stack scopes = new Stack();
public TabbedPrintWriter (OutputStream os, ImportHandler imports,
boolean autoFlush) {
pw = new PrintWriter(os, autoFlush);
this.imports = imports;
this.indentsize = (Decompiler.outputStyle & Decompiler.TAB_SIZE_MASK);
atbol = true;
}
public TabbedPrintWriter (Writer os, ImportHandler imports,
boolean autoFlush) {
pw = new PrintWriter(os, autoFlush);
this.imports = imports;
this.indentsize = (Decompiler.outputStyle & Decompiler.TAB_SIZE_MASK);
atbol = true;
}
public TabbedPrintWriter (OutputStream os, ImportHandler imports) {
this(os, imports, true);
}
public TabbedPrintWriter (Writer os, ImportHandler imports) {
this(os, imports, true);
}
public TabbedPrintWriter (OutputStream os) {
this(os, null);
}
public TabbedPrintWriter (Writer os) {
this(os, null);
}
/**
* Convert the numeric indentation to a string.
*/
protected void makeIndentStr() {
int tabs = (currentIndent >> 3);
// This is a very fast implementation.
if (tabs <= 20)
indentStr = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t "
.substring(20 - tabs, 20 + (currentIndent&7));
else {
/* the slow way */
StringBuffer sb = new StringBuffer(tabs+7);
while (tabs > 20) {
sb.append("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t "
.substring(0,20));
tabs -= 20;
}
sb.append("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t "
.substring(20 - tabs, 20 + (currentIndent&7)));
indentStr = sb.toString();
}
}
public void tab() {
currentIndent += indentsize;
makeIndentStr();
}
public void untab() {
currentIndent -= indentsize;
makeIndentStr();
}
public void println(String str) {
if (atbol)
pw.print(indentStr);
pw.println(str);
atbol = true;
}
public void println() {
pw.println();
atbol = true;
}
public void print(String str) {
if (atbol)
pw.print(indentStr);
pw.print(str);
atbol = false;
}
public void printType(Type type) {
print(getTypeString(type));
}
/**
* Print a opening brace with the current indentation style.
* Called at the end of the line of the instance that opens the
* brace. It doesn't do a tab stop after opening the brace.
*/
public void openBrace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0)
if (atbol)
println("{");
else
println(" {");
else {
if (!atbol)
println();
if (currentIndent > 0)
tab();
println("{");
}
}
public void pushScope(Scope scope) {
scopes.push(scope);
}
public void popScope() {
scopes.pop();
}
/**
* Checks if the name in inScope conflicts with an identifier in a
* higher scope.
*/
public boolean conflicts(String name, Scope inScope, int context) {
int dot = name.indexOf('.');
if (dot >= 0)
name = name.substring(0, dot);
int count = scopes.size();
for (int ptr = count; ptr-- > 0; ) {
Scope scope = (Scope) scopes.elementAt(ptr);
if (scope == inScope)
return false;
if (scope.conflicts(name, context)) {
return true;
}
}
return false;
}
public Scope getScope(Object obj, int scopeType) {
int count = scopes.size();
for (int ptr = count; ptr-- > 0; ) {
Scope scope = (Scope) scopes.elementAt(ptr);
if (scope.isScopeOf(obj, scopeType))
return scope;
}
return null;
}
public String getInnerClassString(ClassInfo info, int scopeType) {
InnerClassInfo[] outers = info.getOuterClasses();
if (outers == null)
return null;
for (int i=0; i< outers.length; i++) {
if (outers[i].name == null || outers[i].outer == null)
return null;
Scope scope = getScope(ClassInfo.forName(outers[i].outer),
Scope.CLASSSCOPE);
if (scope != null &&
!conflicts(outers[i].name, scope, scopeType)) {
StringBuffer sb = new StringBuffer(outers[i].name);
for (int j = i; j-- > 0;) {
sb.append('.').append(outers[j].name);
}
return sb.toString();
}
}
String name = getClassString
(ClassInfo.forName(outers[outers.length-1].outer), scopeType);
StringBuffer sb = new StringBuffer(name);
for (int j = outers.length; j-- > 0;)
sb.append('.').append(outers[j].name);
return sb.toString();
}
public String getAnonymousClassString(ClassInfo info, int scopeType) {
InnerClassInfo[] outers = info.getOuterClasses();
if (outers == null)
return null;
for (int i=0; i< outers.length; i++) {
if (outers[i].name == null)
return "ANONYMOUS CLASS";
Scope scope = getScope(info, Scope.METHODSCOPE);
if (scope != null &&
!conflicts(outers[i].name, scope, scopeType)) {
StringBuffer sb = new StringBuffer(outers[i].name);
for (int j = i; j-- > 0;) {
sb.append('.').append(outers[j].name);
}
return sb.toString();
} else if (outers[i].outer == null) {
StringBuffer sb;
if (scope != null)
sb = new StringBuffer("NAME CONFLICT ");
else
sb = new StringBuffer("UNREACHABLE ");
sb.append(outers[i].name);
for (int j = i; j-- > 0;) {
sb.append('.').append(outers[j].name);
}
return sb.toString();
}
}
String name = getClassString
(ClassInfo.forName(outers[outers.length-1].outer), scopeType);
StringBuffer sb = new StringBuffer(name);
for (int j = outers.length; j-- > 0;)
sb.append('.').append(outers[j].name);
return sb.toString();
}
public String getClassString(ClassInfo clazz, int scopeType) {
String name = clazz.getName();
if (name.indexOf('$') >= 0) {
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0) {
String innerClassName
= getInnerClassString(clazz, scopeType);
if (innerClassName != null)
return innerClassName;
}
if ((Decompiler.options
& Decompiler.OPTION_ANON) != 0) {
String innerClassName
= getAnonymousClassString(clazz, scopeType);
if (innerClassName != null)
return innerClassName;
}
}
if (imports != null) {
String importedName = imports.getClassString(clazz);
if (!conflicts(importedName, null, scopeType))
return importedName;
}
if (conflicts(name, null, Scope.AMBIGUOUSNAME))
return "PKGNAMECONFLICT "+ name;
return name;
}
public String getTypeString(Type type) {
if (type instanceof ArrayType)
return getTypeString(((ArrayType) type).getElementType()) + "[]";
else if (type instanceof ClassInterfacesType) {
ClassInfo clazz = ((ClassInterfacesType) type).getClassInfo();
return getClassString(clazz, Scope.CLASSNAME);
} else if (type instanceof NullType)
return "Object";
else
return type.toString();
}
/**
* Print a opening brace with the current indentation style.
* Called at the end of the line of the instance that opens the
* brace. It doesn't do a tab stop after opening the brace.
*/
public void openBraceNoSpace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0)
println("{");
else {
if (!atbol)
println();
if (currentIndent > 0)
tab();
println("{");
}
}
public void closeBraceContinue() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0)
print("} ");
else {
println("}");
if (currentIndent > 0)
untab();
}
}
public void closeBraceNoSpace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0)
print("}");
else {
println("}");
if (currentIndent > 0)
untab();
}
}
public void closeBrace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0)
println("}");
else {
println("}");
if (currentIndent > 0)
untab();
}
}
public void flush() {
pw.flush();
}
public void close() {
pw.close();
}
}

@ -1,61 +0,0 @@
/* ArrayStoreOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
public class ArrayStoreOperator extends LValueExpression {
public ArrayStoreOperator(Type type) {
super(type);
initOperands(2);
}
public boolean matches(Operator loadop) {
return loadop instanceof ArrayLoadOperator;
}
public int getPriority() {
return 950;
}
public void updateSubTypes() {
subExpressions[0].setType(Type.tArray(type));
subExpressions[1].setType(Type.tSubType(Type.tInt));
}
public void updateType() {
Type subType = subExpressions[0].getType()
.intersection(Type.tArray(type));
if (!(subType instanceof ArrayType))
updateParentType(Type.tError);
else
updateParentType(((ArrayType)subType).getElementType());
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 950);
writer.print("[");
subExpressions[1].dumpExpression(writer, 0);
writer.print("]");
}
}

@ -1,333 +0,0 @@
/* ConstructorOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import jode.type.Type;
import jode.type.NullType;
import jode.type.ClassInterfacesType;
import jode.type.MethodType;
import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo;
import jode.bytecode.Reference;
import jode.Decompiler;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer;
import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope;
import java.lang.reflect.Modifier;
///#ifdef JDK12
///import java.util.Set;
///#else
import jode.util.Set;
///#endif
public class ConstructorOperator extends Operator
implements MatchableOperator {
MethodType methodType;
Type classType;
MethodAnalyzer methodAnalyzer;
public ConstructorOperator(Type classType, MethodType methodType,
MethodAnalyzer methodAna, boolean isVoid) {
super(isVoid ? Type.tVoid : classType, 0);
this.classType = classType;
this.methodType = methodType;
this.methodAnalyzer = methodAna;
initOperands(methodType.getParameterTypes().length);
checkAnonymousClasses();
}
public ConstructorOperator(Reference ref, MethodAnalyzer methodAna,
boolean isVoid) {
this (Type.tType(ref.getClazz()), Type.tMethod(ref.getType()),
methodAna, isVoid);
}
public ConstructorOperator(InvokeOperator invoke, boolean isVoid) {
this (invoke.getClassType(), invoke.getMethodType(),
invoke.methodAnalyzer, isVoid);
}
public MethodType getMethodType() {
return methodType;
}
/**
* Checks if the value of the operator can be changed by this expression.
*/
public boolean matches(Operator loadop) {
return (loadop instanceof InvokeOperator
|| loadop instanceof ConstructorOperator
|| loadop instanceof GetFieldOperator);
}
public int getPriority() {
return 950;
}
public Type getClassType() {
return classType;
}
public void updateSubTypes() {
Type[] paramTypes = methodType.getParameterTypes();
for (int i=0; i < paramTypes.length; i++)
subExpressions[i].setType(Type.tSubType(paramTypes[i]));
}
public void updateType() {
}
public Expression simplifyStringBuffer() {
if (getClassType() == Type.tStringBuffer) {
if (methodType.getParameterTypes().length == 0)
return EMPTYSTRING;
if (methodType.getParameterTypes().length == 1
&& methodType.getParameterTypes()[0].equals(Type.tString))
return subExpressions[0].simplifyString();
}
return (getClassType() == Type.tStringBuffer)
? EMPTYSTRING : null;
}
public Expression simplify() {
return super.simplify();
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType) {
return ((ClassInterfacesType) classType).getClassInfo();
}
return null;
}
public InnerClassInfo getOuterClassInfo(ClassInfo ci) {
if (ci != null) {
InnerClassInfo[] outers = ci.getOuterClasses();
if (outers != null)
return outers[0];
}
return null;
}
public void checkAnonymousClasses() {
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0)
return;
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && (outer.outer == null || outer.name == null)) {
methodAnalyzer.addAnonymousConstructor(this);
if (outer.name == null) {
if (clazz.getInterfaces().length > 0)
type = Type.tClass(clazz.getInterfaces()[0]);
else
type = Type.tClass(clazz.getSuperclass());
}
}
}
public boolean isConstant() {
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0
&& clazzAna != null
&& outer != null && outer.outer == null && outer.name != null
&& clazzAna.getParent() == methodAnalyzer) {
/* This is a named method scope class, it needs
* declaration. And therefore can't be moved into
* a field initializer. */
return false;
}
return super.isConstant();
}
/**
* We add the named method scoped classes to the declarables, and
* only fillDeclarables on the parameters we will print.
*/
public void fillDeclarables(Set used) {
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
int arg = 0;
int length = subExpressions.length;
boolean jikesAnonymousInner = false;
if ((Decompiler.options & Decompiler.OPTION_ANON) != 0
&& clazzAna != null
&& outer != null && (outer.outer == null || outer.name == null)) {
arg += clazzAna.getOuterValues().length;
for (int i=0; i< arg; i++) {
Expression expr = subExpressions[i];
if (expr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) expr;
expr = cno.subExpressions[0];
}
expr.fillDeclarables(used);
}
jikesAnonymousInner = clazzAna.isJikesAnonymousInner();
if (outer.name != null) {
if (clazzAna.getParent() == methodAnalyzer)
/* This is a named method scope class, declare it */
used.add(clazzAna);
} else {
/* This is an anonymous class */
ClassInfo superClazz = clazz.getSuperclass();
ClassInfo[] interfaces = clazz.getInterfaces();
if (interfaces.length == 1
&& (superClazz == null
|| superClazz == ClassInfo.javaLangObject)) {
clazz = interfaces[0];
} else {
clazz = (superClazz != null
? superClazz : ClassInfo.javaLangObject);
}
outer = getOuterClassInfo(clazz);
}
}
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0
&& outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers)) {
Expression outerExpr = jikesAnonymousInner
? subExpressions[--length]
: subExpressions[arg++];
if (outerExpr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) outerExpr;
outerExpr = cno.subExpressions[0];
}
outerExpr.fillDeclarables(used);
}
for (int i=arg; i < length; i++)
subExpressions[i].fillDeclarables(used);
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
int arg = 0;
int length = subExpressions.length;
boolean jikesAnonymousInner = false;
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
boolean dumpBlock = false;
if ((Decompiler.options &
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0
&& clazzAna != null
&& outer != null && (outer.outer == null || outer.name == null)) {
arg += clazzAna.getOuterValues().length;
jikesAnonymousInner = clazzAna.isJikesAnonymousInner();
if (outer.name == null) {
/* This is an anonymous class */
ClassInfo superClazz = clazz.getSuperclass();
ClassInfo[] interfaces = clazz.getInterfaces();
if (interfaces.length == 1
&& (superClazz == null
|| superClazz == ClassInfo.javaLangObject)) {
clazz = interfaces[0];
} else {
if (interfaces.length > 0) {
writer.print("too many supers in ANONYMOUS ");
}
clazz = (superClazz != null
? superClazz : ClassInfo.javaLangObject);
}
outer = getOuterClassInfo(clazz);
dumpBlock = true;
if (jikesAnonymousInner
&& outer.outer == null && outer.name != null) {
Expression thisExpr = subExpressions[--length];
if (thisExpr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) thisExpr;
thisExpr = cno.subExpressions[0];
}
if (!(thisExpr instanceof ThisOperator)
|| (((ThisOperator) thisExpr).getClassInfo()
!= methodAnalyzer.getClazz()))
writer.print("ILLEGAL ANON CONSTR");
}
}
}
if (outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers)
&& (Decompiler.options &
(Decompiler.OPTION_INNER | Decompiler.OPTION_CONTRAFO)) != 0) {
Expression outerExpr = jikesAnonymousInner
? subExpressions[--length]
: subExpressions[arg++];
if (outerExpr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) outerExpr;
outerExpr = cno.subExpressions[0];
} else if (!(outerExpr instanceof ThisOperator)) {
// Bug in jikes: it doesn't do a check null.
// We don't complain here.
if (!jikesAnonymousInner)
writer.print("MISSING CHECKNULL ");
}
if (outerExpr instanceof ThisOperator) {
Scope scope = writer.getScope
(((ThisOperator) outerExpr).getClassInfo(),
Scope.CLASSSCOPE);
if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) {
outerExpr.dumpExpression(writer, 950);
writer.print(".");
}
} else {
if (outerExpr.getType() instanceof NullType) {
writer.print("((");
writer.printType(Type.tClass
(ClassInfo.forName(outer.outer)));
writer.print(") ");
outerExpr.dumpExpression(writer, 700);
writer.print(")");
} else
outerExpr.dumpExpression(writer, 950);
writer.print(".");
}
}
writer.print("new ");
writer.printType(Type.tClass(clazz));
writer.print("(");
for (int i = arg; i < length; i++) {
if (i>arg)
writer.print(", ");
subExpressions[i].dumpExpression(writer, 0);
}
writer.print(")");
if (dumpBlock) {
writer.openBrace();
writer.tab();
clazzAna.dumpBlock(writer);
writer.untab();
writer.closeBraceNoSpace();
}
}
}

@ -1,221 +0,0 @@
/* GetFieldOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import jode.type.Type;
import jode.type.NullType;
import jode.type.ClassInterfacesType;
import jode.bytecode.FieldInfo;
import jode.bytecode.ClassInfo;
import jode.bytecode.Reference;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope;
public class GetFieldOperator extends Operator {
boolean staticFlag;
MethodAnalyzer methodAnalyzer;
Reference ref;
Type classType;
public GetFieldOperator(MethodAnalyzer methodAnalyzer, boolean staticFlag,
Reference ref) {
super(Type.tType(ref.getType()), 0);
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
this.classType = Type.tType(ref.getClazz());
this.ref = ref;
if (staticFlag)
methodAnalyzer.useType(classType);
initOperands(staticFlag ? 0 : 1);
}
public int getPriority() {
return 950;
}
public void updateSubTypes() {
if (!staticFlag)
subExpressions[0].setType(Type.tSubType(classType));
}
public void updateType() {
}
/**
* Checks, whether this is a call of a method from this class or an
* outer instance.
*/
public boolean isOuter() {
if (classType instanceof ClassInterfacesType) {
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz())
return true;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
return false;
}
}
return false;
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType)
return ((ClassInterfacesType) classType).getClassInfo();
return null;
}
public FieldAnalyzer getField() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz()) {
return ana.getField(ref.getName(),
Type.tType(ref.getType()));
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
}
public boolean needsCast(Type type) {
if (type instanceof NullType)
return true;
if (!(type instanceof ClassInterfacesType
&& classType instanceof ClassInterfacesType))
return false;
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo();
while (clazz != parClazz && clazz != null) {
FieldInfo[] fields = parClazz.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(ref.getName()))
return true;
}
parClazz = parClazz.getSuperclass();
}
return false;
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
String fieldName = ref.getName();
if (staticFlag) {
if (!classType.equals(Type.tClass(methodAnalyzer.getClazz()))
|| methodAnalyzer.findLocal(fieldName) != null) {
writer.printType(classType);
writer.print(".");
}
writer.print(fieldName);
} else if (needsCast(subExpressions[0].getType().getCanonic())) {
writer.print("((");
writer.printType(classType);
writer.print(") ");
subExpressions[0].dumpExpression(writer, 700);
writer.print(").");
writer.print(fieldName);
} else {
if (opIsThis) {
ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
if (scope == null || writer.conflicts(fieldName, scope,
Scope.FIELDNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else if (writer.conflicts(fieldName, scope,
Scope.AMBIGUOUSNAME)
|| (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getField() == null
&& writer.conflicts(fieldName, null,
Scope.NOSUPERFIELDNAME))) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this.");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
writer.print(".");
}
}
} else {
subExpressions[0].dumpExpression(writer, 950);
writer.print(".");
}
writer.print(fieldName);
}
}
public Expression simplify() {
if (!staticFlag) {
subExpressions[0] = subExpressions[0].simplify();
subExpressions[0].parent = this;
if (subExpressions[0] instanceof ThisOperator) {
FieldAnalyzer field = getField();
/* This should check for isFinal(), but sadly,
* sometimes jikes doesn't make a val$ field final. I
* don't know when, or why, so I currently ignore
* isFinal.
*/
if (field != null && field.isSynthetic()) {
Expression constant = field.getConstant();
if (constant instanceof ThisOperator
|| constant instanceof OuterLocalOperator)
return constant;
}
}
}
return this;
}
public boolean opEquals(Operator o) {
return o instanceof GetFieldOperator
&& ((GetFieldOperator)o).ref.equals(ref);
}
}

@ -1,111 +0,0 @@
/* IfThenElseOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import jode.type.Type;
import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter;
public class IfThenElseOperator extends Operator {
public IfThenElseOperator(Type type) {
super(type, 0);
initOperands(3);
}
public int getPriority() {
return 200;
}
public void updateSubTypes() {
subExpressions[0].setType(Type.tBoolean);
subExpressions[1].setType(Type.tSubType(type));
subExpressions[2].setType(Type.tSubType(type));
}
public void updateType() {
Type subType = Type.tSuperType(subExpressions[1].getType())
.intersection(Type.tSuperType(subExpressions[2].getType()));
updateParentType(subType);
}
public Expression simplify() {
if (getType().isOfType(Type.tBoolean)) {
if (subExpressions[1] instanceof ConstOperator
&& subExpressions[2] instanceof ConstOperator) {
ConstOperator c1 = (ConstOperator) subExpressions[1];
ConstOperator c2 = (ConstOperator) subExpressions[2];
if (c1.getValue().equals("1") &&
c2.getValue().equals("0"))
return subExpressions[0].simplify();
if (c2.getValue().equals("1") &&
c1.getValue().equals("0"))
return subExpressions[0].negate().simplify();
}
}
if (subExpressions[0] instanceof CompareUnaryOperator
&& (subExpressions[1] instanceof GetFieldOperator)
&& (subExpressions[2] instanceof StoreInstruction)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
CompareUnaryOperator cmp
= (CompareUnaryOperator) subExpressions[0];
GetFieldOperator get = (GetFieldOperator) subExpressions[1];
StoreInstruction put = (StoreInstruction) subExpressions[2];
FieldAnalyzer field;
if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP
&& put.getLValue() instanceof PutFieldOperator
&& ((field = ((PutFieldOperator)put.getLValue()).getField())
!= null) && field.isSynthetic()
&& put.lvalueMatches(get)
&& cmp.subExpressions[0] instanceof GetFieldOperator
&& put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0])
&& put.subExpressions[1] instanceof InvokeOperator) {
InvokeOperator invoke = (InvokeOperator) put.subExpressions[1];
if (invoke.isGetClass()
&& invoke.subExpressions[0] instanceof ConstOperator
&& (invoke.subExpressions[0].getType()
.equals(Type.tString))) {
String clazz =
((ConstOperator)invoke.subExpressions[0]).getValue();
if (field.setClassConstant(clazz))
return new ClassFieldOperator(clazz.charAt(0) == '['
? Type.tType(clazz)
: Type.tClass(clazz));
}
}
}
return super.simplify();
}
public boolean opEquals(Operator o) {
return (o instanceof IfThenElseOperator);
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 201);
writer.print(" ? ");
subExpressions[1].dumpExpression(writer, 0);
writer.print(" : ");
subExpressions[2].dumpExpression(writer, 200);
}
}

@ -1,741 +0,0 @@
/* InvokeOperator Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.expr;
import java.lang.reflect.Modifier;
import jode.Decompiler;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer;
import jode.decompiler.TabbedPrintWriter;
import jode.GlobalOptions;
import jode.bytecode.*;
import jode.jvm.*;
import jode.type.*;
import jode.decompiler.Scope;
import jode.util.SimpleMap;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
///#ifdef JDK12
///import java.util.Collections;
///import java.util.Map;
///import java.util.Iterator;
///#else
import jode.util.Collections;
import jode.util.Map;
import jode.util.Iterator;
///#endif
public final class InvokeOperator extends Operator
implements MatchableOperator {
MethodAnalyzer methodAnalyzer;
boolean staticFlag;
boolean specialFlag;
MethodType methodType;
String methodName;
Type classType;
Type[] hints;
/**
* This hashtable contains hints for every library method. Some
* library method take or return an int, but it should be a char
* instead. We will remember that here to give them the right
* hint.
*
* The key is the string: methodName + "." + methodType, the value
* is a map: It maps base class types for which this hint applies,
* to an array of hint types corresponding to the parameters: The
* first element is the hint type of the return value, the
* remaining entries are the hint types of the parameters. All
* hint types may be null, if that parameter shouldn't be hinted.
*/
private final static Hashtable hintTypes = new Hashtable();
static {
/* Fill the hint type hashtable. For example, the first
* parameter of String.indexOf should be hinted as char, even
* though the formal parameter is an int.
* First hint is hint of return value (even if void)
* other hints are that of the parameters in order
*
* You only have to hint the base class. Other classes will
* inherit the hints.
*
* We reuse a lot of objects, since they are all unchangeable
* this is no problem. We only hint for chars; it doesn't
* make much sense to hint for byte, since its constant
* representation is more difficult than an int
* representation. If you have more hints to suggest, please
* write contact me. (see GlobalOptions.EMAIL)
*/
Type tCharHint = new IntegerType(IntegerType.IT_I, IntegerType.IT_C);
Type[] hintC = new Type[] { tCharHint };
Type[] hint0C = new Type[] { null, tCharHint };
Type[] hint0C0 = new Type[] { null, tCharHint, null };
Map hintString0CMap = new SimpleMap
(Collections.singleton
(new SimpleMap.SimpleEntry(Type.tString, hint0C)));
Map hintString0C0Map = new SimpleMap
(Collections.singleton
(new SimpleMap.SimpleEntry(Type.tString, hint0C0)));
hintTypes.put("indexOf.(I)I", hintString0CMap);
hintTypes.put("lastIndexOf.(I)I", hintString0CMap);
hintTypes.put("indexOf.(II)I", hintString0C0Map);
hintTypes.put("lastIndexOf.(II)I", hintString0C0Map);
hintTypes.put("write.(I)V", new SimpleMap
(Collections.singleton
(new SimpleMap.SimpleEntry
(Type.tClass("java.io.Writer"), hint0C))));
hintTypes.put("read.()I", new SimpleMap
(Collections.singleton
(new SimpleMap.SimpleEntry
(Type.tClass("java.io.Reader"), hintC))));
hintTypes.put("unread.(I)V", new SimpleMap
(Collections.singleton
(new SimpleMap.SimpleEntry
(Type.tClass("java.io.PushbackReader"), hint0C))));
}
public InvokeOperator(MethodAnalyzer methodAnalyzer,
boolean staticFlag, boolean specialFlag,
Reference reference) {
super(Type.tUnknown, 0);
this.methodType = Type.tMethod(reference.getType());
this.methodName = reference.getName();
this.classType = Type.tType(reference.getClazz());
this.hints = null;
Map allHints = (Map) hintTypes.get(methodName+"."+methodType);
if (allHints != null) {
for (Iterator i = allHints.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry) i.next();
if (classType.isOfType(((Type)e.getKey()).getSubType())) {
this.hints = (Type[]) e.getValue();
break;
}
}
}
if (hints != null && hints[0] != null)
this.type = hints[0];
else
this.type = methodType.getReturnType();
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
this.specialFlag = specialFlag;
if (staticFlag)
methodAnalyzer.useType(classType);
initOperands((staticFlag ? 0 : 1)
+ methodType.getParameterTypes().length);
}
public final boolean isStatic() {
return staticFlag;
}
public MethodType getMethodType() {
return methodType;
}
public String getMethodName() {
return methodName;
}
public Type getClassType() {
return classType;
}
public int getPriority() {
return 950;
}
public void updateSubTypes() {
int offset = 0;
if (!isStatic()) {
subExpressions[offset++].setType(Type.tSubType(getClassType()));
}
Type[] paramTypes = methodType.getParameterTypes();
for (int i=0; i < paramTypes.length; i++) {
Type pType = (hints != null && hints[i+1] != null)
? hints[i+1] : paramTypes[i];
subExpressions[offset++].setType(Type.tSubType(pType));
}
}
public void updateType() {
}
public boolean isConstructor() {
return methodName.equals("<init>");
}
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType)
return ((ClassInterfacesType) classType).getClassInfo();
return null;
}
/**
* Checks, whether this is a call of a method from this class.
* @XXX check, if this class implements the method and if not
* allow super class
*/
public boolean isThis() {
return getClassInfo() == methodAnalyzer.getClazz();
}
public InnerClassInfo getOuterClassInfo(ClassInfo ci) {
if (ci != null) {
InnerClassInfo[] outers = ci.getOuterClasses();
if (outers != null)
return outers[0];
}
return null;
}
/**
* Checks, whether this is a call of a method from this class or an
* outer instance.
*/
public boolean isOuter() {
if (classType instanceof ClassInterfacesType) {
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz())
return true;
if (ana.getParent() == null)
break;
if (ana.getParent() instanceof MethodAnalyzer
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer
&& (Decompiler.options
& Decompiler.OPTION_INNER) != 0)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError
("Unknown parent: "+ana+": "+ana.getParent());
}
}
return false;
}
public MethodAnalyzer getMethodAnalyzer() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (true) {
if (clazz == ana.getClazz()) {
return ana.getMethod(methodName, methodType);
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
}
/**
* Checks, whether this is a call of a method from the super class.
* @XXX check, if its the first super class that implements the method.
*/
public boolean isSuperOrThis() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
return clazz.superClassOf(methodAnalyzer.getClazz());
}
return false;
}
/**
* Checks if the value of the operator can be changed by this expression.
*/
public boolean matches(Operator loadop) {
return (loadop instanceof InvokeOperator
|| loadop instanceof ConstructorOperator
|| loadop instanceof GetFieldOperator);
}
/**
* Checks if the method is the magic class$ method.
* @return true if this is the magic class$ method, false otherwise.
*/
public boolean isGetClass() {
if (isThis()) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null && synth.getKind() == SyntheticAnalyzer.GETCLASS)
return true;
}
return false;
}
class Environment extends SimpleRuntimeEnvironment {
public Object invokeMethod(Reference ref, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException {
if (ref.getClazz().equals
("L"+methodAnalyzer.getClazz().getName().replace('.','/')+";")) {
MethodType mt = (MethodType) Type.tType(ref.getType());
BytecodeInfo info = methodAnalyzer.getClassAnalyzer()
.getMethod(ref.getName(), mt).getBytecodeInfo();
Value[] locals = new Value[info.getMaxLocals()];
for (int i=0; i< locals.length; i++)
locals[i] = new Value();
int param = params.length;
int slot = 0;
if (cls != null)
locals[slot++].setObject(cls);
for (int i = 0; i < param; i++) {
locals[slot].setObject(params[i]);
slot += mt.getParameterTypes()[i].stackSize();
}
return Interpreter.interpretMethod(this, info, locals);
} else
return super.invokeMethod(ref, isVirtual, cls, params);
}
}
public ConstOperator deobfuscateString(ConstOperator op) {
ClassAnalyzer clazz = methodAnalyzer.getClassAnalyzer();
MethodAnalyzer ma = clazz.getMethod(methodName, methodType);
if (ma == null)
return null;
Environment env = new Environment();
BytecodeInfo info = ma.getBytecodeInfo();
Value[] locals = new Value[info.getMaxLocals()];
for (int i=0; i< locals.length; i++)
locals[i] = new Value();
locals[0].setObject(op.getValue());
String result;
try {
result = (String) Interpreter.interpretMethod(env, info, locals);
} catch (InterpreterException ex) {
GlobalOptions.err.println("Warning: Can't interpret method "
+methodName);
ex.printStackTrace(GlobalOptions.err);
return null;
} catch (InvocationTargetException ex) {
GlobalOptions.err.println("Warning: Interpreted method throws"
+" an uncaught exception: ");
ex.getTargetException().printStackTrace(GlobalOptions.err);
return null;
}
return new ConstOperator(result);
}
public Expression simplifyStringBuffer() {
if (getClassType().equals(Type.tStringBuffer)
&& !isStatic()
&& getMethodName().equals("append")
&& getMethodType().getParameterTypes().length == 1) {
Expression firstOp = subExpressions[0].simplifyStringBuffer();
if (firstOp == null)
return null;
subExpressions[1] = subExpressions[1].simplifyString();
if (firstOp == EMPTYSTRING
&& subExpressions[1].getType().isOfType(Type.tString))
return subExpressions[1];
if (firstOp instanceof StringAddOperator
&& ((Operator)firstOp).getSubExpressions()[0] == EMPTYSTRING)
firstOp = ((Operator)firstOp).getSubExpressions()[1];
Expression secondOp = subExpressions[1];
Type[] paramTypes = new Type[] {
Type.tStringBuffer, secondOp.getType().getCanonic()
};
if (needsCast(1, paramTypes)) {
Type castType = methodType.getParameterTypes()[0];
Operator castOp = new ConvertOperator(castType, castType);
castOp.addOperand(secondOp);
secondOp = castOp;
}
Operator result = new StringAddOperator();
result.addOperand(secondOp);
result.addOperand(firstOp);
return result;
}
return null;
}
public Expression simplifyString() {
if (getMethodName().equals("toString")
&& !isStatic()
&& getClassType().equals(Type.tStringBuffer)
&& subExpressions.length == 1) {
Expression simple = subExpressions[0].simplifyStringBuffer();
if (simple != null)
return simple;
}
else if (getMethodName().equals("valueOf")
&& isStatic()
&& getClassType().equals(Type.tString)
&& subExpressions.length == 1) {
if (subExpressions[0].getType().isOfType(Type.tString))
return subExpressions[0];
Operator op = new StringAddOperator();
op.addOperand(subExpressions[0]);
op.addOperand(EMPTYSTRING);
}
/* The pizza way (pizza is the compiler of kaffe) */
else if (getMethodName().equals("concat")
&& !isStatic()
&& getClassType().equals(Type.tString)) {
Expression result = new StringAddOperator();
Expression right = subExpressions[1].simplify();
if (right instanceof StringAddOperator) {
Operator op = (Operator) right;
if (op.subExpressions != null
&& op.subExpressions[0] == EMPTYSTRING)
right = op.subExpressions[1];
}
result.addOperand(right);
result.addOperand(subExpressions[0].simplify());
}
else if ((Decompiler.options & Decompiler.OPTION_DECRYPT) != 0
&& isThis() && isStatic()
&& methodType.getParameterTypes().length == 1
&& methodType.getParameterTypes()[0].equals(Type.tString)
&& methodType.getReturnType().equals(Type.tString)) {
Expression expr = subExpressions[0].simplifyString();
if (expr instanceof ConstOperator) {
expr = deobfuscateString((ConstOperator)expr);
if (expr != null)
return expr;
}
}
return this;
}
public Expression simplifyAccess() {
if (getMethodAnalyzer() != null) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null) {
Expression op = null;
switch (synth.getKind()) {
case SyntheticAnalyzer.ACCESSGETFIELD:
op = new GetFieldOperator(methodAnalyzer, false,
synth.getReference());
break;
case SyntheticAnalyzer.ACCESSGETSTATIC:
op = new GetFieldOperator(methodAnalyzer, true,
synth.getReference());
break;
case SyntheticAnalyzer.ACCESSPUTFIELD:
op = new StoreInstruction
(new PutFieldOperator(methodAnalyzer, false,
synth.getReference()));
break;
case SyntheticAnalyzer.ACCESSPUTSTATIC:
op = new StoreInstruction
(new PutFieldOperator(methodAnalyzer, true,
synth.getReference()));
break;
case SyntheticAnalyzer.ACCESSMETHOD:
op = new InvokeOperator(methodAnalyzer, false,
false, synth.getReference());
break;
case SyntheticAnalyzer.ACCESSSTATICMETHOD:
op = new InvokeOperator(methodAnalyzer, true,
false, synth.getReference());
break;
}
if (op != null) {
if (subExpressions != null) {
for (int i=subExpressions.length; i-- > 0; ) {
op = op.addOperand(subExpressions[i]);
if (subExpressions[i].getFreeOperandCount() > 0)
break;
}
}
return op;
}
}
}
return null;
}
public boolean needsCast(int param, Type[] paramTypes) {
Type realClassType;
if (staticFlag)
realClassType = classType;
else {
if (param == 0)
return paramTypes[0] instanceof NullType;
realClassType = paramTypes[0];
}
if (!(realClassType instanceof ClassInterfacesType)) {
/* Arrays don't have overloaded methods, all okay */
return false;
}
ClassInfo clazz = ((ClassInterfacesType) realClassType).getClassInfo();
int offset = staticFlag ? 0 : 1;
Type[] myParamTypes = methodType.getParameterTypes();
if (myParamTypes[param-offset].equals(paramTypes[param])) {
/* Type at param is okay. */
return false;
}
/* Now check if there is a conflicting method in this class or
* a superclass. */
while (clazz != null) {
MethodInfo[] methods = clazz.getMethods();
next_method:
for (int i=0; i< methods.length; i++) {
if (!methods[i].getName().equals(methodName))
/* method name doesn't match*/
continue next_method;
Type[] otherParamTypes
= Type.tMethod(methods[i].getType()).getParameterTypes();
if (otherParamTypes.length != myParamTypes.length) {
/* parameter count doesn't match*/
continue next_method;
}
if (myParamTypes[param-offset].isOfType
(Type.tSubType(otherParamTypes[param-offset]))) {
/* cast to myParamTypes cannot resolve any conflicts. */
continue next_method;
}
for (int p = offset; p < paramTypes.length; p++) {
if (!paramTypes[p]
.isOfType(Type.tSubType(otherParamTypes[p-offset])))
/* No conflict here */
continue next_method;
}
/* There is a conflict that can be resolved by a cast. */
return true;
}
clazz = clazz.getSuperclass();
}
return false;
}
public Expression simplify() {
Expression expr = simplifyAccess();
if (expr != null)
return expr.simplify();
expr = simplifyString();
if (expr != this)
return expr.simplify();
return super.simplify();
}
/* Invokes never equals: they may return different values even if
* they have the same parameters.
*/
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
int arg = 1;
int length = subExpressions.length;
ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz);
Type[] paramTypes = new Type[subExpressions.length];
for (int i=0; i< subExpressions.length; i++)
paramTypes[i] = subExpressions[i].getType().getCanonic();
if (isConstructor()) {
boolean jikesAnonymousInner = false;
if ((Decompiler.options &
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0
&& outer != null
&& (outer.outer == null || outer.name == null)) {
ClassAnalyzer anonymousClass = methodAnalyzer.getClassAnalyzer(clazz);
jikesAnonymousInner = anonymousClass.isJikesAnonymousInner();
if (outer.name == null) {
writer.print("SUPER IS ANONYMOUS?");
outer = null;
}
/* XXX check outerValues */
arg += anonymousClass.getOuterValues().length;
}
if (outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers)
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0) {
Expression outerExpr = jikesAnonymousInner
? subExpressions[--length]
: subExpressions[arg++];
if (outerExpr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) outerExpr;
outerExpr = cno.subExpressions[0];
} else if (!(outerExpr instanceof ThisOperator)) {
if (!jikesAnonymousInner)
// Bug in jikes: it doesn't do a check null.
// We don't complain here.
writer.print("MISSING CHECKNULL ");
}
if (outerExpr instanceof ThisOperator) {
Scope scope = writer.getScope
(((ThisOperator) outerExpr).getClassInfo(),
Scope.CLASSSCOPE);
if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) {
outerExpr.dumpExpression(writer, 950);
writer.print(".");
}
} else {
if (outerExpr.getType() instanceof NullType) {
writer.print("((");
writer.printType(Type.tClass
(ClassInfo.forName(outer.outer)));
writer.print(") ");
outerExpr.dumpExpression(writer, 700);
writer.print(")");
} else
outerExpr.dumpExpression(writer, 950);
writer.print(".");
}
}
}
if (specialFlag) {
if (opIsThis
&& (((ThisOperator)subExpressions[0]).getClassInfo()
== methodAnalyzer.getClazz())) {
if (isThis()) {
/* XXX check if this is a private or final method. */
} else {
/* XXX check that this is the first defined
* super method. */
writer.print("super");
ClassInfo superClazz = getClassInfo().getSuperclass();
paramTypes[0] = superClazz == null
? Type.tObject : Type.tClass(superClazz);
opIsThis = false;
}
} else {
/* XXX check if this is a private or final method. */
int minPriority = 950; /* field access */
if (!isThis()) {
writer.print("(NON VIRTUAL ");
writer.printType(classType);
writer.print(")");
paramTypes[0] = classType;
minPriority = 700;
}
subExpressions[0].dumpExpression(writer, minPriority);
}
} else if (staticFlag) {
arg = 0;
Scope scope = writer.getScope(getClassInfo(),
Scope.CLASSSCOPE);
if (scope != null
&& !writer.conflicts(methodName, scope, Scope.METHODNAME))
opIsThis = true;
else
writer.printType(classType);
} else {
if (opIsThis) {
ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
if (writer.conflicts(methodName, scope, Scope.METHODNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else if (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getMethodAnalyzer() == null
&& writer.conflicts(methodName, null,
Scope.NOSUPERMETHODNAME)) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this.");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
writer.print(".");
}
}
} else {
if (needsCast(0, paramTypes)){
writer.print("((");
writer.printType(classType);
writer.print(") ");
subExpressions[0].dumpExpression(writer, 700);
writer.print(")");
paramTypes[0] = classType;
} else
subExpressions[0].dumpExpression(writer, 950);
}
}
if (isConstructor()) {
if (opIsThis)
writer.print("this");
} else {
if (!opIsThis)
writer.print(".");
writer.print(methodName);
}
writer.print("(");
boolean first = true;
int offset = staticFlag ? 0 : 1;
while (arg < length) {
if (!first)
writer.print(", ");
else
first = false;
int priority = 0;
if (needsCast(arg, paramTypes)) {
Type castType = methodType.getParameterTypes()[arg-offset];
writer.print("(");
writer.printType(castType);
writer.print(") ");
paramTypes[arg] = castType;
priority = 700;
}
subExpressions[arg++].dumpExpression(writer, priority);
}
writer.print(")");
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save