This commit was manufactured by cvs2svn to create tag 'jode_1_1'.

git-svn-id: https://svn.code.sf.net/p/jode/code/tags/jode_1_1@1317 379699f6-c40d-0410-875b-85095c16579e
jode_1_1
(no author) 24 years ago
parent edc69e287a
commit 042c35a412
  1. 13
      CVSROOT/checkoutlist
  2. 15
      CVSROOT/commitinfo
  3. 11
      CVSROOT/config
  4. 1
      CVSROOT/cvsignore
  5. 23
      CVSROOT/cvswrappers
  6. 21
      CVSROOT/editinfo
  7. 26
      CVSROOT/loginfo
  8. 1
      CVSROOT/modules
  9. 12
      CVSROOT/notify
  10. 13
      CVSROOT/rcsinfo
  11. 20
      CVSROOT/taginfo
  12. 21
      CVSROOT/verifymsg
  13. 2
      jode/AUTHORS
  14. 303
      jode/ChangeLog
  15. 17
      jode/INSTALL
  16. 4
      jode/Makefile.am
  17. 5
      jode/NEWS
  18. 97
      jode/README
  19. 5
      jode/THANKS
  20. 13
      jode/TODO
  21. 2
      jode/acinclude.m4
  22. 35
      jode/configure.in
  23. 1
      jode/doc/.cvsignore
  24. 45
      jode/doc/Makefile.am
  25. BIN
      jode/doc/a-logo.gif
  26. 106
      jode/doc/applet.html
  27. 6
      jode/doc/applet.php
  28. 96
      jode/doc/bluesky.html
  29. 131
      jode/doc/download.html
  30. 34
      jode/doc/download.php
  31. 66
      jode/doc/faq.php
  32. 14
      jode/doc/feedback.php
  33. 11
      jode/doc/footer.inc
  34. 55
      jode/doc/header.inc
  35. 98
      jode/doc/history.html
  36. 2
      jode/doc/history.php
  37. 139
      jode/doc/index.html
  38. 44
      jode/doc/index.php
  39. 105
      jode/doc/license.html
  40. 9
      jode/doc/license.php
  41. 106
      jode/doc/links.html
  42. 10
      jode/doc/links.php
  43. 132
      jode/doc/menu.inc
  44. 158
      jode/doc/usage.html
  45. 56
      jode/doc/usage.php
  46. 4
      jode/jode/GlobalOptions.java.in
  47. 132
      jode/jode/bytecode/BytecodeInfo.java.in
  48. 25
      jode/jode/bytecode/ClassInfo.java.in
  49. 3
      jode/jode/bytecode/MethodInfo.java
  50. 87
      jode/jode/bytecode/SearchPath.java
  51. 165
      jode/jode/decompiler/ClassAnalyzer.java.in
  52. 2
      jode/jode/decompiler/Decompiler.java
  53. 4
      jode/jode/decompiler/FieldAnalyzer.java.in
  54. 119
      jode/jode/decompiler/LocalInfo.java
  55. 177
      jode/jode/decompiler/Main.java
  56. 51
      jode/jode/decompiler/MethodAnalyzer.java.in
  57. 11
      jode/jode/decompiler/Options.java
  58. 20
      jode/jode/decompiler/OuterValues.java
  59. 84
      jode/jode/decompiler/TabbedPrintWriter.java
  60. 25
      jode/jode/expr/ArrayStoreOperator.java
  61. 2
      jode/jode/expr/ConstOperator.java
  62. 9
      jode/jode/expr/ConstantArrayOperator.java
  63. 21
      jode/jode/expr/Expression.java.in
  64. 76
      jode/jode/expr/FieldOperator.java.in
  65. 4
      jode/jode/expr/IIncOperator.java
  66. 71
      jode/jode/expr/IfThenElseOperator.java
  67. 214
      jode/jode/expr/InvokeOperator.java.in
  68. 11
      jode/jode/expr/PopOperator.java
  69. 10
      jode/jode/expr/PrePostFixOperator.java
  70. 4
      jode/jode/expr/StoreInstruction.java
  71. 3
      jode/jode/expr/UnaryOperator.java
  72. 6
      jode/jode/flow/CaseBlock.java
  73. 12
      jode/jode/flow/CatchBlock.java.in
  74. 6
      jode/jode/flow/CreateClassField.java
  75. 11
      jode/jode/flow/EmptyBlock.java
  76. 3
      jode/jode/flow/FlowBlock.java.in
  77. 2
      jode/jode/flow/InstructionBlock.java.in
  78. 10
      jode/jode/flow/JsrBlock.java
  79. 3
      jode/jode/flow/LoopBlock.java.in
  80. 1
      jode/jode/flow/Makefile.am
  81. 6
      jode/jode/flow/SpecialBlock.java
  82. 12
      jode/jode/flow/StructuredBlock.java.in
  83. 64
      jode/jode/flow/TransformConstructors.java
  84. 1009
      jode/jode/flow/TransformExceptionHandlers.java.in
  85. 57
      jode/jode/jvm/CodeVerifier.java.in
  86. 170
      jode/jode/jvm/SyntheticAnalyzer.java.in
  87. 15
      jode/jode/obfuscator/ClassBundle.java.in
  88. 9
      jode/jode/obfuscator/ClassIdentifier.java.in
  89. 15
      jode/jode/obfuscator/PackageIdentifier.java.in
  90. 24
      jode/jode/obfuscator/TranslationTable.java.in
  91. 31
      jode/jode/obfuscator/modules/ConstantAnalyzer.java.in
  92. 9
      jode/jode/obfuscator/modules/LocalOptimizer.java.in
  93. 2
      jode/jode/obfuscator/modules/ModifierMatcher.java.in
  94. 53
      jode/jode/swingui/Main.java.in
  95. 51
      jode/jode/type/ArrayType.java
  96. 63
      jode/jode/type/ClassInterfacesType.java
  97. 11
      jode/jode/type/NullType.java
  98. 13
      jode/jode/type/RangeType.java
  99. 75
      jode/jode/util/UnifyHash.java.in

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

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

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

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

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

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

@ -1 +0,0 @@
jode jode

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

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

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

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

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

