This commit was manufactured by cvs2svn to create branch 'stable'.

git-svn-id: https://svn.code.sf.net/p/jode/code/branches/stable@1049 379699f6-c40d-0410-875b-85095c16579e
stable
(no author) 26 years ago
parent 999834f14d
commit e3d7a55d64
  1. 9
      jode/.cvsignore
  2. 1
      jode/AUTHORS
  3. 0
      jode/ChangeLog
  4. 33
      jode/INSTALL
  5. 5
      jode/Makefile.am
  6. 10
      jode/NEWS
  7. 106
      jode/README
  8. 43
      jode/acinclude.m4
  9. 128
      jode/configure.in
  10. 2
      jode/doc/.cvsignore
  11. 5
      jode/doc/Makefile.am
  12. 39
      jode/doc/jode-applet.html
  13. 15
      jode/doc/jode-obfuscator.html
  14. 97
      jode/doc/jode-unix.html
  15. 49
      jode/doc/jode-useapplet.html
  16. 62
      jode/doc/jode-win.html
  17. 125
      jode/doc/jode.html
  18. 4
      jode/jode/.cvsignore
  19. 107
      jode/jode/GlobalOptions.java.in
  20. 231
      jode/jode/Makefile.am
  21. 278
      jode/jode/swingui/Main.java.in
  22. 176
      jode/jode/swingui/PackagesTreeModel.java.in
  23. 2
      jode/test/.cvsignore
  24. 0
      jode/test/Makefile.am

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

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

@ -0,0 +1,33 @@
Before installing, make sure you have a java compiler (e.g javac or
jikes) and the java 1.1 runtime class library installed. If you want
to run this program you need at least a 1.1 compatible java virtual
machine. There are some bugs in javac included in the SUN JDK 1.1, it
won't work.
This package was designed to use the GNU standard for configuration
and makefiles. To build and install do the following:
0). Make sure that you have all libraries that are needed in you
classpath. You need gnu.getopt, and if you have JDK 1.1 you also need
the collection classes and swing for 1.1.
1). Run "aclocal && autoconf && automake --add-missing".
2). Run the "configure" script to configure the package. There are
various options you might want to pass to configure to control how the
package is built. "configure --help" will give a complete list.
If you have jikes, you should specify it with --with-jikes. You can
give a path to the directory where it resides, otherwise it is
searched in the path.
3). Type "make" to build the package. If you don't have jikes, you
should make clean first, since the dependency problem is not yet
resolved.
4). Type "make install" to install everything. This doesn't work yet.
The created jar file is stored in the share directory.
Jochen

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

@ -0,0 +1,10 @@
1.0.90 is a prerelease..
* First version using configure. Jode can now be almost automatically
build, see INSTALL for instructions.
* The decompiler can handler inner and anoymous classes.
* You now need the gnu getopt package.
* You need JDK 1.2 or alternatively the swing and collection packages
for 1.1

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

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

