Compare commits

...

107 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
  1. 1
      CVSROOT/checkoutlist
  2. 3
      CVSROOT/cvswrappers
  3. 1
      CVSROOT/loginfo
  4. 206
      CVSROOT/syncmail
  5. 7
      jode/.classpath
  6. 17
      jode/.project
  7. 353
      jode/.settings/org.eclipse.jdt.core.prefs
  8. 4
      jode/.settings/org.eclipse.jdt.ui.prefs
  9. 3
      jode/.settings/org.eclipse.ltk.core.refactoring.prefs
  10. 2
      jode/AUTHORS
  11. 504
      jode/COPYING.LESSER
  12. 504
      jode/COPYING.LGPL
  13. 563
      jode/ChangeLog
  14. 69
      jode/INSTALL
  15. 3
      jode/MANIFEST.MF
  16. 5
      jode/Makefile.am
  17. 9
      jode/NEWS
  18. 97
      jode/README
  19. 5
      jode/THANKS
  20. 48
      jode/TODO
  21. 44
      jode/acinclude.m4
  22. 380
      jode/build.xml
  23. 28
      jode/config.props
  24. 245
      jode/configure.in
  25. 1
      jode/doc/.cvsignore
  26. 14
      jode/doc/Makefile.am
  27. 97
      jode/doc/applet.html
  28. 25
      jode/doc/applet.htp
  29. 36
      jode/doc/applet.php
  30. 133
      jode/doc/bluesky.html
  31. 17
      jode/doc/bluesky.htp
  32. 92
      jode/doc/download.html
  33. 39
      jode/doc/download.htp
  34. 40
      jode/doc/download.php
  35. 90
      jode/doc/faq.htp
  36. 106
      jode/doc/favicon.xpm
  37. 11
      jode/doc/feedback.htp
  38. 11
      jode/doc/footer.inc
  39. BIN
      jode/doc/gimp/jode-logo.xcf
  40. 57
      jode/doc/header.inc
  41. 84
      jode/doc/history.html
  42. 7
      jode/doc/history.htp
  43. 52
      jode/doc/htp.def
  44. 131
      jode/doc/index.html
  45. 74
      jode/doc/index.htp
  46. 69
      jode/doc/index.php
  47. BIN
      jode/doc/jode-logo.gif
  48. BIN
      jode/doc/jode-logo.png
  49. 67
      jode/doc/jode.htt
  50. 76
      jode/doc/license.html
  51. 21
      jode/doc/license.htp
  52. 15
      jode/doc/license.php
  53. 123
      jode/doc/links.html
  54. 33
      jode/doc/links.htp
  55. 132
      jode/doc/menu.inc
  56. 32
      jode/doc/myproject.jos
  57. BIN
      jode/doc/poweredbyhtp.png
  58. 62
      jode/doc/technical.texi
  59. 281
      jode/doc/usage.html
  60. 114
      jode/doc/usage.htp
  61. BIN
      jode/doc/w3c_ab.png
  62. 4
      jode/jode/.cvsignore
  63. 29
      jode/jode/AssertError.java
  64. 41
      jode/jode/Makefile.am
  65. 2
      jode/jode/bytecode/.cvsignore
  66. 229
      jode/jode/bytecode/BinaryInfo.java.in
  67. 1509
      jode/jode/bytecode/BytecodeInfo.java.in
  68. 868
      jode/jode/bytecode/ClassInfo.java.in
  69. 203
      jode/jode/bytecode/FieldInfo.java
  70. 29
      jode/jode/bytecode/Handler.java
  71. 42
      jode/jode/bytecode/InnerClassInfo.java
  72. 830
      jode/jode/bytecode/Instruction.java
  73. 29
      jode/jode/bytecode/LineNumber.java
  74. 30
      jode/jode/bytecode/LocalVariableInfo.java
  75. 45
      jode/jode/bytecode/Makefile.am
  76. 239
      jode/jode/bytecode/MethodInfo.java
  77. 576
      jode/jode/bytecode/SearchPath.java
  78. 2
      jode/jode/decompiler/.cvsignore
  79. 116
      jode/jode/decompiler/DeadCodeAnalysis.java.in
  80. 45
      jode/jode/decompiler/LocalVarEntry.java
  81. 79
      jode/jode/decompiler/LocalVariableRangeList.java
  82. 43
      jode/jode/decompiler/LocalVariableTable.java
  83. 328
      jode/jode/decompiler/Main.java
  84. 51
      jode/jode/decompiler/Makefile.am
  85. 2
      jode/jode/expr/.cvsignore
  86. 35
      jode/jode/expr/ArrayStoreOperator.java
  87. 71
      jode/jode/expr/Makefile.am
  88. 2
      jode/jode/flow/.cvsignore
  89. 68
      jode/jode/flow/Makefile.am
  90. 982
      jode/jode/flow/TransformExceptionHandlers.java.in
  91. 2
      jode/jode/jvm/.cvsignore
  92. 1127
      jode/jode/jvm/CodeVerifier.java.in
  93. 1901
      jode/jode/jvm/Interpreter.j
  94. 37
      jode/jode/jvm/Makefile.am
  95. 369
      jode/jode/jvm/SyntheticAnalyzer.java.in
  96. 2
      jode/jode/obfuscator/.cvsignore
  97. 47
      jode/jode/obfuscator/Makefile.am
  98. 2
      jode/jode/obfuscator/modules/.cvsignore
  99. 1727
      jode/jode/obfuscator/modules/ConstantAnalyzer.java.in
  100. 941
      jode/jode/obfuscator/modules/LocalOptimizer.java.in
  101. Some files were not shown because too many files have changed in this diff Show More

@ -11,3 +11,4 @@
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
syncmail

@ -20,4 +20,5 @@
#
# and value is a single-quote delimited value.
# For example:
#*.gif -k 'b'
*.gif -k 'b'
*.xcf -k 'b'

@ -24,3 +24,4 @@
#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,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,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,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

@ -1 +1 @@
Jochen Hoenicke <Jochen.Hoenicke@Informatik.Uni-Oldenburg.DE>
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.

@ -1,46 +1,23 @@
Before installing, make sure you have a java compiler (e.g javac or
jikes) and the java 1.1 runtime class library installed. If you want
to run this program you need at least a 1.1 compatible java virtual
machine. There are some bugs in javac included in the SUN JDK 1.1, it
won't work.
This package was designed to use the GNU standard for configuration
and makefiles. To build and install do the following:
1). You need a java development kit (at least version 1.1), some unix
tools and some java packages. Make sure that you have all java
packages that are needed in your classpath. This are gnu.getopt, and
if you have JDK 1.1 you also need the collection classes and swing for
1.1. These packages are accessible from the following urls:
CYGWIN (unix tools for win95/NT):
http://sourceware.cygnus.com/cygwin/
JDK 1.1:
http://java.sun.com/products/jdk/1.1/index.htm
Collection classes and Swing for JDK 1.1:
http://java.sun.com/beans/infobus/#DOWNLOAD_COLLECTIONS
http://java.sun.com/products/jfc/index.html#download-swing
JDK 1.2:
http://java.sun.com/products/jdk/1.2/index.html
Getopt:
http://www.urbanophile.com/arenn/hacking/download.html#getopt
2). Run the "configure" script to configure the package. There are
various options you might want to pass to configure to control how the
package is built. "configure --help" will give a complete list.
Use the --with-jdk option to specify the install directory of the jdk.
If you have jikes, you should specify it with --with-jikes. You can
give a path to the directory where it resides, otherwise it is
searched in the path.
3). Type "make" to build the package.
4). Type "make install" to install the package. This doesn't work yet.
Jochen
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

@ -1,5 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
SUBDIRS = jode bin doc test
EXTRA_DIST = TODO

@ -1,6 +1,11 @@
New in 1.0.94
New in 1.2
* New bytecode interface
* Faster and better flow analyzation
New in 1.1
* break long lines
* small bug fixes
* handle most of javac v8 constructs (jdk 1.3)
* bug fixes
New in 1.0.93
* anonymous and inner class decompilation reworked.