@ -0,0 +1,303 @@
2001-05-27 Jochen Hoenicke <jochen@gnu.org>
* configure.in: Set version to 1.1.
* jode/decompiler/Main.java (main): Also use bootclasspath if no
classpath given.
* jode/swingui/Main.java (main): Likewise.
* jode/decompiler/MethodAnalyzer.java.in (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.in (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.in (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.in (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.
2001-05-26 Jochen Hoenicke <jochen@gnu.org>
* 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.in (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.in (STRICTFP): New Constant.
(isStrictFP): New function.
(initialize): Set strictfp modifier if a constructor has it set.
(dumpSource): Handle strictfp modifier.
* jode/decompiler/MethodAnalyzer.java.in (STRICTFP): New Constant.
(isStrictFP): New function.
(dumpSource): Handle strictfp modifier.
* jode/jvm/SyntheticAnalyzer.java.in (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.in (simplifyAccess): Handle new
synthetics.
* jode/flow/SpecialBlock.java (removePop): Remove pop also for
non void store instructions.
* jode/decompiler/MethodAnalyzer.java.in (skipWriting): Also skip
the new synthetics.
* jode/decompiler/Main.java (main): Call System.exit() after
everything was compiled.
* jode/flow/TransformExceptionHandlers.java.in (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-05-08 Jochen Hoenicke <jochen@gnu.org>
* jode/jvm/CodeVerifier.java.in (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-05-02 Jochen Hoenicke <jochen@gnu.org>
* jode/obfuscator/modules/ConstantAnalyzer.java.in (handleOpcode):
Added divide by zero checks for opc_irem and opc_lrem.
2001-04-11 Jochen Hoenicke <jochen@gnu.org>
* jode/type/ClassInterfacesType.java (keywords): Reworked keyword
list.
* jode/decompiler/OuterValues.java (implicitOuterClass): New field.
(isImplicitOuterClass): new Method.
(setImplicitOuterClass): new Method.
* jode/flow/TransformConstructors.java (checkAnonymousConstructor):
Check for implicitOuterClass, a new javac 1.3 construct.
* jode/expr/FieldOperator.java.in (dumpSource): Removed this
simplification nonesense. Now Outer.this is never printed as
this.
* jode/expr/InvokeOperator.java.in (dumpSource): Removed this
simplification nonesense. Now Outer.this is never printed as
this.
Handle implicitOuterClass.
2001-04-10 Jochen Hoenicke <jochen@gnu.org>
* jode/decompiler/Main.java (usage): Reworked usage message.
2001-04-09 Jochen Hoenicke <jochen@gnu.org>
* jode/bytecode/SearchPath.java: Bug fixes from Joe Bronkema:
(exists): Don't replace '/' with fileSeparator in original
filename; make a copy instead.
(getFile): likewise.
(isDirectory): likewise.
(listFiles): Reset fileNr when a new directory is read.
2001-02-28 Jochen Hoenicke <jochen@gnu.org>
* 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.
2001-02-27 Jochen Hoenicke <jochen@gnu.org>
* jode/swingui/Main.java.in (AreaWriter): Convert all kinds of
line breaks (CR+LF, CR, LF) to a LF character, which a JTextArea
understands.
2001-02-08 Jochen Hoenicke <jochen@gnu.org>
* jode/expr/StoreInstruction.java (dumpExpression): Java doesn't
allow parenthesis around left hand side, so use NO_PAREN and don't
call lhs.dumpExpression() with priority.
* jode/expr/PrePostFixOperator.java (dumpExpression): likewise.
* jode/expr/IIncOperator.java (dumpExpression): likewise.
* jode/flow/TransformConstructors.java (jikesAnonInner): Removed,
since it wasn't used: This information is stored in OuterValues
now.
* jode/decompiler/LocalInfo.java (isConstant): Always return true
so that inner classes that access final locals work, even if we
can't decide that the local can be final.
2001-02-05 Jochen Hoenicke <jochen@gnu.org>
* jode/expr/InvokeOperator.java.in (Environment.invokeMethod):
Fixed the call to ClassInfo.forName: it expects a class name, while
ref.getClazz() gives a type signature.
* jode/flow/TransformExceptionHandlers.java.in:
(checkAndRemoveJSR): Only invoke removeBadJSR, if there are
successors left.
(checkAndRemoveMonitorExit): likewise.
2001-02-04 Jochen Hoenicke <jochen@gnu.org>
* jode/expr/IfThenElseOperator.java (simplify): Allow in the class$
simplification the then and else part to be swapped.
* jode/bytecode/ClassInfo.java.in (read): Accept class version
1.3.
* jode/type/ClassInterfacesType.java (keywords): Added the package
and import keywords.
* jode/flow/TransformExceptionHandlers.java.in:
(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.in (prependBlock): New function.
* jode/flow/CatchBlock.java.in (makeDeclaration): Generate name
of dummyLocal, since nobody else will generate it.
2001-02-03 Jochen Hoenicke <jochen@gnu.org>
* jode/bytecode/BytecodeInfo.java.in (read): 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.in (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-02-01 Jochen Hoenicke <jochen@gnu.org>
* jode/jvm/CodeVerifier.java.in (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.
* jode/flow/TransformExceptionHandlers.java.in: Merged patch from
the 1.2 tree to support javac 1.3 synchronized blocks. Doesn't
handle nested synchronized blocks yet.
* jode/expr/Expression.java.in (dumpExpression): Show runtime
exception when it occurs.
2001-01-31 Jochen Hoenicke <jochen@gnu.org>
* jode/expr/Expression.java.in (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.in (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-01-30 Jochen Hoenicke <jochen@gnu.org>
* jode/jvm/SyntheticAnalyzer.java.in (checkConstructorAccess):
Allow the special unifyParam to be the last parameter.
2001-01-30 Jochen Hoenicke <jochen@gnu.org>
* jode/decompiler/TabbedPrintWriter.java: Better gnu style handling:
(openBraceClass) (closeBraceClass)
(openBraceNoIndent) (closeBraceNoIndent): new functions.
(closeBraceNoSpace): Removed.
* jode/decompiler/Options.java (GNU_SPACING): new constant.
(GNU_STYLE): changed to include GNU_SPACING.
* jode/decompiler/ClassAnalyzer.java.in (dumpSource): Use
open/closeBraceClass.
* jode/decompiler/MethodAnalyzer.java.in (dumpSource): Use
open/closeBraceNoIndent. Insert a space for GNU_SPACING.
* jode/decompiler/InvokeOperator.java.in (dumpExpression): Insert
a space for GNU_SPACING, use open/closeBraceClass for inner
classes.
* jode/decompiler/UnaryOperator.java (dumpExpression): Insert
a space for GNU_SPACING.
2001-01-30 Jochen Hoenicke <jochen@gnu.org>
Added pascal style from Rolf Howarth <rolf@squarebox.co.uk>
* jode/decompiler/Options.java (PASCAL_STYLE): new constant.
(BRACE_FLUSH_LEFT): dito.
* jode/decompiler/Decompiler.java (setOption): detect pascal option.
* jode/decompiler/Main.java (main): dito.
* jode/decompiler/TabbedPrintWriter.java (openBrace,
openBraceContinue, closeBrace, closeBraceNoSpace,
closeBraceContinue): handle flush left.
2001-01-30 Jochen Hoenicke <jochen@gnu.org>
* 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.in (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/jvm/SyntheticAnalyzer.java.in (unifyParam): new field.
(checkConstructorAccess): Allow the special Parameter, whose
purpose is to distinguish the wrapper from the real constructor
and give him a "$" in the type signature, to appear at every
position. It doesn't appear at position 1 for inner classes.
Store the position in unifyParam.
* 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,12 +1,15 @@
Before installing, make sure you have a java compiler (e.g javac or Before installing, make sure you have at least version 1.1 of the java
jikes) and the java 1.1 runtime class library installed. If you want developement kit installed. If you want to run this program you only
to run this program you need at least a 1.1 compatible java virtual need the java runtime environment. Version 1.1 is quite old, I
machine. There are some bugs in javac included in the SUN JDK 1.1, it recommend using Java 2 (jdk1.2 or above).
won't work.
This package was designed to use the GNU standard for configuration This package was designed to use the GNU standard for configuration
and makefiles. To build and install do the following: and makefiles. To build and install do the following:
0). If you have downloaded the code from the CVS repository create
configure and Makefile.in with autoconf-2.13 and automake-1.4. Type
"aclocal; automake -a; autoconf".
1). You need a java development kit (at least version 1.1), some unix 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 tools and some java packages. Make sure that you have all java
packages that are needed in your classpath. This are gnu.getopt, and packages that are needed in your classpath. This are gnu.getopt, and
@ -40,7 +43,3 @@ give a path to the directory where it resides, otherwise it is
searched in the path. searched in the path.
3). Type "make" to build the package. 3). Type "make" to build the package.
4). Type "make install" to install the package. This doesn't work yet.
Jochen

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

@ -1,6 +1,7 @@
New in 1.0.94 New in 1.1
* break long lines * break long lines
* small bug fixes * handle most of javac v8 constructs (jdk 1.3)
* bug fixes
New in 1.0.93 New in 1.0.93
* anonymous and inner class decompilation reworked. * anonymous and inner class decompilation reworked.

@ -1,12 +1,17 @@
JODE (Java Optimize and Decompile Environment) JODE (Java Optimize and Decompile Environment)
This is a decompiler and optimizer for java I have written in my spare JODE is a java package containing a decompiler and an optimizer for
time. The decompiler takes class files as input and produces java. This package is freely available under the GNU General Public
something similar to the original java file. Of course this can't be License.
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 The decompiler reads in class files and produces something similar to
there are often more ways to write the same thing. But jode does its the original java file. Of course this can't be perfect: There is no
job quite well. 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 Please note that most software licenses forbid to decompile class
files. Use this decompiler only, if you have legal rights to 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: 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 - If not all dependent classes can be found, the verifier (which is
run before decompilation starts) may exit with a type error. You run before decompilation starts) may exit with a type error. You
can decompile it with --verify=off, but take the warning serious, 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 happen when you compile with `-O' flag and javac has inlined some
methods. 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: The features of the obfuscator are:
* Modular design, you can plug the obfuscation transformation you need * Modular design, you can plug the obfuscation transformation you need
@ -66,62 +68,23 @@ The features of the obfuscator are:
PRELIMINARIES: PRELIMINARIES:
You need java jdk1.2 or above, and the gnu getopt package. See INSTALL for installation instructions.
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
USAGE: USAGE:
First set the classpath. It should contain the jar file First set the classpath. It should contain the jar file jode-1.1.jar,
jode-x.x.xx.jar, the gnu getopt package and the sun collection package the gnu getopt package and the sun collection package for 1.1. For
for 1.1. For the swingui program you also need swing in you classpath. the swingui program you also need swing in you classpath.
You can then decompile a class file with: 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: For a graphical user interface based on swing try:
java jode.swingui.Main --classpath jarfile1.jar 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 java jode.obfuscator.Main obfuscation.jos
See XXXX for more information about the script syntax. See the web documents 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.

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

@ -4,12 +4,13 @@ Decompiler:
- outline inlined methods. - outline inlined methods.
- remove string decrypt method. - remove string decrypt method.
- remove synthetic methods if and only if all calls to them are resolved. - remove synthetic methods if and only if all calls to them are resolved.
~ handle try catch more thouroughly/safely.
~ decompile jode.jvm.Interpreter (hand optimized bytecode)
Obfuscator: Obfuscator:
- flow obfuscation/optimization. - flow obfuscation/optimization.
- warn about Class.forName and list occurences. - warn about Class.forName and list occurences.
- detect Class.forName on constant strings and handle appropriately.
- work around Class.forName, by creating a new version using a hash
table that maps md5 sums of old names to obfuscated names.
DeObfuscator: DeObfuscator:
- generate nice names: - generate nice names:
@ -20,13 +21,15 @@ DeObfuscator:
User Interface: User Interface:
- make a nice user interface: - make a nice user interface:
~ list classnames: toggable between class hierarchie/package hierarchie.
- list fields/method of selected class. - list fields/method of selected class.
- show decompilation of selected method. - show only decompilation of selected method.
- show usage of method/fields. - show usage of method/fields.
- syntax highlighting, hyper links etc. - syntax highlighting, hyper links etc.
(look at java.swing.JEditorPane or at Java Insight) (look at java.swing.JEditorPane or at Java Insight)
- visual obfuscation/deobfuscation (like klassmaster?, better?) - visual obfuscation/deobfuscation (like klassmaster?, better?)
Internal: 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.

@ -28,7 +28,7 @@ AC_DEFUN(JODE_CHECK_CLASS,
myclasspath=$2; myclasspath=$2;
for path in $myclasspath; do for path in $myclasspath; do
if test -d $path; then if test -d $path; then
if test -e $path/$clazz; then if test -f $path/$clazz; then
exit 0 exit 0
fi fi
elif CLASS_CHECK $path $clazz ; then elif CLASS_CHECK $path $clazz ; then

@ -1,18 +1,10 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT() AC_INIT()
AM_INIT_AUTOMAKE(jode, 1.0.93) AM_INIT_AUTOMAKE(jode, 1.1)
dnl Checks for programs. 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 AC_PROG_MAKE_SET
dnl AC_PROG_RANLIB
dnl AC_PATH_PROG(ZIP, zip)
AC_PATH_PROG(PERL, perl) AC_PATH_PROG(PERL, perl)
AC_PATH_PROG(CYGPATH, cygpath) AC_PATH_PROG(CYGPATH, cygpath)
@ -78,7 +70,7 @@ AM_CONDITIONAL(HAVE_JIKES, test x"$JIKES" != x)
AC_ARG_WITH(javac, AC_ARG_WITH(javac,
[ --with-javac specify location of javac ], [ --with-javac specify location of javac ],
[ [
if test x$USER_SPECIFIED_JIKES == xtrue; then if test x$USER_SPECIFIED_JIKES = xtrue; then
AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes) AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes)
fi fi
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then
@ -114,13 +106,20 @@ JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB,
[ AC_MSG_RESULT(no) [ AC_MSG_RESULT(no)
AC_MSG_ERROR(Please specify location of core java class library) ]) AC_MSG_ERROR(Please specify location of core java class library) ])
AC_MSG_CHECKING(for java.lang.ref.WeakReference)
JODE_CHECK_CLASS(java.lang.ref.WeakReference, $CLASSLIB,
[ AC_MSG_RESULT(yes)
JCPPFLAGS="-DJDK12" ],
[ AC_MSG_RESULT(no)
JCPPFLAGS="-DJDK11" ])
AC_MSG_CHECKING(for collection classes) AC_MSG_CHECKING(for collection classes)
JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB, JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="java.util" [ COLLECTIONS="java.util"
COLLECTIONEXTRA="java.lang" ], COLLECTIONEXTRA="java.lang" ],
[ JODE_CHECK_CLASS(org.gnu.java.util.collections.Set, $CLASSPATH:$CLASSLIB, [ JODE_CHECK_CLASS(gnu.java.util.collections.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="org.gnu.java.util.collections" [ COLLECTIONS="gnu.java.util.collections"
COLLECTIONEXTRA="org.gnu.java.util.collections" ], COLLECTIONEXTRA="gnu.java.util.collections" ],
[ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB, [ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="com.sun.java.util.collections" [ COLLECTIONS="com.sun.java.util.collections"
COLLECTIONEXTRA="com.sun.java.util.collections" ], COLLECTIONEXTRA="com.sun.java.util.collections" ],
@ -240,6 +239,12 @@ bin/Makefile
bin/jode bin/jode
bin/jode.bat bin/jode.bat
doc/Makefile doc/Makefile
doc/download.html
test/Makefile, test/Makefile,
[chmod 755 javaDependencies.pl bin/jode]) [chmod 755 javaDependencies.pl bin/jode],
[for i in \$CONFIG_FILES; do
changequote(, )dnl
if [ \$i != \${i%.java} ]; then
changequote([, ])dnl
$PERL $srcdir/jcpp $JCPPFLAGS \$i
fi
done])

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

@ -1,14 +1,43 @@
## Input file for automake to generate the Makefile.in used by configure ## Input file for automake to generate the Makefile.in used by configure
EXTRA_DIST = \ PHP_FILES = \
applet.html \ applet.php \
download.html.in \ bluesky.php \
history.html \ download.php \
jode.html \ faq.php \
license.html \ feedback.php \
links.html \ history.php \
usage.html \ index.php \
license.php \
links.php \
usage.php
HTML_FILES = $(PHP_FILES:%.php=$(srcdir)/%.html)
noinst_DATA = $(HTML_FILES)
EXTRA_DIST = $(PHP_FILES) $(notdir $(HTML_FILES)) \
a-logo.gif \
myproject.jos \ myproject.jos \
dasm_to_java.perl \ dasm_to_java.perl \
gimp/jode-logo.xcf \ gimp/jode-logo.xcf \
jode-logo.gif jode-logo.gif
.PHONY: public_html_symlink
# The following rules require that you have an apache with php on
# localhost with standard user public_html directories and
# FollowSymLink enabled.
PUBLIC_HTML=$(HOME)/public_html
JODE_PHP_DIR=jode_php
public_html_symlink:
rm -f $(PUBLIC_HTML)/$(JODE_PHP_DIR)
@RELDIR=`pwd | sed s!^$(HOME)!..!`; \
ln -sf $$RELDIR/$(srcdir) $(PUBLIC_HTML)/$(JODE_PHP_DIR); \
echo Created symlink to $$RELDIR/$(srcdir).
footer.inc: public_html_symlink
$(srcdir)/%.html: %.php footer.inc header.inc menu.inc
lynx -source http://localhost/~$(LOGNAME)/$(JODE_PHP_DIR)/$(notdir $<)?extension=.html > $@

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

@ -2,69 +2,74 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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> <h1>The <i>JODE</i> Applet</h1>
Please be patience, loading the applet may take some time.<br><br> <p>Please be patience, loading the applet may take some time.</p>
<center> <center>
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400> <applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400>
<param name=pagecolor value="ffffff"> <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=classpath value="http://jode.sourceforge.net/load.php/http%3a//www.informatik.uni-oldenburg.de/~mw/plasma.jar">
<param name=class value="PlasmaApplet"> <param name=class value="PlasmaApplet">
<p>Sorry you need a java enabled browser to test a java applet ;-)</p> <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> <p>Don't read the rest, it only contains information about the applet.</p>
</applet> </applet>
</center><br> </center><br>
Press the start button to decompile <a <p> Press the start button to decompile <a
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's
Plasma applet</a> (and give the decompiler some time to download the Plasma applet</a> (and give the decompiler some time to download the
jar file). <br><br> jar file). </p>
You may change the classpath to point to a zip or jar file of your 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 choice, using a similar syntax. Use <code>%3a</code> instead of a
@ -75,20 +80,19 @@ 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 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 a server that is accessible from sourceforge. You can try to give
local filenames directly without the load.html wrapper, but that is local filenames directly without the load.php wrapper, but that is
probably forbidden by your browser. Most browser only allow loading probably forbidden by your browser. Most browser only allow loading
files from the same server as the applet, and this is the reason why files from the same server as the applet, and this is the reason why
you have to use such a cryptic URL.<br><br> you have to use such a cryptic URL.<br><br>
Save probably doesn't work, because it is forbidden by your browser.<br><br> Save probably doesn't work, because it is forbidden by your browser.<br><br>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -1,7 +1,7 @@
<?php require("header.inc"); ?> <?php require("header.inc"); ?>
<h1>The <i>JODE</i> Applet</h1> <h1>The <i>JODE</i> Applet</h1>
Please be patience, loading the applet may take some time.<br><br> <p>Please be patience, loading the applet may take some time.</p>
<center> <center>
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400> <applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400>
@ -13,10 +13,10 @@ Please be patience, loading the applet may take some time.<br><br>
</applet> </applet>
</center><br> </center><br>
Press the start button to decompile <a <p> Press the start button to decompile <a
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's
Plasma applet</a> (and give the decompiler some time to download the Plasma applet</a> (and give the decompiler some time to download the
jar file). <br><br> jar file). </p>
You may change the classpath to point to a zip or jar file of your 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 choice, using a similar syntax. Use <code>%3a</code> instead of a

@ -2,51 +2,56 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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> <h1>Blue Sky</h1>
<p>This section contains features that I think would be great to have, <p>This section contains features that I think would be great to have,
@ -117,14 +122,13 @@ copy them back into the java code. </p>
<p>This doesn't need to be built into the decompiler. A script that takes <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> the javadoc pages and the decompiled code can easily merge them.</p>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

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

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

@ -0,0 +1,66 @@
<?php require("header.inc"); ?>
<h1>FAQ - Frequently Asked Questions</h1>
This is a list of some questions that pop up from time to time.
<h2>Decompiler issues</h2>
<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.</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>
<h2>Obfuscator issues</h2>
<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&rt;</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>
<?php require("footer.inc"); ?>

@ -0,0 +1,14 @@
<?php require("header.inc"); ?>
<h1>Feedback</h1>
<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>
<?php require("footer.inc"); ?>

@ -1,11 +1,10 @@
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 30-Jun-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -1,13 +1,17 @@
<?php <?php
$version="1.0.93"; if (! $extension) {
$extension = "php";
}
$version="1.1";
function selflink($link) { function selflink($link) {
global $extension;
echo "<a href=\"./"; echo "<a href=\"./";
if ($link != "jode") { if ($link != "index") {
if (ereg("#", $link)) { if (ereg("#", $link)) {
$link = ereg_replace("#", ".php#", $link); $link = ereg_replace("#", ".$extension#", $link);
} else { } else {
$link .= ".php"; $link .= ".$extension";
} }
echo "$link"; echo "$link";
} }
@ -21,22 +25,39 @@ function sflink($link) {
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
<?php /* <CENTER><img src="constructionint.gif" alt="Under Construction, "><br> ><tr
beware broken links</CENTER> */ ?> ><td align="left"
</td> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ></td
</tr> ><td align="right"
<tr> >Powered by <a href="http://sourceforge.net"><img
<td valign="top"> src="http://sourceforge.net/sflogo.html?group_id=3790&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"); ?> <?php require("menu.inc"); ?>
</td>
<td valign="top">

@ -2,52 +2,57 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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> <h1>History</h1>
</td></tr></table>
</td>
<td valign="top">
<h2>History</h2>
<p>Someday I found <code>guavad</code>, a disassembler for java byte <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 code (it does similar things like <code>javap&nbsp;-c</code>). I used
@ -67,14 +72,13 @@ now, because it suited best.</p>
<p>Just for the records: the java code is now more than 50 times <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> bigger than the original perl script and is still growing.</p>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -1,5 +1,5 @@
<?php require("header.inc"); ?> <?php require("header.inc"); ?>
<h2>History</h2> <h1>History</h1>
<p>Someday I found <code>guavad</code>, a disassembler for java byte <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 code (it does similar things like <code>javap&nbsp;-c</code>). I used

@ -2,64 +2,68 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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 <P><i>JODE</i> is a java package containing a decompiler and an
optimizer for java. This package is freely available under the GPL optimizer for java. This package is <a href="./license..html">freely available</a> under the GNU GPL.<p>
(see <a href="./license.html">license</a>).<p>
<P>The decompiler takes <tt>class</tt> files as input and produces <P>The decompiler reads in <tt>class</tt> files and produces something
something similar to the original <tt>java</tt> file. Of course this similar to the original <tt>java</tt> file. Of course this can't be
can't be perfect: There is no way to produce the comments or the names perfect: There is no way to produce the comments or the names of local
of local variables (except when compiled with debuging) and there are variables (except when compiled with debuging) and there are often
often more ways to write the same thing. But <i>JODE</i> does its job more ways to write the same thing. However, <i>JODE</i> does its job quite
quite well, so you should give it a try: <a href="./applet.html">start well, so you should give it a try and <a href="./applet..html">start the
the applet</a>.</P> applet</a>.</P>
<P>The optimizer transforms <tt>class</tt> files in various ways with <P>The optimizer transforms <tt>class</tt> files in various ways with
can be controlled by a script file. It supports the following can be controlled by a script file. It supports the following
@ -77,14 +81,23 @@ fields</li>
<h2>News</h2> <h2>News</h2>
<ul> <ul>
<li>JODE 1.1 is out. With support for javac v8 (jdk 1.3). </li>
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li> <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>Now long lines are automatically broken.</li>
<li>I can now decompile <b>inner and anonymous</b> classes.</li> <li><b>Inner and anonymous</b> classes are automatically decompiled.</li>
<li>The optimizer (aka obfuscator) can be customized via a small <li>The optimizer (aka obfuscator) can be customized via a small
config file</li> config file</li>
<li>Jode is <tt>autoconf</tt>igured.</li>
</ul> </ul>
<h2>Known bugs of the decompiler</h2>
<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>
<h2>Limitations</h2> <h2>Limitations</h2>
<p>If not all dependent classes can be found, the verifier (which is <p>If not all dependent classes can be found, the verifier (which is
@ -104,25 +117,13 @@ the code should still be compileable. This does especially happen
when you compile with <tt>`-O'</tt> flag and javac has inlined some when you compile with <tt>`-O'</tt> flag and javac has inlined some
methods. </p> methods. </p>
<p>Sometimes this program may exit with an <code>Exception</code> or <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
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> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -1,16 +1,16 @@
<?php require("header.inc"); ?> <?php require("header.inc"); ?>
<P><i>JODE</i> is a java package containing a decompiler and an <P><i>JODE</i> is a java package containing a decompiler and an
optimizer for java. This package is freely available under the GPL optimizer for java. This package is <?php selflink("license")
(see <?php selflink("license") ?>license</a>).<p> ?>freely available</a> under the GNU GPL.<p>
<P>The decompiler takes <tt>class</tt> files as input and produces <P>The decompiler reads in <tt>class</tt> files and produces something
something similar to the original <tt>java</tt> file. Of course this similar to the original <tt>java</tt> file. Of course this can't be
can't be perfect: There is no way to produce the comments or the names perfect: There is no way to produce the comments or the names of local
of local variables (except when compiled with debuging) and there are variables (except when compiled with debuging) and there are often
often more ways to write the same thing. But <i>JODE</i> does its job more ways to write the same thing. However, <i>JODE</i> does its job quite
quite well, so you should give it a try: <? selflink("applet") ?>start well, so you should give it a try and <? selflink("applet") ?>start the
the applet</a>.</P> applet</a>.</P>
<P>The optimizer transforms <tt>class</tt> files in various ways with <P>The optimizer transforms <tt>class</tt> files in various ways with
can be controlled by a script file. It supports the following can be controlled by a script file. It supports the following
@ -28,14 +28,23 @@ fields</li>
<h2>News</h2> <h2>News</h2>
<ul> <ul>
<li>JODE 1.1 is out. With support for javac v8 (jdk 1.3). </li>
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li> <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>Now long lines are automatically broken.</li>
<li>I can now decompile <b>inner and anonymous</b> classes.</li> <li><b>Inner and anonymous</b> classes are automatically decompiled.</li>
<li>The optimizer (aka obfuscator) can be customized via a small <li>The optimizer (aka obfuscator) can be customized via a small
config file</li> config file</li>
<li>Jode is <tt>autoconf</tt>igured.</li>
</ul> </ul>
<h2>Known bugs of the decompiler</h2>
<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>
<h2>Limitations</h2> <h2>Limitations</h2>
<p>If not all dependent classes can be found, the verifier (which is <p>If not all dependent classes can be found, the verifier (which is
@ -55,15 +64,4 @@ the code should still be compileable. This does especially happen
when you compile with <tt>`-O'</tt> flag and javac has inlined some when you compile with <tt>`-O'</tt> flag and javac has inlined some
methods. </p> 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"); ?> <?php require("footer.inc"); ?>

@ -2,72 +2,77 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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> <h1>License</h1>
</td></tr></table>
</td>
<td valign="top">
<p><i>JODE</i> is Copyright &copy; 1998-2000 by Jochen Hoenicke. <br><br> <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 <p>This program is free software; you can redistribute it and/or modify
it under the terms of the <a it under the terms of the <a
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public href="http://www.gnu.org/copyleft/gpl.html">GNU General Public
License</a> as published by the Free Software Foundation; either License</a> as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.<br><br> version 2 of the License, or (at your option) any later version.</p>
This program is distributed in the hope that it will be useful, <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 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 <b>merchantability</b> or <b>fitness for a particular purpose</b>. See the
GNU General Public License for more details. GNU General Public License for more details.</p>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -1,15 +1,16 @@
<?php require("header.inc"); ?> <?php require("header.inc"); ?>
<h1>License</h1>
<p><i>JODE</i> is Copyright &copy; 1998-2000 by Jochen Hoenicke. <br><br> <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 <p>This program is free software; you can redistribute it and/or modify
it under the terms of the <a it under the terms of the <a
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public href="http://www.gnu.org/copyleft/gpl.html">GNU General Public
License</a> as published by the Free Software Foundation; either License</a> as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.<br><br> version 2 of the License, or (at your option) any later version.</p>
This program is distributed in the hope that it will be useful, <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 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 <b>merchantability</b> or <b>fitness for a particular purpose</b>. See the
GNU General Public License for more details. GNU General Public License for more details.</p>
<?php require("footer.inc"); ?> <?php require("footer.inc"); ?>

@ -2,51 +2,56 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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> <h1><i>JODE</i> Links</h1>
<h3>Other decompilers</h3> <h3>Other decompilers</h3>
<ul> <ul>
@ -100,20 +105,21 @@ href="http://jedit.standmed.com/plugins/JavaInsight">JavaInsight plugin</a> for
</dd> </dd>
<dt><a name="collections">Collection Classes</a>:</dt> <dt><a name="collections">Collection Classes</a>:</dt>
<dd>I have written a small script that puts the collection classes <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 from the <a href="http://www.classpath.org">GNU Classpath Project</a>
its own package (<code>org.gnu.java.util.collections</code>). You can into its own package (<code>gnu.java.util.collections</code>). This
download the <a href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.tar.gz">source code</a> (including script is now part of GNU classpath. For your convenience I have put a
the script), or <a href="collections.jar">a precompiled jar file</a>. precompiled <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.jar">jar
file</a> on this server.
</dd> </dd>
</dl> </dl>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -52,10 +52,12 @@ href="http://jedit.standmed.com/plugins/JavaInsight">JavaInsight plugin</a> for
</dd> </dd>
<dt><a name="collections">Collection Classes</a>:</dt> <dt><a name="collections">Collection Classes</a>:</dt>
<dd>I have written a small script that puts the collection classes <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 from the <a href="http://www.classpath.org">GNU Classpath Project</a>
its own package (<code>org.gnu.java.util.collections</code>). You can into its own package (<code>gnu.java.util.collections</code>). This
download the <a href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.tar.gz">source code</a> (including script is now part of GNU classpath. For your convenience I have put a
the script), or <a href="collections.jar">a precompiled jar file</a>. precompiled <a
href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.jar">jar
file</a> on this server.
</dd> </dd>
</dl> </dl>
<?php require("footer.inc"); ?> <?php require("footer.inc"); ?>

@ -1,115 +1,47 @@
<?php <?php
$menu = array( $menu =
"Jode", array("<B>Home</B>" , "selflink", "index",
array("<B>Home</B>" , "selflink", "jode",
"Project page" , "sflink", "project/", "Project page" , "sflink", "project/",
"-", "-", "-",
"Applet" , "selflink", "applet", "Applet" , "selflink", "applet",
"Download" , "selflink", "download", "Download" , "selflink", "download",
"FAQ" , "selflink", "faq",
"Feedback" , "selflink", "feedback",
"Documentation", "selflink", "usage", "Documentation", "selflink", "usage",
"License" , "selflink", "license", "License" , "selflink", "license",
"History" , "selflink", "history", "History" , "selflink", "history",
"Links" , "selflink", "links", "Links" , "selflink", "links",
"Blue Sky" , "selflink", "bluesky"), "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";
reset($menu); <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
while (list($dummy, $header) = each($menu)) { <tr><td class="nav">
list($dummy, $subitems) = each($menu); <?php
echo "<tr bgcolor=\"7272cc\">\n<td align=\"center\">"; reset($menu);
echo "<font color=\"ffffff\"><b>$header</b></font></td></tr>\n"; $self = ereg_replace("^.*/", "", $PHP_SELF);
echo "<tr><td align=\"right\">\n"; while (list($dummy, $name) = each($menu)) {
reset($subitems); list($dummy, $type) = each($menu);
while (list($dummy, $name) = each($subitems)) { list($dummy, $link) = each($menu);
list($dummy, $type) = each($subitems); $name = ereg_replace(" ", "&nbsp;", $name);
list($dummy, $link) = each($subitems); if ($type == "selflink") {
if ($type == "selflink") { if ($self == "$link.$extension") {
selflink($link); echo "$name";
} else if ($type == "sflink") { } else {
sflink($link); selflink($link);
} else if ($type == "-") {
echo "<br>\n";
continue;
} else if ($type == "link") {
echo "<a href=\"$link\">";
}
$name = ereg_replace(" ", "&nbsp;", $name);
echo "$name</a>"; 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"; if (current($menu)) {
echo "<tr bgcolor=\"ffffff\"><td align=\"center\">"; echo " |\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 "<br>$label<br>\n";
echo "<a href=\"$link\"><img src=\"$src\" border=0";
echo " width=88 height=31 alt=\"$alt\"></a><br>\n";
} }
echo "</td></tr></table>\n";
} }
?> ?>
</td></tr>
</table><br>

@ -2,73 +2,80 @@
<html> <html>
<head> <head>
<title>Java Optimize and Decompile Environment (JODE)</title> <title>Java Optimize and Decompile Environment (JODE)</title>
<meta name="date" content="2000-06-30"> <meta name="date" content="2001-05-27">
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> <meta name="description" content="JODE - Java Optimize and Decompile Environment.">
<meta name="author" content="Jochen Hoenicke"> <meta name="author" content="Jochen Hoenicke">
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> <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> </head>
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> <body text=#000000 bgcolor=#FFFFFF>
<table cellpadding=4 cellspacing=1 width=100%>
<tr><td> <table cellpadding=4 cellspacing=1 width=100%
</td> ><tr
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> ><td align="left"
</tr> ><img src="jode-logo.gif" alt="JODE" width=286 height=110
<tr> ></td
<td valign="top"> ><td align="right"
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> >Powered by <a href="http://sourceforge.net"><img
<tr bgcolor="7272cc"> src="http://sourceforge.net/sflogo.html?group_id=3790&type=1"
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> border=0 width=88 height=31 alt="SourceForge"></a><br
<tr><td align="right"> >Best viewed with <a
<a href="./"><B>Home</B></a><br> href="http://www.anybrowser.org/campaign/"><img
<a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a><br> src="a-logo.gif" border=0 width=88 height=31 alt="Any
<br> Browser"></a><br
<a href="./applet.html">Applet</a><br> ></td
<a href="./download.html">Download</a><br> ></tr
<a href="./usage.html">Documentation</a><br> ></table>
<a href="./license.html">License</a><br>
<a href="./history.html">History</a><br>
<a href="./links.html">Links</a><br> <table cellspacing=0 cellpadding=3 border=0 bgcolor=#EEEEF8 class="nav">
<a href="./bluesky.html">Blue&nbsp;Sky</a><tr bgcolor="7272cc"> <tr><td class="nav">
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> <a href="./"><B>Home</B></a> |
<tr><td align="right"> <a href="http://sourceforge.net/project/?group_id=3790">Project&nbsp;page</a> |
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug&nbsp;Tracking</a><br> <a href="./applet..html">Applet</a> |
<a href="http://sourceforge.net/forum/?group_id=3790">Public&nbsp;Forums</a><br> <a href="./download..html">Download</a> |
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing&nbsp;List</a><br> <a href="./faq..html">FAQ</a> |
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private&nbsp;Mail</a><tr bgcolor="7272cc"> <a href="./feedback..html">Feedback</a> |
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> <a href="./usage..html">Documentation</a> |
<tr><td align="right"> <a href="./license..html">License</a> |
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP&nbsp;server</a><br> <a href="./history..html">History</a> |
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source&nbsp;releases</a></td></tr> <a href="./links..html">Links</a> |
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> <a href="./bluesky..html">Blue&nbsp;Sky</a></td></tr>
<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> </table><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"> <a name="decompiler">
<h1>Using the Decompiler</h1></a> <h1>Using the Decompiler</h1></a>
After you have <a href="./download.html">downloaded</a> the necessary <p>After you have <a href="./download..html">downloaded</a> the jar archive
packages, put them into your <tt>CLASSPATH</tt>: 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 <ul><li>Under Windows you have to start a MSDOS session and type
something like: something like:
<pre> <pre>
set CLASSPATH=C:\download\jode-xxx.jar;C:\swing\swingall.jar set CLASSPATH=C:\download\jode-1.1.jar;C:\swing\swingall.jar
</pre> </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-1.1.jar:/usr/local/swing/swingall.jar</pre>
or for csh: or for csh:
<pre>setenv CLASSPATH /tmp/jode-xxx.jar:/usr/local/swing/swingall.jar</pre> <pre>setenv CLASSPATH /tmp/jode-1.1.jar:/usr/local/swing/swingall.jar</pre>
</ul> </ul>
<br> <br>
There is also a batch file for windows and a script file for unix, 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 that you can use. You can extract it with the following command:
convenient location.
<pre> <pre>
jar -xvf jode-xxx.jar bin/jode.bat <i>resp.</i> bin/jode jar -xvf jode-1.1-jdk1.1.jar bin/jode.bat <i>resp.</i> bin/jode
</pre> </pre>
Edit the file to adapt it to your paths and put it to a convenient location.
<a name="cmdline"><h3>Command Line Interface</h3></a> <a name="cmdline"><h3>Command Line Interface</h3></a>
@ -81,10 +88,17 @@ following command will give a complete list of the available commands:
<pre>java jode.decompiler.Main --help</pre> <pre>java jode.decompiler.Main --help</pre>
If you want to decompile a jar package you can do it this way:
<pre>java jode.decompiler.Main --dest srcdir program.jar</pre>
If you have installed the batch file/script, you can use it like this:
<pre>jode --dest srcdir program.jar</pre>
<a name="awt"><h3>AWT Interface</h3></a> <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 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 after setting the <tt>CLASSPATH</tt> (see <a href="./usage..html#decompiler">above</a>), with
<pre>java jode.decompiler.Window</pre> <pre>java jode.decompiler.Window</pre>
@ -97,44 +111,45 @@ appear. You can save it via the <code>save</code> button.
<a name="swing"><h3>Swing Interface</h3></a> <a name="swing"><h3>Swing Interface</h3></a>
For the swing interface you need java version 1.2 or the separately For the swing interface you need java version 1.2 or the separately
available swing package (see <a href="./links.html#swing">link available swing package (see <a href="./links..html#swing">link
page</a>. You can invoke it like this: page</a>. You can invoke it with the following command:
<pre> <pre>
java jode.swingui.Main --classpath classes.jar java jode.swingui.Main classes.jar
<i>resp.</i> jode swi classes.jar
</pre> </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 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 decompiled code will appear on the right side. Via the menu, you may
change the classpath or switch between package hierarchie tree and 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 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 library code. It is not meant to generate <tt>java</tt> files and so
you won't find a save option there.<br> you won't find a save option there.</p>
<a name="java"><h3>Java Interface</h3></a> <a name="java"><h3>Java Interface</h3></a>
If you want to integrate <i>JODE</i> into your own java program, you <p>If you want to integrate <i>JODE</i> into your own java program,
can use the <a you can use the <a
href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a> href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a>
class. Note that the GPL only allows you to integrate <i>JODE</i> 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 into GPL programs. Please tell me if you use <i>JODE</i> in this
way.<br> way.</p>
You may use this <a <p>You may use this <a
href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped
down jar archive</a> containing all necessary classes. down jar archive</a> containing all necessary classes.</p>
<a name="optimizer"><h1>Using the Obfuscator</h1> <a name="optimizer"><h1>Using the Obfuscator</h1>
To use the obfuscator you should first create a script file, say <a <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 href="myproject.jos"><tt>myproject.jos</tt></a>. Then you can invoke the
obfuscator with: obfuscator with:
<pre> <pre>
java jode.obfuscator.Main myproject.jos java jode.obfuscator.Main myproject.jos
</pre> </pre></p>
<p>The script file should contain the following options: </p> <p>The script file should contain the following options: </p>
@ -265,14 +280,13 @@ change the bytecode interface.</p>
<pre> <pre>
post = new LocalOptimizer, new RemovePopAnalyzer post = new LocalOptimizer, new RemovePopAnalyzer
</pre> </pre>
</td></tr> <TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2">
</table>
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c">
<TR> <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> All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 8-May-2000, Last updated on 27-May-2001,
Copyright &copy; 1998-2000 by Jochen Hoenicke.</SPAN></FONT> Copyright &copy; 1998-2001 by Jochen Hoenicke.
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

@ -9,26 +9,28 @@
*/ ?> */ ?>
<a name="decompiler"> <a name="decompiler">
<h1>Using the Decompiler</h1></a> <h1>Using the Decompiler</h1></a>
After you have <?php selflink("download") ?>downloaded</a> the necessary <p>After you have <?php selflink("download") ?>downloaded</a> the jar archive
packages, put them into your <tt>CLASSPATH</tt>: 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 <ul><li>Under Windows you have to start a MSDOS session and type
something like: something like:
<pre> <pre>
set CLASSPATH=C:\download\jode-xxx.jar;C:\swing\swingall.jar set CLASSPATH=C:\download\jode-<?php echo "$version"?>.jar;C:\swing\swingall.jar
</pre> </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-<?php echo "$version"?>.jar:/usr/local/swing/swingall.jar</pre>
or for csh: or for csh:
<pre>setenv CLASSPATH /tmp/jode-xxx.jar:/usr/local/swing/swingall.jar</pre> <pre>setenv CLASSPATH /tmp/jode-<?php echo "$version"?>.jar:/usr/local/swing/swingall.jar</pre>
</ul> </ul>
<br> <br>
There is also a batch file for windows and a script file for unix, 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 that you can use. You can extract it with the following command:
convenient location.
<pre> <pre>
jar -xvf jode-xxx.jar bin/jode.bat <i>resp.</i> bin/jode jar -xvf jode-<?php echo "$version-jdk1.1"?>.jar bin/jode.bat <i>resp.</i> bin/jode
</pre> </pre>
Edit the file to adapt it to your paths and put it to a convenient location.
<a name="cmdline"><h3>Command Line Interface</h3></a> <a name="cmdline"><h3>Command Line Interface</h3></a>
@ -41,6 +43,13 @@ following command will give a complete list of the available commands:
<pre>java jode.decompiler.Main --help</pre> <pre>java jode.decompiler.Main --help</pre>
If you want to decompile a jar package you can do it this way:
<pre>java jode.decompiler.Main --dest srcdir program.jar</pre>
If you have installed the batch file/script, you can use it like this:
<pre>jode --dest srcdir program.jar</pre>
<a name="awt"><h3>AWT Interface</h3></a> <a name="awt"><h3>AWT Interface</h3></a>
The AWT Interface looks exactly like the <?php selflink("applet") ?> The AWT Interface looks exactly like the <?php selflink("applet") ?>
@ -60,43 +69,44 @@ appear. You can save it via the <code>save</code> button.
For the swing interface you need java version 1.2 or the separately For the swing interface you need java version 1.2 or the separately
available swing package (see <?php selflink("links#swing") ?>link available swing package (see <?php selflink("links#swing") ?>link
page</a>. You can invoke it like this: page</a>. You can invoke it with the following command:
<pre> <pre>
java jode.swingui.Main --classpath classes.jar java jode.swingui.Main classes.jar
<i>resp.</i> jode swi classes.jar
</pre> </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 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 decompiled code will appear on the right side. Via the menu, you may
change the classpath or switch between package hierarchie tree and 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 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 library code. It is not meant to generate <tt>java</tt> files and so
you won't find a save option there.<br> you won't find a save option there.</p>
<a name="java"><h3>Java Interface</h3></a> <a name="java"><h3>Java Interface</h3></a>
If you want to integrate <i>JODE</i> into your own java program, you <p>If you want to integrate <i>JODE</i> into your own java program,
can use the <a you can use the <a
href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a> href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a>
class. Note that the GPL only allows you to integrate <i>JODE</i> 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 into GPL programs. Please tell me if you use <i>JODE</i> in this
way.<br> way.</p>
You may use this <a <p>You may use this <a
href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped
down jar archive</a> containing all necessary classes. down jar archive</a> containing all necessary classes.</p>
<a name="optimizer"><h1>Using the Obfuscator</h1> <a name="optimizer"><h1>Using the Obfuscator</h1>
To use the obfuscator you should first create a script file, say <a <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 href="myproject.jos"><tt>myproject.jos</tt></a>. Then you can invoke the
obfuscator with: obfuscator with:
<pre> <pre>
java jode.obfuscator.Main myproject.jos java jode.obfuscator.Main myproject.jos
</pre> </pre></p>
<p>The script file should contain the following options: </p> <p>The script file should contain the following options: </p>

@ -1,4 +1,4 @@
/* GlobalOptions Copyright (C) 1999-2000 Jochen Hoenicke. /* GlobalOptions Copyright (C) 1999-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@ public class GlobalOptions {
public final static String version = "@VERSION@"; public final static String version = "@VERSION@";
public final static String email = "jochen@gnu.org"; public final static String email = "jochen@gnu.org";
public final static String copyright = public final static String copyright =
"Jode (c) 1998-2000 Jochen Hoenicke <"+email+">"; "Jode (c) 1998-2001 Jochen Hoenicke <"+email+">";
public final static String URL = "http://jode.sourceforge.net/"; public final static String URL = "http://jode.sourceforge.net/";
public static PrintWriter err = new PrintWriter(System.err, true); public static PrintWriter err = new PrintWriter(System.err, true);

@ -25,6 +25,8 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.util.BitSet;
import java.util.Stack;
import java.util.Vector; import java.util.Vector;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -845,6 +847,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
int index = input.readUnsignedShort(); int index = input.readUnsignedShort();
exceptionHandlers[i].type = (index == 0) ? null exceptionHandlers[i].type = (index == 0) ? null
: cp.getClassName(index); : cp.getClassName(index);
if (exceptionHandlers[i].catcher.getOpcode() == opc_athrow) {
/* There is an obfuscator, which inserts bogus
* exception entries jumping directly to a throw
* instruction. Remove those handlers.
*/
handlersLength--;
i--;
}
}
if (handlersLength < exceptionHandlers.length) {
Handler[] newHandlers = new Handler[handlersLength];
System.arraycopy(exceptionHandlers, 0, newHandlers, 0,
handlersLength);
exceptionHandlers = newHandlers;
} }
} }
readAttributes(cp, input, FULLINFO); readAttributes(cp, input, FULLINFO);
@ -901,9 +918,73 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} }
} }
private void calculateMaxStack() {
maxStack = 0;
int[] stackHeights = new int[instructions.getCodeLength()];
int[] poppush = new int[2];
Stack todo = new Stack();
for (int i=0; i < stackHeights.length; i++)
stackHeights[i] = -1;
stackHeights[0] = 0;
todo.push(instructions.get(0));
while (!todo.isEmpty()) {
Instruction instr = (Instruction) todo.pop();
Instruction next = instr.getNextByAddr();
Instruction[] succs = instr.getSuccs();
int addr = instr.getAddr();
instr.getStackPopPush(poppush);
int sh = stackHeights[addr] - poppush[0] + poppush[1];
// System.err.println("Instr: "+instr.getDescription()+
// "; before: "+stackHeights[addr]+" after: "+sh);
if (maxStack < sh)
maxStack = sh;
if (instr.getOpcode() == opc_jsr) {
if (stackHeights[next.getAddr()] == -1) {
stackHeights[next.getAddr()] = sh - 1;
todo.push(next);
}
if (stackHeights[succs[0].getAddr()] == -1) {
stackHeights[succs[0].getAddr()] = sh;
todo.push(succs[0]);
}
} else {
if (succs != null) {
for (int i=0; i < succs.length; i++) {
if (stackHeights[succs[i].getAddr()] == -1) {
stackHeights[succs[i].getAddr()] = sh;
todo.push(succs[i]);
}
}
}
if (!instr.doesAlwaysJump()
&& stackHeights[next.getAddr()] == -1) {
stackHeights[next.getAddr()] = sh;
todo.push(next);
}
}
for (int i=0; i< exceptionHandlers.length; i++) {
if (exceptionHandlers[i].start.compareTo(instr) <= 0
&& exceptionHandlers[i].end.compareTo(instr) >= 0) {
int catcher = exceptionHandlers[i].catcher.getAddr();
if (stackHeights[catcher] == -1) {
stackHeights[catcher] = 1;
todo.push(exceptionHandlers[i].catcher);
}
}
}
}
// System.err.println("New maxStack: "+maxStack+" Locals: "+maxLocals);
}
public void prepareWriting(GrowableConstantPool gcp) { public void prepareWriting(GrowableConstantPool gcp) {
/* Recalculate addr, length and add all constants to gcp */ /* Recalculate addr, length, maxStack, maxLocals and add all
* constants to gcp */
int addr = 0; int addr = 0;
maxLocals = (methodInfo.isStatic() ? 0 : 1) +
TypeSignature.getArgumentSize(methodInfo.getType());
for (Iterator iter = instructions.iterator(); iter.hasNext(); ) { for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next(); Instruction instr = (Instruction) iter.next();
int opcode = instr.getOpcode(); int opcode = instr.getOpcode();
@ -957,22 +1038,44 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
length = 3; length = 3;
else else
length = 6; length = 6;
if (slot >= maxLocals)
maxLocals = slot + 1;
break; break;
} }
case opc_iload: case opc_lload: case opc_iload: case opc_fload: case opc_aload:
case opc_fload: case opc_dload: case opc_aload: case opc_istore: case opc_fstore: case opc_astore: {
case opc_istore: case opc_lstore: int slot = instr.getLocalSlot();
case opc_fstore: case opc_dstore: case opc_astore: if (slot < 4)
if (instr.getLocalSlot() < 4) {
length = 1; length = 1;
break; else if (slot < 256)
} length = 2;
/* fall through */ else
length = 4;
if (slot >= maxLocals)
maxLocals = slot + 1;
break;
}
case opc_lload: case opc_dload:
case opc_lstore: case opc_dstore: {
int slot = instr.getLocalSlot();
if (slot < 4)
length = 1;
else if (slot < 256)
length = 2;
else
length = 4;
if (slot+1 >= maxLocals)
maxLocals = slot + 2;
break;
}
case opc_ret: { case opc_ret: {
if (instr.getLocalSlot() < 256) int slot = instr.getLocalSlot();
if (slot < 256)
length = 2; length = 2;
else else
length = 4; length = 4;
if (slot >= maxLocals)
maxLocals = slot + 1;
break; break;
} }
case opc_lookupswitch: { case opc_lookupswitch: {
@ -1092,6 +1195,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
addr += length; addr += length;
} }
instructions.setLastAddr(addr); instructions.setLastAddr(addr);
calculateMaxStack();
for (int i=0; i< exceptionHandlers.length; i++) for (int i=0; i< exceptionHandlers.length; i++)
if (exceptionHandlers[i].type != null) if (exceptionHandlers[i].type != null)
gcp.putClassName(exceptionHandlers[i].type); gcp.putClassName(exceptionHandlers[i].type);
@ -1483,14 +1587,6 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
return lnt; return lnt;
} }
public void setMaxStack(int ms) {
maxStack = ms;
}
public void setMaxLocals(int ml) {
maxLocals = ml;
}
public void setExceptionHandlers(Handler[] handlers) { public void setExceptionHandlers(Handler[] handlers) {
exceptionHandlers = handlers; exceptionHandlers = handlers;
} }

@ -192,6 +192,19 @@ public class ClassInfo extends BinaryInfo {
int access = input.readUnsignedShort(); int access = input.readUnsignedShort();
if (innername != null && innername.length() == 0) if (innername != null && innername.length() == 0)
innername = null; innername = null;
/* Some compilers give method scope classes a valid
* outer field, but we mustn't handle them as inner
* classes. The best way to distinguish this case
* is by the class name.
*/
if (outer != null && innername != null
&& inner.length() > outer.length() + 2 + innername.length()
&& inner.startsWith(outer+"$")
&& inner.endsWith("$"+innername)
&& Character.isDigit(inner.charAt(outer.length() + 1)))
outer = null;
InnerClassInfo ici = new InnerClassInfo InnerClassInfo ici = new InnerClassInfo
(inner, outer, innername, access); (inner, outer, innername, access);
@ -272,10 +285,11 @@ public class ClassInfo extends BinaryInfo {
/* header */ /* header */
if (input.readInt() != 0xcafebabe) if (input.readInt() != 0xcafebabe)
throw new ClassFormatException("Wrong magic"); throw new ClassFormatException("Wrong magic");
if (input.readUnsignedShort() > 3) int version = input.readUnsignedShort();
throw new ClassFormatException("Wrong minor"); version |= input.readUnsignedShort() << 16;
if (input.readUnsignedShort() != 45) if (version < (45 << 16 | 0)
throw new ClassFormatException("Wrong major"); || version > (47 << 16 | 0))
throw new ClassFormatException("Wrong class version");
/* constant pool */ /* constant pool */
ConstantPool cpool = new ConstantPool(); ConstantPool cpool = new ConstantPool();
@ -603,9 +617,6 @@ public class ClassInfo extends BinaryInfo {
String message = ex.getMessage(); String message = ex.getMessage();
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY if ((howMuch & ~(FIELDS|METHODS|HIERARCHY
|INNERCLASSES|OUTERCLASSES)) != 0) { |INNERCLASSES|OUTERCLASSES)) != 0) {
GlobalOptions.err.println
("Can't read class " + name + ".");
ex.printStackTrace(GlobalOptions.err);
throw new NoClassDefFoundError(name); throw new NoClassDefFoundError(name);
} }
// Try getting the info through the reflection interface // Try getting the info through the reflection interface

@ -54,8 +54,7 @@ public class MethodInfo extends BinaryInfo {
if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("Code")) { if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("Code")) {
bytecode = new BytecodeInfo(this); bytecode = new BytecodeInfo(this);
bytecode.read(cp, input); bytecode.read(cp, input);
} else if ((howMuch & KNOWNATTRIBS) != 0 } else if (name.equals("Exceptions")) {
&& name.equals("Exceptions")) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
exceptions = new String[count]; exceptions = new String[count];
for (int i=0; i< count; i++) for (int i=0; i< count; i++)

@ -279,7 +279,7 @@ public class SearchPath {
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println GlobalOptions.err.println
("Warning: Security exception while accessing " ("Warning: Security exception while accessing "
+bases[i]+"."); + bases[i] + ".");
} }
} catch (MalformedURLException ex) { } catch (MalformedURLException ex) {
/* disable entry */ /* disable entry */
@ -309,6 +309,10 @@ public class SearchPath {
} }
public boolean exists(String filename) { public boolean exists(String filename) {
String localFileName =
(java.io.File.separatorChar != '/')
? filename.replace('/', java.io.File.separatorChar)
: filename;
for (int i=0; i<dirs.length; i++) { for (int i=0; i<dirs.length; i++) {
if (zipEntries[i] != null) { if (zipEntries[i] != null) {
if (zipEntries[i].get(filename) != null) if (zipEntries[i].get(filename) != null)
@ -347,11 +351,8 @@ public class SearchPath {
if (ze != null) if (ze != null)
return true; return true;
} else { } else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try { try {
File f = new File(dirs[i], filename); File f = new File(dirs[i], localFileName);
if (f.exists()) if (f.exists())
return true; return true;
} catch (SecurityException ex) { } catch (SecurityException ex) {
@ -369,6 +370,10 @@ public class SearchPath {
* @return An InputStream for the file. * @return An InputStream for the file.
*/ */
public InputStream getFile(String filename) throws IOException { public InputStream getFile(String filename) throws IOException {
String localFileName =
(java.io.File.separatorChar != '/')
? filename.replace('/', java.io.File.separatorChar)
: filename;
for (int i=0; i<dirs.length; i++) { for (int i=0; i<dirs.length; i++) {
if (urlzips[i] != null) { if (urlzips[i] != null) {
ZipInputStream zis = new ZipInputStream ZipInputStream zis = new ZipInputStream
@ -379,26 +384,26 @@ public class SearchPath {
while ((ze = zis.getNextEntry()) != null) { while ((ze = zis.getNextEntry()) != null) {
if (ze.getName().equals(fullname)) { if (ze.getName().equals(fullname)) {
///#ifdef JDK11 ///#ifdef JDK11
// The skip method in jdk1.1.7 ZipInputStream /// // The skip method in jdk1.1.7 ZipInputStream
// is buggy. We return a wrapper that fixes /// // is buggy. We return a wrapper that fixes
// this. /// // this.
return new FilterInputStream(zis) { /// return new FilterInputStream(zis) {
private byte[] tmpbuf = new byte[512]; /// private byte[] tmpbuf = new byte[512];
public long skip(long n) throws IOException { /// public long skip(long n) throws IOException {
long skipped = 0; /// long skipped = 0;
while (n > 0) { /// while (n > 0) {
int count = read(tmpbuf, 0, /// int count = read(tmpbuf, 0,
(int)Math.min(n, 512L)); /// (int)Math.min(n, 512L));
if (count == -1) /// if (count == -1)
return skipped; /// return skipped;
skipped += count; /// skipped += count;
n -= count; /// n -= count;
} /// }
return skipped; /// return skipped;
} /// }
}; /// };
///#else ///#else
/// return zis; return zis;
///#endif ///#endif
} }
zis.closeEntry(); zis.closeEntry();
@ -413,8 +418,8 @@ public class SearchPath {
return conn.getInputStream(); return conn.getInputStream();
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException" GlobalOptions.err.println("Warning: SecurityException"
+" while accessing " + " while accessing "
+bases[i]+filename); + bases[i] + filename);
ex.printStackTrace(GlobalOptions.err); ex.printStackTrace(GlobalOptions.err);
/* ignore and take next element */ /* ignore and take next element */
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
@ -431,17 +436,14 @@ public class SearchPath {
if (ze != null) if (ze != null)
return zips[i].getInputStream(ze); return zips[i].getInputStream(ze);
} else { } else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try { try {
File f = new File(dirs[i], filename); File f = new File(dirs[i], localFileName);
if (f.exists()) if (f.exists())
return new FileInputStream(f); return new FileInputStream(f);
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException" GlobalOptions.err.println("Warning: SecurityException"
+" while accessing " + " while accessing "
+dirs[i]+filename); + dirs[i] + localFileName);
/* ignore and take next element */ /* ignore and take next element */
} }
} }
@ -457,6 +459,10 @@ public class SearchPath {
* @return true, if filename exists and is a directory, false otherwise. * @return true, if filename exists and is a directory, false otherwise.
*/ */
public boolean isDirectory(String filename) { public boolean isDirectory(String filename) {
String localFileName =
(java.io.File.separatorChar != '/')
? filename.replace('/', java.io.File.separatorChar)
: filename;
for (int i=0; i<dirs.length; i++) { for (int i=0; i<dirs.length; i++) {
if (dirs[i] == null) if (dirs[i] == null)
continue; continue;
@ -467,17 +473,14 @@ public class SearchPath {
if (zipEntries[i].containsKey(filename)) if (zipEntries[i].containsKey(filename))
return true; return true;
} else { } else {
if (java.io.File.separatorChar != '/')
filename = filename
.replace('/', java.io.File.separatorChar);
try { try {
File f = new File(dirs[i], filename); File f = new File(dirs[i], localFileName);
if (f.exists()) if (f.exists())
return f.isDirectory(); return f.isDirectory();
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException" GlobalOptions.err.println("Warning: SecurityException"
+" while accessing " + " while accessing "
+dirs[i]+filename); + dirs[i] + localFileName);
} }
} }
} }
@ -543,11 +546,13 @@ public class SearchPath {
if (f.exists() && f.isDirectory()) { if (f.exists() && f.isDirectory()) {
currentDir = f; currentDir = f;
files = f.list(); files = f.list();
fileNr = 0;
} }
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println("Warning: SecurityException" GlobalOptions.err.println
+" while accessing " ("Warning: SecurityException"
+dirs[pathNr]+localDirName); + " while accessing "
+ dirs[pathNr] + localDirName);
/* ignore and take next element */ /* ignore and take next element */
} }
} }

@ -57,6 +57,12 @@ public class ClassAnalyzer
* The minimal visible complexity. * The minimal visible complexity.
*/ */
private static double STEP_COMPLEXITY = 0.03; private static double STEP_COMPLEXITY = 0.03;
/**
* The value of the strictfp modifier.
* JDK1.1 doesn't define it.
*/
private static int STRICTFP = 0x800;
double methodComplexity = 0.0; double methodComplexity = 0.0;
double innerComplexity = 0.0; double innerComplexity = 0.0;
@ -126,6 +132,10 @@ public class ClassAnalyzer
return Modifier.isStatic(modifiers); return Modifier.isStatic(modifiers);
} }
public final boolean isStrictFP() {
return (modifiers & STRICTFP) != 0;
}
public FieldAnalyzer getField(int index) { public FieldAnalyzer getField(int index) {
return fields[index]; return fields[index];
} }
@ -231,6 +241,17 @@ public class ClassAnalyzer
staticConstructor = methods[j]; staticConstructor = methods[j];
else else
constrVector.addElement(methods[j]); constrVector.addElement(methods[j]);
/* Java bytecode can't have strictfp modifier for
* classes, while java can't have strictfp modifier
* for constructors. We handle the difference here.
*
* If only a few constructors are strictfp and the
* methods aren't this would add too much strictfp,
* but that isn't really dangerous.
*/
if (methods[j].isStrictFP())
modifiers |= STRICTFP;
} }
methodComplexity += methods[j].getComplexity(); methodComplexity += methods[j].getComplexity();
} }
@ -400,9 +421,78 @@ public class ClassAnalyzer
public void dumpDeclaration(TabbedPrintWriter writer) throws IOException public void dumpDeclaration(TabbedPrintWriter writer) throws IOException
{ {
dumpSource(writer); dumpDeclaration(writer, null, 0.0, 0.0);
} }
public void dumpDeclaration(TabbedPrintWriter writer,
ProgressListener pl, double done, double scale)
throws IOException
{
if (fields == null) {
/* This means that the class could not be loaded.
* give up.
*/
return;
}
writer.startOp(writer.NO_PAREN, 0);
/* Clear the SUPER bit, which is also used as SYNCHRONIZED bit. */
int modifiedModifiers = modifiers & ~(Modifier.SYNCHRONIZED
| STRICTFP);
if (clazz.isInterface())
/* interfaces are implicitily abstract */
modifiedModifiers &= ~Modifier.ABSTRACT;
if (parent instanceof MethodAnalyzer) {
/* method scope classes are implicitly private */
modifiedModifiers &= ~Modifier.PRIVATE;
/* anonymous classes are implicitly final */
if (name == null)
modifiedModifiers &= ~Modifier.FINAL;
}
String modif = Modifier.toString(modifiedModifiers);
if (modif.length() > 0)
writer.print(modif + " ");
if (isStrictFP()) {
/* The STRICTFP modifier is set.
* We handle it, since java.lang.reflect.Modifier is too dumb.
*/
writer.print("strictfp ");
}
/* interface is in modif */
if (!clazz.isInterface())
writer.print("class ");
writer.print(name);
ClassInfo superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz != ClassInfo.javaLangObject) {
writer.breakOp();
writer.print(" extends " + (writer.getClassString
(superClazz, Scope.CLASSNAME)));
}
ClassInfo[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.breakOp();
writer.print(clazz.isInterface() ? " extends " : " implements ");
writer.startOp(writer.EXPL_PAREN, 1);
for (int i=0; i < interfaces.length; i++) {
if (i > 0) {
writer.print(", ");
writer.breakOp();
}
writer.print(writer.getClassString
(interfaces[i], Scope.CLASSNAME));
}
writer.endOp();
}
writer.println();
writer.openBraceClass();
writer.tab();
dumpBlock(writer, pl, done, scale);
writer.untab();
writer.closeBraceClass();
}
public void dumpBlock(TabbedPrintWriter writer) public void dumpBlock(TabbedPrintWriter writer)
throws IOException throws IOException
{ {
@ -501,6 +591,7 @@ public class ClassAnalyzer
needNewLine = true; needNewLine = true;
} }
writer.popScope(); writer.popScope();
clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS);
} }
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
@ -513,67 +604,8 @@ public class ClassAnalyzer
ProgressListener pl, double done, double scale) ProgressListener pl, double done, double scale)
throws IOException throws IOException
{ {
if (fields == null) { dumpDeclaration(writer, pl, done, scale);
/* This means that the class could not be loaded.
* give up.
*/
return;
}
writer.startOp(writer.NO_PAREN, 0);
/* Clear the SUPER bit, which is also used as SYNCHRONIZED bit. */
int modifiedModifiers = modifiers & ~Modifier.SYNCHRONIZED;
if (clazz.isInterface())
/* interfaces are implicitily abstract */
modifiedModifiers &= ~Modifier.ABSTRACT;
if (parent instanceof MethodAnalyzer) {
/* method scope classes are implicitly private */
modifiedModifiers &= ~Modifier.PRIVATE;
/* anonymous classes are implicitly final */
if (name == null)
modifiedModifiers &= ~Modifier.FINAL;
}
String modif = Modifier.toString(modifiedModifiers);
if (modif.length() > 0)
writer.print(modif + " ");
/* interface is in modif */
if (!clazz.isInterface())
writer.print("class ");
writer.print(name);
ClassInfo superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz != ClassInfo.javaLangObject) {
writer.breakOp();
writer.print(" extends " + (writer.getClassString
(superClazz, Scope.CLASSNAME)));
}
ClassInfo[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.breakOp();
writer.print(clazz.isInterface() ? " extends " : " implements ");
writer.startOp(writer.EXPL_PAREN, 1);
for (int i=0; i < interfaces.length; i++) {
if (i > 0) {
writer.print(", ");
writer.breakOp();
}
writer.print(writer.getClassString
(interfaces[i], Scope.CLASSNAME));
}
writer.endOp();
}
writer.println(); writer.println();
writer.openBrace();
writer.tab();
dumpBlock(writer, pl, done, scale);
writer.untab();
if (parent instanceof MethodAnalyzer) {
/* This is a method scope class */
writer.closeBraceNoSpace();
} else
writer.closeBrace();
clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS);
} }
public void dumpJavaFile(TabbedPrintWriter writer) public void dumpJavaFile(TabbedPrintWriter writer)
@ -611,7 +643,11 @@ public class ClassAnalyzer
} }
public boolean conflicts(String name, int usageType) { public boolean conflicts(String name, int usageType) {
ClassInfo info = clazz; return conflicts(clazz, name, usageType);
}
private static boolean conflicts(ClassInfo info,
String name, int usageType) {
while (info != null) { while (info != null) {
if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) { if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) {
MethodInfo[] minfos = info.getMethods(); MethodInfo[] minfos = info.getMethods();
@ -639,6 +675,11 @@ public class ClassAnalyzer
if (usageType == NOSUPERFIELDNAME if (usageType == NOSUPERFIELDNAME
|| usageType == NOSUPERMETHODNAME) || usageType == NOSUPERMETHODNAME)
return false; return false;
ClassInfo[] ifaces = info.getInterfaces();
for (int i = 0; i < ifaces.length; i++)
if (conflicts(ifaces[i], name, usageType))
return true;
info = info.getSuperclass(); info = info.getSuperclass();
} }
return false; return false;

@ -103,6 +103,8 @@ public class Decompiler {
Options.outputStyle = Options.GNU_STYLE; Options.outputStyle = Options.GNU_STYLE;
else if (value.equals("sun")) else if (value.equals("sun"))
Options.outputStyle = Options.SUN_STYLE; Options.outputStyle = Options.SUN_STYLE;
else if (value.equals("pascal"))
Options.outputStyle = Options.PASCAL_STYLE;
else else
throw new IllegalArgumentException("Invalid style "+value); throw new IllegalArgumentException("Invalid style "+value);
return; return;

@ -57,7 +57,7 @@ public class FieldAnalyzer implements Analyzer {
if (fd.getConstant() != null) { if (fd.getConstant() != null) {
constant = new ConstOperator(fd.getConstant()); constant = new ConstOperator(fd.getConstant());
constant.setType(type); constant.setType(type);
constant.makeInitializer(); constant.makeInitializer(type);
} }
} }
@ -107,7 +107,7 @@ public class FieldAnalyzer implements Analyzer {
} }
analyzedSynthetic(); analyzedSynthetic();
} else } else
expr.makeInitializer(); expr.makeInitializer(type);
constant = expr; constant = expr;
return true; return true;