@ -0,0 +1,128 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AM_INIT_AUTOMAKE(jode, 1.0.90)
dnl Checks for programs.
dnl AC_PROG_CXX
dnl AC_PROG_AWK
dnl AC_PROG_CC
dnl AC_PROG_CPP
dnl AC_PROG_INSTALL
dnl AC_PROG_LN_S
AC_PROG_MAKE_SET
dnl AC_PROG_RANLIB
dnl AC_PATH_PROG(ZIP, zip)
AC_PATH_PROG(UNZIP, unzip)
dnl Checks for libraries.
dnl Checks for header files.
dnl Checks for typedefs, structures, and compiler characteristics.
dnl Checks for library functions.
dnl hack to quote Makefile lines
QUOTE=""
AC_SUBST(QUOTE)
AC_SUBST(SHELL)
AC_ARG_WITH(java,
[ --with-java specify path to a java-like program ],
[
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then
# set javac to user input value
JODE_CHECK_JAVA(${withval})
else
JODE_CHECK_JAVA(/usr/lib/java)
fi
],
[
JODE_CHECK_JAVA(/usr/lib/java)
])
dnl jikes can also handle dependancies.
AC_ARG_WITH(jikes,
[ --with-jikes specify location of jikes ],
[
USER_SPECIFIED_JIKES=true
if test "${withval}" = "yes" || test "${withval}" = ""; then
AC_PATH_PROG(JIKES, jikes, "", $PATH)
else
echo "searching jikes in ${withval}:$PATH"
AC_PATH_PROG(JIKES, jikes, "", ${withval}:$PATH)
fi
if test -n "$JIKES"; then
JAVAC=$JIKES
fi
],
[
USER_SPECIFIED_JIKES=
AC_PATH_PROG(JIKES, jikes, "", $PATH)
])
AM_CONDITIONAL(HAVE_JIKES, test x"$JIKES" != x)
AC_ARG_WITH(javac,
[ --with-javac specify location of javac ],
[
if test x$USER_SPECIFIED_JIKES == xtrue; then
AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes)
fi
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then
AC_CHECK_FILES(${withval},
[ JAVAC=${withval} ],
[ AC_MSG_ERROR(${withval} does not exists) ])
fi
], [ true ])
JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB,
[ true ],
[ AC_MSG_ERROR(Please specify location of java class library for jikes) ])
AC_MSG_CHECKING(for collection classes)
JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="java.util" ],
[ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="com.sun.java.util.collections" ],
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(You need the Java 1.2 collection classes in your classpath)
])
] )
AC_MSG_RESULT($COLLECTIONS)
AC_SUBST(COLLECTIONS)
AC_MSG_CHECKING(for gnu.getopt)
JODE_CHECK_CLASS(gnu.getopt.Getopt, $CLASSPATH:$CLASSLIB,
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(You need gnu getopt for java.) ])
AC_MSG_CHECKING(for swing)
JODE_CHECK_CLASS(javax.swing.JFrame, $CLASSPATH:$CLASSLIB,
[ JAVAX_SWING="javax.swing" ],
[ JODE_CHECK_CLASS(com.sun.swing.JFrame, $CLASSPATH:$CLASSLIB,
[ JAVAX_SWING="com.sun.java.swing" ],
[ JAVAX_SWING="no" ]) ] )
AC_MSG_RESULT($JAVAX_SWING)
AC_SUBST(JAVAX_SWING)
if test x"$JAVAX_SWING" != x; then
SWING_CLASSES="jode/swingui/Main.class"
else
AC_MSG_WARN(Swing is not in classpath ... skipping swingui)
SWING_CLASSES=""
fi
AC_SUBST(SWING_CLASSES)
AC_SUBST(CLASSPATH)
AC_SUBST(JAVAC)
AC_OUTPUT(Makefile
jode/Makefile
doc/Makefile
test/Makefile
jode/GlobalOptions.java
jode/swingui/Main.java
jode/swingui/PackagesTreeModel.java)

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

@ -0,0 +1,5 @@
## Input file for automake to generate the Makefile.in used by configure
EXTRA_DIST = \
jode.html jode-applet.html jode-obfuscator.html jode-unix.html \
jode-useapplet.html jode-win.html

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

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

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

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

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

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

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