@ -1,12 +1,17 @@
JODE (Java Optimize and Decompile Environment)
This is a decompiler and optimizer for java I have written in my spare
time. The decompiler 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 the java files were compiled with `-g') and
there are often more ways to write the same thing. But jode does its
job quite well.
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
@ -25,6 +30,15 @@ The features of the decompilers are:
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,
@ -40,18 +54,6 @@ Known bugs of the decompiler:
happen when you compile with `-O' flag and javac has inlined some
methods.
- Sometimes this program may exit with an Exception or produce
incorrect code. If it produced incorrect code the code probably
can't be compiled, so that the error can be easily spotted. If you
have one of these problems (they are very rare now), I would be
very interested in a bug report (including the .class file, if
possible).
- Sometimes it generates some GOTO expression and labels. This
shouldn't happen any more with code produced by javac or jikes.
But some flow obfuscator likes Zelix Klassmaster may provoke this.
In that case you can run the Obfuscator first (to optimize away the
flow obfuscation ;-).
The features of the obfuscator are:
* Modular design, you can plug the obfuscation transformation you need
@ -66,62 +68,23 @@ The features of the obfuscator are:
PRELIMINARIES:
You need java jdk1.2 or above, and the gnu getopt package.
You should also have the jode-x.x.xx.jar file. Read INSTALL how to
compile it yourself.
Jode also works with jdk1.1, but you need the sun collection classes
and swing in that case.
Here are some URLs for the tools and packages you may need:
CYGWIN (unix tools for win95/NT):
http://sourceware.cygnus.com/cygwin/
JDK 1.1:
http://java.sun.com/products/jdk/1.1/index.htm
Collection classes and Swing for JDK 1.1:
http://java.sun.com/beans/infobus/#DOWNLOAD_COLLECTIONS
http://java.sun.com/products/jfc/index.html#download-swing
JDK 1.2:
http://java.sun.com/products/jdk/1.2/index.html
Getopt:
http://www.urbanophile.com/arenn/hacking/download.html#getopt
See INSTALL for installation instructions.
USAGE:
First set the classpath. It should contain the jar file
jode-x.x.xx.jar, the gnu getopt package and the sun collection package
for 1.1. For the swingui program you also need swing in you classpath.
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 jarfile1.jar,jarfile2.jar org.package.Class
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:
The obfuscator/deobfuscator can be run with a script:
java jode.obfuscator.Main obfuscation.jos
See XXXX for more information about the script syntax.
HISTORY:
Someday I found guavad, a disassembler for java byte code (it does
similar things like `javap -c'). 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 perl script, that does
the same. At the end of the next day I had the first working
decompiler.
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 java now, because it suited
best.
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,22 +1,50 @@
This is a list of features, that would be nice to have:
Decompiler:
- 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:
- 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:
@ -26,7 +54,11 @@ User Interface:
- 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.
- 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.

@ -1,44 +0,0 @@
dnl
dnl Add macros
dnl JODE_CHECK_JAVA
dnl
dnl JODE_CHECK_JAVA(path)
AC_DEFUN(JODE_CHECK_JAVA,
[
AC_PATH_PROG(JAVA, java, "", $1/bin:$1/jre/bin:$PATH)
AC_PATH_PROG(JAVAC, javac, "", $1/bin:$PATH)
AC_PATH_PROG(JAR, jar, "", $1/bin:$PATH)
for path in $1/lib $1/jre/lib $1/shared; do
for classlib in classes.zip rt.jar; do
AC_CHECK_FILES($path/$classlib,
[ CLASSLIB=$path/$classlib
break 3
], [ true ])
done
done
AC_SUBST(CLASSPATH)
AC_SUBST(CLASSLIB)
])
AC_DEFUN(JODE_CHECK_CLASS,
[
if (IFS=":"
clazz=`echo $1 | sed -e 's/\./\//g' -e 's/\(.*\)/\1.class/'`
myclasspath=$2;
for path in $myclasspath; do
if test -d $path; then
if test -e $path/$clazz; then
exit 0
fi
elif CLASS_CHECK $path $clazz ; then
exit 0
fi
done;
exit 1)
then
$3
else
$4
fi
])

@ -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

@ -1,245 +0,0 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AM_INIT_AUTOMAKE(jode, 1.0.93)
dnl Checks for programs.
dnl AC_PROG_CXX
dnl AC_PROG_AWK
dnl AC_PROG_CC
dnl AC_PROG_CPP
dnl AC_PROG_INSTALL
dnl AC_PROG_LN_S
AC_PROG_MAKE_SET
dnl AC_PROG_RANLIB
dnl AC_PATH_PROG(ZIP, zip)
AC_PATH_PROG(PERL, perl)
AC_PATH_PROG(CYGPATH, cygpath)
dnl Checks for libraries.
dnl Checks for header files.
dnl Checks for typedefs, structures, and compiler characteristics.
dnl Checks for library functions.
dnl hack to quote Makefile lines
QUOTE=""
AC_SUBST(QUOTE)
AC_SUBST(SHELL)
if test -n "$CYGPATH"; then
# Extra check if java take windows path?
CLASSPATH=`$CYGPATH --unix --path $CLASSPATH`
SUBSTCP="$CYGPATH --windows --path"
else
SUBSTCP="echo"
fi
AC_SUBST(SUBSTCP)
AC_ARG_WITH(java,
[ --with-java specify path to a java-like program ],
[
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then
# set javac to user input value
JODE_CHECK_JAVA(${withval})
else
JODE_CHECK_JAVA(/usr/lib/java)
fi
],
[
JODE_CHECK_JAVA(/usr/lib/java)
])
dnl jikes can also handle dependancies.
AC_ARG_WITH(jikes,
[ --with-jikes specify location of jikes ],
[
USER_SPECIFIED_JIKES=true
if test "${withval}" = "yes" || test "${withval}" = ""; then
AC_PATH_PROG(JIKES, jikes, "", $PATH)
else
echo "searching jikes in ${withval}:$PATH"
AC_PATH_PROG(JIKES, jikes, "", ${withval}:$PATH)
fi
if test -n "$JIKES"; then
JAVAC=$JIKES
fi
],
[
USER_SPECIFIED_JIKES=
AC_PATH_PROG(JIKES, jikes, "", $PATH)
])
AM_CONDITIONAL(HAVE_JIKES, test x"$JIKES" != x)
AC_ARG_WITH(javac,
[ --with-javac specify location of javac ],
[
if test x$USER_SPECIFIED_JIKES == xtrue; then
AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes)
fi
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then
AC_CHECK_FILES(${withval},
[ JAVAC=${withval} ],
[ AC_MSG_ERROR(${withval} does not exists) ])
fi
], [
dnl use jikes as default, if javac option not given.
if test -n "$JIKES"; then
JAVAC=$JIKES
fi
])
AC_PATH_PROG(UNZIP, unzip)
if test -n "$UNZIP"; then
CLASS_CHECK () {
$UNZIP -v -C `$SUBSTCP $1` $2 >/dev/null 2>&1
}
else
if test -n "$JAR"; then
CLASS_CHECK () {
$JAR -tf `$SUBSTCP $1` 2>&1 | grep $2 >/dev/null
}
else
AC_MSG_ERROR(You need either unzip or jar.)
fi
fi
AC_MSG_CHECKING(for java.lang.Object)
JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB,
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(Please specify location of core java class library) ])
AC_MSG_CHECKING(for collection classes)
JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="java.util"
COLLECTIONEXTRA="java.lang" ],
[ JODE_CHECK_CLASS(gnu.java.util.collections.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="gnu.java.util.collections"
COLLECTIONEXTRA="gnu.java.util.collections" ],
[ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="com.sun.java.util.collections"
COLLECTIONEXTRA="com.sun.java.util.collections" ],
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(You need the Java 1.2 collection classes in your classpath)
])
])
])
AC_MSG_RESULT($COLLECTIONS)
AC_SUBST(COLLECTIONS)
AC_SUBST(COLLECTIONEXTRA)
AC_MSG_CHECKING(for gnu.getopt)
JODE_CHECK_CLASS(gnu.getopt.Getopt, $CLASSPATH:$CLASSLIB,
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(You need gnu getopt for java.) ])
AC_MSG_CHECKING(for swing)
JODE_CHECK_CLASS(javax.swing.JFrame, $CLASSPATH:$CLASSLIB,
[ JAVAX_SWING="javax.swing" ],
[ JODE_CHECK_CLASS(com.sun.java.swing.JFrame, $CLASSPATH:$CLASSLIB,
[ JAVAX_SWING="com.sun.java.swing" ],
[ JAVAX_SWING="no" ]) ] )
AC_MSG_RESULT($JAVAX_SWING)
AC_SUBST(JAVAX_SWING)
if test "$JAVAX_SWING" != "no"; then
SWINGUI="swingui"
else
AC_MSG_WARN(Swing is not in classpath ... skipping swingui)
SWINGUI=""
fi
AC_SUBST(SWINGUI)
AC_SUBST(CLASSPATH)
AC_SUBST(JAVAC)
AC_OUTPUT(Makefile
javaDependencies.pl
jode/Makefile
jode/bytecode/Makefile
jode/decompiler/Makefile
jode/expr/Makefile
jode/flow/Makefile
jode/jvm/Makefile
jode/obfuscator/Makefile
jode/obfuscator/modules/Makefile
jode/swingui/Makefile
jode/type/Makefile
jode/util/Makefile
jode/bytecode/BinaryInfo.java
jode/bytecode/BytecodeInfo.java
jode/bytecode/ClassInfo.java
jode/bytecode/Reference.java
jode/decompiler/ImportHandler.java
jode/decompiler/ClassAnalyzer.java
jode/decompiler/FieldAnalyzer.java
jode/decompiler/MethodAnalyzer.java
jode/decompiler/DeadCodeAnalysis.java
jode/expr/Expression.java
jode/expr/FieldOperator.java
jode/expr/InvokeOperator.java
jode/expr/LocalVarOperator.java
jode/expr/Operator.java
jode/expr/CheckNullOperator.java
jode/flow/RetBlock.java
jode/flow/InstructionContainer.java
jode/flow/LoopBlock.java
jode/flow/SequentialBlock.java
jode/flow/SlotSet.java
jode/flow/StructuredBlock.java
jode/flow/SynchronizedBlock.java
jode/flow/VariableSet.java
jode/flow/CatchBlock.java
jode/flow/IfThenElseBlock.java
jode/flow/InstructionBlock.java
jode/flow/FlowBlock.java
jode/flow/TransformExceptionHandlers.java
jode/jvm/CodeVerifier.java
jode/jvm/Interpreter.java
jode/jvm/SyntheticAnalyzer.java
jode/obfuscator/ClassBundle.java
jode/obfuscator/ClassIdentifier.java
jode/obfuscator/ConstantRuntimeEnvironment.java
jode/obfuscator/FieldIdentifier.java
jode/obfuscator/Identifier.java
jode/obfuscator/LocalIdentifier.java
jode/obfuscator/Main.java
jode/obfuscator/MethodIdentifier.java
jode/obfuscator/OptionHandler.java
jode/obfuscator/PackageIdentifier.java
jode/obfuscator/Renamer.java
jode/obfuscator/ScriptParser.java
jode/obfuscator/TranslationTable.java
jode/obfuscator/modules/ConstantAnalyzer.java
jode/obfuscator/modules/KeywordRenamer.java
jode/obfuscator/modules/LocalOptimizer.java
jode/obfuscator/modules/LocalizeFieldTransformer.java
jode/obfuscator/modules/ModifierMatcher.java
jode/obfuscator/modules/MultiIdentifierMatcher.java
jode/obfuscator/modules/NameSwapper.java
jode/obfuscator/modules/RemovePopAnalyzer.java
jode/obfuscator/modules/SerializePreserver.java
jode/obfuscator/modules/SimpleAnalyzer.java
jode/obfuscator/modules/StrongRenamer.java
jode/obfuscator/modules/UniqueRenamer.java
jode/obfuscator/modules/WildCard.java
jode/swingui/Main.java
jode/swingui/PackagesTreeModel.java
jode/swingui/HierarchyTreeModel.java
jode/type/Type.java
jode/util/SimpleSet.java
jode/util/SimpleMap.java
jode/util/UnifyHash.java
jode/GlobalOptions.java
bin/Makefile
bin/jode
bin/jode.bat
doc/Makefile
doc/download.html
test/Makefile,
[chmod 755 javaDependencies.pl bin/jode])

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

@ -1,14 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
EXTRA_DIST = \
applet.html \
download.html.in \
history.html \
jode.html \
license.html \
links.html \
usage.html \
myproject.jos \
dasm_to_java.perl \
gimp/jode-logo.xcf \
jode-logo.gif

@ -1,97 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<h1>The <i>JODE</i> Applet</h1>
Please be patience, loading the applet may take some time.<br><br>
<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/load.html/http%3a//www.informatik.uni-oldenburg.de/~mw/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>
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). <br><br>
You may change the classpath to point to a zip or jar file of your
choice, using a similar syntax. Use <code>%3a</code> instead of a
colon `:' in the url. You can also point it to a directory containing
the class-files (include a slash `/' at the end in this case), but
this is not recommended, since it is <i>very</i> slow. You may give
multiple entries in the class path field separated by a comma.<br><br>
You can't use this applet for local files; the class files must be on
a server that is accessible from sourceforge. You can try to give
local filenames directly without the load.html wrapper, but that is
probably forbidden by your browser. Most browser only allow loading
files from the same server as the applet, and this is the reason why
you have to use such a cryptic URL.<br><br>
Save probably doesn't work, because it is forbidden by your browser.<br><br>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</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>

@ -1,36 +0,0 @@
<?php require("header.inc"); ?>
<h1>The <i>JODE</i> Applet</h1>
Please be patience, loading the applet may take some time.<br><br>
<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/load.php/http%3a//www.informatik.uni-oldenburg.de/~mw/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>
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). <br><br>
You may change the classpath to point to a zip or jar file of your
choice, using a similar syntax. Use <code>%3a</code> instead of a
colon `:' in the url. You can also point it to a directory containing
the class-files (include a slash `/' at the end in this case), but
this is not recommended, since it is <i>very</i> slow. You may give
multiple entries in the class path field separated by a comma.<br><br>
You can't use this applet for local files; the class files must be on
a server that is accessible from sourceforge. You can try to give
local filenames directly without the load.php wrapper, but that is
probably forbidden by your browser. Most browser only allow loading
files from the same server as the applet, and this is the reason why
you have to use such a cryptic URL.<br><br>
Save probably doesn't work, because it is forbidden by your browser.<br><br>
<?php require("footer.inc"); ?>

@ -1,133 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<h1>Blue Sky</h1>
<p>This section contains features that I think would be great to have,
but are also very hard to implement. The name of the section is
inspired, by <a
href="http://www.mozilla.org/blue-sky/">Mozilla</a>.</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
<pre>
int l_1 = array.length
String l_2 = object.getName()
</pre>
we could name them "length" and "name". If we
have assignments:
<pre>
MenuItem local_1 = new MenuItem("Open");
MenuItem local_2 = new MenuItem("Save");
</pre>
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>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -1,10 +1,7 @@
<?php require("header.inc"); ?>
<h1>Blue Sky</h1>
<section title="Wish List">
<p>This section contains features that I think would be great to have,
but are also very hard to implement. The name of the section is
inspired, by <a
href="http://www.mozilla.org/blue-sky/">Mozilla</a>.</p>
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>
@ -29,18 +26,18 @@ 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
assignments</p>
<pre>
int l_1 = array.length
String l_2 = object.getName()
</pre>
we could name them "length" and "name". If we
have assignments:
<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>
good names would be <code>miOpen</code> and <code>miSave</code>. </p>
<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
@ -69,4 +66,4 @@ 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>
<?php require("footer.inc"); ?>
</section>

@ -1,92 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<h2>Download</h2>
The latest source code of <i>JODE</i> is available at the <a href="http://sourceforge.net/project/?group_id=3790">project page</a>.
You need several other packages to build <i>JODE</i>, check the <a href="./links.html">links page</a>. <br><br>
The simplest way to get it, especially for non unix users, is in
precompiled form, though. I have two jar archives at the <a
href="ftp://jode.sourceforge.net/pub/jode">ftp server</a>. You may
need to press shift while clicking on the link, depending on your
browser.
<ul> <li><a href="ftp://jode.sourceforge.net/pub/jode/jode-1.0.93-1.1.jar">jode-1.0.93-1.1.jar</a> is for JDK&nbsp;1.1. It already
contains Getopt and the collection classes from the GNU Classpath
project. If you want to use the swing interface, you have to download
swing separately. </li>
<li> <a href="ftp://jode.sourceforge.net/pub/jode/jode-1.0.93-1.2.jar">jode-1.0.93-1.2.jar</a> is for JDK&nbsp;1.2. It already
contains Getopt, so you don't need any other package.</li> </ul>
<h2>CVS Repository</h2>
You can get the latest sources from the <a href="http://sourceforge.net/cvs/?group_id=3790">CVS repository</a>.
Follow the instruction on that page; use <code>jode</code> as
<i>modulename</i>. Then change to the directory jode and run
<pre>aclocal && automake -a && autoconf</pre>
Afterwards follow the instruction in the INSTALL file.
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -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>

@ -1,40 +0,0 @@
<?php require("header.inc"); ?>
<h2>Download</h2>
The latest source code of <i>JODE</i> is available at the <?php
sflink("project/") ?>project page</a>.
You need several other packages to build <i>JODE</i>, check the <?php
selflink("links") ?>links page</a>. <br><br>
The simplest way to get it, especially for non unix users, is in
precompiled form, though. I have two jar archives at the <a
href="ftp://jode.sourceforge.net/pub/jode">ftp server</a>. You may
need to press shift while clicking on the link, depending on your
browser.
<?php
function jarlink($what) {
global $version;
echo "<a href=\"ftp://jode.sourceforge.net/pub/jode/jode-".$version.$what;
echo ".jar\">jode-".$version.$what.".jar</a>";
} ?>
<ul> <li><?php jarlink("-1.1") ?> is for JDK&nbsp;1.1. It already
contains Getopt and the collection classes from the GNU Classpath
project. If you want to use the swing interface, you have to download
swing separately. </li>
<li> <?php jarlink("-1.2") ?> is for JDK&nbsp;1.2. It already
contains Getopt, so you don't need any other package.</li> </ul>
<h2>CVS Repository</h2>
You can get the latest sources from the <?php sflink("cvs/") ?>
CVS repository</a>.
Follow the instruction on that page; use <code>jode</code> as
<i>modulename</i>. Then change to the directory jode and run
<pre>aclocal && automake -a && autoconf</pre>
Afterwards follow the instruction in the INSTALL file.
<?php require("footer.inc"); ?>

@ -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>

@ -1,11 +1,10 @@
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
<TD align="center"><SPAN class=footer>
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 30-Jun-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
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>

Binary file not shown.

@ -1,13 +1,17 @@
<?php
$version="1.0.93";
if (! $extension) {
$extension = "php";
}
$version="1.1";
function selflink($link) {
global $extension;
echo "<a href=\"./";
if ($link != "jode") {
if ($link != "index") {
if (ereg("#", $link)) {
$link = ereg_replace("#", ".php#", $link);
$link = ereg_replace("#", ".$extension#", $link);
} else {
$link .= ".php";
$link .= ".$extension";
}
echo "$link";
}
@ -17,26 +21,43 @@ function selflink($link) {
function sflink($link) {
echo "<a href=\"http://sourceforge.net/$link?group_id=3790\">";
}
?><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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 bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
<?php /* <CENTER><img src="constructionint.gif" alt="Under Construction, "><br>
beware broken links</CENTER> */ ?>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<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"); ?>
</td>
<td valign="top">

@ -1,84 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<h2>History</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. 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>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -1,6 +1,4 @@
<?php require("header.inc"); ?>
<h2>History</h2>
<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
@ -19,5 +17,4 @@ 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>
<?php require("footer.inc"); ?>
</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>

@ -1,131 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<P><i>JODE</i> is a java package containing a decompiler and an
optimizer for java. This package is freely available under the GPL
(see <a href="./license.html">license</a>).<p>
<P>The decompiler takes <tt>class</tt> files as input 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. But <i>JODE</i> does its job
quite well, so you should give it a try: <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>
<h2>News</h2>
<ul>
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li>
<li>The latest <a href="http://sourceforge.net/cvs/?group_id=3790">CVS</a> version breaks long lines</li>
<li>I can now decompile <b>inner and anonymous</b> classes.</li>
<li>The optimizer (aka obfuscator) can be customized via a small
config file</li>
<li>Jode is <tt>autoconf</tt>igured.</li>
</ul>
<h2>Limitations</h2>
<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>
<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 <i>JODE</i> generates some GOTO expression and labels.
This shouldn't happen any more with code produced by javac or jikes.
But some flow obfuscator may provoke this. In that case you can run
the Obfuscator first (to optimize away the flow obfuscation ;-).</p>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -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>

@ -1,69 +0,0 @@
<?php require("header.inc"); ?>
<P><i>JODE</i> is a java package containing a decompiler and an
optimizer for java. This package is freely available under the GPL
(see <?php selflink("license") ?>license</a>).<p>
<P>The decompiler takes <tt>class</tt> files as input 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. But <i>JODE</i> does its job
quite well, so you should give it a try: <? selflink("applet") ?>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>
<h2>News</h2>
<ul>
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li>
<li>The latest <?php sflink("cvs/") ?>CVS</a> version breaks long lines</li>
<li>I can now decompile <b>inner and anonymous</b> classes.</li>
<li>The optimizer (aka obfuscator) can be customized via a small
config file</li>
<li>Jode is <tt>autoconf</tt>igured.</li>
</ul>
<h2>Limitations</h2>
<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>
<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 <i>JODE</i> generates some GOTO expression and labels.
This shouldn't happen any more with code produced by javac or jikes.
But some flow obfuscator may provoke this. In that case you can run
the Obfuscator first (to optimize away the flow obfuscation ;-).</p>
<?php require("footer.inc"); ?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

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>

@ -1,76 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<p><i>JODE</i> is Copyright &copy; 1998-2000 by Jochen Hoenicke. <br><br>
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.<br><br>
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.
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</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>

@ -1,15 +0,0 @@
<?php require("header.inc"); ?>
<p><i>JODE</i> is Copyright &copy; 1998-2000 by Jochen Hoenicke. <br><br>
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.<br><br>
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.
<?php require("footer.inc"); ?>

@ -1,123 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<h1><i>JODE</i> Links</h1>
<h3>Other decompilers</h3>
<ul>
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/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/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>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>org.gnu.java.util.collections</code>). You can
download the <a href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.tar.gz">source code</a> (including
the script), or <a href="collections.jar">a precompiled jar file</a>.
</dd>
</dl>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -1,8 +1,7 @@
<?php require("header.inc") ?>
<h1><i>JODE</i> Links</h1>
<section title="<i>JODE</i> Links">
<h3>Other decompilers</h3>
<ul>
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Decompilers_and_Disassemblers/">The Open Directory list</a></li>
<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
@ -15,7 +14,7 @@ Dyer.
</ul>
<h3>Other obfuscators</h3>
<ul>
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Obfuscators/">The Open Directory list</a></li>
<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
@ -28,6 +27,19 @@ strings. But <i>JODE</i>'s deobfuscator can undo both.</li>
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>
@ -52,11 +64,12 @@ href="http://jedit.standmed.com/plugins/JavaInsight">JavaInsight plugin</a> for
</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>org.gnu.java.util.collections</code>). You can
download the <a href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.tar.gz">source code</a> (including
the script), or <a href="collections.jar">a precompiled jar file</a>.
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>
<?php require("footer.inc"); ?>
</section>

@ -1,115 +1,47 @@
<?php
$menu = array(
"Jode",
array("<B>Home</B>" , "selflink", "jode",
$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"),
"Feedback",
array("Bug Tracking" , "sflink", "bugs/",
"Public Forums" , "sflink", "forum/",
"Mailing List" , "link",
"http://lists.sourceforge.net/mailman/listinfo/jode-users",
"Private Mail" , "link",
"http://sourceforge.net/sendmessage.php?touser=18252"),
"Download",
array("FTP server", "link", "ftp://jode.sourceforge.net/pub/jode/",
"Source releases", "sflink", "project/filelist.php"));
$images = array(
"Powered by ", "http://sourceforge.net/sflogo.php?group_id=3790&type=1",
"SourceForge", "http://sourceforge.net",
"Best viewed with ", "a-logo.gif",
"Any Browser", "http://www.anybrowser.org/campaign/");
if (eregi("^Lynx", $HTTP_USER_AGENT)) {
reset($menu);
while (list($dummy, $header) = each($menu)) {
list($dummy, $subitems) = each($menu);
echo "<b>$header:</b>\n";
reset($subitems);
while (list($dummy, $name) = each($subitems)) {
list($dummy, $type) = each($subitems);
list($dummy, $link) = each($subitems);
if ($type == "selflink") {
selflink($link);
} else if ($type == "sflink") {
sflink($link);
} else if ($type == "-") {
echo "<br>\n";
continue;
} else if ($type == "link") {
echo "<a href=\"$link\">";
}
$name = ereg_replace(" ", "&nbsp;", $name);
echo "$name</a>";
if (current($subitems)) {
echo " |\n";
}
}
echo "<br>\n\n";
}
echo "<right>\n";
reset($images);
while (list($dummy, $label) = each($images)) {
list($dummy, $src) = each($images);
list($dummy, $alt) = each($images);
list($dummy, $link) = each($images);
echo "$label<a href=\"$link\"><img src=\"$src\" border=0";
echo " width=88 height=31 alt=\"$alt\"></a>\n";
}
echo "</right>\n";
} else {
echo "<table cellspacing=0 cellpadding=3 width=100%";
echo " border=0 bgcolor=eeeef8>\n";
"Blue Sky" , "selflink", "bluesky");
?>
reset($menu);
while (list($dummy, $header) = each($menu)) {
list($dummy, $subitems) = each($menu);
echo "<tr bgcolor=\"7272cc\">\n<td align=\"center\">";
echo "<font color=\"ffffff\"><b>$header</b></font></td></tr>\n";
echo "<tr><td align=\"right\">\n";
reset($subitems);
while (list($dummy, $name) = each($subitems)) {
list($dummy, $type) = each($subitems);
list($dummy, $link) = each($subitems);
if ($type == "selflink") {
selflink($link);
} else if ($type == "sflink") {
sflink($link);
} else if ($type == "-") {
echo "<br>\n";
continue;
} else if ($type == "link") {
echo "<a href=\"$link\">";
}
$name = ereg_replace(" ", "&nbsp;", $name);
<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>";
if (current($subitems)) {
echo "<br>\n";
}
}
} 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>";
}
echo "</td></tr>\n";
echo "<tr bgcolor=\"ffffff\"><td align=\"center\">";
reset($images);
while (list($dummy, $label) = each($images)) {
list($dummy, $src) = each($images);
list($dummy, $alt) = each($images);
list($dummy, $link) = each($images);
echo "<br>$label<br>\n";
echo "<a href=\"$link\"><img src=\"$src\" border=0";
echo " width=88 height=31 alt=\"$alt\"></a><br>\n";
if (current($menu)) {
echo " |\n";
}
echo "</td></tr></table>\n";
}
?>
</td></tr>
</table><br>

@ -50,3 +50,35 @@ analyzer = new ConstantAnalyzer
# 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.

@ -1,281 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<html>
<head>
<title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30">
<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">
</head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0">
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td>
</td>
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td>
</tr>
<tr>
<td valign="top">
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8>
<tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr>
<tr><td align="right">
<a href="./"><B>Home</B></a><br>
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br>
<br>
<a href="./applet.html">Applet</a><br>
<a href="./download.html">Download</a><br>
<a href="./usage.html">Documentation</a><br>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br>
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr>
<tr><td align="right">
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br>
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br>
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br>
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc">
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr>
<tr><td align="right">
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br>
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr>
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br>
<br>Best viewed with <br>
<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>
</td>
<td valign="top">
<a name="decompiler">
<h1>Using the Decompiler</h1></a>
After you have <a href="./download.html">downloaded</a> the necessary
packages, put them into your <tt>CLASSPATH</tt>:
<ul><li>Under Windows you have to start a MSDOS session and type
something like:
<pre>
set CLASSPATH=C:\download\jode-xxx.jar;C:\swing\swingall.jar
</pre>
</li><li>Under Unix you start a shell and type (for bourne shell):
<pre>export CLASSPATH=/tmp/jode-xxx.jar:/usr/local/swing/swingall.jar</pre>
or for csh:
<pre>setenv CLASSPATH /tmp/jode-xxx.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. Adapt the CLASSPATH in the file and put it to a
convenient location.
<pre>
jar -xvf jode-xxx.jar bin/jode.bat <i>resp.</i> bin/jode
</pre>
<a name="cmdline"><h3>Command Line Interface</h3></a>
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>
<a name="awt"><h3>AWT Interface</h3></a>
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="./usage.html#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.
<a name="swing"><h3>Swing Interface</h3></a>
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 like this:
<pre>
java jode.swingui.Main --classpath classes.jar
</pre>
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.<br>
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.<br>
<a name="java"><h3>Java Interface</h3></a>
If you want to integrate <i>JODE</i> into your own java program, you
can use the <a
href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a>
class. Note that the GPL only allows you to integrate <i>JODE</i>
into GPL programs. Please contact me if you use <i>JODE</i> in this
way.<br>
You may use this <a
href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped
down jar archive</a> containing all necessary classes.
<a name="optimizer"><h1>Using the Obfuscator</h1>
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:
<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.</p>
<pre>
preserve = 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.
<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>
</p>
<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>
</td></tr>
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR>
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar">
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

@ -1,36 +1,40 @@
<?php require("header.inc") ?>
<?php /* MOVE TO menu.inc
<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>
*/ ?>
<a name="decompiler">
<h1>Using the Decompiler</h1></a>
After you have <?php selflink("download") ?>downloaded</a> the necessary
packages, put them into your <tt>CLASSPATH</tt>:
</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-xxx.jar;C:\swing\swingall.jar
set CLASSPATH=C:\download\jode-<use version>.jar;C:\swing\swingall.jar
</pre>
</li><li>Under Unix you start a shell and type (for bourne shell):
<pre>export CLASSPATH=/tmp/jode-xxx.jar:/usr/local/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-xxx.jar:/usr/local/swing/swingall.jar</pre>
<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. Adapt the CLASSPATH in the file and put it to a
convenient location.
that you can use. You can extract it with the following command:
<pre>
jar -xvf jode-xxx.jar bin/jode.bat <i>resp.</i> bin/jode
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>
<a name="cmdline"><h3>Command Line Interface</h3></a>
<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
@ -41,12 +45,19 @@ following command will give a complete list of the available commands:
<pre>java jode.decompiler.Main --help</pre>
<a name="awt"><h3>AWT Interface</h3></a>
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 <?php selflink("applet") ?>
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 <?php
selflink("usage#decompiler") ?>above</a>), with
after setting the <tt>CLASSPATH</tt> (see <a
href="#decompiler">above</a>), with
<pre>java jode.decompiler.Window</pre>
@ -56,44 +67,49 @@ 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.
<a name="swing"><h3>Swing Interface</h3></a>
<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 <?php selflink("links#swing") ?>link
page</a>. You can invoke it like this:
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 jode.swingui.Main --classpath classes.jar
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>
The swing interface will show the package hierarchie of all classes
<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.<br>
class inheritence tree.</p>
The swing interface is very useful to browse through class files if
<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.<br>
<a name="java"><h3>Java Interface</h3></a>
you won't find a save option there.</p>
If you want to integrate <i>JODE</i> into your own java program, you
can use the <a
href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a>
class. Note that the GPL only allows you to integrate <i>JODE</i>
into GPL programs. Please contact me if you use <i>JODE</i> in this
way.<br>
<h3><a name="java">Java Interface</a></h3>
You may use this <a
href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped
down jar archive</a> containing all necessary classes.
<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>
<a name="optimizer"><h1>Using the Obfuscator</h1>
<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>
To use the obfuscator you should first create a script file, say <a
<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:
obfuscator with:</p>
<pre>
java jode.obfuscator.Main myproject.jos
</pre>
@ -155,12 +171,16 @@ load = new WildCard { value = "org.myorg.myproject" },
<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
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.</p>
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 WildCard { value = "org.myorg.ApplicationClass.main.*" },
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>
@ -191,7 +211,7 @@ renamer = new StrongRenamer
<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>
renamer.</p>
<pre>
table = "translat.tbl"
</pre>
@ -201,6 +221,7 @@ 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>
@ -212,7 +233,6 @@ 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>
</p>
<pre>
analyzer = new ConstantAnalyzer
</pre>
@ -227,4 +247,4 @@ change the bytecode interface.</p>
<pre>
post = new LocalOptimizer, new RemovePopAnalyzer
</pre>
<?php require("footer.inc") ?>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -1,4 +0,0 @@
Makefile
Makefile.in
.java.deps
jode.jar

@ -1,29 +0,0 @@
/* AssertError 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;
public class AssertError extends Error {
public AssertError() {
}
public AssertError(String detail) {
super(detail);
}
}

@ -1,41 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
SUBDIRS = util bytecode type jvm expr flow decompiler obfuscator @SWINGUI@
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
AssertError.java \
GlobalOptions.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
JARFILE = jode-@VERSION@.jar
#data_DATA = $(JARFILE)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep
$(JARFILE): $(noinst_DATA)
CLASSPATH=$(top_builddir):$(CLASSPATH) $(JAVA) -mx80m \
jode.obfuscator.Main --classpath=$(top_builddir) \
--dest=$(JARFILE) -v -v $(srcdir)/jode.jodescript

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

@ -1,229 +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.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import jode.util.SimpleMap;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator;
/**
*
* @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 KNOWNATTRIBS = 0x10;
public static final int INNERCLASSES = 0x20;
public static final int OUTERCLASSES = 0x40;
public static final int UNKNOWNATTRIBS = 0x80;
public static final int FULLINFO = 0xff;
public static final int MOSTINFO = 0x7f;
public static final int REFLECTINFO = 0x6f;
private Map unknownAttributes = null;
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 & UNKNOWNATTRIBS) != 0) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
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 = null;
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();
}
}
public void dropInfo(int howMuch) {
if ((howMuch & UNKNOWNATTRIBS) != 0)
unknownAttributes = null;
}
protected void prepareAttributes(GrowableConstantPool gcp) {
if (unknownAttributes == null)
return;
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 = getKnownAttributeCount();
if (unknownAttributes != null)
count += unknownAttributes.size();
output.writeShort(count);
writeKnownAttributes(constantPool, output);
if (unknownAttributes != null) {
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 */
if (unknownAttributes != null) {
Iterator i = unknownAttributes.values().iterator();
while (i.hasNext())
size += 2 + 4 + ((byte[]) i.next()).length;
}
return size;
}
public byte[] findAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.get(name);
return null;
}
public Iterator getAttributes() {
if (unknownAttributes != null)
return unknownAttributes.values().iterator();
return Collections.EMPTY_SET.iterator();
}
public void setAttribute(String name, byte[] content) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
unknownAttributes.put(name, content);
}
public byte[] removeAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.remove(name);
return null;
}
public void removeAllAttributes() {
unknownAttributes = null;
}
}

File diff suppressed because it is too large Load Diff

@ -1,868 +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.util.UnifyHash;
import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import @COLLECTIONS@.Iterator;
import java.lang.reflect.Constructor;
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. <br>
*
* 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. <br>
*
* <h2>The InnerClasses attribute</h2>
*
* The InnerClasses attribute is transformed in a special way by this
* class so we want to taker a closer look. According to the <a
* href="http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html#18814">inner
* class specification</a> there must be an InnerClass attribute for
* every non top-level class that is referenced somewhere in the
* bytecode. This implies that if this is an inner class, it must
* contain a inner class attribute for itself. Before a class is
* referenced as outer class in an InnerClass attribute, it must be
* described by another InnerClass attribute. <br>
*
* Since every class references itself, there must be informations
* about the outer class for each class scoped class. If that outer
* class is an outer class again, there must be information about it,
* too. This particular chain of InnerClassInfos is returned by the
* getOuterClasses() method; for convenience in reverse order, i.e.
* current class first, then the outer classes from innermost to
* outermost. <br>
*
* A valid bytecode must also contain InnerClass infos for each inner
* classes it declares. These information are returned by the
* getInnerClasses() method. The order of these classes is the same
* as in the bytecode attribute.
*
* All remaining attributes are returned by getExtraClasses() in the
* same order as in the bytecode attribute.
*
* @author Jochen Hoenicke
*/
public class ClassInfo extends BinaryInfo {
private static SearchPath classpath;
private static final UnifyHash classes = new UnifyHash();
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) {
setClassPath(new SearchPath(path));
}
public static void setClassPath(SearchPath path) {
if (classpath != path) {
classpath = path;
Iterator i = classes.iterator();
while (i.hasNext()) {
ClassInfo ci = (ClassInfo) i.next();
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);
int hash = name.hashCode();
Iterator iter = classes.iterateHashCode(hash);
while (iter.hasNext()) {
ClassInfo clazz = (ClassInfo) iter.next();
if (clazz.name.equals(name))
return clazz;
}
ClassInfo clazz = new ClassInfo(name);
classes.put(hash, clazz);
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 & KNOWNATTRIBS) != 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();
if (length != 2 + 8 * count)
throw new ClassFormatException
("InnerClasses attribute has wrong length");
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;
}
/* Now innerClasses are at the front of innerClassInfo array
* in correct order. The other InnerClassInfos are in reverse
* order in the rest of the innerClassInfo array.
*/
/* We now count the outerClasses. The reverse order is the
* right thing for us.
*/
{
String lastOuterName = getName();
for (int i = count - extraCount;
i < count && lastOuterName != null; i++) {
InnerClassInfo ici = innerClassInfo[i];
if (ici.inner.equals(lastOuterName)) {
outerCount++;
extraCount--;
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];
} else
outerClasses = null;
if (extraCount > 0) {
extraClasses = new InnerClassInfo[extraCount];
} else
extraClasses = null;
/* The last part: We split between outer and extra classes.
* In this step we will also revert the order of the extra
* classes.
*/
{
int outerPtr = 0;
String lastOuterName = getName();
for (int i = count - extraCount - outerCount;
i < count; i++) {
InnerClassInfo ici = innerClassInfo[i];
/* If we counted correctly there is no NullPointer
* or ArrayIndexOutOfBoundsException here
*/
if (ici.inner.equals(lastOuterName)) {
outerClasses[outerPtr++] = ici;
lastOuterName = ici.outer;
} else
extraClasses[--extraCount] = ici;
}
}
} else
super.readAttribute(name, length, cp, input, howMuch);
}
public void read(DataInputStream input, int howMuch) throws IOException {
/* Since we have to read the whole class anyway, we load all
* info, that we may need later and that does not take much memory.
*/
howMuch |= HIERARCHY | INNERCLASSES | OUTERCLASSES;
howMuch &= ~status;
/* 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 | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
int count = input.readUnsignedShort();
if ((status & FIELDS) == 0)
fields = new FieldInfo[count];
for (int i=0; i< count; i++) {
if ((status & FIELDS) == 0)
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 | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
int count = input.readUnsignedShort();
if ((status & METHODS) == 0)
methods = new MethodInfo[count];
for (int i=0; i< count; i++) {
if ((status & METHODS) == 0)
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);
status |= 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 = clazz == Object.class ? null : javaLangObject;
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 = TypeSignature.getSignature(fs[i].getType());
fields[i] = new FieldInfo
(this, fs[i].getName(), type, fs[i].getModifiers());
}
}
if ((howMuch & METHODS) != 0 && methods == null) {
Constructor[] cs;
Method[] ms;
try {
cs = clazz.getDeclaredConstructors();
ms = clazz.getDeclaredMethods();
} catch (SecurityException ex) {
cs = clazz.getConstructors();
ms = clazz.getMethods();
GlobalOptions.err.println
("Could only get public methods of class "
+ name + ".");
}
methods = new MethodInfo[cs.length + ms.length];
for (int i = cs.length; --i >= 0; ) {
String type = TypeSignature.getSignature
(cs[i].getParameterTypes(), void.class);
methods[i] = new MethodInfo
(this, "<init>", type, cs[i].getModifiers());
}
for (int i = ms.length; --i >= 0; ) {
String type = TypeSignature.getSignature
(ms[i].getParameterTypes(), ms[i].getReturnType());
methods[cs.length+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 inner classes 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
(new BufferedInputStream
(classpath.getFile(name.replace('.', '/') + ".class")));
read(input, 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 : "") + ")");
ex.printStackTrace(GlobalOptions.err);
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;
}
}
/**
* This is the counter part to loadInfo. It will drop all info specified
* in howMuch and clean up the memory.
* @param howMuch tells how much info we should drop
*/
public void dropInfo(int howMuch) {
if ((status & howMuch) == 0)
return;
if (modified) {
System.err.println("Dropping info 0x"
+ Integer.toHexString(howMuch)
+ " (status 0x" + Integer.toHexString(status)
+ ") in class " + this);
Thread.dumpStack();
return;
}
howMuch &= status;
if ((howMuch & FIELDS) != 0) {
fields = null;
} else if ((status & FIELDS) != 0
&& (howMuch & (KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
for (int i=0; i < fields.length; i++)
fields[i].dropInfo(howMuch);
}
if ((howMuch & METHODS) != 0) {
methods = null;
} else if ((status & METHODS) != 0
&& (howMuch & (KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
for (int i=0; i < methods.length; i++)
methods[i].dropInfo(howMuch);
}
if ((howMuch & KNOWNATTRIBS) != 0)
sourceFile = null;
if ((howMuch & OUTERCLASSES) != 0)
outerClasses = null;
if ((howMuch & INNERCLASSES) != 0) {
innerClasses = null;
extraClasses = null;
}
super.dropInfo(howMuch);
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< fields.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,203 +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.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
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 & KNOWNATTRIBS) != 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 void dropInfo(int howMuch) {
if ((howMuch & KNOWNATTRIBS) != 0)
constant = null;
super.dropInfo(howMuch);
}
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() {
clazzInfo.loadInfo(KNOWNATTRIBS);
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,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,42 +0,0 @@
/* InnerClassInfo 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 inner class.
*/
public class InnerClassInfo {
public String inner, outer;
public String name;
public int modifiers;
public InnerClassInfo(String inner, String outer, String name, int modif) {
this.inner = inner;
this.outer = outer;
this.name = name;
this.modifiers = modif;
}
public String toString() {
return "InnerClassInfo["+inner+","+outer+","+name+","
+java.lang.reflect.Modifier.toString(modifiers)+"]";
}
}

@ -1,830 +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;
/**
* This class represents an instruction in the byte code.
*
*/
public final class Instruction implements Opcodes{
/**
* The opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre>
*/
// a byte would be enough, but then we would need an unsigned convert.
private int opcode;
/**
* If this opcode uses a local this gives the slot. For multianewarray
* this gives the dimension.
*/
private int shortData;
/**
* The address of this opcode.
*/
private int addr;
/**
* Optional object data for this opcode. There are four different
* usages of this field:
* <dl>
* <dt>opc_ldc / opc_ldc2_w</dt>
* <dd>The constant of type Integer/Long/Float/Double/String. </dd>
* <dt>opc_invokexxx / opc_xxxfield / opc_xxxstatic</dt>
* <dd>The field/method Reference</dd>
* <dt>opc_new / opc_checkcast / opc_instanceof / opc_multianewarray</dt>
* <dd>The typesignature of the class/array</dd>
* <dt>opc_lookupswitch</dt>
* <dd>The array of values of type int[]</dd>
* </dl>
*/
private Object objData;
/**
* The successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null means no successor, if there is one succesor, this
* is of type Instruction, otherwise, this is an array of Instruction.
*/
private Object succs;
/**
* The predecessors of this opcode, orthogonal to the succs array.
* This must be null or a non empty array.
*/
private Instruction[] preds;
/**
* The next instruction in code order.
*/
Instruction nextByAddr;
/**
* The previous instruction in code order, useful when changing
* the order.
*/
Instruction prevByAddr;
/**
* You can use this field to add some info to each instruction.
* After using, you must set it to null again.
* @XXX Do we really need this. Every field here can quickly take
* half a megabyte!
*/
private Object tmpInfo;
public Instruction(int opcode) {
this.opcode = opcode;
}
/**
* Returns the opcode of the instruction. We map some opcodes:
* <pre>
* [iflda]load_x -&gt; [iflda]load
* [iflda]store_x -&gt; [iflda]store
* [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre>
*/
public final int getOpcode() {
return opcode;
}
/**
* Returns the address of this opcode. As long as you don't remove
* or insert instructions, you can be sure, that the addresses of the
* opcodes are unique, and that
* <pre>
* instr.getAddr() + instr.getLength() == instr.getNextByAddr().getAddr()
* <pre>
*
* If you insert/remove Instructions, you should be aware that the
* above property is not guaranteed anymore.
*/
public final int getAddr() {
return addr;
}
public final int getNextAddr() {
return nextByAddr.addr;
}
/**
* Returns the length of this opcode. See getAddr() for some
* notes. Note that the length doesn't necessarily reflect the
* real length, when this bytecode is written again, since the
* length of an ldc instruction depends on the number of entries
* in constant pool, and the order they are allocated.
*/
public final int getLength() {
return getNextAddr() - addr;
}
final void setAddr(int addr) {
this.addr = addr;
}
public final boolean hasLocalSlot() {
return opcode == opc_iinc || opcode == opc_ret
|| opcode >= opc_iload && opcode <= opc_aload
|| opcode >= opc_istore && opcode <= opc_astore;
}
public final int getLocalSlot()
/*{ require { hasLocalSlot()
:: "Instruction has no slot" } }*/
{
return shortData;
}
public final void setLocalSlot(int slot)
/*{ require { hasLocalSlot()
:: "Instruction has no slot" } }*/
{
shortData = slot;
}
/**
* Optional integer data for this opcode. There are various uses
* for this:
* <dl>
* <dt>opc_iinc</dt>
* <dd>The value by which the constant is increased/decreased. (short)</dd>
* <dt>opc_multianewarray</dt>
* <dd>The number of dimensions (1..255)</dd>
* </dl>
*/
public final int getIncrement()
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray
|| opcode == opc_tableswitch
:: "Instruction has no int data" } }*/
{
/* shortData already used for local slot */
return ((Short) objData).shortValue();
}
/**
* Optional integer data for this opcode. There are various uses
* for this:
* <dl>
* <dt>opc_iinc</dt>
* <dd>The value by which the constant is increased/decreased. (short)</dd>
* <dt>opc_multianewarray</dt>
* <dd>The number of dimensions (1..255)</dd>
* </dl>
*/
public final void setIncrement(int incr)
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray
:: "Instruction has no int data" } }*/
{
/* shortData already used for local slot */
objData = new Short((short) incr);
}
/**
*
*/
public final int getDimensions()
/*{ require { opcode == opc_multianewarray
:: "Instruction has no dimensions" } }*/
{
return shortData;
}
/**
*
*/
public final void setDimensions(int dims)
/*{ require { opcode == opc_multianewarray
:: "Instruction has no dimensions" } }*/
{
shortData = dims;
}
public final Object getConstant()
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
:: "Instruction has no constant" } }*/
{
return objData;
}
public final void setConstant(Object constant)
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
:: "Instruction has no constant" } }*/
{
objData = constant;
}
public final Reference getReference()
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
:: "Instruction has no reference" } }*/
{
return (Reference) objData;
}
public final void setReference(Reference ref)
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
:: "Instruction has no reference" } }*/
{
objData = ref;
}
public final String getClazzType()
/*{ require { opcode == opc_new
|| opcode == opc_checkcast
|| opcode == opc_instanceof
|| opcode == opc_multianewarray
:: "Instruction has no typesig" } }*/
{
return (String) objData;
}
public final void setClazzType(String type)
/*{ require { opcode == opc_new
|| opcode == opc_checkcast
|| opcode == opc_instanceof
|| opcode == opc_multianewarray
:: "Instruction has no typesig" } }*/
{
objData = type;
}
public final int[] getValues()
/*{ require { opcode == opc_lookupswitch
:: "Instruction has no values" } }*/
{
return (int[]) objData;
}
public final void setValues(int[] values)
/*{ require { opcode == opc_lookupswitch
:: "Instruction has no values" } }*/
{
objData = values;
}
public final boolean doesAlwaysJump() {
switch (opcode) {
case opc_ret:
case opc_goto:
case opc_jsr:
case opc_tableswitch:
case opc_lookupswitch:
case opc_ireturn:
case opc_lreturn:
case opc_freturn:
case opc_dreturn:
case opc_areturn:
case opc_return:
case opc_athrow:
return true;
default:
return false;
}
}
public final Instruction[] getPreds() {
return preds;
}
/**
* Returns true if this opcode has successors, other than the implicit
* getNextByAddr().
*/
public boolean hasSuccs() {
return succs != null;
}
/**
* Returns the successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null means that there is no successor.
*/
public final Instruction[] getSuccs() {
if (succs instanceof Instruction)
return new Instruction[] { (Instruction) succs };
return (Instruction[]) succs;
}
/**
* Returns the single successor of this opcodes. This gives the
* target of a goto, jsr, or if opcode.
* @return null if there is no successor, otherwise the successor.
* @exception ClassCastException if this has more than one succ.
*/
public final Instruction getSingleSucc() {
return (Instruction) succs;
}
public final Instruction getPrevByAddr() {
if (prevByAddr.opcode == opc_impdep1)
return null;
return prevByAddr;
}
public final Instruction getNextByAddr() {
if (nextByAddr.opcode == opc_impdep1)
return null;
return nextByAddr;
}
public final Object getTmpInfo() {
return tmpInfo;
}
public final void setTmpInfo(Object info) {
tmpInfo = info;
}
// INTERNAL FUNCTIONS TO KEEP PREDS AND SUCCS CONSISTENT
final void removeSuccs() {
if (succs == null)
return;
if (succs instanceof Instruction[]) {
Instruction[] ss = (Instruction[]) succs;
for (int i = 0; i < ss.length; i++)
if (ss[i] != null)
ss[i].removePredecessor(this);
} else
((Instruction) succs).removePredecessor(this);
succs = null;
}
/**
* @param to may be null
*/
private final void promoteSuccs(Instruction from, Instruction to) {
if (succs == from)
succs = to;
else if (succs instanceof Instruction[]) {
Instruction[] ss = (Instruction[]) succs;
for (int i = 0; i < ss.length; i++)
if (ss[i] == from)
ss[i] = to;
}
}
/**
* @exception ClassCastException if newSuccs is neither an Instruction
* nor an array of instructions.
*/
public final void setSuccs(Object newSuccs) {
if (succs == newSuccs)
return;
removeSuccs();
if (newSuccs == null)
return;
if (newSuccs instanceof Instruction[]) {
Instruction[] ns = (Instruction[]) newSuccs;
switch (ns.length) {
case 0:
break;
case 1:
succs = ns[0];
ns[0].addPredecessor(this);
break;
default:
succs = ns;
for (int i = 0; i < ns.length; i++)
ns[i].addPredecessor(this);
break;
}
} else {
succs = newSuccs;
((Instruction) newSuccs).addPredecessor(this);
}
}
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;
}
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;
}
}
// ADDING, REMOVING AND REPLACING INSTRUCTIONS
/**
* Replaces the opcode of this instruction. You should only use the
* mapped opcodes:
* <pre>
* [iflda]load_x -&gt; [iflda]load
* [iflda]store_x -&gt; [iflda]store
* [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre>
*/
public final void replaceInstruction(Instruction newInstr,
BytecodeInfo codeinfo) {
/* remove predecessors of successors */
removeSuccs();
newInstr.addr = addr;
nextByAddr.prevByAddr = newInstr;
newInstr.nextByAddr = nextByAddr;
prevByAddr.nextByAddr = newInstr;
newInstr.prevByAddr = prevByAddr;
prevByAddr = null;
nextByAddr = null;
/* promote the successors of the predecessors to newInstr */
if (preds != null) {
for (int j=0; j < preds.length; j++)
preds[j].promoteSuccs(this, newInstr);
newInstr.preds = preds;
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 = newInstr;
if (handlers[i].end == this)
handlers[i].end = newInstr;
if (handlers[i].catcher == this)
handlers[i].catcher = newInstr;
}
/* 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 = newInstr;
if (lvt[i].end == this)
lvt[i].end = newInstr;
}
}
LineNumber[] lnt = codeinfo.getLineNumberTable();
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this)
lnt[i].start = newInstr;
}
}
}
void appendInstruction(Instruction newInstr, BytecodeInfo codeinfo) {
newInstr.addr = nextByAddr.addr;
newInstr.nextByAddr = nextByAddr;
nextByAddr.prevByAddr = newInstr;
newInstr.prevByAddr = this;
nextByAddr = newInstr;
/* adjust exception handlers end */
Handler[] handlers = codeinfo.getExceptionHandlers();
if (handlers != null) {
for (int i=0; i< handlers.length; i++) {
if (handlers[i].end == this)
handlers[i].end = newInstr;
}
}
}
/**
* Removes this instruction (as if it would be replaced by a nop).
*/
void removeInstruction(BytecodeInfo codeinfo) {
/* remove from chained list and adjust addr / length */
prevByAddr.nextByAddr = nextByAddr;
nextByAddr.prevByAddr = prevByAddr;
/* remove predecessors of successors */
removeSuccs();
/* promote the predecessors to next instruction */
if (preds != null) {
for (int j=0; j < preds.length; j++)
preds[j].promoteSuccs(this, nextByAddr);
if (nextByAddr.preds == null)
nextByAddr.preds = preds;
else {
Instruction[] newPreds = new Instruction
[nextByAddr.preds.length + preds.length];
System.arraycopy(nextByAddr.preds, 0, newPreds, 0,
nextByAddr.preds.length);
System.arraycopy(preds, 0, newPreds, nextByAddr.preds.length,
preds.length);
nextByAddr.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].end == this) {
/* 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--;
} else {
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;
}
}
/* 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].end == this) {
/* 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--;
} else {
if (lvt[i].start == this)
lvt[i].start = nextByAddr;
if (lvt[i].end == this)
lvt[i].end = prevByAddr;
}
}
}
LineNumber[] lnt = codeinfo.getLineNumberTable();
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this) {
if (nextByAddr.opcode == opc_impdep1
|| (i+1 < lnt.length
&& lnt[i+1].start == nextByAddr)) {
/* 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--;
} else
lnt[i].start = nextByAddr;
}
}
}
prevByAddr = null;
nextByAddr = null;
}
public int compareTo(Instruction instr) {
if (addr != instr.addr)
return addr - instr.addr;
if (this == instr)
return 0;
do {
instr = instr.nextByAddr;
if (instr.addr > addr)
return -1;
} while (instr != this);
return 1;
}
/**
* 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 = (byte) stackDelta.charAt(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 = getReference();
String typeSig = ref.getType();
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
poppush[0] += TypeSignature.getArgumentSize(typeSig);
poppush[1] = TypeSignature.getReturnSize(typeSig);
break;
}
case opc_putfield:
case opc_putstatic: {
Reference ref = getReference();
poppush[1] = 0;
poppush[0] = TypeSignature.getTypeSize(ref.getType());
if (opcode == opc_putfield)
poppush[0]++;
break;
}
case opc_getstatic:
case opc_getfield: {
Reference ref = getReference();
poppush[1] = TypeSignature.getTypeSize(ref.getType());
poppush[0] = opcode == opc_getfield ? 1 : 0;
break;
}
case opc_multianewarray: {
poppush[1] = 1;
poppush[0] = getDimensions();
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.doesAlwaysJump())
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.doesAlwaysJump())
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]);
if (opcode != opc_lookupswitch) {
if (hasLocalSlot())
result.append(' ').append(getLocalSlot());
if (succs != null)
result.append(' ').append(((Instruction) succs).addr);
if (objData != null)
result.append(' ').append(objData);
if (opcode == opc_multianewarray)
result.append(' ').append(getDimensions());
} else {
int[] values = getValues();
Instruction[] succs = getSuccs();
for (int i=0; i < values.length; i++) {
result.append(' ').append(values[i]).append("->")
.append(((Instruction) succs[i]).addr);
}
result.append(' ').append("default: ")
.append(((Instruction) succs[values.length]).addr);
}
return result.toString();
}
public String toString() {
return "" + addr + "_" + Integer.toHexString(hashCode());
}
private final static String stackDelta =
"\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";
/* 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,30 +0,0 @@
/* LocalVariableInfo 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 LocalVariableTable
*/
public class LocalVariableInfo {
public Instruction start, end;
public String name, type;
public int slot;
}

@ -1,45 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
BinaryInfo.java \
BytecodeInfo.java \
ClassFormatException.java \
ClassInfo.java \
ConstantPool.java \
FieldInfo.java \
GrowableConstantPool.java \
Handler.java \
InnerClassInfo.java \
Instruction.java \
LineNumber.java \
LocalVariableInfo.java \
MethodInfo.java \
Opcodes.java \
Reference.java \
SearchPath.java \
TypeSignature.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,239 +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.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
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 & KNOWNATTRIBS) != 0 && name.equals("Code")) {
bytecode = new BytecodeInfo(this);
bytecode.read(cp, input);
} else if ((howMuch & KNOWNATTRIBS) != 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 void dropInfo(int howMuch) {
if ((howMuch & KNOWNATTRIBS) != 0) {
bytecode = null;
exceptions = null;
}
if (bytecode != null)
bytecode.dropInfo(howMuch);
super.dropInfo(howMuch);
}
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) {
clazzInfo.loadInfo(KNOWNATTRIBS);
bytecode = newBytecode;
}
public void setExceptions(String[] newExceptions) {
clazzInfo.loadInfo(KNOWNATTRIBS);
exceptions = newExceptions;
}
public String toString() {
return "Method "+Modifier.toString(modifier)+" "+
typeSig + " " + clazzInfo.getName() + "."+ name;
}
}

@ -1,576 +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.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
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.
*
* We currently allow both pathSeparatorChar and
* altPathSeparatorChar and decide if it is a protocol separator
* by context.
*/
public static final char altPathSeparatorChar = ',';
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) {
// Calculate a good approximation (rounded upwards) of the tokens
// in this path.
int length = 1;
for (int index=path.indexOf(File.pathSeparatorChar);
index != -1; length++)
index = path.indexOf(File.pathSeparatorChar, index+1);
if (File.pathSeparatorChar != altPathSeparatorChar) {
for (int index=path.indexOf(altPathSeparatorChar);
index != -1; length++)
index = path.indexOf(altPathSeparatorChar, index+1);
}
bases = new URL[length];
urlzips = new byte[length][];
dirs = new File[length];
zips = new ZipFile[length];
zipEntries = new Hashtable[length];
zipDirs = new String[length];
int i = 0;
for (int ptr=0; ptr < path.length(); ptr++, i++) {
int next = ptr;
while (next < path.length()
&& path.charAt(next) != File.pathSeparatorChar
&& path.charAt(next) != altPathSeparatorChar)
next++;
int index = ptr;
colon_separator:
while (next > ptr
&& next < path.length()
&& path.charAt(next) == ':') {
// Check if this is a URL instead of a pathSeparator
// Since this is a while loop it allows nested urls like
// jar:ftp://ftp.foo.org/pub/foo.jar!/
while (index < next) {
char c = path.charAt(index);
// According to RFC 1738 letters, digits, '+', '-'
// and '.' are allowed SCHEMA characters. We
// disallow '.' because it is a good marker that
// the user has specified a filename instead of a
// URL.
if ((c < 'A' || c > 'Z')
&& (c < 'a' || c > 'z')
&& (c < '0' || c > '9')
&& "+-".indexOf(c) == -1) {
break colon_separator;
}
index++;
}
next++;
index++;
while (next < path.length()
&& path.charAt(next) != File.pathSeparatorChar
&& path.charAt(next) != altPathSeparatorChar)
next++;
}
String token = path.substring(ptr, next);
ptr = next;
boolean mustBeJar = false;
// We handle jar URL's ourself.
if (token.startsWith("jar:")) {
index = 0;
do {
index = token.indexOf('!', index);
} while (index != -1 && index != token.length()-1
&& token.charAt(index+1) != '/');
if (index == -1 || index == token.length()-1) {
GlobalOptions.err.println("Warning: Illegal jar url "
+ token + ".");
continue;
}
zipDirs[i] = token.substring(index+2);
if (!zipDirs[i].endsWith("/"))
zipDirs[i] = zipDirs[i] + "/";
token = token.substring(4, index);
mustBeJar = true;
}
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,2 +0,0 @@
Makefile
Makefile.in

@ -1,116 +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;
import @COLLECTIONS@.Iterator;
public class DeadCodeAnalysis {
private final static String REACHABLE = "R";
private final static String REACHCHANGED = "C";
private static void propagateReachability(BytecodeInfo code) {
boolean changed;
do {
changed = false;
for (Iterator iter = code.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getTmpInfo() == REACHCHANGED) {
changed = true;
instr.setTmpInfo(REACHABLE);
Instruction[] succs = instr.getSuccs();
if (succs != null)
for (int i=0; i< succs.length; i++)
if (succs[i].getTmpInfo() == null)
succs[i].setTmpInfo(REACHCHANGED);
if (!instr.doesAlwaysJump()
&& instr.getNextByAddr() != null)
if (instr.getNextByAddr().getTmpInfo() == null)
instr.getNextByAddr().setTmpInfo(REACHCHANGED);
/*XXX code after jsr reachable iff ret is reachable...*/
if (instr.getOpcode() == Opcodes.opc_jsr)
if (instr.getNextByAddr().getTmpInfo() == null)
instr.getNextByAddr().setTmpInfo(REACHCHANGED);
}
}
} while (changed);
}
public static void removeDeadCode(BytecodeInfo code) {
((Instruction) code.getInstructions().get(0)).setTmpInfo(REACHCHANGED);
propagateReachability(code);
Handler[] handlers = code.getExceptionHandlers();
boolean changed;
do {
changed = false;
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher.getTmpInfo() == 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.getNextByAddr()) {
if (instr.getTmpInfo() != null) {
handlers[i].catcher.setTmpInfo(REACHCHANGED);
propagateReachability(code);
changed = true;
break;
}
if (instr == handlers[i].end)
break;
}
}
}
} while (changed);
for (int i=0; i< handlers.length; i++) {
/* A handler is not reachable iff the catcher is not reachable */
if (handlers[i].catcher.getTmpInfo() == 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.getTmpInfo() == null)
handlers[i].start = handlers[i].start.getNextByAddr();
while (handlers[i].end.getTmpInfo() == null)
handlers[i].end = handlers[i].end.getPrevByAddr();
}
}
/* Now remove the dead code and clean up tmpInfo */
for (Iterator i = code.getInstructions().iterator(); i.hasNext(); ) {
Instruction instr = (Instruction) i.next();
if (instr.getTmpInfo() != null)
instr.setTmpInfo(null);
else
i.remove();
}
}
}

@ -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,43 +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 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.getAddr(),
lvt[i].end.getAddr(),
lvt[i].name, Type.tType(lvt[i].type));
}
public LocalVarEntry getLocal(int slot, int addr)
throws ArrayIndexOutOfBoundsException
{
return locals[slot].getInfo(addr);
}
}

@ -1,328 +0,0 @@
/* Main 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.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.GlobalOptions;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;
import gnu.getopt.LongOpt;
import gnu.getopt.Getopt;
public class Main extends Options {
private static final int OPTION_START=0x10000;
private static final int OPTION_END =0x20000;
private static final LongOpt[] longOptions = new LongOpt[] {
new LongOpt("cp", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("classpath", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("dest", LongOpt.REQUIRED_ARGUMENT, null, 'd'),
new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V'),
new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v'),
new LongOpt("debug", LongOpt.OPTIONAL_ARGUMENT, null, 'D'),
new LongOpt("import", LongOpt.REQUIRED_ARGUMENT, null, 'i'),
new LongOpt("style", LongOpt.REQUIRED_ARGUMENT, null, 's'),
new LongOpt("lvt", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+0),
new LongOpt("inner", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+1),
new LongOpt("anonymous", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+2),
new LongOpt("push", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+3),
new LongOpt("pretty", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+4),
new LongOpt("decrypt", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+5),
new LongOpt("onetime", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+6),
new LongOpt("immediate", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+7),
new LongOpt("verify", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+8),
new LongOpt("contrafo", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+9)
};
public static void usage() {
PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version);
err.println("Usage: java jode.decompiler.Main [OPTIONS]... [CLASSES]...");
err.println(" -h, --help "+
"show this information.");
err.println(" -V, --version "+
"output version information and exit.");
err.println(" -v, --verbose "+
"be verbose (multiple times means more verbose).");
err.println(" -c, --classpath <path> "+
"search for classes in specified classpath.");
err.println(" "+
"The directories should be separated by ','.");
err.println(" -d, --dest <dir> "+
"write decompiled files to disk into directory destdir.");
err.println(" -s, --style {sun|gnu} "+
"specify indentation style");
err.println(" -i, --import <pkglimit>,<clslimit>");
err.println(" "+
"import classes used more than clslimit times");
err.println(" "+
"and packages with more then pkglimit used classes.");
err.println(" "+
"Limit 0 means, never import, default is 0,1.");
err.println("The following options can be turned on or off with `yes' or `no' argument.");
err.println(" --inner "+
"decompile inner classes (default).");
err.println(" --anonymous "+
"decompile anonymous classes (default).");
err.println(" --contrafo "+
"transform constructors of inner classes (default).");
err.println(" --lvt "+
"use the local variable table (default).");
err.println(" --pretty "+
"use `pretty' names for local variables.");
err.println(" --push "+
"allow PUSH instructions in output.");
err.println(" --decrypt "+
"decrypt encrypted strings (default).");
err.println(" --onetime "+
"remove locals, that are used only one time.");
err.println(" --immediate "+
"output source immediately (may produce buggy code).");
err.println(" --verify "+
"verify code before decompiling it.");
err.println("Debugging options, mainly used to debug this decompiler:");
err.println(" -D, --debug=... "+
"use --debug=help for more information.");
}
public static boolean handleOption(int option, int longind, String arg) {
if (arg == null)
options ^= 1 << option;
else if ("yes".startsWith(arg) || arg.equals("on"))
options |= 1 << option;
else if ("no".startsWith(arg) || arg.equals("off"))
options &= ~(1 << option);
else {
GlobalOptions.err.println
("jode.decompiler.Main: option --"+longOptions[longind].getName()
+" takes one of `yes', `no', `on', `off' as parameter");
return false;
}
return true;
}
public static void main(String[] params) {
if (params.length == 0) {
usage();
return;
}
String classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.altPathSeparatorChar);
String destDir = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;;
GlobalOptions.err.println(GlobalOptions.copyright);
boolean errorInParams = false;
Getopt g = new Getopt("jode.decompiler.Main", params, "hVvc:d:D:i:s:",
longOptions, true);
for (int opt = g.getopt(); opt != -1; opt = g.getopt()) {
switch(opt) {
case 0:
break;
case 'h':
usage();
errorInParams = true;
break;
case 'V':
GlobalOptions.err.println(GlobalOptions.version);
break;
case 'c':
classPath = g.getOptarg();
break;
case 'd':
destDir = g.getOptarg();
break;
case 'v': {
String arg = g.getOptarg();
if (arg == null)
GlobalOptions.verboseLevel++;
else {
try {
GlobalOptions.verboseLevel = Integer.parseInt(arg);
} catch (NumberFormatException ex) {
GlobalOptions.err.println
("jode.decompiler.Main: Argument `"
+arg+"' to --verbose must be numeric:");
errorInParams = true;
}
}
break;
}
case 'D': {
String arg = g.getOptarg();
if (arg == null)
arg = "help";
errorInParams |= !GlobalOptions.setDebugging(arg);
break;
}
case 's': {
String arg = g.getOptarg();
if ("sun".startsWith(arg))
outputStyle = SUN_STYLE;
else if ("gnu".startsWith(arg))
outputStyle = GNU_STYLE;
else {
GlobalOptions.err.println
("jode.decompiler.Main: Unknown style `"+arg+"'.");
errorInParams = true;
}
break;
}
case 'i': {
String arg = g.getOptarg();
int comma = arg.indexOf(',');
try {
int packLimit = Integer.parseInt(arg.substring(0, comma));
if (packLimit == 0)
packLimit = Integer.MAX_VALUE;
if (packLimit < 0)
throw new IllegalArgumentException();
int clazzLimit = Integer.parseInt(arg.substring(comma+1));
if (clazzLimit == 0)
clazzLimit = Integer.MAX_VALUE;
if (clazzLimit < 0)
throw new IllegalArgumentException();
importPackageLimit = packLimit;
importClassLimit = clazzLimit;
} catch (RuntimeException ex) {
GlobalOptions.err.println
("jode.decompiler.Main: Invalid argument for -i option.");
errorInParams = true;
}
break;
}
default:
if (opt >= OPTION_START && opt <= OPTION_END) {
errorInParams |= !handleOption(opt-OPTION_START,
g.getLongind(),
g.getOptarg());
} else
errorInParams = true;
break;
}
}
if (errorInParams)
return;
ClassInfo.setClassPath(classPath.toString());
ImportHandler imports = new ImportHandler(importPackageLimit,
importClassLimit);
ZipOutputStream destZip = null;
TabbedPrintWriter writer = null;
if (destDir == null)
writer = new TabbedPrintWriter(System.out, imports);
else if (destDir.toLowerCase().endsWith(".zip")
|| destDir.toLowerCase().endsWith(".jar")) {
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 (int i= g.getOptind(); 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,51 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
Analyzer.java \
Applet.java \
ClassAnalyzer.java \
ClassDeclarer.java \
DeadCodeAnalysis.java \
Declarable.java \
Decompiler.java \
FieldAnalyzer.java \
ImportHandler.java \
LocalInfo.java \
LocalVarEntry.java \
LocalVariableRangeList.java \
LocalVariableTable.java \
Main.java \
MethodAnalyzer.java \
Opcodes.java \
Options.java \
OuterValueListener.java \
OuterValues.java \
ProgressListener.java \
Scope.java \
TabbedPrintWriter.java \
Window.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

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

@ -1,35 +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 ArrayLoadOperator
implements LValueExpression {
public ArrayStoreOperator(Type type) {
super(type);
}
public boolean matches(Operator loadop) {
return loadop instanceof ArrayLoadOperator;
}
}

@ -1,71 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
ArrayLengthOperator.java \
ArrayLoadOperator.java \
ArrayStoreOperator.java \
BinaryOperator.java \
CheckCastOperator.java \
CheckNullOperator.java \
ClassFieldOperator.java \
CombineableOperator.java \
CompareBinaryOperator.java \
CompareToIntOperator.java \
CompareUnaryOperator.java \
ConstOperator.java \
ConstantArrayOperator.java \
ConvertOperator.java \
Expression.java \
FieldOperator.java \
GetFieldOperator.java \
IIncOperator.java \
IfThenElseOperator.java \
InstanceOfOperator.java \
InvokeOperator.java \
LValueExpression.java \
LocalLoadOperator.java \
LocalStoreOperator.java \
LocalVarOperator.java \
MatchableOperator.java \
MonitorEnterOperator.java \
MonitorExitOperator.java \
NewArrayOperator.java \
NewOperator.java \
NoArgOperator.java \
NopOperator.java \
Operator.java \
OuterLocalOperator.java \
PopOperator.java \
PrePostFixOperator.java \
PutFieldOperator.java \
ShiftOperator.java \
SimpleOperator.java \
StoreInstruction.java \
StringAddOperator.java \
ThisOperator.java \
UnaryOperator.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

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

@ -1,68 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
BreakBlock.java \
BreakableBlock.java \
CaseBlock.java \
CatchBlock.java \
CombineIfGotoExpressions.java \
CompleteSynchronized.java \
ConditionalBlock.java \
ContinueBlock.java \
CreateAssignExpression.java \
CreateCheckNull.java \
CreateClassField.java \
CreateConstantArray.java \
CreateExpression.java \
CreateForInitializer.java \
CreateIfThenElseOperator.java \
CreateNewConstructor.java \
CreatePrePostIncExpression.java \
DescriptionBlock.java \
EmptyBlock.java \
FinallyBlock.java \
FlowBlock.java \
IfThenElseBlock.java \
InstructionBlock.java \
InstructionContainer.java \
JsrBlock.java \
Jump.java \
LoopBlock.java \
RetBlock.java \
ReturnBlock.java \
SequentialBlock.java \
SpecialBlock.java \
StructuredBlock.java \
SwitchBlock.java \
SynchronizedBlock.java \
ThrowBlock.java \
TransformConstructors.java \
TransformExceptionHandlers.java \
TryBlock.java \
VariableSet.java \
VariableStack.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,982 +0,0 @@
/* TransformExceptionHandlers 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.flow;
import jode.AssertError;
import jode.GlobalOptions;
import jode.type.Type;
import jode.decompiler.LocalInfo;
import jode.expr.*;
import @COLLECTIONS@.TreeSet;
import @COLLECTIONS@.SortedSet;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.Comparable;
/**
*
* @author Jochen Hoenicke
*/
public class TransformExceptionHandlers {
SortedSet handlers;
static class Handler implements Comparable {
FlowBlock start;
int endAddr;
FlowBlock handler;
Type type;
public Handler(FlowBlock tryBlock, int end,
FlowBlock catchBlock, Type type) {
this.start = tryBlock;
this.endAddr = end;
this.handler = catchBlock;
this.type = type;
}
public int compareTo (Object o) {
Handler second = (Handler) o;
/* First sort by start offsets, highest address first...*/
if (start.getAddr() != second.start.getAddr())
/* this subtraction is save since addresses are only 16 bit */
return second.start.getAddr() - start.getAddr();
/* ...Second sort by end offsets, lowest address first...
* this will move the innermost blocks to the beginning. */
if (endAddr != second.endAddr)
return endAddr - second.endAddr;
/* ...Last sort by handler offsets, lowest first */
if (handler.getAddr() != second.handler.getAddr())
return handler.getAddr() - second.handler.getAddr();
/* ...Last sort by typecode signature. Shouldn't happen to often.
*/
if (type == second.type)
return 0;
if (type == null)
return -1;
if (second.type == null)
return 1;
return type.getTypeSignature()
.compareTo(second.type.getTypeSignature());
}
}
public TransformExceptionHandlers() {
handlers = new TreeSet();
}
/**
* Add an exception Handler.
* @param start The start address of the exception range.
* @param end The end address of the exception range + 1.
* @param handler The address of the handler.
* @param type The type of the exception, null for ALL.
*/
public void addHandler(FlowBlock tryBlock, int end,
FlowBlock catchBlock, Type type) {
handlers.add(new Handler(tryBlock, end, catchBlock, type));
}
/* simple try catch block:
*
* try-header
* |- first instruction
* | ...
* | last instruction
* |- optional jump (last+1)
* | ...
* `- catch block
*/
static void analyzeCatchBlock(Type type,
FlowBlock tryFlow, FlowBlock catchFlow) {
StructuredBlock catchBlock = catchFlow.block;
CatchBlock newBlock = new CatchBlock(type);
((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeAddr(catchFlow);
}
/* And now the complicated parts. */
/**
* This transforms a sub routine, that is checks if the beginning
* local assignment matches the final ret and then returns.
*/
boolean transformSubRoutine(StructuredBlock subRoutine) {
if (!(subRoutine instanceof SequentialBlock)
|| !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock) subRoutine;
InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0];
if (!(instr.getInstruction() instanceof StoreInstruction)
|| !(((StoreInstruction) instr.getInstruction()).getLValue()
instanceof LocalStoreOperator))
return false;
LocalStoreOperator store = (LocalStoreOperator)
((StoreInstruction)instr.getInstruction()).getLValue();
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
/* XXX - Check that the local isn't used for any other purposes
* than RET and replace any RET with a flow control to end of
* flow block.
*
* This is a complicated task which isn't needed for javac nor jikes.
*/
if (sequBlock.subBlocks[1].jump != null
&& sequBlock.subBlocks[1].jump.destination
== FlowBlock.END_OF_METHOD) {
instr.removeBlock();
return true;
}
if (! (sequBlock.subBlocks[1] instanceof RetBlock)
|| !(((RetBlock)sequBlock.subBlocks[1])
.local.equals(store.getLocalInfo())))
return false;
instr.removeBlock();
sequBlock.subBlocks[1].removeBlock();
return true;
}
/**
* Remove the JSR's jumping to the specified subRoutine. It
* is checked if the next block is a leaving instruction, and
* otherwise the JsrBlock is not removed (to give the user a
* hint that something went wrong). This will also remove the
* local javac generates for returns.
* @param tryFlow the FlowBLock of the try block.
* @param subRoutine the FlowBlock of the sub routine.
*/
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
for (Jump jumps = tryFlow.removeJumps(subRoutine);
jumps != null; jumps = jumps.next) {
StructuredBlock prev = jumps.prev;
prev.removeJump();
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
if (prev.outer.getNextFlowBlock() != null) {
/* The jsr is directly before a jump, okay. */
prev.outer.removeBlock();
continue;
}
if (prev.outer.outer instanceof SequentialBlock
&& prev.outer.outer.getSubBlocks()[0] == prev.outer) {
SequentialBlock seq = (SequentialBlock) prev.outer.outer;
if (seq.subBlocks[1] instanceof JsrBlock
|| (seq.subBlocks[1] instanceof SequentialBlock
&& seq.subBlocks[1].getSubBlocks()[0]
instanceof JsrBlock)) {
/* The jsr is followed by a jsr, okay. */
prev.outer.removeBlock();
continue;
}
if (seq.subBlocks[1] instanceof ReturnBlock
&& !(seq.subBlocks[1] instanceof ThrowBlock)) {
/* The jsr is followed by a return, okay. */
ReturnBlock ret = (ReturnBlock) seq.subBlocks[1];
prev.outer.removeBlock();
if (ret.outer != null
&& ret.outer instanceof SequentialBlock) {
/* Try to eliminate the local that javac uses
* in this case.
*/
try {
StoreInstruction store = (StoreInstruction)
((InstructionBlock)
ret.outer.getSubBlocks()[0]).instr;
LocalInfo local =
((LocalStoreOperator) store.getLValue())
.getLocalInfo();
if (store.lvalueMatches
((LocalLoadOperator)
ret.getInstruction())) {
Expression expr =
store.getSubExpressions()[1];
ret.setInstruction(expr);
ret.replace(ret.outer);
}
} catch(ClassCastException ex) {
/* didn't succeed */
}
}
continue;
}
}
}
/* Now we have a jump to the subroutine, that is wrong.
* We complain here.
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
prev.appendBlock(msg);
}
}
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine,
int startOutExit, int endOutExit) {
boolean foundSub = false;
Iterator iter = tryFlow.getSuccessors().iterator();
dest_loop:
while (iter.hasNext()) {
FlowBlock dest = (FlowBlock) iter.next();
if (dest == subRoutine) {
foundSub = true;
continue dest_loop;
}
boolean isFirstJump = true;
for (Jump jumps = tryFlow.getJumps(dest);
jumps != null; jumps = jumps.next, isFirstJump = false) {
StructuredBlock prev = jumps.prev;
if (prev instanceof ThrowBlock) {
/* The jump is a throw. We have a catch-all block
* that will do the finally.
*/
continue;
}
if (prev instanceof JsrBlock) {
/* The jump is directly preceeded by a jsr.
* Everything okay.
*/
continue;
}
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
/* If jump is a jsr check the outer
* block instead.
*/
prev = prev.outer;
}
if ((prev instanceof ReturnBlock
|| prev instanceof JsrBlock)
&& prev.outer instanceof SequentialBlock) {
SequentialBlock seq = (SequentialBlock) prev.outer;
if (seq.subBlocks[1] == prev
&& (seq.subBlocks[0] instanceof JsrBlock)) {
/* The jump is preceeded by another jsr, okay.
*/
continue;
}
if (seq.subBlocks[0] == prev
&& seq.outer instanceof SequentialBlock
&& (seq.outer.getSubBlocks()[0] instanceof JsrBlock)) {
/* Again the jump is preceeded by another jsr, okay.
*/
continue;
}
}
if (isFirstJump) {
/* Now we have a jump that is not preceded by the
* jsr. There's a last chance: the jump jumps
* directly to a correct jsr instruction, which
* lies outside the try/catch block.
*/
if (jumps.destination.predecessors.size() == 1
&& jumps.destination.getAddr() >= startOutExit
&& jumps.destination.getNextAddr() <= endOutExit) {
jumps.destination.analyze(startOutExit, endOutExit);
StructuredBlock sb = jumps.destination.block;
if (sb instanceof SequentialBlock)
sb = sb.getSubBlocks()[0];
if (sb instanceof JsrBlock
&& sb.getSubBlocks()[0] instanceof EmptyBlock
&& (sb.getSubBlocks()[0].jump.destination
== subRoutine)) {
StructuredBlock jsrInner = sb.getSubBlocks()[0];
jumps.destination.removeSuccessor(jsrInner.jump);
jsrInner.removeJump();
sb.removeBlock();
continue dest_loop;
}
}
}
/* Now we have a jump with a wrong destination.
* Complain!
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO JSR TO FINALLY");
prev.appendBlock(msg);
msg.moveJump(jumps);
}
}
if (foundSub)
removeJSR(tryFlow, subRoutine);
}
static boolean isMonitorExit(Expression instr, LocalInfo local) {
if (instr instanceof MonitorExitOperator) {
MonitorExitOperator monExit = (MonitorExitOperator)instr;
if (monExit.getFreeOperandCount() == 0
&& monExit.getSubExpressions()[0] instanceof LocalLoadOperator
&& (((LocalLoadOperator) monExit.getSubExpressions()[0])
.getLocalInfo().getSlot() == local.getSlot())) {
return true;
}
}
return false;
}
boolean isMonitorExitSubRoutine(FlowBlock subRoutine, LocalInfo local) {
if (transformSubRoutine(subRoutine.block)) {
if (subRoutine.block instanceof InstructionBlock) {
Expression instr =
((InstructionBlock)subRoutine.block)
.getInstruction();
if (isMonitorExit(instr, local)) {
return true;
}
}
}
return false;
}
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local,
int startOutExit, int endOutExit,
int startMonExit, int endMonExit) {
FlowBlock subRoutine = null;
Iterator succs = tryFlow.getSuccessors().iterator();
dest_loop:
while (succs.hasNext()) {
boolean isFirstJump = true;
FlowBlock successor = (FlowBlock) succs.next();
for (Jump jumps = tryFlow.getJumps(successor);
jumps != null; jumps = jumps.next, isFirstJump = false) {
StructuredBlock prev = jumps.prev;
if (prev instanceof ThrowBlock) {
/* The jump is a throw. We have a catch all block
* that will do the monitorexit.
*/
continue;
}
if (prev instanceof JsrBlock) {
/* The jump is directly preceeded by a jsr.
*/
continue;
}
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
/* If jump is a jsr check the outer
* block instead.
*/
prev = prev.outer;
}
/* If the block is a jsr or a return block, check if
* it is preceeded by another jsr.
*/
if ((prev instanceof JsrBlock
|| prev instanceof ReturnBlock)
&& prev.outer instanceof SequentialBlock) {
SequentialBlock seq = (SequentialBlock) prev.outer;
StructuredBlock pred = null;
if (seq.subBlocks[1] == prev)
pred = seq.subBlocks[0];
else if (seq.outer instanceof SequentialBlock)
pred = seq.outer.getSubBlocks()[0];
if (pred != null) {
if (pred instanceof JsrBlock)
/* The jump is preceeded by another jsr, okay.
*/
continue;
if (pred instanceof InstructionBlock) {
Expression instr =
((InstructionBlock)pred).getInstruction();
if (isMonitorExit(instr, local))
continue;
}
}
}
if (prev instanceof InstructionBlock
&& isMonitorExit(((InstructionBlock)prev).instr, local)) {
/* This is probably the last expression in the
* synchronized block, and has the right monitor exit
* attached. Remove this block.
*/
prev.removeBlock();
continue;
}
if (isFirstJump) {
/* This is the first jump to that destination.
* Check if the destination does the monitorExit
*/
/* The block is a jsr that is not preceeded by
* another jsr. This must be the monitorexit
* subroutine.
*/
if (prev instanceof JsrBlock) {
if (subRoutine == null
&& successor.getAddr() >= startMonExit
&& successor.getNextAddr() <= endMonExit) {
successor.analyze(startMonExit, endMonExit);
if (isMonitorExitSubRoutine(successor, local))
subRoutine = successor;
}
if (subRoutine == successor)
continue dest_loop;
}
/* Now we have a jump that is not preceded by a
* monitorexit. There's a last chance: the jump
* jumps directly to the correct monitorexit
* instruction, which lies outside the try/catch
* block.
*/
if (successor.predecessors.size() == 1
&& successor.getAddr() >= startOutExit
&& successor.getNextAddr() <= endOutExit) {
successor.analyze(startOutExit, endOutExit);
StructuredBlock sb = successor.block;
if (sb instanceof SequentialBlock)
sb = sb.getSubBlocks()[0];
if (sb instanceof JsrBlock
&& sb.getSubBlocks()[0] instanceof EmptyBlock) {
StructuredBlock jsrInner = sb.getSubBlocks()[0];
FlowBlock dest = jsrInner.jump.destination;
if (subRoutine == null
&& dest.getAddr() >= startMonExit
&& dest.getNextAddr() <= endMonExit) {
dest.analyze(startMonExit, endMonExit);
if (isMonitorExitSubRoutine(dest, local))
subRoutine = dest;
}
if (subRoutine == dest) {
sb.removeBlock();
continue dest_loop;
}
}
if (sb instanceof InstructionBlock) {
Expression instr = ((InstructionBlock)sb)
.getInstruction();
if (isMonitorExit(instr, local)) {
sb.removeBlock();
continue dest_loop;
}
}
}
}
/* Complain!
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO MONITOREXIT");
prev.appendBlock(msg);
msg.moveJump(jumps);
}
}
if (subRoutine != null) {
removeJSR(tryFlow, subRoutine);
tryFlow.mergeAddr(subRoutine);
}
}
private boolean analyzeSynchronized(FlowBlock tryFlow,
FlowBlock catchFlow,
int endHandler) {
if (!(catchFlow.block instanceof SequentialBlock
&& catchFlow.block.getSubBlocks()[0]
instanceof InstructionBlock))
return false;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction();
if (instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0]
instanceof LocalLoadOperator)
&& catchBlock.subBlocks[1] instanceof ThrowBlock
&& (((ThrowBlock)catchBlock.subBlocks[1]).instr
instanceof NopOperator)) {
/* This is a synchronized block:
*
* local_x = monitor object; // later
* monitorenter local_x // later
* tryFlow:
* |- synchronized block
* | ...
* | every jump to outside is preceded by jsr subroutine-,
* | ... |
* |- monitorexit local_x |
* ` jump after this block (without jsr monexit) |
* |
* catchFlow: |
* local_n = stack |
* monitorexit local_x |
* throw local_n |
* optional subroutine: <-----------------------------------'
* astore_n
* monitorexit local_x
* return_n
*/
/* Now remove the jump (after the throw) from the
* catch block so that we can forget about it.
*/
catchFlow.removeSuccessor(catchBlock.subBlocks[1].jump);
MonitorExitOperator monexit = (MonitorExitOperator)
((InstructionBlock) catchBlock.subBlocks[0]).instr;
LocalInfo local =
((LocalLoadOperator)monexit.getSubExpressions()[0])
.getLocalInfo();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeSynchronized(" + tryFlow.getAddr()
+ "," + tryFlow.getNextAddr() + "," + catchFlow.getAddr()
+ "," + catchFlow.getNextAddr() + "," + endHandler + ")");
checkAndRemoveMonitorExit
(tryFlow, local,
tryFlow.getNextAddr(), catchFlow.getAddr(),
catchFlow.getNextAddr(), endHandler);
tryFlow.mergeAddr(catchFlow);
SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block;
syncBlock.replace(tryBlock);
syncBlock.moveJump(tryBlock.jump);
syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1
? tryBlock.subBlocks[0] : tryBlock);
tryFlow.lastModified = syncBlock;
return true;
}
return false;
}
private boolean analyzeFinally(FlowBlock tryFlow, FlowBlock catchFlow,
int end) {
/* Layout of a try-finally block:
*
* tryFlow:
* |- first instruction
* | ...
* | every jump to outside is preceded by jsr finally
* | ...
* | jsr finally -----------------,
* `- jump after finally |
* |
* catchFlow: (already checked) |
* local_n = stack v
* jsr finally ---------------->|
* throw local_n; |
* finally: <-----------------------'
* astore_n
* ...
* return_n
*/
if (!(catchFlow.block instanceof SequentialBlock)
|| !(catchFlow.block.getSubBlocks()[0]
instanceof InstructionBlock)
|| !(catchFlow.block.getSubBlocks()[1]
instanceof SequentialBlock))
return false;
StructuredBlock finallyBlock = null;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction();
catchBlock = (SequentialBlock)catchBlock.subBlocks[1];
if (catchBlock.subBlocks[0] instanceof LoopBlock) {
/* In case the try block has no exit (that means, it throws
* an exception), the finallyBlock was already merged with
* the catchBlock. We have to check for this case separately:
*
* do {
* JSR
* break;
* throw local_x
* } while(false);
* finallyBlock;
*/
LoopBlock doWhileFalse = (LoopBlock)catchBlock.subBlocks[0];
if (doWhileFalse.type == LoopBlock.DOWHILE
&& doWhileFalse.cond == LoopBlock.FALSE
&& doWhileFalse.bodyBlock instanceof SequentialBlock) {
finallyBlock = catchBlock.subBlocks[1];
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
}
}
if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof StoreInstruction
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
return false;
JsrBlock jsrBlock = (JsrBlock)catchBlock.getSubBlocks()[0];
ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1];
if (!(throwBlock.instr instanceof LocalLoadOperator)
|| !(((StoreInstruction) instr).lvalueMatches
((LocalLoadOperator) throwBlock.instr)))
return false;
/* Wow that was complicated :-)
* But now we know that the catch block looks
* exactly like it should:
*
* catchBlock:
* JSR
* finally
* throw local_n <- matches the local in instr.
*/
if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't
* need to check if it breaks to the right block, because
* we know that there is only one Block around the jsr.
*/
if (!(jsrBlock.innerBlock instanceof BreakBlock))
return false;
/* Check if the try block has no exit (except throws)
*/
Set succs = tryFlow.getSuccessors();
if (succs.size() > 0) {
if (!succs.contains(FlowBlock.END_OF_METHOD))
return false;
Jump throwJumps
= tryFlow.getJumps(FlowBlock.END_OF_METHOD);
for (/**/; throwJumps != null;
throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock))
/* There is a return exit in the try block */
return false;
}
}
/* Remove the jump of the throw instruction.
*/
catchFlow.removeSuccessor(throwBlock.jump);
throwBlock.removeJump();
/* Replace the catchBlock with the finallyBlock.
*/
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
} else {
FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination;
checkAndRemoveJSR(tryFlow, subRoutine,
tryFlow.getNextAddr(), catchFlow.getAddr());
while (subRoutine.analyze(catchFlow.getNextAddr(), end));
/* Now check if the subroutine is correct and has only the
* catchFlow as predecessor.
*/
if (subRoutine.predecessors.size() == 1
&& transformSubRoutine(subRoutine.block)) {
subRoutine.mergeAddr(catchFlow);
/* Now remove the jump to the JSR from the catch block
* and the jump of the throw instruction.
*/
catchFlow.removeSuccessor(jsrBlock.innerBlock.jump);
jsrBlock.innerBlock.removeJump();
catchFlow.removeSuccessor(throwBlock.jump);
throwBlock.removeJump();
tryFlow.updateInOutCatch(subRoutine);
tryFlow.mergeAddr(subRoutine);
tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block;
} else {
catchFlow.removeSuccessor(throwBlock.jump);
throwBlock.removeJump();
finallyBlock = jsrBlock;
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
}
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the surrounding tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
return true;
}
private boolean analyzeSpecialFinally(FlowBlock tryFlow,
FlowBlock catchFlow, int end) {
StructuredBlock firstInstr =
catchFlow.block instanceof SequentialBlock
? catchFlow.block.getSubBlocks()[0]: catchFlow.block;
if (firstInstr instanceof SpecialBlock
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock)firstInstr).count == 1) {
/* This is a special try/finally-block, where
* the finally block ends with a break, return or
* similar.
*/
FlowBlock succ = (firstInstr.jump != null) ?
firstInstr.jump.destination : null;
boolean hasExit = false;
Iterator iter = tryFlow.getSuccessors().iterator();
while (iter.hasNext()) {
FlowBlock dest = (FlowBlock) iter.next();
if (dest == succ)
continue;
if (dest != FlowBlock.END_OF_METHOD) {
/* There is another exit in the try block, bad */
return false;
}
for (Jump throwJumps = (Jump) tryFlow.getJumps(dest);
throwJumps != null; throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock)) {
/* There is a return exit in the try block */
return false;
}
}
}
/* remove the pop now */
firstInstr.removeBlock();
tryFlow.mergeAddr(catchFlow);
if (succ != null) {
Jump jumps = tryFlow.removeJumps(succ);
/* Handle the jumps in the tryFlow.
*/
jumps = tryFlow.resolveSomeJumps(jumps, succ);
tryFlow.resolveRemaining(jumps);
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the unnecessary tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = innerTry;
}
FinallyBlock newBlock = new FinallyBlock();
tryBlock.addCatchBlock(newBlock);
/* try block has no successors */
if (succ != null && succ.predecessors.size() == 1) {
while (succ.analyze(catchFlow.getNextAddr(), end));
tryFlow.mergeAddr(succ);
tryFlow.removeJumps(succ);
newBlock.setCatchBlock(succ.block);
tryFlow.mergeSuccessors(succ);
} else {
/* Put the catchBlock in instead.
*/
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeSuccessors(catchFlow);
}
return true;
}
return false;
}
/**
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
*/
public void analyze() {
/* Check if try/catch ranges are okay. The following succeeds
* for all classes generated by the sun java compiler, but hand
* optimized classes (or generated by other compilers) will fail.
*/
{
Handler last = null;
for (Iterator i = handlers.iterator(); i.hasNext(); ) {
Handler exc = (Handler) i.next();
int start = exc.start.getAddr();
int end = exc.endAddr;
int handler = exc.handler.getAddr();
if (start >= end || handler < end)
throw new AssertError
("ExceptionHandler order failed: not "
+ start + " < " + end + " <= " + handler);
if (last != null
&& (last.start.getAddr() != start || last.endAddr != end)) {
/* The last handler does catch another range.
* Due to the order:
* start < last.start.getAddr() || end > last.end.getAddr()
*/
if (end > last.start.getAddr() && end < last.endAddr)
throw new AssertError
("Exception handlers ranges are intersecting: ["
+ last.start.getAddr()+", "+last.endAddr+"] and ["
+ start+", "+end+"].");
}
last = exc;
}
}
{
Iterator i = handlers.iterator();
Handler exc = null;
Handler next = i.hasNext() ? (Handler) i.next() : null;
while(next != null) {
Handler last = exc;
exc = next;
next = i.hasNext() ? (Handler) i.next() : null;
int endHandler = Integer.MAX_VALUE;
/* If the next exception handler catches a bigger range
* it must surround the handler completely.
*/
if (next != null && next.endAddr > exc.endAddr)
endHandler = next.endAddr;
FlowBlock tryFlow = exc.start;
tryFlow.checkConsistent();
if (last == null || exc.type == null
|| last.start.getAddr() != exc.start.getAddr()
|| last.endAddr != exc.endAddr) {
/* The last handler does catch another range.
* Create a new try block.
*/
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTry("
+ exc.start.getAddr() + ", " + exc.endAddr+")");
while (tryFlow.analyze(tryFlow.getAddr(), exc.endAddr));
TryBlock tryBlock = new TryBlock(tryFlow);
} else if (!(tryFlow.block instanceof TryBlock))
throw new AssertError("no TryBlock");
FlowBlock catchFlow = exc.handler;
boolean isMultiUsed = catchFlow.predecessors.size() != 0;
if (!isMultiUsed && next != null) {
for (Iterator j = handlers.tailSet(next).iterator();
j.hasNext();) {
Handler h = (Handler) j.next();
if (h.handler == catchFlow) {
isMultiUsed = true;
break;
}
}
}
if (isMultiUsed) {
/* If this exception is used in other exception handlers,
* create a new flow block, that jumps to the handler.
* This will be our new exception handler.
*/
EmptyBlock jump = new EmptyBlock(new Jump(catchFlow));
FlowBlock newFlow = new FlowBlock(catchFlow.method,
catchFlow.getAddr());
newFlow.appendBlock(jump, 0);
catchFlow.prevByAddr.nextByAddr = newFlow;
newFlow.prevByAddr = catchFlow.prevByAddr;
newFlow.nextByAddr = catchFlow;
catchFlow.prevByAddr = newFlow;
catchFlow = newFlow;
} else {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeCatch("
+ catchFlow.getAddr() + ", " + endHandler + ")");
while (catchFlow.analyze(catchFlow.getAddr(), endHandler));
}
tryFlow.updateInOutCatch(catchFlow);
if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow);
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler)
&& ! analyzeFinally(tryFlow, catchFlow, endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow,
endHandler))
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow);
tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTryCatch(" + tryFlow.getAddr() + ", "
+ tryFlow.getNextAddr() + ") done.");
}
}
}
}

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,37 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
CodeVerifier.java \
Interpreter.java \
InterpreterException.java \
NewObject.java \
RuntimeEnvironment.java \
SimpleRuntimeEnvironment.java \
SyntheticAnalyzer.java \
Value.java \
VerifyException.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,369 +0,0 @@
/* SyntheticAnalyzer 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.jvm;
import jode.GlobalOptions;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.Handler;
import jode.bytecode.Instruction;
import jode.bytecode.MethodInfo;
import jode.bytecode.Opcodes;
import jode.bytecode.Reference;
import jode.type.Type;
import jode.type.MethodType;
import java.lang.reflect.Modifier;
import @COLLECTIONS@.Iterator;
public class SyntheticAnalyzer implements Opcodes {
public final static int UNKNOWN = 0;
public final static int GETCLASS = 1;
public final static int ACCESSGETFIELD = 2;
public final static int ACCESSPUTFIELD = 3;
public final static int ACCESSMETHOD = 4;
public final static int ACCESSGETSTATIC = 5;
public final static int ACCESSPUTSTATIC = 6;
public final static int ACCESSSTATICMETHOD = 7;
public final static int ACCESSCONSTRUCTOR = 8;
int kind = UNKNOWN;
Reference reference;
MethodInfo method;
public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
this.method = method;
if (method.getBytecode() == null)
return;
if (!checkName || method.getName().equals("class$"))
if (checkGetClass())
return;
if (!checkName || method.getName().startsWith("access$"))
if (checkAccess())
return;
if (method.getName().equals("<init>"))
if (checkConstructorAccess())
return;
}
public int getKind() {
return kind;
}
public Reference getReference() {
return reference;
}
private static final int[] getClassOpcodes = {
opc_aload, opc_invokestatic, opc_areturn,
opc_astore, opc_new, opc_dup, opc_aload,
opc_invokevirtual, opc_invokespecial, opc_athrow
};
private static final Reference[] getClassRefs = {
null, Reference.getReference("Ljava/lang/Class;", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;"),
null, null, null, null, null,
Reference.getReference("Ljava/lang/Throwable;", "getMessage",
"()Ljava/lang/String;"),
Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>",
"(Ljava/lang/String;)V"), null
};
boolean checkGetClass() {
if (!method.isStatic()
|| !(method.getType()
.equals("(Ljava/lang/String;)Ljava/lang/Class;")))
return false;
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers.length != 1
|| !"java.lang.ClassNotFoundException".equals(excHandlers[0].type))
return false;
int excSlot = -1;
int i = 0;
for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) {
Instruction instr = (Instruction) iter.next();
if (i == getClassOpcodes.length
|| instr.getOpcode() != getClassOpcodes[i])
return false;
if (i == 0 && (instr.getLocalSlot() != 0
|| excHandlers[0].start != instr))
return false;
if (i == 2 && excHandlers[0].end != instr)
return false;
if (i == 3) {
if (excHandlers[0].catcher != instr)
return false;
excSlot = instr.getLocalSlot();
}
if (i == 4 && !instr.getClazzType().equals
("Ljava/lang/NoClassDefFoundError;"))
return false;
if (i == 6 && instr.getLocalSlot() != excSlot)
return false;
if (getClassRefs[i] != null
&& !getClassRefs[i].equals(instr.getReference()))
return false;
}
this.kind = GETCLASS;
return true;
}
private final int modifierMask = (Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.PUBLIC | Modifier.STATIC);
public boolean checkStaticAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Iterator iter = bytecode.getInstructions().iterator();
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETSTATIC;
return true;
}
int params = 0, slot = 0;
while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload
&& instr.getLocalSlot() == slot) {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putstatic) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
reference = ref;
kind = ACCESSPUTSTATIC;
return true;
}
if (instr.getOpcode() == opc_invokestatic) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC)
|| refType.getParameterTypes().length != params)
return false;
instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
if (instr.getOpcode() != opc_return)
return false;
} else {
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
}
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSSTATICMETHOD;
return true;
}
return false;
}
public boolean checkAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0)
return false;
if (method.isStatic()) {
if (checkStaticAccess())
return true;
}
Iterator iter = bytecode.getInstructions().iterator();
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getfield) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETFIELD;
return true;
}
int params = 0, slot = 1;
while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload
&& instr.getLocalSlot() == slot) {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putfield) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
reference = ref;
kind = ACCESSPUTFIELD;
return true;
}
if (instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| refType.getParameterTypes().length != params)
return false;
instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
if (instr.getOpcode() != opc_return)
return false;
} else {
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
}
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSMETHOD;
return true;
}
return false;
}
public boolean checkConstructorAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0)
return false;
Iterator iter = bytecode.getInstructions().iterator();
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
return false;
instr = (Instruction) iter.next();
// slot begins with 2. Slot 1 contains a dummy value, that
// is used so that the constructor has a different type signature.
int params = 0, slot = 2;
while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload
&& instr.getLocalSlot() == slot) {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| !refMethod.getName().equals("<init>")
|| refType.getParameterTypes().length != params)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSCONSTRUCTOR;
return true;
}
return false;
}
}

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

@ -1,47 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
SUBDIRS = modules
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
-depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
MY_JAVA_FILES = \
ClassBundle.java \
ClassIdentifier.java \
CodeAnalyzer.java \
CodeTransformer.java \
ConstantRuntimeEnvironment.java \
FieldIdentifier.java \
Identifier.java \
IdentifierMatcher.java \
LocalIdentifier.java \
Main.java \
MethodIdentifier.java \
OptionHandler.java \
PackageIdentifier.java \
ParseException.java \
Renamer.java \
ScriptParser.java \
TranslationTable.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include Makefile.dep
%.class: %.java
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
Makefile.dep: $(MY_JAVA_FILES:.java=.class)
$(JAVADEP) $^
clean-local:
@rm -f *.class
@rm -f *.dep

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

File diff suppressed because it is too large Load Diff

@ -1,941 +0,0 @@
/* LocalOptimizer 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.obfuscator.modules;
import java.util.*;
import jode.bytecode.*;
import jode.obfuscator.*;
import jode.AssertError;
import jode.GlobalOptions;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/**
* This class takes some bytecode and tries to minimize the number
* of locals used. It will also remove unnecessary stores.
*
* This class can only work on verified code. There should also be no
* deadcode, since the verifier doesn't check that deadcode behaves
* okay.
*
* This is done in two phases. First we determine which locals are
* the same, and which locals have a overlapping life time. In the
* second phase we will then redistribute the locals with a coloring
* graph algorithm.
*
* The idea for the first phase is: For each read we follow the
* instruction flow backward to find the corresponding writes. We can
* also merge with another control flow that has a different read, in
* this case we merge with that read, too.
*
* The tricky part is the subroutine handling. We follow the local
* that is used in a ret and find the corresponding jsr target (there
* must be only one, if the verifier should accept this class). While
* we do this we remember in the info of the ret, which locals are
* used in that subroutine.
*
* When we know the jsr target<->ret correlation, we promote from the
* nextByAddr of every jsr the locals that are accessed by the
* subroutine to the corresponding ret and the others to the jsr. Also
* we will promote all reads from the jsr targets to the jsr.
*
* If you think this might be to complicated, keep in mind that jsr's
* are not only left by the ret instructions, but also "spontanously"
* (by not reading the return address again).
*/
public class LocalOptimizer implements Opcodes, CodeTransformer {
/**
* This class keeps track of which locals must be the same, which
* name and type each local (if there is a local variable table) and
* which other locals have an intersecting life time.
*/
class LocalInfo {
LocalInfo shadow = null;
public LocalInfo getReal() {
LocalInfo real = this;
while (real.shadow != null)
real = real.shadow;
return real;
}
String name;
String type;
Vector usingInstrs = new Vector();
Vector conflictingLocals = new Vector();
int size;
int newSlot = -1;
LocalInfo() {
}
LocalInfo(InstrInfo instr) {
usingInstrs.addElement(instr);
}
void conflictsWith(LocalInfo l) {
if (shadow != null) {
getReal().conflictsWith(l);
} else {
l = l.getReal();
if (!conflictingLocals.contains(l)) {
conflictingLocals.addElement(l);
l.conflictingLocals.addElement(this);
}
}
}
void combineInto(LocalInfo l) {
if (shadow != null) {
getReal().combineInto(l);
return;
}
l = l.getReal();
if (this == l)
return;
shadow = l;
if (shadow.name == null) {
shadow.name = name;
shadow.type = type;
}
Enumeration enum = usingInstrs.elements();
while (enum.hasMoreElements()) {
InstrInfo instr = (InstrInfo) enum.nextElement();
instr.local = l;
l.usingInstrs.addElement(instr);
}
}
public int getFirstAddr() {
int minAddr = Integer.MAX_VALUE;
Enumeration enum = usingInstrs.elements();
while (enum.hasMoreElements()) {
InstrInfo info = (InstrInfo) enum.nextElement();
if (info.instr.getAddr() < minAddr)
minAddr = info.instr.getAddr();
}
return minAddr;
}
}
private static class TodoQueue {
public final InstrInfo LAST = new InstrInfo();
InstrInfo first = LAST;
public void add(InstrInfo info) {
if (info.nextTodo == null) {
/* only enqueue if not already on queue */
info.nextTodo = first;
first = info;
}
}
public boolean isEmpty() {
return first == LAST;
}
public InstrInfo remove() {
if (first == LAST)
throw new NoSuchElementException();
InstrInfo result = first;
first = result.nextTodo;
result.nextTodo = null;
return result;
}
}
/**
* This class contains information for each instruction.
*/
static class InstrInfo {
/**
* The next changed InstrInfo, or null, if this instr info did
* not changed.
*/
InstrInfo nextTodo;
/**
* The LocalInfo that this instruction manipulates, or null
* if this is not an ret, iinc, load or store instruction.
*/
LocalInfo local;
/**
* For each slot, this contains the InstrInfo of one of the
* next Instruction, that may read from that slot, without
* prior writing. */
InstrInfo[] nextReads;
/**
* This only has a value for ret instructions. In that case
* this bitset contains all locals, that may be used between
* jsr and ret.
*/
BitSet usedBySub;
/**
* For each slot if get() is true, no instruction may read
* this slot, since it may contain different locals, depending
* on flow.
*/
LocalInfo[] lifeLocals;
/**
* If instruction is the destination of a jsr, this contains
* the single allowed ret instruction info, or null if there
* is no ret at all (or not yet detected).
*/
InstrInfo retInfo;
/**
* If this instruction is a ret, this contains the single
* allowed jsr target to which this ret belongs.
*/
InstrInfo jsrTargetInfo;
/**
* The Instruction of this info
*/
Instruction instr;
/**
* The next info in the chain.
*/
InstrInfo nextInfo;
}
BytecodeInfo bc;
TodoQueue changedInfos;
InstrInfo firstInfo;
Hashtable instrInfos;
boolean produceLVT;
int maxlocals;
LocalInfo[] paramLocals;
public LocalOptimizer() {
}
/**
* Merges the given vector to a new vector. Both vectors may
* be null in which case they are interpreted as empty vectors.
* The vectors will never changed, but the result may be one
* of the given vectors.
*/
Vector merge(Vector v1, Vector v2) {
if (v1 == null || v1.isEmpty())
return v2;
if (v2 == null || v2.isEmpty())
return v1;
Vector result = (Vector) v1.clone();
Enumeration enum = v2.elements();
while (enum.hasMoreElements()) {
Object elem = enum.nextElement();
if (!result.contains(elem))
result.addElement(elem);
}
return result;
}
void promoteReads(InstrInfo info, Instruction preInstr,
BitSet mergeSet, boolean inverted) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1;
if (preInstr.getOpcode() >= opc_istore
&& preInstr.getOpcode() <= opc_astore) {
/* This is a store */
omitLocal = preInstr.getLocalSlot();
if (info.nextReads[omitLocal] != null)
preInfo.local.combineInto(info.nextReads[omitLocal].local);
}
for (int i=0; i < maxlocals; i++) {
if (info.nextReads[i] != null && i != omitLocal
&& (mergeSet == null || mergeSet.get(i) != inverted)) {
if (preInfo.nextReads[i] == null) {
preInfo.nextReads[i] = info.nextReads[i];
changedInfos.add(preInfo);
} else {
preInfo.nextReads[i].local
.combineInto(info.nextReads[i].local);
}
}
}
}
void promoteReads(InstrInfo info, Instruction preInstr) {
promoteReads(info, preInstr, null, false);
}
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
int slot, int addr) {
LocalVariableInfo match = null;
for (int i=0; i < lvt.length; i++) {
if (lvt[i].slot == slot
&& lvt[i].start.getAddr() <= addr
&& lvt[i].end.getAddr() >= addr) {
if (match != null
&& (!match.name.equals(lvt[i].name)
|| !match.type.equals(lvt[i].type))) {
/* Multiple matches..., give no info */
return null;
}
match = lvt[i];
}
}
return match;
}
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) {
int addr;
if (instr.getOpcode() >= opc_istore
&& instr.getOpcode() <= opc_astore)
addr = instr.getNextAddr();
else
addr = instr.getAddr();
return findLVTEntry(lvt, instr.getLocalSlot(), addr);
}
public void calcLocalInfo() {
maxlocals = bc.getMaxLocals();
Handler[] handlers = bc.getExceptionHandlers();
LocalVariableInfo[] lvt = bc.getLocalVariableTable();
if (lvt != null)
produceLVT = true;
/* Initialize paramLocals */
{
String methodType = bc.getMethodInfo().getType();
int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1)
+ TypeSignature.getArgumentSize(methodType);
paramLocals = new LocalInfo[paramCount];
int slot = 0;
if (!bc.getMethodInfo().isStatic()) {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, 0, 0);
if (lvi != null) {
local.name = lvi.name;
local.type = lvi.type;
}
}
local.size = 1;
paramLocals[slot++] = local;
}
int pos = 1;
while (pos < methodType.length()
&& methodType.charAt(pos) != ')') {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0);
if (lvi != null) {
local.name = lvi.name;
}
}
int start = pos;
pos = TypeSignature.skipType(methodType, pos);
local.type = methodType.substring(start, pos);
local.size = TypeSignature.getTypeSize(local.type);
paramLocals[slot] = local;
slot += local.size;
}
}
/* Initialize the InstrInfos and LocalInfos
*/
changedInfos = new TodoQueue();
instrInfos = new Hashtable();
{
InstrInfo info = firstInfo = new InstrInfo();
Iterator i = bc.getInstructions().iterator();
while (true) {
Instruction instr = (Instruction) i.next();
instrInfos.put(instr, info);
info.instr = instr;
info.nextReads = new InstrInfo[maxlocals];
if (instr.hasLocalSlot()) {
info.local = new LocalInfo(info);
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, instr);
if (lvi != null) {
info.local.name = lvi.name;
info.local.type = lvi.type;
}
}
info.local.size = 1;
switch (instr.getOpcode()) {
case opc_lload: case opc_dload:
info.local.size = 2;
/* fall through */
case opc_iload: case opc_fload: case opc_aload:
case opc_iinc:
/* this is a load instruction */
info.nextReads[instr.getLocalSlot()] = info;
changedInfos.add(info);
break;
case opc_ret:
/* this is a ret instruction */
info.usedBySub = new BitSet();
info.nextReads[instr.getLocalSlot()] = info;
changedInfos.add(info);
break;
case opc_lstore: case opc_dstore:
info.local.size = 2;
//case opc_istore: case opc_fstore: case opc_astore:
}
}
if (!i.hasNext())
break;
info = info.nextInfo = new InstrInfo();
}
}
/* find out which locals are the same.
*/
while (!changedInfos.isEmpty()) {
InstrInfo info = changedInfos.remove();
Instruction instr = info.instr;
/* Mark the local as used in all ret instructions */
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
for (int i=0; i< maxlocals; i++) {
InstrInfo retInfo = info.nextReads[i];
if (retInfo != null
&& retInfo.instr.getOpcode() == opc_ret
&& !retInfo.usedBySub.get(slot)) {
retInfo.usedBySub.set(slot);
if (retInfo.jsrTargetInfo != null)
changedInfos.add(retInfo.jsrTargetInfo);
}
}
}
Instruction prevInstr = instr.getPrevByAddr();
if (prevInstr != null) {
if (!prevInstr.doesAlwaysJump())
promoteReads(info, prevInstr);
else if (prevInstr.getOpcode() == opc_jsr) {
/* Prev instr is a jsr, promote reads to the
* corresponding ret.
*/
InstrInfo jsrInfo =
(InstrInfo) instrInfos.get(prevInstr.getSingleSucc());
if (jsrInfo.retInfo != null) {
/* Now promote reads that are modified by the
* subroutine to the ret, and those that are not
* to the jsr instruction.
*/
promoteReads(info, jsrInfo.retInfo.instr,
jsrInfo.retInfo.usedBySub, false);
promoteReads(info, prevInstr,
jsrInfo.retInfo.usedBySub, true);
}
}
}
if (instr.getPreds() != null) {
for (int i = 0; i < instr.getPreds().length; i++) {
Instruction predInstr = instr.getPreds()[i];
if (instr.getPreds()[i].getOpcode() == opc_jsr) {
/* This is the target of a jsr instr.
*/
if (info.instr.getOpcode() != opc_astore) {
/* XXX Grrr, the bytecode verifier doesn't
* test if a jsr starts with astore. So
* it is possible to do something else
* before putting the ret address into a
* local. */
throw new AssertError("Non standard jsr");
}
InstrInfo retInfo = info.nextInfo.nextReads
[info.instr.getLocalSlot()];
if (retInfo != null) {
if (retInfo.instr.getOpcode() != opc_ret)
throw new AssertError
("reading return address");
info.retInfo = retInfo;
retInfo.jsrTargetInfo = info;
/* Now promote reads from the instruction
* after the jsr to the ret instruction if
* they are modified by the subroutine,
* and to the jsr instruction otherwise.
*/
Instruction nextInstr = predInstr.getNextByAddr();
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(nextInstr);
promoteReads(nextInfo, retInfo.instr,
retInfo.usedBySub, false);
promoteReads(nextInfo, predInstr,
retInfo.usedBySub, true);
}
}
promoteReads(info, instr.getPreds()[i]);
}
}
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher == instr) {
for (Instruction preInstr = handlers[i].start;
preInstr != handlers[i].end.getNextByAddr();
preInstr = preInstr.getNextByAddr()) {
promoteReads(info, preInstr);
}
}
}
}
changedInfos = null;
/* Now merge with the parameters
* The params should be the locals in firstInfo.nextReads
*/
for (int i=0; i< paramLocals.length; i++) {
if (firstInfo.nextReads[i] != null) {
firstInfo.nextReads[i].local.combineInto(paramLocals[i]);
paramLocals[i] = paramLocals[i].getReal();
}
}
}
public void stripLocals() {
ListIterator iter = bc.getInstructions().listIterator();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
Instruction instr = (Instruction) iter.next();
if (info.local != null && info.local.usingInstrs.size() == 1) {
/* If this is a store, whose value is never read; it can
* be removed, i.e replaced by a pop. */
switch (instr.getOpcode()) {
case opc_istore:
case opc_fstore:
case opc_astore:
iter.set(new Instruction(opc_pop));
break;
case opc_lstore:
case opc_dstore:
iter.set(new Instruction(opc_pop2));
break;
default:
}
}
}
}
void distributeLocals(Vector locals) {
if (locals.size() == 0)
return;
/* Find the local with the least conflicts. */
int min = Integer.MAX_VALUE;
LocalInfo bestLocal = null;
Enumeration enum = locals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
int conflicts = 0;
Enumeration conflenum = li.conflictingLocals.elements();
while (conflenum.hasMoreElements()) {
if (((LocalInfo)conflenum.nextElement()).newSlot != -2)
conflicts++;
}
if (conflicts < min) {
min = conflicts;
bestLocal = li;
}
}
/* Mark the local as taken */
locals.removeElement(bestLocal);
bestLocal.newSlot = -2;
/* Now distribute the remaining locals recursively. */
distributeLocals(locals);
/* Finally find a new slot */
next_slot:
for (int slot = 0; ; slot++) {
Enumeration conflenum = bestLocal.conflictingLocals.elements();
while (conflenum.hasMoreElements()) {
LocalInfo conflLocal = (LocalInfo)conflenum.nextElement();
if (bestLocal.size == 2 && conflLocal.newSlot == slot+1) {
slot++;
continue next_slot;
}
if (conflLocal.size == 2 && conflLocal.newSlot+1 == slot)
continue next_slot;
if (conflLocal.newSlot == slot) {
if (conflLocal.size == 2)
slot++;
continue next_slot;
}
}
bestLocal.newSlot = slot;
break;
}
}
public void distributeLocals() {
/* give locals new slots. This is a graph coloring
* algorithm (the optimal solution is NP complete, but this
* should be a good approximation).
*/
/* first give the params the same slot as they had before.
*/
for (int i=0; i<paramLocals.length; i++)
if (paramLocals[i] != null)
paramLocals[i].newSlot = i;
/* Now calculate the conflict settings.
*/
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.instr.getOpcode() >= BytecodeInfo.opc_istore
&& info.instr.getOpcode() <= BytecodeInfo.opc_astore) {
/* This is a store. It conflicts with every local, whose
* value will be read without write.
*
* If this is inside a ret, it also conflicts with
* locals, that are not used inside, and where any jsr
* would conflict with.
*/
for (int i=0; i < maxlocals; i++) {
if (i != info.instr.getLocalSlot()
&& info.nextReads[i] != null)
info.local.conflictsWith(info.nextReads[i].local);
if (info.nextInfo.nextReads[i] != null
&& info.nextInfo.nextReads[i].jsrTargetInfo != null) {
Instruction[] jsrs = info.nextInfo.nextReads[i]
.jsrTargetInfo.instr.getPreds();
for (int j=0; j< jsrs.length; j++) {
InstrInfo jsrInfo
= (InstrInfo) instrInfos.get(jsrs[j]);
for (int k=0; k < maxlocals; k++) {
if (!info.nextInfo.nextReads[i].usedBySub
.get(k)
&& jsrInfo.nextReads[k] != null)
info.local.conflictsWith
(jsrInfo.nextReads[k].local);
}
}
}
}
}
}
/* Now put the locals that need a color into a vector.
*/
Vector locals = new Vector();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null
&& info.local.newSlot == -1
&& !locals.contains(info.local))
locals.addElement(info.local);
}
/* Now distribute slots recursive.
*/
distributeLocals(locals);
/* Update the instructions and calculate new maxlocals.
*/
maxlocals = paramLocals.length;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) {
if (info.local.newSlot+info.local.size > maxlocals)
maxlocals = info.local.newSlot + info.local.size;
info.instr.setLocalSlot(info.local.newSlot);
}
}
bc.setMaxLocals(maxlocals);
/* Update LocalVariableTable
*/
if (produceLVT)
buildNewLVT();
}
private InstrInfo CONFLICT = new InstrInfo();
boolean promoteLifeLocals(LocalInfo[] newLife, InstrInfo nextInfo) {
if (nextInfo.lifeLocals == null) {
nextInfo.lifeLocals = (LocalInfo[]) newLife.clone();
return true;
}
boolean changed = false;
for (int i=0; i< maxlocals; i++) {
LocalInfo local = nextInfo.lifeLocals[i];
if (local == null)
/* A conflict has already happened, or this slot
* may not have been initialized. */
continue;
local = local.getReal();
LocalInfo newLocal = newLife[i];
if (newLocal != null)
newLocal = newLocal.getReal();
if (local != newLocal) {
nextInfo.lifeLocals[i] = null;
changed = true;
}
}
return changed;
}
public void buildNewLVT() {
/* First we recalculate the usedBySub, to use the new local numbers.
*/
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo)
if (info.usedBySub != null)
info.usedBySub = new BitSet();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) {
for (int i=0; i < info.nextReads.length; i++) {
if (info.nextReads[i] != null
&& info.nextReads[i].instr.getOpcode() == opc_ret)
info.nextReads[i].usedBySub.set(info.local.newSlot);
}
}
}
/* Now we begin with the first Instruction and follow program flow.
* We remember which locals are life in lifeLocals.
*/
firstInfo.lifeLocals = new LocalInfo[maxlocals];
for (int i=0; i < paramLocals.length; i++)
firstInfo.lifeLocals[i] = paramLocals[i];
Stack changedInfo = new Stack();
changedInfo.push(firstInfo);
Handler[] handlers = bc.getExceptionHandlers();
while (!changedInfo.isEmpty()) {
InstrInfo info = (InstrInfo) changedInfo.pop();
Instruction instr = info.instr;
LocalInfo[] newLife = info.lifeLocals;
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
LocalInfo instrLocal = info.local.getReal();
newLife = (LocalInfo[]) newLife.clone();
newLife[slot] = instrLocal;
if (instrLocal.name != null) {
for (int j=0; j< newLife.length; j++) {
if (j != slot
&& newLife[j] != null
&& instrLocal.name.equals(newLife[j].name)) {
/* This local changed the slot. */
newLife[j] = null;
}
}
}
}
if (!instr.doesAlwaysJump()) {
InstrInfo nextInfo = info.nextInfo;
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
if (instr.hasSuccs()) {
Instruction[] succs = instr.getSuccs();
for (int i = 0; i < succs.length; i++) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(succs[i]);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
for (int i=0; i < handlers.length; i++) {
if (handlers[i].start.compareTo(instr) <= 0
&& handlers[i].end.compareTo(instr) >= 0) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(handlers[i].catcher);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
if (info.instr.getOpcode() == opc_jsr) {
/* On a jsr we do a special merge */
Instruction jsrTargetInstr = info.instr.getSingleSucc();
InstrInfo jsrTargetInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr);
InstrInfo retInfo = jsrTargetInfo.retInfo;
if (retInfo != null && retInfo.lifeLocals != null) {
LocalInfo[] retLife = (LocalInfo[]) newLife.clone();
for (int i=0; i< maxlocals; i++) {
if (retInfo.usedBySub.get(i))
retLife[i] = retInfo.lifeLocals[i];
}
if (promoteLifeLocals(retLife, info.nextInfo))
changedInfo.push(info.nextInfo);
}
}
if (info.jsrTargetInfo != null) {
/* On a ret we do a special merge */
Instruction jsrTargetInstr = info.jsrTargetInfo.instr;
for (int j=0; j< jsrTargetInstr.getPreds().length; j++) {
InstrInfo jsrInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr.getPreds()[j]);
if (jsrInfo.lifeLocals == null)
/* life locals are not calculated, yet */
continue;
LocalInfo[] retLife = (LocalInfo[]) newLife.clone();
for (int i=0; i< maxlocals; i++) {
if (!info.usedBySub.get(i))
retLife[i] = jsrInfo.lifeLocals[i];
}
if (promoteLifeLocals(retLife, jsrInfo.nextInfo))
changedInfo.push(jsrInfo.nextInfo);
}
}
}
Vector lvtEntries = new Vector();
LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals];
LocalInfo[] currentLocal = new LocalInfo[maxlocals];
for (int i=0; i< paramLocals.length; i++) {
if (paramLocals[i] != null) {
currentLocal[i] = paramLocals[i];
if (currentLocal[i].name != null) {
lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */
lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type);
lvi[i].start = (Instruction) bc.getInstructions().get(0);
lvi[i].slot = i;
}
}
}
Instruction lastInstr = null;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
for (int i=0; i< maxlocals; i++) {
LocalInfo lcl = info.lifeLocals != null ? info.lifeLocals[i]
: null;
if (lcl != currentLocal[i]
&& (lcl == null || currentLocal[i] == null
|| lcl.name == null || lcl.type == null
|| !lcl.name.equals(currentLocal[i].name)
|| !lcl.type.equals(currentLocal[i].type))) {
if (lvi[i] != null) {
lvi[i].end = info.instr.getPrevByAddr();
}
lvi[i] = null;
currentLocal[i] = lcl;
if (currentLocal[i] != null
&& currentLocal[i].name != null
&& currentLocal[i].type != null) {
lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name;
lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type);
lvi[i].start = info.instr;
lvi[i].slot = i;
}
}
}
lastInstr = info.instr;
}
for (int i=0; i< maxlocals; i++) {
if (lvi[i] != null)
lvi[i].end = lastInstr;
}
LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()];
lvtEntries.copyInto(lvt);
bc.setLocalVariableTable(lvt);
}
public void dumpLocals() {
Vector locals = new Vector();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
GlobalOptions.err.println(info.instr.getDescription());
GlobalOptions.err.print("nextReads: ");
for (int i=0; i<maxlocals; i++)
if (info.nextReads[i] == null)
GlobalOptions.err.print("-,");
else
GlobalOptions.err.print(info.nextReads[i].instr.getAddr()+",");
if (info.usedBySub != null)
GlobalOptions.err.print(" usedBySub: "+info.usedBySub);
if (info.retInfo != null)
GlobalOptions.err.print(" ret info: "
+info.retInfo.instr.getAddr());
if (info.jsrTargetInfo != null)
GlobalOptions.err.print(" jsr info: "
+info.jsrTargetInfo.instr.getAddr());
GlobalOptions.err.println();
if (info.local != null && !locals.contains(info.local))
locals.addElement(info.local);
}
Enumeration enum = locals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
int slot = ((InstrInfo)li.usingInstrs.elementAt(0))
.instr.getLocalSlot();
GlobalOptions.err.print("Slot: "+slot+" conflicts:");
Enumeration enum1 = li.conflictingLocals.elements();
while (enum1.hasMoreElements()) {
LocalInfo cfl = (LocalInfo)enum1.nextElement();
GlobalOptions.err.print(cfl.getFirstAddr()+", ");
}
GlobalOptions.err.println();
GlobalOptions.err.print(li.getFirstAddr());
GlobalOptions.err.print(" instrs: ");
Enumeration enum2 = li.usingInstrs.elements();
while (enum2.hasMoreElements())
GlobalOptions.err.print(((InstrInfo)enum2.nextElement())
.instr.getAddr()+", ");
GlobalOptions.err.println();
}
GlobalOptions.err.println("-----------");
}
public void transformCode(BytecodeInfo bytecode) {
this.bc = bytecode;
calcLocalInfo();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_LOCALS) != 0) {
GlobalOptions.err.println("Before Local Optimization: ");
dumpLocals();
}
stripLocals();
distributeLocals();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_LOCALS) != 0) {
GlobalOptions.err.println("After Local Optimization: ");
dumpLocals();
}
firstInfo = null;
changedInfos = null;
instrInfos = null;
paramLocals = null;
}
}

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

Loading…
Cancel
Save