@ -126,56 +126,58 @@ public class LocalInfo implements Declarable {
* If this is called with ourself nothing will happen. * If this is called with ourself nothing will happen.
* @param li the local info that we want to shadow. * @param li the local info that we want to shadow.
*/ */
public void combineWith(LocalInfo li) { public void combineWith(LocalInfo shadow) {
li = li.getLocalInfo(); if (this.shadow != null) {
if (shadow != null) { getLocalInfo().combineWith(shadow);
getLocalInfo().combineWith(li); return;
} else { }
if (this != li) {
shadow = li;
if (!nameIsGenerated)
shadow.name = name;
if (constExpr != null) {
if (shadow.constExpr != null)
throw new jode.AssertError
("local has multiple constExpr");
shadow.constExpr = constExpr;
}
// GlobalOptions.err.println("combining "+name+"("+type+") and "
// +shadow.name+"("+shadow.type+")");
shadow.setType(type);
boolean needTypeUpdate = !li.type.equals(type);
java.util.Enumeration enum = operators.elements();
while (enum.hasMoreElements()) {
LocalVarOperator lvo =
(LocalVarOperator) enum.nextElement();
if (needTypeUpdate) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("updating " + lvo);
lvo.updateType();
}
shadow.operators.addElement(lvo);
}
enum = hints.elements();
while (enum.hasMoreElements()) {
Object hint = enum.nextElement();
if (!shadow.hints.contains(hint))
shadow.hints.addElement(hint);
}
/* Clear unused fields, to allow garbage collection. shadow = shadow.getLocalInfo();
*/ if (this == shadow)
type = null; return;
name = null;
operators = null; this.shadow = shadow;
} if (!nameIsGenerated)
} shadow.name = name;
if (constExpr != null) {
if (shadow.constExpr != null)
throw new jode.AssertError
("local has multiple constExpr");
shadow.constExpr = constExpr;
}
// GlobalOptions.err.println("combining "+name+"("+type+") and "
// +shadow.name+"("+shadow.type+")");
shadow.setType(type);
boolean needTypeUpdate = !shadow.type.equals(type);
java.util.Enumeration enum = operators.elements();
while (enum.hasMoreElements()) {
LocalVarOperator lvo =
(LocalVarOperator) enum.nextElement();
if (needTypeUpdate) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("updating " + lvo);
lvo.updateType();
}
shadow.operators.addElement(lvo);
}
enum = hints.elements();
while (enum.hasMoreElements()) {
Object hint = enum.nextElement();
if (!shadow.hints.contains(hint))
shadow.hints.addElement(hint);
}
/* Clear unused fields, to allow garbage collection.
*/
type = null;
name = null;
operators = null;
} }
/** /**
@ -359,15 +361,13 @@ public class LocalInfo implements Declarable {
} }
public boolean isConstant() { public boolean isConstant() {
LocalInfo li = getLocalInfo(); /* Checking if a local can be declared final is tricky,
Enumeration enum = li.operators.elements(); * since it can also be the case if it is written in
int writes = 0; * the "then" and "else" part of an if statement.
while (enum.hasMoreElements()) { *
if (((LocalVarOperator) enum.nextElement()).isWrite()) * We return true now, otherwise some code would not be
writes++; * decompilable.
} */
if (writes > 1)
return false;
return true; return true;
} }
@ -383,8 +383,7 @@ public class LocalInfo implements Declarable {
if (((LocalVarOperator) enum.nextElement()).isWrite()) if (((LocalVarOperator) enum.nextElement()).isWrite())
writes++; writes++;
} }
if (writes > 1) /* FIXME: Check if declaring final is okay */
return false;
li.isFinal = true; li.isFinal = true;
return true; return true;
} }