@ -0,0 +1,107 @@
/* GlobalOptions Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class GlobalOptions {
public final static String version = "@VERSION@";
public final static String email = "jochen@gnu.org";
public final static String copyright =
"Jode (c) 1998,1999 Jochen Hoenicke <"+email+">";
public final static String URL =
"http://www.informatik.uni-oldenburg.de/~delwi/jode/jode.html";
public static PrintWriter err = new PrintWriter(System.err, true);
public static int verboseLevel = 0;
public static int debuggingFlags = 0;
public static final int DEBUG_BYTECODE = 0x001;
public static final int DEBUG_VERIFIER = 0x002;
public static final int DEBUG_TYPES = 0x004;
public static final int DEBUG_FLOW = 0x008;
public static final int DEBUG_INOUT = 0x010;
public static final int DEBUG_ANALYZE = 0x020;
public static final int DEBUG_LVT = 0x040;
public static final int DEBUG_CHECK = 0x080;
public static final int DEBUG_LOCALS = 0x100;
public static final int DEBUG_CONSTRS = 0x200;
public static final int DEBUG_INTERPRT = 0x400;
public static final String[] debuggingNames = {
"bytecode", "verifier", "types", "flow",
"inout", "analyze", "lvt", "check", "locals",
"constructors", "interpreter"
};
public static void usageDebugging() {
err.println("Debugging option: --debug=flag1,flag2,...");
err.println("possible flags:");
err.println(" bytecode " +
"show bytecode, as it is read from class file.");
err.println(" verifier " +
"show result of bytecode verification.");
err.println(" types " +
"show type intersections");
err.println(" flow " +
"show flow block merging.");
err.println(" analyze " +
"show T1/T2 analyzation of flow blocks.");
err.println(" inout " +
"show in/out set analysis.");
err.println(" lvt " +
"dump LocalVariableTable.");
err.println(" check " +
"do time consuming sanity checks.");
err.println(" locals " +
"dump local merging information.");
err.println(" constructors " +
"dump constructor simplification.");
err.println(" interpreter " +
"debug execution of interpreter.");
System.exit(0);
}
/**
* Parse the argument given to the debugging flag.
* @return true, if the argument parsed without problems.
*/
public static boolean setDebugging(String debuggingString) {
if (debuggingString.length() == 0 || debuggingString.equals("help")) {
usageDebugging();
return false;
}
StringTokenizer st = new StringTokenizer(debuggingString, ",");
next_token:
while (st.hasMoreTokens()) {
String token = st.nextToken().intern();
for (int i=0; i<debuggingNames.length; i++) {
if (token == debuggingNames[i]) {
debuggingFlags |= 1 << i;
continue next_token;
}
}
err.println("Illegal debugging flag: "+token);
return false;
}
return true;
}
}