@ -1,4 +1,4 @@
/* Main Copyright (C) 1998-1999 Jochen Hoenicke. /* Main Copyright (C) 1998-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -19,7 +19,6 @@
package jode.decompiler; package jode.decompiler;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.GlobalOptions; import jode.GlobalOptions;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -28,7 +27,9 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.Enumeration;
import gnu.getopt.LongOpt; import gnu.getopt.LongOpt;
import gnu.getopt.Getopt; import gnu.getopt.Getopt;
@ -73,7 +74,10 @@ public class Main extends Options {
public static void usage() { public static void usage() {
PrintWriter err = GlobalOptions.err; PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version); err.println("Version: " + GlobalOptions.version);
err.println("Usage: java jode.decompiler.Main [OPTIONS]... [CLASSES]..."); err.println("Usage: java jode.decompiler.Main [OPTION]* {CLASS|JAR}*");
err.println("Give a fully qualified CLASS name, e.g. jode.decompiler.Main, if you want to");
err.println("decompile a single class, or a JAR file containing many classes.");
err.println("OPTION is any of these:");
err.println(" -h, --help "+ err.println(" -h, --help "+
"show this information."); "show this information.");
err.println(" -V, --version "+ err.println(" -V, --version "+
@ -94,9 +98,13 @@ public class Main extends Options {
err.println(" "+ err.println(" "+
"and packages with more then pkglimit used classes."); "and packages with more then pkglimit used classes.");
err.println(" "+ err.println(" "+
"Limit 0 means, never import, default is 0,1."); "Limit 0 means never import. Default is 0,1.");
err.println(" -D, --debug=... "+
"use --debug=help for more information.");
err.println("The following options can be turned on or off with `yes' or `no' argument."); err.println("NOTE: The following options can be turned on or off with `yes' or `no'.");
err.println("The options tagged with (default) are normally on. Omitting the yes/no");
err.println("argument will toggle the option, e.g. --verify is equivalent to --verify=no.");
err.println(" --inner "+ err.println(" --inner "+
"decompile inner classes (default)."); "decompile inner classes (default).");
err.println(" --anonymous "+ err.println(" --anonymous "+
@ -106,7 +114,7 @@ public class Main extends Options {
err.println(" --lvt "+ err.println(" --lvt "+
"use the local variable table (default)."); "use the local variable table (default).");
err.println(" --pretty "+ err.println(" --pretty "+
"use `pretty' names for local variables."); "use `pretty' names for local variables (default).");
err.println(" --push "+ err.println(" --push "+
"allow PUSH instructions in output."); "allow PUSH instructions in output.");
err.println(" --decrypt "+ err.println(" --decrypt "+
@ -116,10 +124,7 @@ public class Main extends Options {
err.println(" --immediate "+ err.println(" --immediate "+
"output source immediately (may produce buggy code)."); "output source immediately (may produce buggy code).");
err.println(" --verify "+ err.println(" --verify "+
"verify code before decompiling it."); "verify code before decompiling it (default).");
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) { public static boolean handleOption(int option, int longind, String arg) {
@ -131,21 +136,98 @@ public class Main extends Options {
options &= ~(1 << option); options &= ~(1 << option);
else { else {
GlobalOptions.err.println GlobalOptions.err.println
("jode.decompiler.Main: option --"+longOptions[longind].getName() ("jode.decompiler.Main: option --"
+" takes one of `yes', `no', `on', `off' as parameter"); + longOptions[longind].getName()
+ " takes one of `yes', `no', `on', `off' as parameter");
return false; return false;
} }
return true; return true;
} }
public static void decompileClass(String className,
ZipOutputStream destZip, String destDir,
TabbedPrintWriter writer,
ImportHandler imports) {
try {
ClassInfo clazz;
try {
clazz = ClassInfo.forName(className);
} catch (IllegalArgumentException ex) {
GlobalOptions.err.println
("`"+className+"' is not a class name");
return;
}
if (skipClass(clazz))
return;
String filename =
className.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(className);
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 "+className+".");
GlobalOptions.err.println("Check the permissions.");
ex.printStackTrace(GlobalOptions.err);
}
}
public static void main(String[] params) { public static void main(String[] params) {
try {
decompile(params);
} catch (ExceptionInInitializerError ex) {
ex.getException().printStackTrace();
} catch (Throwable ex) {
ex.printStackTrace();
}
/* When AWT applications are compiled with insufficient
* classpath the type guessing by reflection code can
* generate an awt thread that will prevent normal
* exiting.
*/
System.exit(0);
}
public static void decompile(String[] params) {
if (params.length == 0) { if (params.length == 0) {
usage(); usage();
return; return;
} }
String classPath = System.getProperty("java.class.path") String classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.altPathSeparatorChar); .replace(File.pathSeparatorChar, Decompiler.altPathSeparatorChar);
String bootClassPath = System.getProperty("sun.boot.class.path");
if (bootClassPath != null)
classPath += Decompiler.altPathSeparatorChar
+ bootClassPath.replace(File.pathSeparatorChar,
Decompiler.altPathSeparatorChar);
String destDir = null; String destDir = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT; int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
@ -202,6 +284,8 @@ public class Main extends Options {
outputStyle = SUN_STYLE; outputStyle = SUN_STYLE;
else if ("gnu".startsWith(arg)) else if ("gnu".startsWith(arg))
outputStyle = GNU_STYLE; outputStyle = GNU_STYLE;
else if ("pascal".startsWith(arg))
outputStyle = Options.PASCAL_STYLE;
else { else {
GlobalOptions.err.println GlobalOptions.err.println
("jode.decompiler.Main: Unknown style `"+arg+"'."); ("jode.decompiler.Main: Unknown style `"+arg+"'.");
@ -246,7 +330,7 @@ public class Main extends Options {
} }
if (errorInParams) if (errorInParams)
return; return;
ClassInfo.setClassPath(classPath.toString()); ClassInfo.setClassPath(classPath);
ImportHandler imports = new ImportHandler(importPackageLimit, ImportHandler imports = new ImportHandler(importPackageLimit,
importClassLimit); importClassLimit);
@ -268,51 +352,32 @@ public class Main extends Options {
} }
for (int i= g.getOptind(); i< params.length; i++) { for (int i= g.getOptind(); i< params.length; i++) {
try { try {
ClassInfo clazz; if ((params[i].endsWith(".jar") || params[i].endsWith(".zip"))
try { && new File(params[i]).isFile()) {
clazz = ClassInfo.forName(params[i]); /* The user obviously wants to decompile a jar/zip file.
} catch (IllegalArgumentException ex) { * Lets do him a pleasure and allow this.
GlobalOptions.err.println */
("`"+params[i]+"' is not a class name"); ClassInfo.setClassPath(params[i]
continue; + Decompiler.altPathSeparatorChar
} + classPath);
if (skipClass(clazz)) Enumeration enum = new ZipFile(params[i]).entries();
continue; while (enum.hasMoreElements()) {
String entry
String filename = = ((ZipEntry) enum.nextElement()).getName();
params[i].replace('.', File.separatorChar)+".java"; if (entry.endsWith(".class")) {
if (destZip != null) { entry = entry.substring(0, entry.length() - 6)
writer.flush(); .replace('/', '.');
destZip.putNextEntry(new ZipEntry(filename)); decompileClass(entry, destZip, destDir,
} else if (destDir != null) { writer, imports);
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 ClassInfo.setClassPath(classPath);
(new BufferedOutputStream(new FileOutputStream(file)), } else
imports, false); decompileClass(params[i], destZip, destDir,
} writer, imports);
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) { } catch (IOException ex) {
GlobalOptions.err.println GlobalOptions.err.println
("Can't write source of "+params[i]+"."); ("Can't read zip file " + params[i] + ".");
GlobalOptions.err.println("Check the permissions.");
ex.printStackTrace(GlobalOptions.err); ex.printStackTrace(GlobalOptions.err);
} }
} }

@ -27,6 +27,7 @@ import jode.bytecode.Handler;
import jode.bytecode.Instruction; import jode.bytecode.Instruction;
import jode.bytecode.LocalVariableInfo; import jode.bytecode.LocalVariableInfo;
import jode.jvm.SyntheticAnalyzer; import jode.jvm.SyntheticAnalyzer;
import jode.decompiler.Options;
import jode.type.*; import jode.type.*;
import jode.expr.Expression; import jode.expr.Expression;
import jode.expr.ConstOperator; import jode.expr.ConstOperator;
@ -80,6 +81,11 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
* The minimal visible complexity. * The minimal visible complexity.
*/ */
private static double STEP_COMPLEXITY = 0.01; private static double STEP_COMPLEXITY = 0.01;
/**
* The value of the strictfp modifier.
* JDK1.1 doesn't define it.
*/
private static int STRICTFP = 0x800;
/** /**
* The import handler where we should register our types. * The import handler where we should register our types.
*/ */
@ -316,6 +322,14 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
return minfo.isSynthetic(); return minfo.isSynthetic();
} }
/**
* Checks if this method is strictfp
* @return true, iff this method is synthetic.
*/
public final boolean isStrictFP() {
return (minfo.getModifiers() & STRICTFP) != 0;
}
/** /**
* Tells if this method is the constructor$xx method generated by jikes. * Tells if this method is the constructor$xx method generated by jikes.
* @param value true, iff this method is the jikes constructor. * @param value true, iff this method is the jikes constructor.
@ -593,7 +607,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
CodeVerifier verifier CodeVerifier verifier
= new CodeVerifier(getClazz(), minfo, code); = new CodeVerifier(getClazz(), minfo, code);
try { try {
verifier.verify(); verifier.verify();
} catch (VerifyException ex) { } catch (VerifyException ex) {
ex.printStackTrace(GlobalOptions.err); ex.printStackTrace(GlobalOptions.err);
throw new jode.AssertError("Verification error"); throw new jode.AssertError("Verification error");
@ -719,7 +733,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
if (synth.getKind() == synth.GETCLASS) if (synth.getKind() == synth.GETCLASS)
return true; return true;
if (synth.getKind() >= synth.ACCESSGETFIELD if (synth.getKind() >= synth.ACCESSGETFIELD
&& synth.getKind() <= synth.ACCESSCONSTRUCTOR && synth.getKind() <= synth.ACCESSDUPPUTSTATIC
&& (Options.options & Options.OPTION_INNER) != 0 && (Options.options & Options.OPTION_INNER) != 0
&& (Options.options & Options.OPTION_ANON) != 0) && (Options.options & Options.OPTION_ANON) != 0)
return true; return true;
@ -746,10 +760,12 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
if (isJikesBlockInitializer) if (isJikesBlockInitializer)
return true; return true;
/* The default constructor must be empty of course */ /* The default constructor must be empty
* and mustn't throw exceptions */
if (getMethodHeader() == null if (getMethodHeader() == null
|| !(getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock) || !(getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock)
|| !getMethodHeader().hasNoJumps()) || !getMethodHeader().hasNoJumps()
|| exceptions.length > 0)
return false; return false;
if (declareAsConstructor if (declareAsConstructor
@ -839,6 +855,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
if (isConstructor() && isStatic()) if (isConstructor() && isStatic())
modifiedModifiers &= ~(Modifier.FINAL | Modifier.PUBLIC modifiedModifiers &= ~(Modifier.FINAL | Modifier.PUBLIC
| Modifier.PROTECTED | Modifier.PRIVATE); | Modifier.PROTECTED | Modifier.PRIVATE);
modifiedModifiers &= ~STRICTFP;
writer.startOp(writer.NO_PAREN, 1); writer.startOp(writer.NO_PAREN, 1);
String delim = ""; String delim = "";
@ -847,11 +864,28 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
delim = " "; delim = " ";
} }
String modif = Modifier.toString(modifiedModifiers); String modif = Modifier.toString(modifiedModifiers);
if (modif.length() > 0) { if (modif.length() > 0) {
writer.print(delim + modif); writer.print(delim + modif);
delim = " "; delim = " ";
} }
if (isStrictFP()) {
/* The STRICTFP modifier is set.
* We handle it, since java.lang.reflect.Modifier is too dumb.
*/
/* If STRICTFP is already set for class don't set it for method.
* And don't set STRICTFP for native methods or constructors.
*/
if (!classAnalyzer.isStrictFP()
&& !isConstructor()
&& (modifiedModifiers & Modifier.NATIVE) == 0) {
writer.print(delim + "strictfp");
delim = " ";
}
}
if (isConstructor if (isConstructor
&& (isStatic() && (isStatic()
|| (classAnalyzer.getName() == null || (classAnalyzer.getName() == null
@ -866,6 +900,8 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
writer.print(" " + methodName); writer.print(" " + methodName);
} }
writer.breakOp(); writer.breakOp();
if ((Options.outputStyle & Options.GNU_SPACING) != 0)
writer.print(" ");
writer.print("("); writer.print("(");
writer.startOp(writer.EXPL_PAREN, 0); writer.startOp(writer.EXPL_PAREN, 0);
int offset = skipParams + (isStatic() ? 0 : 1); int offset = skipParams + (isStatic() ? 0 : 1);
@ -895,11 +931,11 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
} }
writer.endOp(); writer.endOp();
if (code != null) { if (code != null) {
writer.openBrace(); writer.openBraceNoIndent();
writer.tab(); writer.tab();
methodHeader.dumpSource(writer); methodHeader.dumpSource(writer);
writer.untab(); writer.untab();
writer.closeBrace(); writer.closeBraceNoIndent();
} else } else
writer.println(";"); writer.println(";");
writer.popScope(); writer.popScope();
@ -1008,8 +1044,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
expr).getSubExpressions()[0]; expr).getSubExpressions()[0];
if (expr instanceof ThisOperator) { if (expr instanceof ThisOperator) {
outerValueArray[j] = outerValueArray[j] =
new ThisOperator(((ThisOperator) new ThisOperator(((ThisOperator) expr).getClassInfo());
expr).getClassInfo());
continue; continue;
} }
LocalInfo li = null; LocalInfo li = null;

@ -22,10 +22,13 @@ import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo; import jode.bytecode.InnerClassInfo;
public class Options { public class Options {
public static final int TAB_SIZE_MASK = 0x0f; public static final int TAB_SIZE_MASK = 0x0f;
public static final int BRACE_AT_EOL = 0x10; public static final int BRACE_AT_EOL = 0x10;
public static final int SUN_STYLE = 0x14; public static final int BRACE_FLUSH_LEFT = 0x20;
public static final int GNU_STYLE = 0x02; public static final int GNU_SPACING = 0x40;
public static final int SUN_STYLE = 0x14;
public static final int GNU_STYLE = 0x42;
public static final int PASCAL_STYLE = 0x24;
public static final int OPTION_LVT = 0x0001; public static final int OPTION_LVT = 0x0001;
public static final int OPTION_INNER = 0x0002; public static final int OPTION_INNER = 0x0002;

@ -71,6 +71,7 @@ public class OuterValues
private Expression[] head; private Expression[] head;
private Vector ovListeners; private Vector ovListeners;
private boolean jikesAnonymousInner; private boolean jikesAnonymousInner;
private boolean implicitOuterClass;
/** /**
* The maximal number of parameters used for outer values. * The maximal number of parameters used for outer values.
@ -270,6 +271,17 @@ public class OuterValues
return jikesAnonymousInner; return jikesAnonymousInner;
} }
/**
* Javac 1.3 doesn't give an outer class reference for anonymous
* classes that extend inner classes, provided the outer class is
* the normal this parameter. Instead it takes a normal outer
* value parameter for this. This method tells if this is such a
* class.
*/
public boolean isImplicitOuterClass() {
return implicitOuterClass;
}
public void addOuterValueListener(OuterValueListener l) { public void addOuterValueListener(OuterValueListener l) {
if (ovListeners == null) if (ovListeners == null)
ovListeners = new Vector(); ovListeners = new Vector();
@ -285,6 +297,10 @@ public class OuterValues
jikesAnonymousInner = value; jikesAnonymousInner = value;
} }
public void setImplicitOuterClass(boolean value) {
implicitOuterClass = value;
}
private static int countSlots(Expression[] exprs, int length) { private static int countSlots(Expression[] exprs, int length) {
int slots = 0; int slots = 0;
for (int i=0; i < length; i++) for (int i=0; i < length; i++)
@ -346,8 +362,8 @@ public class OuterValues
} }
if (jikesAnonymousInner) if (jikesAnonymousInner)
sb.append("!jikesAnonymousInner"); sb.append("!jikesAnonymousInner");
if (implicitOuterClass)
sb.append("!implicitOuterClass");
return sb.append("]").toString(); return sb.append("]").toString();
} }
} }

@ -101,11 +101,8 @@ public class TabbedPrintWriter {
} }
public void startOp(int opts, int penalty, int pos) { public void startOp(int opts, int penalty, int pos) {
if (startPos != -1) { if (startPos != -1)
System.err.println("WARNING: missing breakOp"); throw new InternalError("missing breakOp");
Thread.dumpStack();
return;
}
startPos = pos; startPos = pos;
options = opts; options = opts;
breakPenalty = penalty; breakPenalty = penalty;
@ -120,17 +117,15 @@ public class TabbedPrintWriter {
public void endOp(int pos) { public void endOp(int pos) {
endPos = pos; endPos = pos;
if (childBPs.size() == 1) { if (childBPs.size() == 1) {
BreakPoint child = /* There is no breakpoint in this op, replace this with
(BreakPoint) currentBP.childBPs.elementAt(0); * our child, if possible.
if (child.startPos == -1) { */
startPos = endPos = -1; BreakPoint child = (BreakPoint) childBPs.elementAt(0);
childBPs = null; options = Math.min(options, child.options);
} else if (child.startPos == currentBP.startPos startPos = child.startPos;
&& child.endPos == currentBP.endPos) { endPos = child.endPos;
if (options == DONT_BREAK) breakPenalty = child.breakPenalty;
options = child.options; childBPs = child.childBPs;
childBPs = child.childBPs;
}
} }
} }
@ -541,8 +536,9 @@ public class TabbedPrintWriter {
Stack state = new Stack(); Stack state = new Stack();
int pos = currentLine.length(); int pos = currentLine.length();
while (currentBP.parentBP != null) { while (currentBP.parentBP != null) {
state.push(new Integer(currentBP.options));
state.push(new Integer(currentBP.breakPenalty)); state.push(new Integer(currentBP.breakPenalty));
/* We don't want parentheses or unconventional line breaking */
currentBP.options = DONT_BREAK;
currentBP.endPos = pos; currentBP.endPos = pos;
currentBP = currentBP.parentBP; currentBP = currentBP.parentBP;
} }
@ -553,8 +549,7 @@ public class TabbedPrintWriter {
Stack state = (Stack) s; Stack state = (Stack) s;
while (!state.isEmpty()) { while (!state.isEmpty()) {
int penalty = ((Integer) state.pop()).intValue(); int penalty = ((Integer) state.pop()).intValue();
int options = ((Integer) state.pop()).intValue(); startOp(DONT_BREAK, penalty);
startOp(options, penalty);
} }
} }
@ -746,12 +741,38 @@ public class TabbedPrintWriter {
} else { } else {
if (currentLine.length() > 0) if (currentLine.length() > 0)
println(); println();
if (currentIndent > 0) if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0
&& currentIndent > 0)
tab(); tab();
println("{"); println("{");
} }
} }
public void openBraceClass() {
if (currentLine.length() > 0) {
if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
print(" ");
else
println();
}
println("{");
}
/**
* Print a opening brace with the current indentation style.
* Called at the end the line of a method declaration.
*/
public void openBraceNoIndent() {
if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0) {
print(currentLine.length() > 0 ? " {" : "{");
println();
} else {
if (currentLine.length() > 0)
println();
println("{");
}
}
/** /**
* Print a opening brace with the current indentation style. * Print a opening brace with the current indentation style.
* Called at the end of the line of the instance that opens the * Called at the end of the line of the instance that opens the
@ -763,7 +784,8 @@ public class TabbedPrintWriter {
else { else {
if (currentLine.length() > 0) if (currentLine.length() > 0)
println(); println();
if (currentIndent > 0) if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0
&& currentIndent > 0)
tab(); tab();
println("{"); println("{");
} }
@ -774,19 +796,14 @@ public class TabbedPrintWriter {
print("} "); print("} ");
else { else {
println("}"); println("}");
if (currentIndent > 0) if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0
&& currentIndent > 0)
untab(); untab();
} }
} }
public void closeBraceNoSpace() { public void closeBraceClass() {
if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0) print("}");
print("}");
else {
println("}");
if (currentIndent > 0)
untab();
}
} }
public void closeBrace() { public void closeBrace() {
@ -794,11 +811,16 @@ public class TabbedPrintWriter {
println("}"); println("}");
else { else {
println("}"); println("}");
if (currentIndent > 0) if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0
&& currentIndent > 0)
untab(); untab();
} }
} }
public void closeBraceNoIndent() {
println("}");
}
public void flush() { public void flush() {
pw.flush(); pw.flush();
} }

@ -32,4 +32,29 @@ public class ArrayStoreOperator extends ArrayLoadOperator
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return loadop instanceof ArrayLoadOperator; return loadop instanceof ArrayLoadOperator;
} }
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
Type arrType = subExpressions[0].getType().getHint();
if (arrType instanceof ArrayType) {
Type elemType = ((ArrayType) arrType).getElementType();
if (!elemType.isOfType(getType())) {
/* We need an explicit widening cast */
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 1);
writer.print("(");
writer.printType(Type.tArray(getType().getHint()));
writer.print(") ");
writer.breakOp();
subExpressions[0].dumpExpression(writer, 700);
writer.print(")");
writer.breakOp();
writer.print("[");
subExpressions[1].dumpExpression(writer, 0);
writer.print("]");
return;
}
}
super.dumpExpression(writer);
}
} }

@ -109,7 +109,7 @@ public class ConstOperator extends NoArgOperator {
return false; return false;
} }
public void makeInitializer() { public void makeInitializer(Type type) {
isInitializer = true; isInitializer = true;
} }

@ -48,7 +48,7 @@ public class ConstantArrayOperator extends Operator {
empty = new ConstOperator(emptyVal); empty = new ConstOperator(emptyVal);
empty.setType(argType); empty.setType(argType);
empty.makeInitializer(); empty.makeInitializer(argType);
initOperands(size); initOperands(size);
for (int i=0; i < subExpressions.length; i++) for (int i=0; i < subExpressions.length; i++)
setSubExpressions(i, empty); setSubExpressions(i, empty);
@ -74,7 +74,7 @@ public class ConstantArrayOperator extends Operator {
setType(Type.tSuperType(Type.tArray(value.getType()))); setType(Type.tSuperType(Type.tArray(value.getType())));
subExpressions[index] = value; subExpressions[index] = value;
value.parent = this; value.parent = this;
value.makeInitializer(); value.makeInitializer(argType);
return true; return true;
} }
@ -82,8 +82,9 @@ public class ConstantArrayOperator extends Operator {
return 200; return 200;
} }
public void makeInitializer() { public void makeInitializer(Type type) {
isInitializer = true; if (type.getHint().isOfType(getType()))
isInitializer = true;
} }
public Expression simplify() { public Expression simplify() {

@ -53,23 +53,7 @@ public abstract class Expression {
} }
public void updateParentType(Type otherType) { public void updateParentType(Type otherType) {
Type newType = otherType.intersection(type); setType(otherType);
if (type.equals(newType))
return;
if (newType == Type.tError) {
if (otherType == Type.tError) {
// Don't propagate type errors.
return;
}
GlobalOptions.err.println("updateParentType: Type error in "
+this+": merging "+getType()
+" and "+otherType);
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
Thread.dumpStack();
}
type = newType;
if (parent != null) if (parent != null)
parent.updateType(); parent.updateType();
} }
@ -224,7 +208,7 @@ public abstract class Expression {
return null; return null;
} }
public void makeInitializer() { public void makeInitializer(Type type) {
} }
public boolean isConstant() { public boolean isConstant() {
@ -299,6 +283,7 @@ public abstract class Expression {
dumpExpression(writer); dumpExpression(writer);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
writer.print("(RUNTIME ERROR IN EXPRESSION)"); writer.print("(RUNTIME ERROR IN EXPRESSION)");
ex.printStackTrace(GlobalOptions.err);
} }
if (needEndOp2) { if (needEndOp2) {

@ -25,6 +25,7 @@ import jode.bytecode.FieldInfo;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
import jode.bytecode.Reference; import jode.bytecode.Reference;
import jode.bytecode.InnerClassInfo; import jode.bytecode.InnerClassInfo;
import jode.bytecode.TypeSignature;
import jode.decompiler.MethodAnalyzer; import jode.decompiler.MethodAnalyzer;
import jode.decompiler.ClassAnalyzer; import jode.decompiler.ClassAnalyzer;
import jode.decompiler.MethodAnalyzer; import jode.decompiler.MethodAnalyzer;
@ -33,6 +34,7 @@ import jode.decompiler.Options;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
import jode.decompiler.Scope; import jode.decompiler.Scope;
import java.lang.reflect.Modifier;
import @COLLECTIONS@.Collection; import @COLLECTIONS@.Collection;
/** /**
@ -120,6 +122,33 @@ public abstract class FieldOperator extends Operator {
return Type.tType(ref.getType()); return Type.tType(ref.getType());
} }
private static FieldInfo getFieldInfo(ClassInfo clazz,
String name, String type) {
while (clazz != null) {
FieldInfo field = clazz.findField(name, type);
if (field != null)
return field;
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i = 0; i < ifaces.length; i++) {
field = getFieldInfo(ifaces[i], name, type);
if (field != null)
return field;
}
clazz = clazz.getSuperclass();
}
return null;
}
public FieldInfo getFieldInfo() {
ClassInfo clazz;
if (ref.getClazz().charAt(0) == '[')
clazz = ClassInfo.javaLangObject;
else
clazz = TypeSignature.getClassInfo(ref.getClazz());
return getFieldInfo(clazz, ref.getName(), ref.getType());
}
public boolean needsCast(Type type) { public boolean needsCast(Type type) {
if (type instanceof NullType) if (type instanceof NullType)
return true; return true;
@ -129,6 +158,37 @@ public abstract class FieldOperator extends Operator {
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo(); ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo(); ClassInfo parClazz = ((ClassInterfacesType) type).getClassInfo();
FieldInfo field = clazz.findField(ref.getName(), ref.getType());
find_field:
while (field == null) {
ClassInfo ifaces[] = clazz.getInterfaces();
for (int i = 0; i < ifaces.length; i++) {
field = ifaces[i].findField(ref.getName(), ref.getType());
if (field != null)
break find_field;
}
clazz = clazz.getSuperclass();
if (clazz == null)
/* Weird, field not existing? */
return false;
field = clazz.findField(ref.getName(), ref.getType());
}
if (Modifier.isPrivate(field.getModifiers()))
return parClazz != clazz;
else if ((field.getModifiers()
& (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
/* Field is protected. We need a cast if parClazz is in
* other package than clazz.
*/
int lastDot = clazz.getName().lastIndexOf('.');
if (lastDot == -1
|| lastDot != parClazz.getName().lastIndexOf('.')
|| !(parClazz.getName()
.startsWith(clazz.getName().substring(0,lastDot))))
return true;
}
while (clazz != parClazz && clazz != null) { while (clazz != parClazz && clazz != null) {
FieldInfo[] fields = parClazz.getFields(); FieldInfo[] fields = parClazz.getFields();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
@ -216,20 +276,8 @@ public abstract class FieldOperator extends Operator {
*/ */
getField() == null getField() == null
&& writer.conflicts(fieldName, null, && writer.conflicts(fieldName, null,
Scope.NOSUPERFIELDNAME))) { Scope.NOSUPERFIELDNAME))) {
thisOp.dumpExpression(writer, 950);
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope)
// For a simple outer class we can say this
writer.print("this");
else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
}
writer.breakOp(); writer.breakOp();
writer.print("."); writer.print(".");
} }

@ -81,7 +81,9 @@ public class IIncOperator extends Operator
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 950); writer.startOp(writer.NO_PAREN, 2);
subExpressions[0].dumpExpression(writer);
writer.endOp();
writer.print(getOperatorString() + value); writer.print(getOperatorString() + value);
} }
} }

@ -39,9 +39,9 @@ public class IfThenElseOperator extends Operator {
} }
public void updateType() { public void updateType() {
Type subType = Type.tSuperType(subExpressions[1].getType()) Type commonType = Type.tSuperType(subExpressions[1].getType())
.intersection(Type.tSuperType(subExpressions[2].getType())); .intersection(Type.tSuperType(subExpressions[2].getType()));
updateParentType(subType); updateParentType(commonType);
} }
public Expression simplify() { public Expression simplify() {
@ -59,37 +59,46 @@ public class IfThenElseOperator extends Operator {
} }
} }
if (subExpressions[0] instanceof CompareUnaryOperator if (subExpressions[0] instanceof CompareUnaryOperator
&& (subExpressions[1] instanceof GetFieldOperator) && ((((CompareUnaryOperator) subExpressions[0])
&& (subExpressions[2] instanceof StoreInstruction)) { .getOperatorIndex() & ~1) == Operator.COMPARE_OP)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
CompareUnaryOperator cmp CompareUnaryOperator cmp
= (CompareUnaryOperator) subExpressions[0]; = (CompareUnaryOperator) subExpressions[0];
GetFieldOperator get = (GetFieldOperator) subExpressions[1]; int cmpType = cmp.getOperatorIndex() & 1;
StoreInstruction put = (StoreInstruction) subExpressions[2]; if ((subExpressions[2 - cmpType] instanceof GetFieldOperator)
FieldAnalyzer field; && (subExpressions[1 + cmpType] instanceof StoreInstruction)) {
if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP // Check for
&& put.getLValue() instanceof PutFieldOperator // class$classname != null ? class$classname :
&& ((field = ((PutFieldOperator)put.getLValue()).getField()) // (class$classname = class$("classname"))
!= null) && field.isSynthetic() // and replace with
&& put.lvalueMatches(get) // classname.class
&& cmp.subExpressions[0] instanceof GetFieldOperator GetFieldOperator get
&& put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0]) = (GetFieldOperator) subExpressions[2 - cmpType];
&& put.subExpressions[1] instanceof InvokeOperator) { StoreInstruction put
InvokeOperator invoke = (InvokeOperator) put.subExpressions[1]; = (StoreInstruction) subExpressions[1 + cmpType];
if (invoke.isGetClass() int opIndex = cmp.getOperatorIndex();
&& invoke.subExpressions[0] instanceof ConstOperator FieldAnalyzer field;
&& (invoke.subExpressions[0].getType() if (put.getLValue() instanceof PutFieldOperator
.equals(Type.tString))) { && ((field = ((PutFieldOperator)put.getLValue())
String clazz = (String) .getField()) != null) && field.isSynthetic()
((ConstOperator)invoke.subExpressions[0]).getValue(); && put.lvalueMatches(get)
if (field.setClassConstant(clazz)) && (cmp.subExpressions[0] instanceof GetFieldOperator)
return new ClassFieldOperator(clazz.charAt(0) == '[' && put.lvalueMatches((GetFieldOperator)
? Type.tType(clazz) cmp.subExpressions[0])
: Type.tClass(clazz)); && put.subExpressions[1] instanceof InvokeOperator) {
InvokeOperator invoke = (InvokeOperator)
put.subExpressions[1];
if (invoke.isGetClass()
&& invoke.subExpressions[0] instanceof ConstOperator
&& (invoke.subExpressions[0].getType()
.equals(Type.tString))) {
String clazz = (String)
((ConstOperator)invoke.subExpressions[0])
.getValue();
if (field.setClassConstant(clazz))
return new ClassFieldOperator
(clazz.charAt(0) == '['
? Type.tType(clazz) : Type.tClass(clazz));
}
} }
} }
} }