@ -0,0 +1,231 @@
## Input file for automake to generate the Makefile.in used by configure
EXTRA_DIST = \
AssertError.java \
bytecode/BinaryInfo.java \
bytecode/BytecodeInfo.java \
bytecode/ClassFormatException.java \
bytecode/ClassInfo.java \
bytecode/ConstantPool.java \
bytecode/FieldInfo.java \
bytecode/GrowableConstantPool.java \
bytecode/Handler.java \
bytecode/InnerClassInfo.java \
bytecode/Instruction.java \
bytecode/LineNumber.java \
bytecode/LocalVariableInfo.java \
bytecode/MethodInfo.java \
bytecode/Opcodes.java \
bytecode/Reference.java \
bytecode/SearchPath.java \
decompiler/Analyzer.java \
decompiler/ClassAnalyzer.java \
decompiler/ClassDeclarer.java \
decompiler/DeadCodeAnalysis.java \
decompiler/Declarable.java \
decompiler/FieldAnalyzer.java \
decompiler/ImportHandler.java \
decompiler/LocalInfo.java \
decompiler/LocalVarEntry.java \
decompiler/LocalVariableRangeList.java \
decompiler/LocalVariableTable.java \
decompiler/MethodAnalyzer.java \
decompiler/Opcodes.java \
decompiler/OuterValueListener.java \
decompiler/Scope.java \
decompiler/TabbedPrintWriter.java \
Decompiler.java \
expr/ArrayLengthOperator.java \
expr/ArrayLoadOperator.java \
expr/ArrayStoreOperator.java \
expr/BinaryOperator.java \
expr/CheckCastOperator.java \
expr/CheckNullOperator.java \
expr/ClassFieldOperator.java \
expr/CombineableOperator.java \
expr/CompareBinaryOperator.java \
expr/CompareToIntOperator.java \
expr/CompareUnaryOperator.java \
expr/ConstOperator.java \
expr/ConstantArrayOperator.java \
expr/ConstructorOperator.java \
expr/ConvertOperator.java \
expr/Expression.java \
expr/GetFieldOperator.java \
expr/IIncOperator.java \
expr/IfThenElseOperator.java \
expr/InstanceOfOperator.java \
expr/InvokeOperator.java \
expr/LValueExpression.java \
expr/LocalLoadOperator.java \
expr/LocalStoreOperator.java \
expr/LocalVarOperator.java \
expr/MatchableOperator.java \
expr/MonitorEnterOperator.java \
expr/MonitorExitOperator.java \
expr/NewArrayOperator.java \
expr/NewOperator.java \
expr/NoArgOperator.java \
expr/NopOperator.java \
expr/Operator.java \
expr/OuterLocalOperator.java \
expr/PopOperator.java \
expr/PrePostFixOperator.java \
expr/PutFieldOperator.java \
expr/ShiftOperator.java \
expr/SimpleOperator.java \
expr/StoreInstruction.java \
expr/StringAddOperator.java \
expr/ThisOperator.java \
expr/UnaryOperator.java \
flow/BreakBlock.java \
flow/BreakableBlock.java \
flow/CaseBlock.java \
flow/CatchBlock.java \
flow/CombineIfGotoExpressions.java \
flow/CompleteSynchronized.java \
flow/ConditionalBlock.java \
flow/ContinueBlock.java \
flow/CreateAssignExpression.java \
flow/CreateCheckNull.java \
flow/CreateClassField.java \
flow/CreateConstantArray.java \
flow/CreateExpression.java \
flow/CreateForInitializer.java \
flow/CreateIfThenElseOperator.java \
flow/CreateNewConstructor.java \
flow/CreatePrePostIncExpression.java \
flow/DescriptionBlock.java \
flow/EmptyBlock.java \
flow/FinallyBlock.java \
flow/FlowBlock.java \
flow/IfThenElseBlock.java \
flow/InstructionBlock.java \
flow/InstructionContainer.java \
flow/JsrBlock.java \
flow/Jump.java \
flow/LoopBlock.java \
flow/RetBlock.java \
flow/ReturnBlock.java \
flow/SequentialBlock.java \
flow/SlotSet.java \
flow/SpecialBlock.java \
flow/StructuredBlock.java \
flow/SwitchBlock.java \
flow/SynchronizedBlock.java \
flow/ThrowBlock.java \
flow/TransformConstructors.java \
flow/TransformExceptionHandlers.java \
flow/TryBlock.java \
flow/VariableSet.java \
flow/VariableStack.java \
GlobalOptions.java.in \
JodeApplet.java \
JodeWindow.java \
jvm/CodeVerifier.java \
jvm/Interpreter.java \
jvm/InterpreterException.java \
jvm/NewObject.java \
jvm/RuntimeEnvironment.java \
jvm/SimpleRuntimeEnvironment.java \
jvm/SyntheticAnalyzer.java \
jvm/Value.java \
jvm/VerifyException.java \
obfuscator/ClassBundle.java \
obfuscator/ClassIdentifier.java \
obfuscator/CodeAnalyzer.java \
obfuscator/CodeTransformer.java \
obfuscator/ConstantAnalyzer.java \
obfuscator/ConstantRuntimeEnvironment.java \
obfuscator/FieldIdentifier.java \
obfuscator/Identifier.java \
obfuscator/IdentifierMatcher.java \
obfuscator/LocalIdentifier.java \
obfuscator/LocalOptimizer.java \
obfuscator/LocalizeFieldTransformer.java \
obfuscator/Main.java \
obfuscator/MethodIdentifier.java \
obfuscator/ModifierMatcher.java \
obfuscator/NameSwapper.java \
obfuscator/PackageIdentifier.java \
obfuscator/RemovePopAnalyzer.java \
obfuscator/Renamer.java \
obfuscator/SimpleAnalyzer.java \
obfuscator/StrongRenamer.java \
obfuscator/TranslationTable.java \
obfuscator/WildCard.java \
swingui/Main.java \
swingui/Main.java.in \
swingui/PackagesTreeModel.java.in \
swingui/PackagesTreeModel.java \
type/ArrayType.java \
type/ClassInterfacesType.java \
type/IntegerType.java \
type/MethodType.java \
type/NullType.java \
type/RangeType.java \
type/ReferenceType.java \
type/Type.java \
util/AbstractCollection.java \
util/AbstractList.java \
util/AbstractMap.java \
util/AbstractSequentialList.java \
util/AbstractSet.java \
util/ArrayEnum.java \
util/ArrayList.java \
util/Arrays.java \
util/BasicMapEntry.java \
util/Bucket.java \
util/Collection.java \
util/Collections.java \
util/Comparable.java \
util/Comparator.java \
util/ConcurrentModificationException.java \
util/HashMap.java \
util/HashSet.java \
util/Iterator.java \
util/LinkedList.java \
util/List.java \
util/ListIterator.java \
util/Map.java \
util/Set.java \
util/SimpleMap.java \
util/SimpleSet.java \
util/SortedMap.java \
util/SortedSet.java \
util/TreeMap.java \
util/TreeSet.java \
util/UnsupportedOperationException.java
JAR = @JAR@
JAVAC = @JAVAC@
JIKES = @JIKES@
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):.:$(CLASSPATH)
VPATH=$(srcdir):$(top_srcdir):$(top_builddir)
MY_CLASSES = jode/Decompiler.class jode/JodeApplet.class jode/JodeWindow.class jode/obfuscator/Main.class @SWING_CLASSES@
pkgdata_DATA = jode.jar
if HAVE_JIKES
@QUOTE@-include .java.deps
%.class: %.java
$(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=.java.deps -d . $<
else
%.class: %.java
$(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d . $<
endif
clean-local:
@rm -rf jode
@rm -f jode.jar .java.deps
jode.jar: $(MY_CLASSES)
CLASSPATH= $(JAR) -cf jode.jar jode

@ -0,0 +1,278 @@
/* Main Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.GlobalOptions;
import jode.decompiler.*;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import @JAVAX_SWING@.*;
import @JAVAX_SWING@.event.*;
import @JAVAX_SWING@.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main
implements ActionListener, Runnable, TreeSelectionListener {
JFrame frame;
JTree classTree;
PackagesTreeModel classModel;
JTextArea sourcecodeArea, errorArea;
Thread decompileThread;
String currentClassPath, lastClassName;
public Main(String classpath) {
setClasspath(classpath);
frame = new JFrame(GlobalOptions.copyright);
fillContentPane(frame.getContentPane());
addMenu(frame);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void show() {
frame.pack();
frame.show();
}
public void fillContentPane(Container contentPane) {
Font monospaced = new Font("monospaced", Font.PLAIN, 12);
classModel = new PackagesTreeModel();
classTree = new JTree(classModel);
classTree.setRootVisible(false);
DefaultTreeSelectionModel selModel = new DefaultTreeSelectionModel();
selModel.setSelectionMode(selModel.SINGLE_TREE_SELECTION);
classTree.setSelectionModel(selModel);
classTree.addTreeSelectionListener(this);
JScrollPane spClassTree = new JScrollPane(classTree);
sourcecodeArea = new JTextArea(20, 80);
sourcecodeArea.setFont(monospaced);
JScrollPane spText = new JScrollPane(sourcecodeArea);
errorArea = new JTextArea(3, 80);
errorArea.setFont(monospaced);
JScrollPane spError = new JScrollPane(errorArea);
JSplitPane rightPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
spText, spError);
JSplitPane allPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
spClassTree, rightPane);
contentPane.add(allPane);
rightPane.setDividerLocation(300);
rightPane.setDividerSize(4);
allPane.setDividerLocation(200);
allPane.setDividerSize(4);
GlobalOptions.err = new PrintWriter(new AreaWriter(errorArea), true);
}
public synchronized void valueChanged(TreeSelectionEvent e) {
if (decompileThread != null)
return;
TreePath path = e.getNewLeadSelectionPath();
if (path == null)
return;
Object node = path.getLastPathComponent();
if (node != null && classModel.isLeaf(node)) {
lastClassName = classModel.getFullName(node);
decompileThread = new Thread(this);
decompileThread.setPriority(Thread.MIN_PRIORITY);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
}
}
public synchronized void actionPerformed(ActionEvent e) {
if (e.getSource() == classTree && decompileThread == null) {
// startButton.setEnabled(false);
decompileThread = new Thread(this);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
// } else if (e.getSource() == saveButton) {
// if (frame == null)
// frame = new Frame(); //XXX
// FileDialog fd = new FileDialog(frame,
// "Save decompiled code",
// FileDialog.SAVE);
// fd.setFile(lastClassName.substring
// (lastClassName.lastIndexOf('.')+1).concat(".java"));
// fd.show();
// String fileName = fd.getFile();
// if (fileName == null)
// return;
// try {
// File f = new File(new File(fd.getDirectory()), fileName);
// FileWriter out = new FileWriter(f);
// out.write(sourcecodeArea.getText());
// out.close();
// } catch (IOException ex) {
// errorArea.setText("");
// GlobalOptions.err.println("Couldn't write to file "
// + fileName + ": ");
// ex.printStackTrace(GlobalOptions.err);
// }
}
}
public class AreaWriter extends Writer {
boolean initialized = false;
private JTextArea area;
public AreaWriter(JTextArea a) {
area = a;
}
public void write(char[] b, int off, int len) throws IOException {
if (!initialized) {
area.setText("");
initialized = true;
}
///#ifdef AWT10
/// area.appendText(new String(b, off, len));
///#else
area.append(new String(b, off, len));
///#endif
}
public void flush() {
}
public void close() {
}
}
public void run() {
// Decompiler.isVerbose = verboseCheck.getState();
// if (prettyCheck.getState())
// Decompiler.options |= Decompiler.OPTION_PRETTY;
// else
// Decompiler.options &= ~Decompiler.OPTION_PRETTY;
errorArea.setText("");
// saveButton.setEnabled(false);
ImportHandler imports = new ImportHandler();
try {
ClassInfo clazz = ClassInfo.forName(lastClassName);
imports.init(lastClassName);
ClassAnalyzer clazzAna = new ClassAnalyzer(null, clazz, imports);
clazzAna.analyze();
clazzAna.analyzeInnerClasses();
clazzAna.makeDeclaration();
sourcecodeArea.setText("");
TabbedPrintWriter writer =
new TabbedPrintWriter
(new BufferedWriter
(new AreaWriter(sourcecodeArea), 1024), imports, false);
imports.dumpHeader(writer);
clazzAna.dumpSource(writer);
writer.close();
// saveButton.setEnabled(true);
} catch (Throwable t) {
sourcecodeArea.setText("Didn't succeed.\n"
+"Check the below area for more info.");
t.printStackTrace(GlobalOptions.err);
} finally {
synchronized(this) {
decompileThread = null;
// startButton.setEnabled(true);
}
}
}
public void addMenu(JFrame frame) {
JMenuBar bar = new JMenuBar();
JMenu menu;
JMenuItem item;
menu = new JMenu("File");
item = new JMenuItem("Garbage collect");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.gc();
System.runFinalization();
}
});
menu.add(item);
item = new JMenuItem("Exit");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.exit(0);
}
});
menu.add(item);
bar.add(menu);
menu = new JMenu("Options");
item = new JMenuItem("Set classpath...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
String newClassPath = (String) JOptionPane.showInputDialog
(null, "New classpath:", null,
JOptionPane.QUESTION_MESSAGE, null,
null, currentClassPath);
if (newClassPath != null
&& !newClassPath.equals(currentClassPath))
setClasspath(newClassPath);
}
});
menu.add(item);
item = new JMenuItem("Reload classpath");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
setClasspath(currentClassPath);
}
});
menu.add(item);
bar.add(menu);
frame.setJMenuBar(bar);
}
public void setClasspath(String classpath) {
if (classpath == null || classpath.length() == 0)
classpath = ".";
currentClassPath = classpath;
ClassInfo.setClassPath(classpath);
if (classModel != null) {
classTree.clearSelection();
classModel.rebuild();
}
}
public static void main(String[] params) {
String cp = System.getProperty("java.class.path", "");
cp = cp.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar);
for (int i=0; i<params.length; i++) {
if (params[i].equals("--cp"))
cp = params[++i];
else
return;
}
GlobalOptions.verboseLevel = 1;
Main win = new Main(cp);
win.show();
}
}

@ -0,0 +1,176 @@
/* PackagesTreeModel Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.Decompiler;
import jode.bytecode.ClassInfo;
import @JAVAX_SWING@.tree.TreeModel;
import @JAVAX_SWING@.tree.TreePath;
import @JAVAX_SWING@.event.TreeModelListener;
import @JAVAX_SWING@.event.TreeModelEvent;
///#ifndef JDK12
///import java.util.Arrays;
///import java.util.TreeSet;
///import java.util.HashSet;
///import java.util.Set;
///import java.util.HashMap;
///import java.util.Map;
///#else
import jode.util.Comparable;
import jode.util.Arrays;
import jode.util.TreeSet;
import jode.util.HashSet;
import jode.util.Set;
import jode.util.HashMap;
import jode.util.Map;
///#endif
import java.util.Enumeration;
import java.util.NoSuchElementException;
public class PackagesTreeModel implements TreeModel {
Map cachedChildrens = new HashMap();
class TreeElement implements Comparable {
String fullName;
String name;
boolean leaf;
public TreeElement(String prefix, String name, boolean isLeaf) {
this.fullName = prefix+name;
this.name = name;
this.leaf = isLeaf;
}
public String getFullName() {
return fullName;
}
public String getName() {
return name;
}
public boolean isLeaf() {
return leaf;
}
public String toString() {
return name;
}
public int compareTo(Object o) {
TreeElement other = (TreeElement) o;
if (leaf != other.leaf)
// files come after directories
return leaf ? 1 : -1;
return fullName.compareTo(other.fullName);
}
public boolean equals(Object o) {
return (o instanceof TreeElement)
&& fullName.equals(((TreeElement)o).fullName);
}
public int hashCode() {
return fullName.hashCode();
}
}
TreeElement root = new TreeElement("", "", false);
Set listeners = new HashSet();
public void rebuild() {
cachedChildrens.clear();
TreeModelListener[] ls;
synchronized (listeners) {
ls = (TreeModelListener[])
listeners.toArray(new TreeModelListener[listeners.size()]);
}
TreeModelEvent ev = new TreeModelEvent(this, new Object[] { root });
for (int i=0; i< ls.length; i++)
ls[i].treeStructureChanged(ev);
}
public TreeElement[] getChildrens(TreeElement parent) {
TreeElement[] result =
(TreeElement[]) cachedChildrens.get(parent);
if (result == null) {
TreeSet v = new TreeSet();
String prefix = parent == root ? "" : parent.getFullName() + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(parent.getFullName());
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
boolean isClass = !ClassInfo.isPackage(fqn);
if (isClass && Decompiler.skipClass(ClassInfo.forName(fqn)))
continue;
TreeElement newElem = new TreeElement(prefix, name, isClass);
v.add(newElem);
}
result = (TreeElement[]) v.toArray(new TreeElement[v.size()]);
cachedChildrens.put(parent, result);
}
return result;
}
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// we don't allow values
}
public Object getChild(Object parent, int index) {
return getChildrens((TreeElement) parent)[index];
}
public int getChildCount(Object parent) {
return getChildrens((TreeElement) parent).length;
}
public int getIndexOfChild(Object parent, Object child) {
TreeElement[] childrens = getChildrens((TreeElement) parent);
int i = Arrays.binarySearch(childrens, child);
if (i >= 0)
return i;
throw new NoSuchElementException
(((TreeElement)parent).getFullName() + "." + child);
}
public Object getRoot() {
return root;
}
public boolean isLeaf(Object node) {
return ((TreeElement)node).isLeaf();
}
public String getFullName(Object node) {
return ((TreeElement) node).getFullName();
}
}

@ -0,0 +1,2 @@
Makefile
Makefile.in
Loading…
Cancel
Save