@ -58,6 +58,7 @@ public final class InvokeOperator extends Operator
int methodFlag; int methodFlag;
MethodType methodType; MethodType methodType;
String methodName; String methodName;
Reference ref;
int skippedArgs; int skippedArgs;
Type classType; Type classType;
Type[] hints; Type[] hints;
@ -127,6 +128,7 @@ public final class InvokeOperator extends Operator
public InvokeOperator(MethodAnalyzer methodAnalyzer, public InvokeOperator(MethodAnalyzer methodAnalyzer,
int methodFlag, Reference reference) { int methodFlag, Reference reference) {
super(Type.tUnknown, 0); super(Type.tUnknown, 0);
this.ref = reference;
this.methodType = Type.tMethod(reference.getType()); this.methodType = Type.tMethod(reference.getType());
this.methodName = reference.getName(); this.methodName = reference.getName();
this.classType = Type.tType(reference.getClazz()); this.classType = Type.tType(reference.getClazz());
@ -166,6 +168,25 @@ public final class InvokeOperator extends Operator
return methodName; return methodName;
} }
private static MethodInfo getMethodInfo(ClassInfo clazz,
String name, String type) {
while (clazz != null) {
MethodInfo method = clazz.findMethod(name, type);
if (method != null)
return method;
clazz = clazz.getSuperclass();
}
return null;
}
public MethodInfo getMethodInfo() {
ClassInfo clazz;
if (ref.getClazz().charAt(0) == '[')
clazz = ClassInfo.javaLangObject;
else
clazz = TypeSignature.getClassInfo(ref.getClazz());
return getMethodInfo(clazz, ref.getName(), ref.getType());
}
public Type getClassType() { public Type getClassType() {
return classType; return classType;
} }
@ -201,7 +222,7 @@ public final class InvokeOperator extends Operator
} }
/** /**
* Makes a non void expression out of this store instruction. * Makes a non void expression, in case this is a constructor.
*/ */
public void makeNonVoid() { public void makeNonVoid() {
if (type != Type.tVoid) if (type != Type.tVoid)
@ -398,12 +419,12 @@ public final class InvokeOperator extends Operator
* @return true if this is the magic class$ method, false otherwise. * @return true if this is the magic class$ method, false otherwise.
*/ */
public boolean isGetClass() { public boolean isGetClass() {
if (isThis()) { MethodAnalyzer mana = getMethodAnalyzer();
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); if (mana == null)
if (synth != null && synth.getKind() == SyntheticAnalyzer.GETCLASS) return false;
return true; SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
} return (synth != null
return false; && synth.getKind() == SyntheticAnalyzer.GETCLASS);
} }
class Environment extends SimpleRuntimeEnvironment { class Environment extends SimpleRuntimeEnvironment {
@ -419,8 +440,10 @@ public final class InvokeOperator extends Operator
Object cls, Object[] params) Object cls, Object[] params)
throws InterpreterException, InvocationTargetException { throws InterpreterException, InvocationTargetException {
if (cls == null && ref.getClazz().equals(classSig)) { if (cls == null && ref.getClazz().equals(classSig)) {
BytecodeInfo info = String clazzName = ref.getClazz();
ClassInfo.forName(ref.getClazz()) clazzName = clazzName.substring(1, ref.getClazz().length() - 1)
.replace('/', '.');
BytecodeInfo info = ClassInfo.forName(clazzName)
.findMethod(ref.getName(), ref.getType()) .findMethod(ref.getName(), ref.getType())
.getBytecode(); .getBytecode();
if (info != null) if (info != null)
@ -572,6 +595,7 @@ public final class InvokeOperator extends Operator
if (getMethodAnalyzer() != null) { if (getMethodAnalyzer() != null) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null) { if (synth != null) {
int unifyParam = synth.getUnifyParam();
Expression op = null; Expression op = null;
switch (synth.getKind()) { switch (synth.getKind()) {
case SyntheticAnalyzer.ACCESSGETFIELD: case SyntheticAnalyzer.ACCESSGETFIELD:
@ -583,14 +607,20 @@ public final class InvokeOperator extends Operator
synth.getReference()); synth.getReference());
break; break;
case SyntheticAnalyzer.ACCESSPUTFIELD: case SyntheticAnalyzer.ACCESSPUTFIELD:
case SyntheticAnalyzer.ACCESSDUPPUTFIELD:
op = new StoreInstruction op = new StoreInstruction
(new PutFieldOperator(methodAnalyzer, false, (new PutFieldOperator(methodAnalyzer, false,
synth.getReference())); synth.getReference()));
if (synth.getKind() == synth.ACCESSDUPPUTFIELD)
((StoreInstruction) op).makeNonVoid();
break; break;
case SyntheticAnalyzer.ACCESSPUTSTATIC: case SyntheticAnalyzer.ACCESSPUTSTATIC:
case SyntheticAnalyzer.ACCESSDUPPUTSTATIC:
op = new StoreInstruction op = new StoreInstruction
(new PutFieldOperator(methodAnalyzer, true, (new PutFieldOperator(methodAnalyzer, true,
synth.getReference())); synth.getReference()));
if (synth.getKind() == synth.ACCESSDUPPUTSTATIC)
((StoreInstruction) op).makeNonVoid();
break; break;
case SyntheticAnalyzer.ACCESSMETHOD: case SyntheticAnalyzer.ACCESSMETHOD:
op = new InvokeOperator(methodAnalyzer, ACCESSSPECIAL, op = new InvokeOperator(methodAnalyzer, ACCESSSPECIAL,
@ -601,9 +631,9 @@ public final class InvokeOperator extends Operator
synth.getReference()); synth.getReference());
break; break;
case SyntheticAnalyzer.ACCESSCONSTRUCTOR: case SyntheticAnalyzer.ACCESSCONSTRUCTOR:
if (subExpressions[1] instanceof ConstOperator if (subExpressions[unifyParam] instanceof ConstOperator
&& ((ConstOperator) && ((ConstOperator)
subExpressions[1]).getValue() == null) { subExpressions[unifyParam]).getValue() == null) {
op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR, op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR,
synth.getReference()); synth.getReference());
} }
@ -613,7 +643,7 @@ public final class InvokeOperator extends Operator
if (op != null) { if (op != null) {
if (subExpressions != null) { if (subExpressions != null) {
for (int i=subExpressions.length; i-- > 0; ) { for (int i=subExpressions.length; i-- > 0; ) {
if (i == 1 && synth.getKind() if (i == unifyParam && synth.getKind()
== SyntheticAnalyzer.ACCESSCONSTRUCTOR) == SyntheticAnalyzer.ACCESSCONSTRUCTOR)
// skip the null param. // skip the null param.
continue; continue;
@ -633,9 +663,35 @@ public final class InvokeOperator extends Operator
Type realClassType; Type realClassType;
if (methodFlag == STATIC) if (methodFlag == STATIC)
realClassType = classType; realClassType = classType;
else { else if (param == 0) {
if (param == 0) if (paramTypes[0] instanceof NullType)
return paramTypes[0] instanceof NullType; return true;
if (!(paramTypes[0] instanceof ClassInterfacesType
&& classType instanceof ClassInterfacesType))
return false;
ClassInfo clazz = ((ClassInterfacesType) classType).getClassInfo();
ClassInfo parClazz
= ((ClassInterfacesType) paramTypes[0]).getClassInfo();
MethodInfo method = getMethodInfo();
if (method == null)
/* This is a NoSuchMethodError */
return false;
if (Modifier.isPrivate(method.getModifiers()))
return parClazz != clazz;
else if ((method.getModifiers()
& (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
/* Method is protected. We need a cast if parClazz is in
* other package than clazz.
*/
int lastDot = clazz.getName().lastIndexOf('.');
if (lastDot != parClazz.getName().lastIndexOf('.')
|| !(parClazz.getName()
.startsWith(clazz.getName().substring(0,lastDot+1))))
return true;
}
return false;
} else {
realClassType = paramTypes[0]; realClassType = paramTypes[0];
} }
@ -675,9 +731,10 @@ public final class InvokeOperator extends Operator
} }
for (int p = offset; p < paramTypes.length; p++) { for (int p = offset; p < paramTypes.length; p++) {
if (!paramTypes[p] if (!paramTypes[p]
.isOfType(Type.tSubType(otherParamTypes[p-offset]))) .isOfType(Type.tSubType(otherParamTypes[p-offset]))){
/* No conflict here */ /* No conflict here */
continue next_method; continue next_method;
}
} }
/* There is a conflict that can be resolved by a cast. */ /* There is a conflict that can be resolved by a cast. */
return true; return true;
@ -727,6 +784,7 @@ public final class InvokeOperator extends Operator
int arg = 1; int arg = 1;
int length = subExpressions.length; int length = subExpressions.length;
boolean jikesAnonymousInner = false; boolean jikesAnonymousInner = false;
boolean implicitOuterClass = false;
if ((Options.options & Options.OPTION_ANON) != 0 if ((Options.options & Options.OPTION_ANON) != 0
&& clazzAna != null && clazzAna != null
@ -735,6 +793,7 @@ public final class InvokeOperator extends Operator
OuterValues ov = clazzAna.getOuterValues(); OuterValues ov = clazzAna.getOuterValues();
arg += ov.getCount(); arg += ov.getCount();
jikesAnonymousInner = ov.isJikesAnonymousInner(); jikesAnonymousInner = ov.isJikesAnonymousInner();
implicitOuterClass = ov.isImplicitOuterClass();
for (int i=1; i< arg; i++) { for (int i=1; i< arg; i++) {
Expression expr = subExpressions[i]; Expression expr = subExpressions[i];
@ -764,7 +823,9 @@ public final class InvokeOperator extends Operator
if ((Options.options & Options.OPTION_INNER) != 0 if ((Options.options & Options.OPTION_INNER) != 0
&& outer != null && outer.outer != null && outer.name != null && outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers)) { && !Modifier.isStatic(outer.modifiers)
&& !implicitOuterClass
&& arg < length) {
Expression outerExpr = jikesAnonymousInner Expression outerExpr = jikesAnonymousInner
? subExpressions[--length] ? subExpressions[--length]
@ -826,6 +887,7 @@ public final class InvokeOperator extends Operator
boolean qualifiedNew = false; boolean qualifiedNew = false;
boolean jikesAnonymousInner = false; boolean jikesAnonymousInner = false;
boolean implicitOuterClass = false;
/* Check if this is an anonymous constructor. In this case /* Check if this is an anonymous constructor. In this case
@ -833,7 +895,8 @@ public final class InvokeOperator extends Operator
* super class and anonymousNew will be set. * super class and anonymousNew will be set.
*/ */
InnerClassInfo outer = getOuterClassInfo(clazz); InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && outer.name == null) if (outer != null && outer.name == null
&& (Options.options & Options.OPTION_ANON) != 0)
anonymousNew = true; anonymousNew = true;
clazzAna = methodAnalyzer.getClassAnalyzer(clazz); clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if ((~Options.options & if ((~Options.options &
@ -846,6 +909,7 @@ public final class InvokeOperator extends Operator
OuterValues ov = clazzAna.getOuterValues(); OuterValues ov = clazzAna.getOuterValues();
arg += ov.getCount(); arg += ov.getCount();
jikesAnonymousInner = ov.isJikesAnonymousInner(); jikesAnonymousInner = ov.isJikesAnonymousInner();
implicitOuterClass = ov.isImplicitOuterClass();
if (outer.name == null) { if (outer.name == null) {
/* This is an anonymous class */ /* This is an anonymous class */
@ -888,47 +952,54 @@ public final class InvokeOperator extends Operator
(Options.OPTION_INNER (Options.OPTION_INNER
| Options.OPTION_CONTRAFO)) == 0) { | Options.OPTION_CONTRAFO)) == 0) {
Expression outerExpr = jikesAnonymousInner if (implicitOuterClass) {
? subExpressions[--length] /* Outer class is "this" and is not given
* explicitly. No need to print something.
*/
} else if (arg < length) {
Expression outerExpr = jikesAnonymousInner
? subExpressions[--length]
: subExpressions[arg++]; : subExpressions[arg++];
if (outerExpr instanceof CheckNullOperator) { if (outerExpr instanceof CheckNullOperator) {
CheckNullOperator cno = (CheckNullOperator) outerExpr; CheckNullOperator cno = (CheckNullOperator) outerExpr;
outerExpr = cno.subExpressions[0]; outerExpr = cno.subExpressions[0];
} else if (!(outerExpr instanceof ThisOperator)) { } else {
if (!jikesAnonymousInner) /* We used to complain about MISSING CHECKNULL
// Bug in jikes: it doesn't do a check null. * here except for ThisOperators. But javac
// We don't complain here. * v8 doesn't seem to create CHECKNULL ops.
writer.print("MISSING CHECKNULL "); */
} }
if (outerExpr instanceof ThisOperator) { if (outerExpr instanceof ThisOperator) {
Scope scope = writer.getScope Scope scope = writer.getScope
(((ThisOperator) outerExpr).getClassInfo(), (((ThisOperator) outerExpr).getClassInfo(),
Scope.CLASSSCOPE); Scope.CLASSSCOPE);
if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) { if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) {
qualifiedNew = true;
outerExpr.dumpExpression(writer, 950);
writer.breakOp();
writer.print(".");
}
} else {
qualifiedNew = true; qualifiedNew = true;
outerExpr.dumpExpression(writer, 950); if (outerExpr.getType() instanceof NullType) {
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 1);
writer.print("(");
writer.printType(Type.tClass
(ClassInfo.forName(outer.outer)));
writer.print(") ");
writer.breakOp();
outerExpr.dumpExpression(writer, 700);
writer.endOp();
writer.print(")");
} else
outerExpr.dumpExpression(writer, 950);
writer.breakOp(); writer.breakOp();
writer.print("."); writer.print(".");
} }
} else { } else
qualifiedNew = true; writer.print("MISSING OUTEREXPR ");
if (outerExpr.getType() instanceof NullType) {
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 1);
writer.print("(");
writer.printType(Type.tClass
(ClassInfo.forName(outer.outer)));
writer.print(") ");
writer.breakOp();
outerExpr.dumpExpression(writer, 700);
writer.endOp();
writer.print(")");
} else
outerExpr.dumpExpression(writer, 950);
writer.breakOp();
writer.print(".");
}
} }
if (subExpressions[0] instanceof NewOperator if (subExpressions[0] instanceof NewOperator
@ -1056,30 +1127,19 @@ public final class InvokeOperator extends Operator
ThisOperator thisOp = (ThisOperator) subExpressions[0]; ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(), Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE); Scope.CLASSSCOPE);
if (writer.conflicts(methodName, scope, Scope.METHODNAME)) { if (writer.conflicts(methodName, scope, Scope.METHODNAME)
|| (/* This method is inherited from the parent of
* an outer class, or it is inherited from the
* parent of this class and there is a conflicting
* method in some outer class.
*/
getMethodAnalyzer() == null
&& (!isThis() ||
writer.conflicts(methodName, null,
Scope.NOSUPERMETHODNAME)))) {
thisOp.dumpExpression(writer, 950); thisOp.dumpExpression(writer, 950);
writer.breakOp(); writer.breakOp();
writer.print("."); writer.print(".");
} else if (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getMethodAnalyzer() == null
&& writer.conflicts(methodName, null,
Scope.NOSUPERMETHODNAME)) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope) {
// For a simple outer class we can say this
writer.print("this");
} else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
}
writer.breakOp();
writer.print(".");
} }
} else { } else {
if (needsCast(0, paramTypes)){ if (needsCast(0, paramTypes)){
@ -1103,6 +1163,8 @@ public final class InvokeOperator extends Operator
writer.endOp(); writer.endOp();
writer.breakOp(); writer.breakOp();
if ((Options.outputStyle & Options.GNU_SPACING) != 0)
writer.print(" ");
writer.print("("); writer.print("(");
writer.startOp(writer.EXPL_PAREN, 0); writer.startOp(writer.EXPL_PAREN, 0);
boolean first = true; boolean first = true;
@ -1136,11 +1198,11 @@ public final class InvokeOperator extends Operator
* dump the source code of the anonymous class. * dump the source code of the anonymous class.
*/ */
Object state = writer.saveOps(); Object state = writer.saveOps();
writer.openBrace(); writer.openBraceClass();
writer.tab(); writer.tab();
clazzAna.dumpBlock(writer); clazzAna.dumpBlock(writer);
writer.untab(); writer.untab();
writer.closeBraceNoSpace(); writer.closeBraceClass();
writer.restoreOps(state); writer.restoreOps(state);
} }
} }

@ -41,8 +41,17 @@ public class PopOperator extends Operator {
public void updateType() { public void updateType() {
} }
public int getBreakPenalty() {
if (subExpressions[0] instanceof Operator)
return ((Operator) subExpressions[0]).getBreakPenalty();
return 0;
}
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 0); /* Don't give a priority; we can't allow parens around
* a statement.
*/
subExpressions[0].dumpExpression(writer);
} }
} }

@ -52,13 +52,11 @@ public class PrePostFixOperator extends Operator {
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
boolean needBrace = false; if (!postfix)
int priority = 700;
if (!postfix) {
writer.print(getOperatorString()); writer.print(getOperatorString());
priority = 800; writer.startOp(writer.NO_PAREN, 2);
} subExpressions[0].dumpExpression(writer);
subExpressions[0].dumpExpression(writer, priority); writer.endOp();
if (postfix) if (postfix)
writer.print(getOperatorString()); writer.print(getOperatorString());
} }

@ -111,7 +111,9 @@ public class StoreInstruction extends Operator
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
subExpressions[0].dumpExpression(writer, 950); writer.startOp(writer.NO_PAREN, 2);
subExpressions[0].dumpExpression(writer);
writer.endOp();
writer.breakOp(); writer.breakOp();
writer.print(getOperatorString()); writer.print(getOperatorString());
subExpressions[1].dumpExpression(writer, 100); subExpressions[1].dumpExpression(writer, 100);

@ -19,6 +19,7 @@
package jode.expr; package jode.expr;
import jode.type.Type; import jode.type.Type;
import jode.decompiler.Options;
import jode.decompiler.TabbedPrintWriter; import jode.decompiler.TabbedPrintWriter;
public class UnaryOperator extends Operator { public class UnaryOperator extends Operator {
@ -57,6 +58,8 @@ public class UnaryOperator extends Operator {
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
writer.print(getOperatorString()); writer.print(getOperatorString());
if ((Options.outputStyle & Options.GNU_SPACING) != 0)
writer.print(" ");
subExpressions[0].dumpExpression(writer, 700); subExpressions[0].dumpExpression(writer, 700);
} }
} }

@ -19,6 +19,7 @@
package jode.flow; package jode.flow;
import jode.expr.ConstOperator; import jode.expr.ConstOperator;
import jode.type.Type;
/** /**
* This block represents a case instruction. A case instruction is a * This block represents a case instruction. A case instruction is a
@ -173,8 +174,9 @@ public class CaseBlock extends StructuredBlock {
writer.untab(); writer.untab();
} }
ConstOperator constOp = new ConstOperator(new Integer(value)); ConstOperator constOp = new ConstOperator(new Integer(value));
constOp.setType(((SwitchBlock)outer).getInstruction().getType()); Type type = ((SwitchBlock)outer).getInstruction().getType();
constOp.makeInitializer(); constOp.setType(type);
constOp.makeInitializer(type);
writer.print("case " + constOp.toString() + ":"); writer.print("case " + constOp.toString() + ":");
} }
if (subBlock != null) { if (subBlock != null) {

@ -20,6 +20,7 @@
package jode.flow; package jode.flow;
import jode.type.Type; import jode.type.Type;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.decompiler.Declarable;
import jode.expr.Expression; import jode.expr.Expression;
import jode.expr.LocalLoadOperator; import jode.expr.LocalLoadOperator;
import jode.expr.LocalStoreOperator; import jode.expr.LocalStoreOperator;
@ -27,6 +28,7 @@ import jode.expr.StoreInstruction;
import jode.util.SimpleSet; import jode.util.SimpleSet;
import @COLLECTIONS@.Collections; import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Set; import @COLLECTIONS@.Set;
@ -160,6 +162,16 @@ public class CatchBlock extends StructuredBlock {
ib.appendBlock(catchBlock); ib.appendBlock(catchBlock);
catchBlock = ib; catchBlock = ib;
exceptionLocal = dummyLocal; exceptionLocal = dummyLocal;
String localName = dummyLocal.guessName();
Iterator doneIter = done.iterator();
while (doneIter.hasNext()) {
Declarable previous = (Declarable) doneIter.next();
if (localName.equals(previous.getName())) {
/* A name conflict happened. */
dummyLocal.makeNameUnique();
break;
}
}
} }
} }
} }

@ -63,10 +63,12 @@ public class CreateClassField {
return false; return false;
InvokeOperator invoke = (InvokeOperator) store.getSubExpressions()[1]; InvokeOperator invoke = (InvokeOperator) store.getSubExpressions()[1];
if (!invoke.isGetClass())
return false;
Expression param = invoke.getSubExpressions()[0]; Expression param = invoke.getSubExpressions()[0];
if (invoke.isGetClass() if (param instanceof ConstOperator
&& param instanceof ConstOperator
&& ((ConstOperator)param).getValue() instanceof String) { && ((ConstOperator)param).getValue() instanceof String) {
String clazz = (String) ((ConstOperator)param).getValue(); String clazz = (String) ((ConstOperator)param).getValue();
if (put.getField().setClassConstant(clazz)) { if (put.getField().setClassConstant(clazz)) {

@ -56,6 +56,17 @@ public class EmptyBlock extends StructuredBlock {
return block; return block;
} }
/**
* Prepends a block to this block.
* @return the new combined block.
*/
public StructuredBlock prependBlock(StructuredBlock block) {
/* For empty blocks: append == prepend modulo jump */
block = appendBlock(block);
block.moveJump(this.jump);
return block;
}
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {

@ -1708,7 +1708,8 @@ public class FlowBlock {
java.io.StringWriter strw = new java.io.StringWriter(); java.io.StringWriter strw = new java.io.StringWriter();
TabbedPrintWriter writer = new TabbedPrintWriter(strw); TabbedPrintWriter writer = new TabbedPrintWriter(strw);
writer.println(super.toString() + ": "+addr+"-"+(addr+length)); writer.println(super.toString() + ": "+addr+"-"+(addr+length));
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INOUT) != 0) {
writer.println("in: "+in); writer.println("in: "+in);
} }
writer.tab(); writer.tab();

@ -116,7 +116,6 @@ public class InstructionBlock extends InstructionContainer {
* change this to a initializing variable declaration. * change this to a initializing variable declaration.
*/ */
isDeclaration = true; isDeclaration = true;
storeOp.getSubExpressions()[1].makeInitializer();
declareSet.remove(local); declareSet.remove(local);
} }
} }
@ -144,6 +143,7 @@ public class InstructionBlock extends InstructionContainer {
local.dumpDeclaration(writer); local.dumpDeclaration(writer);
writer.breakOp(); writer.breakOp();
writer.print(" = "); writer.print(" = ");
store.getSubExpressions()[1].makeInitializer(local.getType());
store.getSubExpressions()[1].dumpExpression(writer.IMPL_PAREN, store.getSubExpressions()[1].dumpExpression(writer.IMPL_PAREN,
writer); writer);
writer.endOp(); writer.endOp();

@ -33,14 +33,22 @@ public class JsrBlock extends StructuredBlock {
* The inner block that jumps to the subroutine. * The inner block that jumps to the subroutine.
*/ */
StructuredBlock innerBlock; StructuredBlock innerBlock;
boolean good = false;
public JsrBlock(Jump subroutine, Jump next) { public JsrBlock(Jump subroutine, Jump next) {
innerBlock = new EmptyBlock(subroutine); innerBlock = new EmptyBlock(subroutine);
innerBlock.outer = this; innerBlock.outer = this;
setJump(next); setJump(next);
} }
public void setGood(boolean g) {
good = g;
}
public boolean isGood() {
return good;
}
/* The implementation of getNext[Flow]Block is the standard /* The implementation of getNext[Flow]Block is the standard
* implementation */ * implementation */

@ -265,7 +265,6 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
* change this to a initializing variable declaration. * change this to a initializing variable declaration.
*/ */
isDeclaration = true; isDeclaration = true;
storeOp.getSubExpressions()[1].makeInitializer();
declareSet.remove(local); declareSet.remove(local);
} }
} }
@ -332,6 +331,8 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
local.dumpDeclaration(writer); local.dumpDeclaration(writer);
writer.breakOp(); writer.breakOp();
writer.print(" = "); writer.print(" = ");
store.getSubExpressions()[1]
.makeInitializer(local.getType());
store.getSubExpressions()[1].dumpExpression(writer, 100); store.getSubExpressions()[1].dumpExpression(writer, 100);
writer.endOp(); writer.endOp();
} else } else

@ -41,6 +41,7 @@ MY_JAVA_FILES = \
RetBlock.java \ RetBlock.java \
ReturnBlock.java \ ReturnBlock.java \
SequentialBlock.java \ SequentialBlock.java \
SlotSet.java \
SpecialBlock.java \ SpecialBlock.java \
StructuredBlock.java \ StructuredBlock.java \
SwitchBlock.java \ SwitchBlock.java \

@ -148,6 +148,9 @@ public class SpecialBlock extends StructuredBlock {
* to: * to:
* method_invocation() * method_invocation()
* *
* With java1.3 due to access$ methods the method_invocation can
* already be a non void store instruction.
*
* PUSH arg1 * PUSH arg1
* PUSH arg2 * PUSH arg2
* POP2 * POP2
@ -174,7 +177,8 @@ public class SpecialBlock extends StructuredBlock {
if (instr.getType().stackSize() == count) { if (instr.getType().stackSize() == count) {
StructuredBlock newBlock; StructuredBlock newBlock;
if (instr instanceof InvokeOperator) { if (instr instanceof InvokeOperator
|| instr instanceof StoreInstruction) {
Expression newExpr Expression newExpr
= new PopOperator(instr.getType()).addOperand(instr); = new PopOperator(instr.getType()).addOperand(instr);
prev.setInstruction(newExpr); prev.setInstruction(newExpr);

@ -301,6 +301,18 @@ public abstract class StructuredBlock {
} }
} }
/**
* Prepends a block to this block.
* @return the new combined block.
*/
public StructuredBlock prependBlock(StructuredBlock block) {
SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(this);
sequBlock.setFirst(block);
sequBlock.setSecond(this);
return sequBlock;
}
/** /**
* Removes this block, or replaces it with an EmptyBlock. * Removes this block, or replaces it with an EmptyBlock.
*/ */

@ -1,4 +1,4 @@
/* TransformConstructors Copyright (C) 1998-1999 Jochen Hoenicke. /* TransformConstructors Copyright (C) 1998-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -33,6 +33,7 @@ import jode.type.MethodType;
import jode.type.Type; import jode.type.Type;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo; import jode.bytecode.InnerClassInfo;
import jode.bytecode.MethodInfo;
import java.util.Vector; import java.util.Vector;
import java.util.Enumeration; import java.util.Enumeration;
@ -99,8 +100,6 @@ public class TransformConstructors {
OuterValues outerValues; OuterValues outerValues;
boolean jikesAnonInner = false;
public TransformConstructors(ClassAnalyzer clazzAnalyzer, public TransformConstructors(ClassAnalyzer clazzAnalyzer,
boolean isStatic, MethodAnalyzer[] cons) { boolean isStatic, MethodAnalyzer[] cons) {
this.clazzAnalyzer = clazzAnalyzer; this.clazzAnalyzer = clazzAnalyzer;
@ -320,7 +319,18 @@ public class TransformConstructors {
} }
} }
if (minSuperOuter > 0) { if (minSuperOuter == 1
&& superAna.getParent() instanceof ClassAnalyzer) {
/* Check if this is the implicit Outer Class */
LocalLoadOperator llop = (LocalLoadOperator) subExpr[start];
if (outerValues.getValueBySlot(llop.getLocalInfo().getSlot())
instanceof ThisOperator) {
minSuperOuter = 0;
outerValues.setImplicitOuterClass(true);
}
}
if (minSuperOuter > 0) {
if (superOV == null || superOV.getCount() < minSuperOuter) { if (superOV == null || superOV.getCount() < minSuperOuter) {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_CONSTRS) != 0) & GlobalOptions.DEBUG_CONSTRS) != 0)
@ -573,7 +583,8 @@ public class TransformConstructors {
* @param expr the initializer to check * @param expr the initializer to check
* @return the transformed initializer or null if expr is not valid. * @return the transformed initializer or null if expr is not valid.
*/ */
public Expression transformFieldInitializer(Expression expr) { private Expression transformFieldInitializer(int fieldSlot,
Expression expr) {
if (expr instanceof LocalVarOperator) { if (expr instanceof LocalVarOperator) {
if (!(expr instanceof LocalLoadOperator)) { if (!(expr instanceof LocalLoadOperator)) {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
@ -594,11 +605,39 @@ public class TransformConstructors {
+" "+outerValues); +" "+outerValues);
return null; return null;
} }
if (expr instanceof FieldOperator) {
if (expr instanceof PutFieldOperator)
return null;
FieldOperator fo = (FieldOperator) expr;
if (fo.getClassInfo() == clazzAnalyzer.getClazz()
&& clazzAnalyzer.getFieldIndex(fo.getFieldName(),
fo.getFieldType()) >= fieldSlot)
return null;
}
if (expr instanceof InvokeOperator) {
/* Don't allow method invocations that can throw a checked
* exception to leave the constructor.
*/
MethodInfo method = ((InvokeOperator) expr).getMethodInfo();
String[] excs = method == null ? null : method.getExceptions();
if (excs != null) {
ClassInfo runtimeException
= ClassInfo.forName("java.lang.RuntimeException");
ClassInfo error = ClassInfo.forName("java.lang.Error");
for (int i = 0; i < excs.length; i++) {
ClassInfo exClass = ClassInfo.forName(excs[i]);
if (!runtimeException.superClassOf(exClass)
&& !error.superClassOf(exClass))
return null;
}
}
}
if (expr instanceof Operator) { if (expr instanceof Operator) {
Operator op = (Operator) expr; Operator op = (Operator) expr;
Expression[] subExpr = op.getSubExpressions(); Expression[] subExpr = op.getSubExpressions();
for (int i=0; i< subExpr.length; i++) { for (int i=0; i< subExpr.length; i++) {
Expression transformed = transformFieldInitializer(subExpr[i]); Expression transformed
= transformFieldInitializer(fieldSlot, subExpr[i]);
if (transformed == null) if (transformed == null)
return null; return null;
if (transformed != subExpr[i]) if (transformed != subExpr[i])
@ -675,7 +714,7 @@ public class TransformConstructors {
break big_loop; break big_loop;
Expression expr = store.getSubExpressions()[1]; Expression expr = store.getSubExpressions()[1];
expr = transformFieldInitializer(expr); expr = transformFieldInitializer(field, expr);
if (expr == null) if (expr == null)
break big_loop; break big_loop;
@ -762,8 +801,14 @@ public class TransformConstructors {
} }
} }
int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
pfo.getFieldType());
if (field <= lastField)
return -1;
Expression expr = store.getSubExpressions()[1]; Expression expr = store.getSubExpressions()[1];
expr = transformFieldInitializer(expr); expr = transformFieldInitializer(field, expr);
if (expr == null) if (expr == null)
return -1; return -1;
@ -772,9 +817,6 @@ public class TransformConstructors {
GlobalOptions.err.println(" field " + pfo.getFieldName() GlobalOptions.err.println(" field " + pfo.getFieldName()
+ " = " + expr); + " = " + expr);
int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
pfo.getFieldType());
// if field does not exists: -1 <= lastField. // if field does not exists: -1 <= lastField.
if (field <= lastField if (field <= lastField
|| !(clazzAnalyzer.getField(field).setInitializer(expr))) { || !(clazzAnalyzer.getField(field).setInitializer(expr))) {

File diff suppressed because it is too large Load Diff

@ -207,19 +207,17 @@ public class CodeVerifier implements Opcodes {
dimensions++; dimensions++;
} }
if (c1 == '[' || c2 == '[') { // One of them is array now, the other is an object,
// Only one of them is array now, the other must be an // the common super is tObject
// object, the common super is tObject if ((c1 == '[' && c2 == 'L')
if (c1 == 'L' || c2 == 'L') { || (c1 == 'L' && c2 == '[')) {
if (dimensions == 0) if (dimensions == 0)
return tObject; return tObject;
StringBuffer result = new StringBuffer(dimensions + 18); StringBuffer result = new StringBuffer(dimensions + 18);
for (int i=0; i< dimensions; i++) for (int i=0; i< dimensions; i++)
result.append("["); result.append("[");
result.append("Ljava/lang/Object;"); result.append("Ljava/lang/Object;");
return tType(result.toString()); return tType(result.toString());
}
return tNone;
} }
if (c1 == 'L' && c2 == 'L') { if (c1 == 'L' && c2 == 'L') {
@ -240,6 +238,18 @@ public class CodeVerifier implements Opcodes {
.append(clazz1.getName().replace('.', '/')).append(";"); .append(clazz1.getName().replace('.', '/')).append(";");
return tType(result.toString()); return tType(result.toString());
} }
// Both were arrays, but of different primitive types. The
// common super is tObject with one dimension less.
if (dimensions > 0) {
if (dimensions == 1)
return tObject;
StringBuffer result = new StringBuffer(dimensions + 17);
for (int i=0; i < dimensions - 1; i++)
result.append("[");
result.append("Ljava/lang/Object;");
return tType(result.toString());
}
return tNone; return tNone;
} }
@ -1044,21 +1054,6 @@ public class CodeVerifier implements Opcodes {
} }
if (instr.getSuccs() != null) { if (instr.getSuccs() != null) {
for (int i=0; i< instr.getSuccs().length; i++) { for (int i=0; i< instr.getSuccs().length; i++) {
if (instr.getSuccs()[i].getAddr() < instr.getAddr()) {
/* This is a backwards branch */
for (int j = 0; j < prevInfo.locals.length; j++) {
if (prevInfo.locals[j]
.getTypeSig().charAt(0) == 'N')
throw new VerifyException
("Uninitialized local in back-branch");
}
for (int j = 0; j < prevInfo.stackHeight; j++) {
if (prevInfo.stack[j]
.getTypeSig().charAt(0) == 'N')
throw new VerifyException
("Uninitialized stack in back-branch");
}
}
if (mergeInfo(instr.getSuccs()[i], if (mergeInfo(instr.getSuccs()[i],
(VerifyInfo) info.clone())) (VerifyInfo) info.clone()))
todoSet.add(instr.getSuccs()[i]); todoSet.add(instr.getSuccs()[i]);
@ -1067,12 +1062,6 @@ public class CodeVerifier implements Opcodes {
for (int i=0; i<handlers.length; i++) { for (int i=0; i<handlers.length; i++) {
if (handlers[i].start.compareTo(instr) <= 0 if (handlers[i].start.compareTo(instr) <= 0
&& handlers[i].end.compareTo(instr) >= 0) { && handlers[i].end.compareTo(instr) >= 0) {
for (int j = 0; j < prevInfo.locals.length; j++) {
if (prevInfo.locals[j]
.getTypeSig().charAt(0) == 'N')
throw new VerifyException
("Uninitialized local in try block");
}
VerifyInfo excInfo = (VerifyInfo) prevInfo.clone(); VerifyInfo excInfo = (VerifyInfo) prevInfo.clone();
excInfo.stackHeight = 1; excInfo.stackHeight = 1;
if (handlers[i].type != null) if (handlers[i].type != null)

@ -27,6 +27,7 @@ import jode.bytecode.Instruction;
import jode.bytecode.MethodInfo; import jode.bytecode.MethodInfo;
import jode.bytecode.Opcodes; import jode.bytecode.Opcodes;
import jode.bytecode.Reference; import jode.bytecode.Reference;
import jode.bytecode.TypeSignature;
import jode.type.Type; import jode.type.Type;
import jode.type.MethodType; import jode.type.MethodType;
@ -44,10 +45,13 @@ public class SyntheticAnalyzer implements Opcodes {
public final static int ACCESSPUTSTATIC = 6; public final static int ACCESSPUTSTATIC = 6;
public final static int ACCESSSTATICMETHOD = 7; public final static int ACCESSSTATICMETHOD = 7;
public final static int ACCESSCONSTRUCTOR = 8; public final static int ACCESSCONSTRUCTOR = 8;
public final static int ACCESSDUPPUTFIELD = 9;
public final static int ACCESSDUPPUTSTATIC = 10;
int kind = UNKNOWN; int kind = UNKNOWN;
Reference reference; Reference reference;
MethodInfo method; MethodInfo method;
int unifyParam = -1;
public SyntheticAnalyzer(MethodInfo method, boolean checkName) { public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
this.method = method; this.method = method;
@ -72,6 +76,14 @@ public class SyntheticAnalyzer implements Opcodes {
return reference; return reference;
} }
/**
* Gets the index of the dummy parameter for an ACCESSCONSTRUCTOR.
* Normally the 1 but for inner classes it may be 2.
*/
public int getUnifyParam() {
return unifyParam;
}
private static final int[] getClassOpcodes = { private static final int[] getClassOpcodes = {
opc_aload, opc_invokestatic, opc_areturn, opc_aload, opc_invokestatic, opc_areturn,
opc_astore, opc_new, opc_dup, opc_aload, opc_astore, opc_new, opc_dup, opc_aload,
@ -131,25 +143,23 @@ public class SyntheticAnalyzer implements Opcodes {
return true; return true;
} }
private final int modifierMask = (Modifier.PRIVATE | Modifier.PROTECTED | private final int modifierMask = Modifier.PUBLIC | Modifier.STATIC;
Modifier.PUBLIC | Modifier.STATIC);
public boolean checkStaticAccess() { public boolean checkStaticAccess() {
ClassInfo clazzInfo = method.getClazzInfo(); ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode(); BytecodeInfo bytecode = method.getBytecode();
Iterator iter = bytecode.getInstructions().iterator(); Iterator iter = bytecode.getInstructions().iterator();
boolean dupSeen = false;
Instruction instr = (Instruction) iter.next(); Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getstatic) { if (instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
FieldInfo refField FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType()); = refClazz.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
(Modifier.PRIVATE | Modifier.STATIC))
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn if (instr.getOpcode() < opc_ireturn
@ -169,38 +179,50 @@ public class SyntheticAnalyzer implements Opcodes {
|| instr.getOpcode() == opc_dload) ? 2 : 1; || instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
} }
if (instr.getOpcode() == (opc_dup - 3) + 3 * slot) {
/* This is probably a opc_dup or opc_dup2,
* preceding a opc_putstatic
*/
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_putstatic)
return false;
dupSeen = true;
}
if (instr.getOpcode() == opc_putstatic) { if (instr.getOpcode() == opc_putstatic) {
if (params != 1) if (params != 1)
return false; return false;
/* For valid bytecode the type of param matches automatically */ /* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
FieldInfo refField FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType()); = refClazz.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
(Modifier.PRIVATE | Modifier.STATIC))
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return) if (dupSeen) {
return false; if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
kind = ACCESSDUPPUTSTATIC;
} else {
if (instr.getOpcode() != opc_return)
return false;
kind = ACCESSPUTSTATIC;
}
reference = ref; reference = ref;
kind = ACCESSPUTSTATIC;
return true; return true;
} }
if (instr.getOpcode() == opc_invokestatic) { if (instr.getOpcode() == opc_invokestatic) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
MethodInfo refMethod MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType()); = refClazz.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType()); MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != if ((refMethod.getModifiers() & modifierMask) != Modifier.STATIC
(Modifier.PRIVATE | Modifier.STATIC)
|| refType.getParameterTypes().length != params) || refType.getParameterTypes().length != params)
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
@ -225,6 +247,7 @@ public class SyntheticAnalyzer implements Opcodes {
ClassInfo clazzInfo = method.getClazzInfo(); ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode(); BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers(); Handler[] excHandlers = bytecode.getExceptionHandlers();
boolean dupSeen = false;
if (excHandlers != null && excHandlers.length != 0) if (excHandlers != null && excHandlers.length != 0)
return false; return false;
@ -241,13 +264,12 @@ public class SyntheticAnalyzer implements Opcodes {
if (instr.getOpcode() == opc_getfield) { if (instr.getOpcode() == opc_getfield) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
FieldInfo refField FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType()); = refClazz.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE) if ((refField.getModifiers() & modifierMask) != 0)
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn if (instr.getOpcode() < opc_ireturn
@ -267,36 +289,51 @@ public class SyntheticAnalyzer implements Opcodes {
|| instr.getOpcode() == opc_dload) ? 2 : 1; || instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
} }
if (instr.getOpcode() == (opc_dup_x1 - 6) + 3 * slot) {
/* This is probably a opc_dup_x1 or opc_dup2_x1,
* preceding a opc_putfield
*/
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_putfield)
return false;
dupSeen = true;
}
if (instr.getOpcode() == opc_putfield) { if (instr.getOpcode() == opc_putfield) {
if (params != 1) if (params != 1)
return false; return false;
/* For valid bytecode the type of param matches automatically */ /* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
FieldInfo refField FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType()); = refClazz.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE) if ((refField.getModifiers() & modifierMask) != 0)
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return) if (dupSeen) {
return false; if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
kind = ACCESSDUPPUTFIELD;
} else {
if (instr.getOpcode() != opc_return)
return false;
kind = ACCESSPUTFIELD;
}
reference = ref; reference = ref;
kind = ACCESSPUTFIELD;
return true; return true;
} }
if (instr.getOpcode() == opc_invokespecial) { if (instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (!refClazz.superClassOf(clazzInfo))
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
MethodInfo refMethod MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType()); = refClazz.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType()); MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE if ((refMethod.getModifiers() & modifierMask) != 0
|| refType.getParameterTypes().length != params) || refType.getParameterTypes().length != params)
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
@ -320,45 +357,60 @@ public class SyntheticAnalyzer implements Opcodes {
public boolean checkConstructorAccess() { public boolean checkConstructorAccess() {
ClassInfo clazzInfo = method.getClazzInfo(); ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode(); BytecodeInfo bytecode = method.getBytecode();
String[] paramTypes
= TypeSignature.getParameterTypes(method.getType());
Handler[] excHandlers = bytecode.getExceptionHandlers(); Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0) if (excHandlers != null && excHandlers.length != 0)
return false; return false;
Iterator iter = bytecode.getInstructions().iterator(); 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 Instruction instr = (Instruction) iter.next();
// is used so that the constructor has a different type signature. int params = 0, slot = 0;
int params = 0, slot = 2;
while (instr.getOpcode() >= opc_iload while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload && instr.getOpcode() <= opc_aload) {
&& instr.getLocalSlot() == slot) {
if (instr.getLocalSlot() > slot
&& unifyParam == -1 && params > 0
&& paramTypes[params - 1].charAt(0) == 'L') {
unifyParam = params;
params++;
slot++;
}
if (instr.getLocalSlot() != slot)
return false;
params++; params++;
slot += (instr.getOpcode() == opc_lload slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1; || instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
} }
if (instr.getOpcode() == opc_invokespecial) { if (params > 0 && instr.getOpcode() == opc_invokespecial) {
if (unifyParam == -1 && params <= paramTypes.length
&& paramTypes[params - 1].charAt(0) == 'L')
unifyParam = params++;
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1); ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
if (!(refClazz.substring(0, refClazz.length()-1) if (refClazz != clazzInfo)
.equals(clazzInfo.getName().replace('.','/'))))
return false; return false;
MethodInfo refMethod MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType()); = refClazz.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType()); MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE if ((refMethod.getModifiers() & modifierMask) != 0
|| !refMethod.getName().equals("<init>") || !refMethod.getName().equals("<init>")
|| refType.getParameterTypes().length != params) || unifyParam == -1
|| refType.getParameterTypes().length != params - 2)
return false; return false;
instr = (Instruction) iter.next(); instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return) if (instr.getOpcode() != opc_return)
return false; return false;
/* For valid bytecode the types matches automatically */ /* We don't check if types matches. No problem since we only
* need to make sure, this constructor doesn't do anything
* more than relay to the real one.
*/
reference = ref; reference = ref;
kind = ACCESSCONSTRUCTOR; kind = ACCESSCONSTRUCTOR;
return true; return true;

@ -38,7 +38,7 @@ import @COLLECTIONS@.TreeMap;
import @COLLECTIONEXTRA@.UnsupportedOperationException; import @COLLECTIONEXTRA@.UnsupportedOperationException;
///#ifdef JDK12 ///#ifdef JDK12
///import @COLLECTIONS@.WeakHashMap; import @COLLECTIONS@.WeakHashMap;
///#endif ///#endif
public class ClassBundle implements OptionHandler { public class ClassBundle implements OptionHandler {
@ -74,9 +74,9 @@ public class ClassBundle implements OptionHandler {
} }
///#ifdef JDK12 ///#ifdef JDK12
/// private static final Map aliasesHash = new WeakHashMap(); private static final Map aliasesHash = new WeakHashMap();
///#else ///#else
private static final Map aliasesHash = new HashMap(); /// private static final Map aliasesHash = new HashMap();
///#endif ///#endif
private static final Map clazzCache = new HashMap(); private static final Map clazzCache = new HashMap();
private static final Map referenceCache = new HashMap(); private static final Map referenceCache = new HashMap();
@ -248,6 +248,13 @@ public class ClassBundle implements OptionHandler {
return alias; return alias;
} }
public String getClassAlias(String className) {
ClassIdentifier classIdent = getClassIdentifier(className);
if (classIdent == null)
return className;
return classIdent.getFullAlias();
}
public String getTypeAlias(String typeSig) { public String getTypeAlias(String typeSig) {
String alias = (String) aliasesHash.get(typeSig); String alias = (String) aliasesHash.get(typeSig);
if (alias == null) { if (alias == null) {
@ -256,7 +263,7 @@ public class ClassBundle implements OptionHandler {
while ((nextindex = typeSig.indexOf('L', index)) != -1) { while ((nextindex = typeSig.indexOf('L', index)) != -1) {
newSig.append(typeSig.substring(index, nextindex+1)); newSig.append(typeSig.substring(index, nextindex+1));
index = typeSig.indexOf(';', nextindex); index = typeSig.indexOf(';', nextindex);
String typeAlias = basePackage.findAlias String typeAlias = getClassAlias
(typeSig.substring(nextindex+1, index).replace('/','.')); (typeSig.substring(nextindex+1, index).replace('/','.'));
newSig.append(typeAlias.replace('.', '/')); newSig.append(typeAlias.replace('.', '/'));
} }

@ -401,15 +401,11 @@ public class ClassIdentifier extends Identifier {
ifaceNames = new String[ifaces.length]; ifaceNames = new String[ifaces.length];
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
ifaceNames[i] = ifaces[i].getName(); ifaceNames[i] = ifaces[i].getName();
ClassIdentifier ifaceident = Main.getClassBundle()
.getClassIdentifier(ifaceNames[i]);
initSuperClasses(ifaces[i]); initSuperClasses(ifaces[i]);
} }
if (info.getSuperclass() != null) { if (info.getSuperclass() != null) {
superName = info.getSuperclass().getName(); superName = info.getSuperclass().getName();
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superName);
initSuperClasses(info.getSuperclass()); initSuperClasses(info.getSuperclass());
} }
@ -458,11 +454,10 @@ public class ClassIdentifier extends Identifier {
* @param ancestor The ancestor whose interfaces should be added. * @param ancestor The ancestor whose interfaces should be added.
*/ */
public void addIfaces(Collection result, ClassIdentifier ancestor) { public void addIfaces(Collection result, ClassIdentifier ancestor) {
String[] ifaces = ancestor.ifaceNames;
ClassInfo[] ifaceInfos = ancestor.info.getInterfaces(); ClassInfo[] ifaceInfos = ancestor.info.getInterfaces();
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaceInfos.length; i++) {
ClassIdentifier ifaceident ClassIdentifier ifaceident
= Main.getClassBundle().getClassIdentifier(ifaces[i]); = Main.getClassBundle().getClassIdentifier(ifaceInfos[i].getName());
if (ifaceident != null && !ifaceident.isReachable()) if (ifaceident != null && !ifaceident.isReachable())
addIfaces(result, ifaceident); addIfaces(result, ifaceident);
else else

@ -310,21 +310,6 @@ public class PackageIdentifier extends Identifier {
return ""; return "";
} }
public String findAlias(String className) {
int index = className.indexOf('.');
if (index == -1) {
Identifier ident = getIdentifier(className);
if (ident != null)
return ident.getFullAlias();
} else {
Identifier pack = getIdentifier(className.substring(0, index));
if (pack != null)
return ((PackageIdentifier)pack)
.findAlias(className.substring(index+1));
}
return className;
}
public void buildTable(Renamer renameRule) { public void buildTable(Renamer renameRule) {
loadOnDemand = false; loadOnDemand = false;
super.buildTable(renameRule); super.buildTable(renameRule);

@ -24,7 +24,7 @@ import @COLLECTIONS@.TreeMap;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
///#ifndef JDK12 ///#ifndef JDK12
import @COLLECTIONS@.Comparator; ///import @COLLECTIONS@.Comparator;
///#endif ///#endif
import java.io.InputStream; import java.io.InputStream;
@ -37,17 +37,17 @@ import java.io.IOException;
public class TranslationTable extends TreeMap { public class TranslationTable extends TreeMap {
///#ifndef JDK12 ///#ifndef JDK12
public TranslationTable() { /// public TranslationTable() {
super(createStringComparator()); /// super(createStringComparator());
} /// }
///
private static Comparator createStringComparator() { /// private static Comparator createStringComparator() {
return new Comparator() { /// return new Comparator() {
public int compare(Object o1, Object o2) { /// public int compare(Object o1, Object o2) {
return ((String) o1).compareTo((String) o2); /// return ((String) o1).compareTo((String) o2);
} /// }
}; /// };
} /// }
///#endif ///#endif
public void load(InputStream in) throws IOException { public void load(InputStream in) throws IOException {

@ -734,9 +734,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
boolean known = value1.value != ConstValue.VOLATILE boolean known = value1.value != ConstValue.VOLATILE
&& value2.value != ConstValue.VOLATILE; && value2.value != ConstValue.VOLATILE;
if (known) { if (known) {
if ((opcode == opc_idiv if (((opcode == opc_idiv || opcode == opc_irem)
&& ((Integer)value2.value).intValue() == 0) && ((Integer)value2.value).intValue() == 0)
|| (opcode == opc_ldiv || ((opcode == opc_ldiv || opcode == opc_lrem)
&& ((Long)value2.value).longValue() == 0)) && ((Long)value2.value).longValue() == 0))
known = false; known = false;
} }
@ -1522,10 +1522,6 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_ineg: case opc_fneg: case opc_ineg: case opc_fneg:
iter.set(new Instruction(opc_pop)); iter.set(new Instruction(opc_pop));
break; break;
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_lcmp: case opc_lcmp:
case opc_dcmpg: case opc_dcmpl: case opc_dcmpg: case opc_dcmpl:
case opc_ladd: case opc_dadd: case opc_ladd: case opc_dadd:
@ -1535,7 +1531,12 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_lrem: case opc_drem: case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor: case opc_land: case opc_lor : case opc_lxor:
iter.set(new Instruction(opc_pop2)); iter.set(new Instruction(opc_pop2));
/* fall through */ iter.add(new Instruction(opc_pop2));
break;
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_fcmpg: case opc_fcmpl: case opc_fcmpg: case opc_fcmpl:
case opc_l2i: case opc_l2f: case opc_l2d: case opc_l2i: case opc_l2f: case opc_l2d:
case opc_d2i: case opc_d2l: case opc_d2f: case opc_d2i: case opc_d2l: case opc_d2f:
@ -1574,14 +1575,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_invokevirtual: { case opc_invokevirtual: {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
String[] pt = TypeSignature.getParameterTypes(ref.getType()); String[] pt = TypeSignature.getParameterTypes(ref.getType());
int arg = 0; int len = pt.length;
if (instr.getOpcode() != opc_invokestatic)
iter.set(new Instruction(opc_pop)); if (len > 0)
else if (pt.length > 0) { iter.set(new Instruction(TypeSignature.getTypeSize(pt[--len])
iter.set(new Instruction(TypeSignature.getTypeSize(pt[0])
+ opc_pop - 1)); + opc_pop - 1));
arg++; else if (instr.getOpcode() != opc_invokestatic)
} else { iter.set(new Instruction(opc_pop));
else {
if (replacement == null) if (replacement == null)
iter.remove(); iter.remove();
else else
@ -1589,7 +1590,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
return; return;
} }
for (int i=arg; i < pt.length; i++) for (int i = len - 1; i >= 0; i++)
iter.add(new Instruction(TypeSignature.getTypeSize(pt[i]) iter.add(new Instruction(TypeSignature.getTypeSize(pt[i])
+ opc_pop - 1)); + opc_pop - 1));
} }

@ -657,17 +657,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
*/ */
distributeLocals(locals); distributeLocals(locals);
/* Update the instructions and calculate new maxlocals. /* Update the instructions.
*/ */
maxlocals = paramLocals.length;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) { 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); info.instr.setLocalSlot(info.local.newSlot);
}
} }
bc.setMaxLocals(maxlocals);
/* Update LocalVariableTable /* Update LocalVariableTable
*/ */

@ -109,7 +109,7 @@ public class ModifierMatcher implements IdentifierMatcher, OptionHandler, Clonea
: str.equals("NATIVE") ? Modifier.NATIVE : str.equals("NATIVE") ? Modifier.NATIVE
: str.equals("STATIC") ? Modifier.STATIC : str.equals("STATIC") ? Modifier.STATIC
///#ifdef JDK12 ///#ifdef JDK12
/// : str.equals("STRICT") ? Modifier.STRICT : str.equals("STRICT") ? Modifier.STRICT
///#endif ///#endif
: str.equals("SYNCHRONIZED") ? Modifier.SYNCHRONIZED : str.equals("SYNCHRONIZED") ? Modifier.SYNCHRONIZED
: str.equals("TRANSIENT") ? Modifier.TRANSIENT : str.equals("TRANSIENT") ? Modifier.TRANSIENT

@ -79,9 +79,11 @@ public class Main
classTree.addTreeSelectionListener(this); classTree.addTreeSelectionListener(this);
JScrollPane spClassTree = new JScrollPane(classTree); JScrollPane spClassTree = new JScrollPane(classTree);
sourcecodeArea = new JTextArea(20, 80); sourcecodeArea = new JTextArea(20, 80);
sourcecodeArea.setEditable(false);
sourcecodeArea.setFont(monospaced); sourcecodeArea.setFont(monospaced);
JScrollPane spText = new JScrollPane(sourcecodeArea); JScrollPane spText = new JScrollPane(sourcecodeArea);
errorArea = new JTextArea(3, 80); errorArea = new JTextArea(3, 80);
errorArea.setEditable(false);
errorArea.setFont(monospaced); errorArea.setFont(monospaced);
JScrollPane spError = new JScrollPane(errorArea); JScrollPane spError = new JScrollPane(errorArea);
@ -141,6 +143,7 @@ public class Main
public class AreaWriter extends Writer { public class AreaWriter extends Writer {
boolean initialized = false; boolean initialized = false;
boolean lastCR = false;
private JTextArea area; private JTextArea area;
public AreaWriter(JTextArea a) { public AreaWriter(JTextArea a) {
@ -153,7 +156,23 @@ public class Main
area.setText(""); area.setText("");
initialized = true; initialized = true;
} }
area.append(new String(b, off, len)); String str = new String(b, off, len);
StringBuffer sb = new StringBuffer(len);
while (str != null && str.length() > 0) {
if (lastCR && str.charAt(0) == '\n')
str = str.substring(1);
int crIndex = str.indexOf('\r');
if (crIndex >= 0) {
sb.append(str.substring(0, crIndex));
sb.append("\n");
str = str.substring(crIndex+1);
lastCR = true;
} else {
sb.append(str);
str = null;
}
}
area.append(sb.toString());
} }
public void flush() { public void flush() {
@ -325,16 +344,42 @@ public class Main
} }
} }
} }
public static void usage() {
System.err.println("Usage: java jode.swingui.Main [CLASSPATH]");
System.err.println("The directories in CLASSPATH should be separated by ','.");
System.err.println("If no CLASSPATH is given the virtual machine classpath is used.");
}
public static void main(String[] params) { public static void main(String[] params) {
String cp = System.getProperty("java.class.path", ""); String cp = System.getProperty("java.class.path", "");
cp = cp.replace(File.pathSeparatorChar, cp = cp.replace(File.pathSeparatorChar,
Decompiler.altPathSeparatorChar); Decompiler.altPathSeparatorChar);
for (int i=0; i<params.length; i++) { String bootClassPath = System.getProperty("sun.boot.class.path");
if (params[i].equals("--classpath")) if (bootClassPath != null)
cp += Decompiler.altPathSeparatorChar
+ bootClassPath.replace(File.pathSeparatorChar,
Decompiler.altPathSeparatorChar);
int i = 0;
if (i < params.length) {
if (params[i].equals("--classpath")
|| params[i].equals("--cp")
|| params[i].equals("-c"))
cp = params[++i]; cp = params[++i];
else else if (params[i].startsWith("-")) {
if (!params[i].equals("--help")
&& !params[i].equals("-h"))
System.err.println("Unknown option: "+params[i]);
usage();
return; return;
} else
cp = params[i];
i++;
}
if (i < params.length) {
System.err.println("Too many arguments.");
usage();
return;
} }
Main win = new Main(cp); Main win = new Main(cp);
win.show(); win.show();

@ -47,12 +47,18 @@ public class ArrayType extends ReferenceType {
} }
public Type getSuperType() { public Type getSuperType() {
return tRange(tObject, if (elementType instanceof IntegerType)
(ReferenceType) tArray(elementType.getSuperType())); return tRange(tObject, this);
else
return tRange(tObject,
(ReferenceType) tArray(elementType.getSuperType()));
} }
public Type getSubType() { public Type getSubType() {
return tArray(elementType.getSubType()); if (elementType instanceof IntegerType)
return this;
else
return tArray(elementType.getSubType());
} }
public Type getHint() { public Type getHint() {
@ -69,11 +75,11 @@ public class ArrayType extends ReferenceType {
* @return the range type, or tError if not possible. * @return the range type, or tError if not possible.
*/ */
public Type createRangeType(ReferenceType bottom) { public Type createRangeType(ReferenceType bottom) {
/* /*
* tArray(y), tArray(x) -> tArray( y.intersection(x) ) * tArray(y), tArray(x) -> tArray( y.intersection(x) )
* obj , tArray(x) -> <obj, tArray(x)> * obj , tArray(x) -> <obj, tArray(x)>
* iff tArray extends and implements obj * iff tArray extends and implements obj
*/ */
if (bottom.getTypeCode() == TC_ARRAY) if (bottom.getTypeCode() == TC_ARRAY)
return tArray(elementType.intersection return tArray(elementType.intersection
(((ArrayType)bottom).elementType)); (((ArrayType)bottom).elementType));
@ -93,19 +99,20 @@ public class ArrayType extends ReferenceType {
* @return the common sub type. * @return the common sub type.
*/ */
public Type getSpecializedType(Type type) { public Type getSpecializedType(Type type) {
/* /*
* tArray(x), object -> tArray(x) iff tArray implements object * tArray(x), iface -> tArray(x) iff tArray implements iface
* tArray(x), tArray(y) -> tArray(x.intersection(y)) * tArray(x), tArray(y) -> tArray(x.intersection(y))
* tArray(x), other -> tError * tArray(x), other -> tError
*/ */
if (type.getTypeCode() == TC_RANGE) { if (type.getTypeCode() == TC_RANGE) {
type = ((RangeType) type).getBottom(); type = ((RangeType) type).getBottom();
} }
if (type == tNull) if (type == tNull)
return this; return this;
if (type.getTypeCode() == TC_ARRAY) { if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
return elType != tError ? tArray(elType) : tError;
} }
if (type.getTypeCode() == TC_CLASS) { if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type; ClassInterfacesType other = (ClassInterfacesType) type;
@ -122,19 +129,23 @@ public class ArrayType extends ReferenceType {
* @return the common super type. * @return the common super type.
*/ */
public Type getGeneralizedType(Type type) { public Type getGeneralizedType(Type type) {
/* tArray(x), tNull -> tArray(x) /* tArray(x), tNull -> tArray(x)
* tArray(x), tClass(y) -> common ifaces of tArray and tClass * tArray(x), tClass(y) -> common ifaces of tArray and tClass
* tArray(x), tArray(y) -> tArray(x.intersection(y)) * tArray(x), tArray(y) -> tArray(x.intersection(y)) or tObject
* tArray(x), other -> tError * tArray(x), other -> tError
*/ */
if (type.getTypeCode() == TC_RANGE) { if (type.getTypeCode() == TC_RANGE) {
type = ((RangeType) type).getTop(); type = ((RangeType) type).getTop();
} }
if (type == tNull) if (type == tNull)
return this; return this;
if (type.getTypeCode() == TC_ARRAY) if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
if (elType != tError)
return tArray(elType);
return ClassInterfacesType.create(null, arrayIfaces);
}
if (type.getTypeCode() == TC_CLASS) { if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type; ClassInterfacesType other = (ClassInterfacesType) type;
if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces)) if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces))

@ -509,34 +509,57 @@ public class ClassInterfacesType extends ReferenceType {
private final static Hashtable keywords = new Hashtable(); private final static Hashtable keywords = new Hashtable();
static { static {
keywords.put("abstract", Boolean.TRUE);
keywords.put("default", Boolean.TRUE);
keywords.put("if", Boolean.TRUE); keywords.put("if", Boolean.TRUE);
keywords.put("else", Boolean.TRUE); keywords.put("private", Boolean.TRUE);
keywords.put("for", Boolean.TRUE);
keywords.put("while", Boolean.TRUE);
keywords.put("throw", Boolean.TRUE); keywords.put("throw", Boolean.TRUE);
keywords.put("return", Boolean.TRUE); keywords.put("boolean", Boolean.TRUE);
keywords.put("class", Boolean.TRUE); keywords.put("do", Boolean.TRUE);
keywords.put("interface", Boolean.TRUE);
keywords.put("implements", Boolean.TRUE); keywords.put("implements", Boolean.TRUE);
keywords.put("extends", Boolean.TRUE); keywords.put("protected", Boolean.TRUE);
keywords.put("throws", Boolean.TRUE);
keywords.put("break", Boolean.TRUE);
keywords.put("double", Boolean.TRUE);
keywords.put("import", Boolean.TRUE);
keywords.put("public", Boolean.TRUE);
keywords.put("transient", Boolean.TRUE);
keywords.put("byte", Boolean.TRUE);
keywords.put("else", Boolean.TRUE);
keywords.put("instanceof", Boolean.TRUE); keywords.put("instanceof", Boolean.TRUE);
keywords.put("new", Boolean.TRUE); keywords.put("return", Boolean.TRUE);
keywords.put("try", Boolean.TRUE);
keywords.put("case", Boolean.TRUE);
keywords.put("extends", Boolean.TRUE);
keywords.put("int", Boolean.TRUE); keywords.put("int", Boolean.TRUE);
keywords.put("boolean", Boolean.TRUE);
keywords.put("long", Boolean.TRUE);
keywords.put("float", Boolean.TRUE);
keywords.put("double", Boolean.TRUE);
keywords.put("short", Boolean.TRUE); keywords.put("short", Boolean.TRUE);
keywords.put("public", Boolean.TRUE); keywords.put("void", Boolean.TRUE);
keywords.put("protected", Boolean.TRUE); keywords.put("catch", Boolean.TRUE);
keywords.put("private", Boolean.TRUE); keywords.put("final", Boolean.TRUE);
keywords.put("interface", Boolean.TRUE);
keywords.put("static", Boolean.TRUE); keywords.put("static", Boolean.TRUE);
keywords.put("synchronized", Boolean.TRUE);
keywords.put("strict", Boolean.TRUE);
keywords.put("transient", Boolean.TRUE);
keywords.put("abstract", Boolean.TRUE);
keywords.put("volatile", Boolean.TRUE); keywords.put("volatile", Boolean.TRUE);
keywords.put("final", Boolean.TRUE); keywords.put("char", Boolean.TRUE);
keywords.put("finally", Boolean.TRUE);
keywords.put("long", Boolean.TRUE);
keywords.put("super", Boolean.TRUE);
keywords.put("while", Boolean.TRUE);
keywords.put("class", Boolean.TRUE);
keywords.put("float", Boolean.TRUE);
keywords.put("native", Boolean.TRUE);
keywords.put("switch", Boolean.TRUE);
keywords.put("const", Boolean.TRUE);
keywords.put("for", Boolean.TRUE);
keywords.put("new", Boolean.TRUE);
keywords.put("synchronized", Boolean.TRUE);
keywords.put("continue", Boolean.TRUE);
keywords.put("goto", Boolean.TRUE);
keywords.put("package", Boolean.TRUE);
keywords.put("this", Boolean.TRUE);
keywords.put("strictfp", Boolean.TRUE);
keywords.put("null", Boolean.TRUE);
keywords.put("true", Boolean.TRUE);
keywords.put("false", Boolean.TRUE);
} }
/** /**

@ -71,15 +71,4 @@ public class NullType extends ReferenceType {
public String toString() { public String toString() {
return "tNull"; return "tNull";
} }
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == this)
return type;
return tError;
}
} }

@ -107,13 +107,18 @@ public class RangeType extends Type {
/** /**
* Returns the hint type of this range type set. This returns the * Returns the hint type of this range type set. This returns the
* singleton set containing only the first top type, except if it * singleton set containing only the first top type, except if it
* is null and there is a unique bottom type, in which case it returns * is null and there is a unique bottom type, in which case it
* the bottom type. * returns the bottom type.
* @return the hint type. * @return the hint type.
*/ */
public Type getHint() { public Type getHint() {
return topType == tNull && bottomType.equals(bottomType.getHint()) Type bottomHint = bottomType.getHint();
? bottomType.getHint(): topType.getHint(); Type topHint = topType.getHint();
if (topType == tNull && bottomType.equals(bottomHint))
return bottomHint;
return topHint;
} }
/** /**

@ -1,4 +1,4 @@
/* UnifyHash Copyright (C) 1999 Jochen Hoenicke. /* UnifyHash Copyright (C) 1999-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
package jode.util; package jode.util;
///#ifdef JDK12 ///#ifdef JDK12
///import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
///#endif ///#endif
import @COLLECTIONS@.Comparator; import @COLLECTIONS@.Comparator;
@ -40,28 +40,28 @@ public class UnifyHash extends AbstractCollection {
private static final float DEFAULT_LOAD_FACTOR = 0.75F; private static final float DEFAULT_LOAD_FACTOR = 0.75F;
///#ifdef JDK12 ///#ifdef JDK12
/// private ReferenceQueue queue = new ReferenceQueue(); private ReferenceQueue queue = new ReferenceQueue();
///#endif ///#endif
static class Bucket static class Bucket
///#ifdef JDK12 ///#ifdef JDK12
/// extends WeakReference extends WeakReference
///#endif ///#endif
{ {
///#ifdef JDK12 ///#ifdef JDK12
/// public Bucket(Object o, ReferenceQueue q) { public Bucket(Object o, ReferenceQueue q) {
/// super(o, q); super(o, q);
/// }
///#else
public Bucket(Object o) {
this.obj = o;
}
Object obj;
public Object get() {
return obj;
} }
///#else
/// public Bucket(Object o) {
/// this.obj = o;
/// }
///
/// Object obj;
///
/// public Object get() {
/// return obj;
/// }
///#endif ///#endif
int hash; int hash;
@ -107,21 +107,21 @@ public class UnifyHash extends AbstractCollection {
} }
///#ifdef JDK12 ///#ifdef JDK12
/// public final void cleanUp() { public final void cleanUp() {
/// Bucket died; Bucket died;
/// while ((died = (Bucket)queue.poll()) != null) { while ((died = (Bucket)queue.poll()) != null) {
/// int diedSlot = Math.abs(died.hash % buckets.length); int diedSlot = Math.abs(died.hash % buckets.length);
/// if (buckets[diedSlot] == died) if (buckets[diedSlot] == died)
/// buckets[diedSlot] = died.next; buckets[diedSlot] = died.next;
/// else { else {
/// Bucket b = buckets[diedSlot]; Bucket b = buckets[diedSlot];
/// while (b.next != died) while (b.next != died)
/// b = b.next; b = b.next;
/// b.next = died.next; b.next = died.next;
/// } }
/// size--; size--;
/// } }
/// } }
///#endif ///#endif
@ -131,7 +131,7 @@ public class UnifyHash extends AbstractCollection {
public Iterator iterator() { public Iterator iterator() {
///#ifdef JDK12 ///#ifdef JDK12
/// cleanUp(); cleanUp();
///#endif ///#endif
return new Iterator() { return new Iterator() {
@ -182,6 +182,9 @@ public class UnifyHash extends AbstractCollection {
} }
public Iterator iterateHashCode(final int hash) { public Iterator iterateHashCode(final int hash) {
///#ifdef JDK12
cleanUp();
///#endif
return new Iterator() { return new Iterator() {
private int known = modCount; private int known = modCount;
private Bucket nextBucket private Bucket nextBucket
@ -232,9 +235,9 @@ public class UnifyHash extends AbstractCollection {
int slot = Math.abs(hash % buckets.length); int slot = Math.abs(hash % buckets.length);
///#ifdef JDK12 ///#ifdef JDK12
/// Bucket b = new Bucket(o, queue); Bucket b = new Bucket(o, queue);
///#else ///#else
Bucket b = new Bucket(o); /// Bucket b = new Bucket(o);
///#endif ///#endif
b.hash = hash; b.hash = hash;
b.next = buckets[slot]; b.next = buckets[slot];
@ -243,7 +246,7 @@ public class UnifyHash extends AbstractCollection {
public Object unify(Object o, int hash, Comparator comparator) { public Object unify(Object o, int hash, Comparator comparator) {
///#ifdef JDK12 ///#ifdef JDK12
/// cleanUp(); cleanUp();
///#endif ///#endif
int slot = Math.abs(hash % buckets.length); int slot = Math.abs(hash % buckets.length);
for (Bucket b = buckets[slot]; b != null; b = b.next) { for (Bucket b = buckets[slot]; b != null; b = b.next) {

Loading…
Cancel
Save