Initial attempt for generics support, does not work yet

git-svn-id: https://svn.code.sf.net/p/jode/code/branches/generics@1397 379699f6-c40d-0410-875b-85095c16579e
generics
hoenicke 18 years ago
commit a5a48b3727
  1. 9
      jode/.cvsignore
  2. 1
      jode/AUTHORS
  3. 340
      jode/COPYING
  4. 504
      jode/COPYING.LESSER
  5. 504
      jode/COPYING.LGPL
  6. 563
      jode/ChangeLog
  7. 23
      jode/INSTALL
  8. 3
      jode/MANIFEST.MF
  9. 36
      jode/NEWS
  10. 90
      jode/README
  11. 5
      jode/THANKS
  12. 64
      jode/TODO
  13. 2
      jode/bin/.cvsignore
  14. 5
      jode/bin/Makefile.am
  15. 19
      jode/bin/jode.bat.in
  16. 14
      jode/bin/jode.in
  17. 380
      jode/build.xml
  18. 28
      jode/config.props
  19. 58
      jode/create.sh
  20. 3
      jode/doc/.cvsignore
  21. 25
      jode/doc/applet.htp
  22. 69
      jode/doc/bluesky.htp
  23. 711
      jode/doc/dasm_to_java.perl
  24. 38
      jode/doc/download.htp
  25. 90
      jode/doc/faq.htp
  26. 106
      jode/doc/favicon.xpm
  27. 11
      jode/doc/feedback.htp
  28. 13
      jode/doc/footer.inc
  29. BIN
      jode/doc/gimp/arrow.gif
  30. BIN
      jode/doc/gimp/bytecode.gif
  31. 9
      jode/doc/gimp/bytecode.txt
  32. BIN
      jode/doc/gimp/flow.gif
  33. BIN
      jode/doc/gimp/jode-logo.xcf
  34. BIN
      jode/doc/gimp/statement.gif
  35. 9
      jode/doc/gimp/statement.txt
  36. 42
      jode/doc/gimp/vects.fig
  37. 63
      jode/doc/header.inc
  38. 20
      jode/doc/history.htp
  39. 52
      jode/doc/htp.def
  40. 74
      jode/doc/index.htp
  41. BIN
      jode/doc/jode-logo.png
  42. 67
      jode/doc/jode.htt
  43. 11
      jode/doc/jode.texi
  44. 21
      jode/doc/license.htp
  45. 75
      jode/doc/links.htp
  46. 47
      jode/doc/menu.inc
  47. 84
      jode/doc/myproject.jos
  48. 65
      jode/doc/pattern.txt
  49. BIN
      jode/doc/poweredbyhtp.png
  50. 279
      jode/doc/technical.texi
  51. 250
      jode/doc/usage.htp
  52. BIN
      jode/doc/w3c_ab.png
  53. 28
      jode/jode/jode.jos
  54. BIN
      jode/lib/java-getopt-1.0.8.jar
  55. 40
      jode/makesnapshot
  56. 84
      jode/prj.el
  57. 34
      jode/project-ext.dtd
  58. 273
      jode/project.dtd
  59. 96
      jode/props/net/sf/jode/decompiler/OptionNames.properties
  60. 28
      jode/props/net/sf/jode/swingui/Resources.properties
  61. 28
      jode/props/net/sf/jode/swingui/Resources_de.properties
  62. 94
      jode/scripts/addHeader.pl
  63. 134
      jode/scripts/createStackDelta.pl
  64. 184
      jode/scripts/javaDependencies.pl
  65. 234
      jode/scripts/jcpp.pl
  66. 15
      jode/scripts/php2html.pl
  67. 107
      jode/src/net/sf/jode/GlobalOptions.java
  68. 1076
      jode/src/net/sf/jode/bytecode/BasicBlockReader.java
  69. 1011
      jode/src/net/sf/jode/bytecode/BasicBlockWriter.java
  70. 409
      jode/src/net/sf/jode/bytecode/BasicBlocks.java
  71. 405
      jode/src/net/sf/jode/bytecode/BinaryInfo.java
  72. 296
      jode/src/net/sf/jode/bytecode/Block.java
  73. 43
      jode/src/net/sf/jode/bytecode/ClassFormatException.java
  74. 1599
      jode/src/net/sf/jode/bytecode/ClassInfo.java
  75. 1040
      jode/src/net/sf/jode/bytecode/ClassPath.java
  76. 53
      jode/src/net/sf/jode/bytecode/ConstantInstruction.java
  77. 280
      jode/src/net/sf/jode/bytecode/ConstantPool.java
  78. 340
      jode/src/net/sf/jode/bytecode/FieldInfo.java
  79. 348
      jode/src/net/sf/jode/bytecode/GrowableConstantPool.java
  80. 94
      jode/src/net/sf/jode/bytecode/Handler.java
  81. 60
      jode/src/net/sf/jode/bytecode/IncInstruction.java
  82. 503
      jode/src/net/sf/jode/bytecode/Instruction.java
  83. 135
      jode/src/net/sf/jode/bytecode/LocalVariableInfo.java
  84. 339
      jode/src/net/sf/jode/bytecode/MethodInfo.java
  85. 280
      jode/src/net/sf/jode/bytecode/Opcodes.java
  86. 79
      jode/src/net/sf/jode/bytecode/Reference.java
  87. 86
      jode/src/net/sf/jode/bytecode/ReferenceInstruction.java
  88. 72
      jode/src/net/sf/jode/bytecode/SlotInstruction.java
  89. 58
      jode/src/net/sf/jode/bytecode/SwitchInstruction.java
  90. 72
      jode/src/net/sf/jode/bytecode/TypeDimensionInstruction.java
  91. 50
      jode/src/net/sf/jode/bytecode/TypeInstruction.java
  92. 710
      jode/src/net/sf/jode/bytecode/TypeSignature.java
  93. 106
      jode/src/net/sf/jode/bytecode/package.html
  94. 26
      jode/src/net/sf/jode/decompiler/Analyzer.java
  95. 124
      jode/src/net/sf/jode/decompiler/Applet.java
  96. 825
      jode/src/net/sf/jode/decompiler/ClassAnalyzer.java
  97. 42
      jode/src/net/sf/jode/decompiler/ClassDeclarer.java
  98. 38
      jode/src/net/sf/jode/decompiler/Declarable.java
  99. 233
      jode/src/net/sf/jode/decompiler/Decompiler.java
  100. 206
      jode/src/net/sf/jode/decompiler/FieldAnalyzer.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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 of the License, 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; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

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

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

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

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

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

Binary file not shown.

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

@ -0,0 +1,11 @@
\input texinfo @c -*- texinfo -*-
@setfilename jode.info
@settitle Jode, a Java Decompiler
@direntry
* Jode: (jode). A Java Decompiler
@end direntry
@include technical.texi
@bye

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

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

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

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

@ -0,0 +1,65 @@
inner classes:
access methods:
Method int access$0(jode.test.InnerClass)
0 aload_0
1 getfield #13 <Field int x>
4 ireturn
Method void access$1(jode.test.InnerClass, int)
0 aload_0
1 iload_1
2 putfield #13 <Field int x>
5 return
inner class:
private final jode.test.InnerClass this$0;
Constructor
Method jode.test.InnerClass. Inner(jode.test.InnerClass)
0 aload_0
1 invokespecial #6 <Method java.lang.Object()>
4 aload_0
5 aload_1
6 putfield #11 <Field jode.test.InnerClass this$0>
9 aload_0
10 aload_1
11 putfield #11 <Field jode.test.InnerClass this$0>
14 aload_0
.class operator:
usage:
0 getstatic #23 <Field java.lang.Class class$Ljava$lang$Object>
3 ifnull 12
6 getstatic #23 <Field java.lang.Class class$Ljava$lang$Object>
9 goto 21
12 ldc #25 <String "java.lang.Object">
14 invokestatic #21 <Method java.lang.Class class$(java.lang.String)>
17 dup
18 putstatic #23 <Field java.lang.Class class$Ljava$lang$Object>
or:
0 getstatic #13 <Field java.lang.Class class$java$lang$Object>
3 ifnonnull 14
6 ldc #1 <String "java.lang.Object">
8 invokestatic #12 <Method java.lang.Class class$(java.lang.String)>
11 putstatic #13 <Field java.lang.Class class$java$lang$Object>
Method java.lang.Class class$(java.lang.String)
0 aload_0
1 invokestatic #39 <Method java.lang.Class forName(java.lang.String)>
4 areturn
5 astore_1
6 new #41 <Class java.lang.NoClassDefFoundError>
9 dup
10 aload_1
11 invokevirtual #47 <Method java.lang.String getMessage()>
14 invokespecial #51 <Method java.lang.NoClassDefFoundError(java.lang.String)>
17 athrow
Exception table:
from to target type
0 5 5 <Class java.lang.ClassNotFoundException>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,279 @@
@node Technical Info, Top, Top, Top
@chapter Technical Information
This chapter contains information, how the decompiler works.
@menu
* Types::
* Expression analysis::
* Flow analysis::
* Solving unknown stack-ops::
* Highlevel analysis::
@end menu
@node Types, Expression analysis, Technical Info, Technical Info
@section Type checking and guessing
@cindex Types, Conversions
The class jode.Type is the base class of all types (except MethodType).
A type under jode is really a set of types, since it sometimes cannot
know the exact type. A special type is Type.tError which represents the
empty set and means, that something has gone wrong.
A type has the following operators:
@table @asis
@item getSubType
Get the set of types, that are implicitly castable to one of the types
in this type set.
@item getSuperType
Get the set of types, to which the types in this type set can be casted
without a bytecode cast.
@item intersection
Get the intersection of the type sets.
(getCastHelper?)
(getImplicitCast?)
@end table
There are simple types, that can only casted to themself (like long,
float, double, void), 32 bit integer types (boolean, byte, char, short,
int) and reference types (classes, interfaces, arrays and null type).
There is also a type range to represent sets of reference types.
createRangeType
getSpecializedType
getGeneralizedType
The meaning is
ref1.intersection(ref2) =
ref1.getSpecializedType(ref2).createRangeType(ref1.getGeneralizedType(ref2))
<Object - NULL>
<Object[] - NULL>
<Object[] - Serialized[]>
<tUnknown[]>
<Object - tUnknown[]>
{IBCS}[] intersect {CSZ}[] = {CS}[]
<Object - {ICSB}[]> intersect <Serializable - {CSZ}[]>
--> <Serializable - {CS}[]>
The byte code distinguishes five different types:
@enumerate
@item 16 bit integral types (boolean, byte, short, char and int)
@item long
@item float
@item double
@item reference types (objects, interfaces, arrays, null type)
@end enumerate
It sometimes makes a difference between byte, short, char and int, but
not always.
16bit integral types:
We differ seven different 16 bit integral types:
@table @asis
@item I
@code{int} type
@item C
@code{char} type
@item S
@code{short} type
@item B
@code{byte} type
@item Z
@code{boolean} type
@item cS
An @code{int} constant whose value is in @code{short} range.
@item cB
An @code{int} constant whose value is in @code{byte} range.
@end table
Each of this types has a super range and a sub range:
@multitable {type} {(I,C,S,B,Z,cS,cB)} {(I,C,S,B,Z,cS,cB)}
@item type @tab sub types @tab super types
@item I @tab (I,C,S,B,cS,cB) @tab (I)
@item C @tab (C) @tab (I,C)
@item S @tab (S,B,cS,cB) @tab (I,S)
@item B @tab (B,cB) @tab (I,S,B)
@item Z @tab (Z) @tab (Z)
@item cS @tab (cS,cB) @tab (I,S,cS)
@item cB @tab (cB) @tab (I,S,B,cS,cB)
@end multitable
getTop() getBottom() give the type directly.
createRangeType(Type bottom) does the following:
If top == tUnknown , union all supertypes
If top is 16bit type,
intersect (union of subtypes of top) (union of supertypes)
Return tError otherwise.
Type.createRangeType(Type top) does the following:
if Type == tUnknown
if top is IntegerType
new IntegerType(union of subtypes of top)
Hints. We distinguish strong and weak Hints:
strong Hints:
assignment:
lhs.strongHint = mergeHint(lhs.strongHint, rhs.strongHint)
lhs.weakHint = mergeHint(lhs.weakHint, rhs.weakHint)
rhs.strongHint = lhs.strongHint
binary op:
left.weakHint = mergeHints(left.weakHint, right.strongHint?strongHint: weakHint)
binary op
types that may occur directly in bytecode:
(I,Z)
(I)
(Z)
(I,C,S,B,Z)
(I,cS,cB)
(I,cS)
(I,C,cS,cB)
(I,C,cS)
(I,C)
(C)
(S)
(B)
(B,Z)
now the sub (>) and super (<) operators
>(I,Z) = (I,C,S,B,Z,cS,cB) New!
>(I) = (I,C,S,B,cS,cB) New!
>(Z) = (Z)
>(I,C,S,B,Z) = (I,C,S,B,Z,cS,cB)
>(I,cS,cB) = (I,C,S,B,cS,cB)
>(I,cS) = (I,C,S,B,cS,cB)
>(I,C,cS,cB) = (I,C,S,B,cS,cB)
>(I,C,cS) = (I,C,S,B,cS,cB)
>(I,C) = (I,C,S,B,cS,cB)
>(C) = (C)
>(S) = (S,B,cS,cB) New!
>(B) = (B,cB) New!
>(B,Z) = (B,Z,cB) New!
<(I,Z) = (I,Z)
<(I) = (I)
<(Z) = (Z)
<(I,C,S,B,Z) = (I,C,S,B,Z)
<(I,cS,cB) = (I,S,B,cS,cB) New!
<(I,cS) = (I,S,cS) New!
<(I,C,cS,cB) = (I,C,S,B,cS,cB)
<(I,C,cS) = (I,C,S,cS) New!
<(I,C) = (I,C)
<(C) = (I,C)
<(S) = (I,S) New!
<(B) = (I,S,B) New!
<(B,Z) = (I,S,B,Z) New!
>(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB)
>(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB)
>(B,Z,cB) = (B,Z,cB)
>(I,C,S,cS) = (I,C,S,B,cS,cB)
>(I,S,B,Z) = (I,C,S,B,Z,cS,cB)
>(I,S,B,cS,cB) = (I,C,S,B,cS,cB)
<(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB)
<(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB)
<(B,Z,cB) = (I,S,B,Z,cS,cB)
<(I,C,S,cS) = (I,C,S,cS)
<(I,S,B,Z) = (I,S,B,Z)
<(I,S,B,cS,cB) = (I,S,B,cS,cB)
Zu betrachtende 32bit Typen:
(I,Z) = (I,Z)
(I) = (I)
(Z) = (Z)
(I,C,S,B,Z)
(I,cS,cB)
(I,cS)
(I,C,cS,cB)
(I,C,cS)
(I,C)
(B,Z)
(I,C,S,B,Z,cS,cB)
(I,C,S,B,cS,cB)
(B,Z,cB)
(I,C,S,cS)
(I,S,B,Z)
(I,S,B,cS,cB)
@node Highlevel analysis, Technical Info, Solving unknown stack-ops, Technical Info
@section Highlevel analysis
@cindex passes
@section The passes
JODE works in three passes:
@subsection Pass 1: Initialize
In the initialize pass the methods, fields and inner classes are read in
and the inner classes are recursively initialized. In this pass the
complexity of the class is calculated. Anonymous and method scoped
classes aren't even considered yet.
@subsection Pass 2: Analyze
The analyze pass is the real decompilation pass: The code of the methods
is transformed into flow blocks and merged to one flow block as
described in a previous section. The in/out analysis for the local
variables is completed, and the locals are merged as necessary. The
parameter 0 for non static method is marked as ThisOperator in this
pass.
The constructors are analyzed first. If they initialize synthetic
fields, this is taken as clear sign that this are outer value
parameters. So afterwards, these synthetic fields know their value.
Then the methods are analyzed. Each method remembers the anonymous
classes it creates for Pass 3, but these classes are not yet
initialized. Inner classes aren't analyzed yet, either.
@subsection Pass 3: Analyze Inner
As the name of this pass makes clear the inner classes are initialized
in this pass, i.e. first Pass 2 and 3 are invoked for the inner classes.
After that the method scoped classes are analyzed: For each constructor
it is first check if one surrounding method knows about it. If not, a
new class analyzer is created for the method scoped class and Pass 1--3
are invoked. Every surrounding method is then told about this new class
analyzer.
After this pass, every anonymous constructor is analyzed, so we know
which constructor parameters can be outer values. The constructor
transformation may force some other outer values, though. It is also
known, in which method a method scoped class must be declared.
@subsection Pass 4: Make Declarations
The last pass begins with transforming the constructors of a class. Now
the outer values are fixed and the constructor parameters and synthetic
fields are told their values.
After that every method determines where to declare local variables and
method scoped classes. Local variables are declared as final if a
method scoped class uses it as outer value. The name of local
variables is guessed now.
This pass is done recursively for inner and method scoped classes.

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

Binary file not shown.

@ -0,0 +1,28 @@
# This is a sample script file to obfuscate the JODE project.
# First we select what we want to strip. There are several possibilities:
# unreach - strip unreachable methods and classes.
# source - strip source file attribute.
# lnt - strip line number table.
# lvt - strip local variable table.
# inner - strip inner class info
strip = "unreach"
load = new WildCard { value = "jode" }
preserve = new WildCard { value = "jode.Decompiler.main.*" },
new WildCard { value = "jode.JodeApplet.<init>.()V" },
new WildCard { value = "jode.JodeWindow.main.*" },
new WildCard { value = "jode.obfuscator.Main.main.*" },
new WildCard { value = "jode.swingui.Main.main.*" },
new WildCard { value = "jode.obfuscator.modules.*.<init>.()V" },
new WildCard { value = "jode.obfuscator.modules.*.setOption.*" }
# value = "jode.Decompiler.main.*",
# "jode.JodeApplet.<init>.()V",
# "jode.JodeWindow.main.*",
# "jode.obfuscator.Main.main.*",
# "jode.swingui.Main.main.*"
analyzer = new SimpleAnalyzer
post = new LocalOptimizer, new RemovePopAnalyzer

Binary file not shown.

@ -0,0 +1,40 @@
#!/bin/sh
OLDDIR=`pwd`
TIME=`date +"%Y%m%d %H:%M"`
if [ "${1#-D}" != "$1" ] ; then
TIME=`date +"%Y%m%d %H:%M" --date="${1#-D}"`
shift;
fi
DATE=`echo $TIME | cut -c0-8`
echo $TIME
echo $DATE
TEMP=`mktemp -d $HOME/tmp.XXXXXX`
trap "cd $OLDDIR; rm -rf $TEMP" EXIT
cd $TEMP
CLASSPATH=$TEMP:/usr/local/swing-1.1/swing.jar
export CLASSPATH
cvs export -D"$TIME" jode
cd jode
perl -i -pe's/(snapshot )[0-9]+/${1}'"$TIME"'/
if /public final static String version/;' GlobalOptions.java
COMPILER=${1:-jikes}
if [ -z "$1" ]; then
FLAGS="-g"
else
shift
FLAGS="$*"
fi
# jasmin -d .. jvm/Interpreter.j
eval $COMPILER $FLAGS -d .. \
Decompiler.java obfuscator/Main.java JodeApplet.java swingui/Main.java
cd ..
zip -r $HOME/jode-$DATE.zip jode

@ -0,0 +1,84 @@
(jde-set-project-name "jode")
(jde-set-variables
'(jde-run-option-properties nil)
'(jde-run-option-stack-size (quote ((128 . "kilobytes") (400 . "kilobytes"))))
'(jde-gen-buffer-templates (quote (("Class" . jde-gen-class) ("Console" . jde-gen-console) ("Swing App" . jde-gen-jfc-app))))
'(jde-compile-option-command-line-args "")
'(jde-gen-action-listener-template (quote ("'& (P \"Component name: \")" "\".addActionListener(new ActionListener() {\" 'n>" "\"public void actionPerformed(ActionEvent e) {\" 'n>" "\"}});\" 'n>")))
'(jde-compile-option-depend nil)
'(jde-compile-option-optimize nil)
'(jde-run-option-verify (quote (nil t)))
'(jde-gen-inner-class-template (quote ("'& \"class \" (P \"Class name: \" class)" "(P \"Superclass: \" super t)" "(let ((parent (jde-gen-lookup-named 'super)))" "(if (not (string= parent \"\"))" "(concat \" extends \" parent))) \" {\" 'n>" "\"public \" (s class) \"() {\" 'n> \"}\" 'n> \"}\" 'n>")))
'(jde-run-read-vm-args nil)
'(jde-entering-java-buffer-hooks (quote (jde-reload-project-file)))
'(jde-run-applet-viewer "appletviewer")
'(jde-compile-option-debug t t)
'(jde-project-file-name "prj.el")
'(jde-run-option-verbose (quote (nil nil nil)))
'(jde-run-application-class "")
'(jde-db-option-vm-args nil)
'(jde-run-option-heap-size (quote ((1 . "megabytes") (16 . "megabytes"))))
'(jde-db-read-vm-args nil)
'(jde-db-option-heap-profile (quote (nil "./java.hprof" 5 20 "Allocation objects")))
'(jde-db-mode-hook nil)
'(jde-run-option-garbage-collection (quote (t t)))
'(jde-compile-option-vm-args nil)
'(jde-run-applet-doc "index.html")
'(jde-db-option-java-profile (quote (nil . "./java.prof")))
'(jde-gen-get-set-var-template (quote ("'n>" "(P \"Variable type: \" type) \" \"" "(P \"Variable name: \" name) \";\" 'n> 'n>" "\"/**\" 'n>" "\"* Get the value of \" (s name) \".\" 'n>" "\"* @return Value of \" (s name) \".\" 'n>" "\"*/\" 'n>" "\"public \" (s type) \" get\" (jde-gen-init-cap (jde-gen-lookup-named 'name))" "\"() {return \" (s name) \";}\" 'n> 'n>" "\"/**\" 'n>" "\"* Set the value of \" (s name) \".\" 'n>" "\"* @param v Value to assign to \" (s name) \".\" 'n>" "\"*/\" 'n>" "\"public void set\" (jde-gen-init-cap (jde-gen-lookup-named 'name))" "\"(\" (s type) \" v) {this.\" (s name) \" = v;}\" 'n>")))
'(jde-db-option-verify (quote (nil t)))
'(jde-run-mode-hook nil)
'(jde-db-option-classpath nil)
'(jde-compile-option-deprecation nil)
'(jde-db-startup-commands nil)
'(jde-gen-boilerplate-function (quote jde-gen-create-buffer-boilerplate))
'(jde-compile-option-nodebug nil)
'(jde-compile-option-classpath nil)
'(jde-build-use-make nil)
'(jde-quote-classpath t)
'(jde-gen-to-string-method-template (quote ("'&" "\"public String toString() {\" 'n>" "\"return super.toString();\" 'n>" "\"}\" 'n>")))
'(jde-run-read-app-args nil)
'(jde-db-source-directories (quote ("d:/jdk1.2/src/")))
'(jde-db-option-properties nil)
'(jde-db-option-stack-size (quote ((128 . "kilobytes") (400 . "kilobytes"))))
'(jde-db-set-initial-breakpoint t)
'(jde-run-option-application-args (quote ("-v" "--debug=analyze,inout" "--classpath=/home/jochen/output/share/jode-1.0.90.jar" "jode.Decompiler")) t)
'(jde-gen-mouse-listener-template (quote ("'& (P \"Component name: \")" "\".addMouseListener(new MouseAdapter() {\" 'n>" "\"public void mouseClicked(MouseEvent e) {}\" 'n>" "\"public void mouseEntered(MouseEvent e) {}\" 'n>" "\"public void mouseExited(MouseEvent e) {}\" 'n>" "\"public void mousePressed(MouseEvent e) {}\" 'n>" "\"public void mouseReleased(MouseEvent e) {}});\" 'n>")))
'(jde-gen-console-buffer-template (quote ("(funcall jde-gen-boilerplate-function) 'n" "\"/**\" 'n" "\" * \"" "(file-name-nondirectory buffer-file-name) 'n" "\" *\" 'n" "\" *\" 'n" "\" * Created: \" (current-time-string) 'n" "\" *\" 'n" "\" * @author \" (user-full-name) 'n" "\" * @version\" 'n" "\" */\" 'n>" "'n>" "\"public class \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" {\" 'n> 'n>" "\"public \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"() {\" 'n>" "'n>" "\"}\" 'n>" "'n>" "\"public static void main(String[] args) {\" 'n>" "'p 'n>" "\"}\" 'n> 'n>" "\"} // \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "'n>")))
'(jde-compile-option-directory "/home/jochen/java/unstable/build" t)
'(jde-run-option-vm-args nil)
'(jde-make-program "make")
'(jde-use-font-lock t)
'(jde-db-option-garbage-collection (quote (t t)))
'(jde-gen-class-buffer-template (quote ("(funcall jde-gen-boilerplate-function)" "\"package jode;\" 'n" "'n" "\"/**\" 'n" "\" * \" 'n" "\" * @author \" (user-full-name) 'n" "\" */\" 'n" "\"public class \" (file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" \" (jde-gen-get-super-class) \" {\" 'n" "> 'n" "> \"public \" (file-name-sans-extension (file-name-nondirectory buffer-file-name)) \"() {\" 'n" "> 'p 'n" "> \"}\" 'n" "> 'n" "> \"}\" 'n")))
'(jde-compiler "jikes +E")
'(jde-jdk-doc-url "file:/usr/doc/packages/jdk115/docs/index.html")
'(jde-db-debugger (quote ("jdb" . "Executable")))
'(jde-compile-option-optimize-interclass nil)
'(jde-run-option-classpath nil)
'(jde-key-bindings (quote (("" . jde-compile) ("" . jde-run) ("" . jde-db) ("" . jde-build) ("" . jde-run-menu-run-applet) ("" . jde-browse-jdk-doc) ("" . jde-save-project) (" " . jde-gen-println))))
'(jde-gen-mouse-motion-listener-template (quote ("'& (P \"Component name: \")" "\".addMouseMotionListener(new MouseMotionAdapter() {\" 'n>" "\"public void mouseDragged(MouseEvent e) {}\" 'n>" "\"public void mouseMoved(MouseEvent e) {}});\" 'n>")))
'(jde-db-marker-regexp "^Breakpoint hit: .*(\\([^$]*\\).*:\\([0-9]*\\))")
'(jde-run-working-directory "")
'(jde-gen-window-listener-template (quote ("'& (P \"Window name: \")" "\".addWindowListener(new WindowAdapter() {\" 'n>" "\"public void windowActivated(WindowEvent e) {}\" 'n>" "\"public void windowClosed(WindowEvent e) {}\" 'n>" "\"public void windowClosing(WindowEvent e) {System.exit(0);}\" 'n>" "\"public void windowDeactivated(WindowEvent e) {}\" 'n>" "\"public void windowDeiconified(WindowEvent e) {}\" 'n>" "\"public void windowIconified(WindowEvent e) {}\" 'n>" "\"public void windowOpened(WindowEvent e) {}});\" 'n>")))
'(jde-global-classpath (quote ("/usr/local/swing-1.1/swing.jar" "/usr/local/1.1collections/lib/collections.jar" "/home/jochen/java/jars/getopt.zip" "/home/jochen/java/unstable/jode" "/home/jochen/java/unstable/build" "/usr/lib/java/lib/classes.zip")) t)
'(jde-enable-abbrev-mode nil)
'(jde-gen-println (quote ("'&" "\"System.out.println(\" (P \"Print out: \") \");\" 'n>")))
'(jde-run-option-heap-profile (quote (nil "./java.hprof" 5 20 "Allocation objects")))
'(jde-db-read-app-args nil)
'(jde-db-option-verbose (quote (nil nil nil)))
'(jde-run-java-vm "java")
'(jde-read-compile-args nil)
'(jde-run-option-java-profile (quote (nil . "./java.prof")))
'(jde-compile-option-encoding nil)
'(jde-run-java-vm-w "javaw")
'(jde-compile-option-nowarn nil)
'(jde-gen-jfc-app-buffer-template (quote ("(funcall jde-gen-boilerplate-function) 'n" "\"import java.awt.*;\" 'n" "\"import java.awt.event.*;\" 'n" "\"import com.sun.java.swing.*;\" 'n 'n" "\"/**\" 'n" "\" * \"" "(file-name-nondirectory buffer-file-name) 'n" "\" *\" 'n" "\" *\" 'n" "\" * Created: \" (current-time-string) 'n" "\" *\" 'n" "\" * @author \" (user-full-name) 'n" "\" * @version\" 'n" "\" */\" 'n>" "'n>" "\"public class \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" extends JFrame {\" 'n> 'n>" "\"public \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"() {\" 'n>" "\"super(\\\"\" (P \"Enter app title: \") \"\\\");\" 'n>" "\"setSize(600, 400);\" 'n>" "\"addWindowListener(new WindowAdapter() {\" 'n>" "\"public void windowClosing(WindowEvent e) {System.exit(0);}\" 'n>" "\"public void windowOpened(WindowEvent e) {}});\" 'n>" "\"}\" 'n>" "'n>" "\"public static void main(String[] args) {\" 'n>" "'n>" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" f = new \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"();\" 'n>" "\"f.show();\" 'n>" "'p 'n>" "\"}\" 'n> 'n>" "\"} // \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "'n>")))
'(jde-db-option-application-args nil)
'(jde-gen-buffer-boilerplate (quote ("/* " (file-name-nondirectory buffer-file-name) " Copyright (C) 1997-1998 Jochen Hoenicke." (quote n) " *" (quote n) " * This program is free software; you can redistribute it and/or modify" (quote n) " * it under the terms of the GNU General Public License as published by" (quote n) " * the Free Software Foundation; either version 2, or (at your option)" (quote n) " * any later version." (quote n) " *" (quote n) " * This program is distributed in the hope that it will be useful," (quote n) " * but WITHOUT ANY WARRANTY; without even the implied warranty of" (quote n) " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" (quote n) " * GNU General Public License for more details." (quote n) " *" (quote n) " * You should have received a copy of the GNU General Public License" (quote n) " * along with this program; see the file COPYING. If not, write to" (quote n) " * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA." (quote n) " *" (quote n) " * $" "Id$" (quote n) " */" (quote n))))
'(jde-db-option-heap-size (quote ((1 . "megabytes") (16 . "megabytes"))))
'(jde-compile-option-verbose nil)
'(jde-mode-abbreviations (quote (("ab" . "abstract") ("bo" . "boolean") ("br" . "break") ("by" . "byte") ("byv" . "byvalue") ("cas" . "cast") ("ca" . "catch") ("ch" . "char") ("cl" . "class") ("co" . "const") ("con" . "continue") ("de" . "default") ("dou" . "double") ("el" . "else") ("ex" . "extends") ("fa" . "false") ("fi" . "final") ("fin" . "finally") ("fl" . "float") ("fo" . "for") ("fu" . "future") ("ge" . "generic") ("go" . "goto") ("impl" . "implements") ("impo" . "import") ("ins" . "instanceof") ("in" . "int") ("inte" . "interface") ("lo" . "long") ("na" . "native") ("ne" . "new") ("nu" . "null") ("pa" . "package") ("pri" . "private") ("pro" . "protected") ("pu" . "public") ("re" . "return") ("sh" . "short") ("st" . "static") ("su" . "super") ("sw" . "switch") ("sy" . "synchronized") ("th" . "this") ("thr" . "throw") ("throw" . "throws") ("tra" . "transient") ("tr" . "true") ("vo" . "void") ("vol" . "volatile") ("wh" . "while"))))
'(jde-make-args "")
'(jde-gen-code-templates (quote (("Get Set Pair" . jde-gen-get-set) ("toString method" . jde-gen-to-string-method) ("Action Listener" . jde-gen-action-listener) ("Window Listener" . jde-gen-window-listener) ("Mouse Listener" . jde-gen-mouse-listener) ("Mouse Motion Listener" . jde-gen-mouse-motion-listener) ("Inner Class" . jde-gen-inner-class) ("println" . jde-gen-println)))))

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!--
Copyright (c) 2000 Michel CASABIANCA. All Rights Reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby
granted, provided that both the above copyright notice and this
permission notice appear in all copies of the software and
documentation or portions thereof, including modifications, that you
make.
THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
OR DOCUMENTATION.
-->
<!-- project ext DTD for Ant -->
<!-- 2000-04-03 -->
<!ENTITY % ext "| xt">
<!ELEMENT xt EMPTY>
<!ATTLIST xt
xml CDATA #REQUIRED
xsl CDATA #REQUIRED
out CDATA #REQUIRED>

@ -0,0 +1,273 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!--
Copyright (c) 2000 Michel CASABIANCA. All Rights Reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee or royalty is hereby
granted, provided that both the above copyright notice and this
permission notice appear in all copies of the software and
documentation or portions thereof, including modifications, that you
make.
THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
OR DOCUMENTATION.
-->
<!-- project DTD for Ant -->
<!-- 2000-04-03 -->
<!ENTITY % ext-file SYSTEM "project-ext.dtd">
%ext-file;
<!ELEMENT project (target | property)*>
<!ATTLIST project
name CDATA #REQUIRED
default CDATA #REQUIRED
basedir CDATA #REQUIRED>
<!ELEMENT target (ant | available | chmod | copydir | copyfile |
cvs | delete | deltree | echo | exec | expand |
filter | get | gzip | fixcrlf | jar | java |
javac | javadoc | javadoc2 | keysubst | mkdir |
property | rename | replace | rmic | tar |
taskdef | tstamp | zip %ext;)*>
<!ATTLIST target
name CDATA #REQUIRED
depends CDATA #IMPLIED
if CDATA #IMPLIED>
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #IMPLIED
value CDATA #IMPLIED
resource CDATA #IMPLIED
file CDATA #IMPLIED>
<!ELEMENT ant EMPTY>
<!ATTLIST ant
antfile CDATA #IMPLIED
dir CDATA #REQUIRED
target CDATA #IMPLIED>
<!ELEMENT available EMPTY>
<!ATTLIST available
property CDATA #REQUIRED
classname CDATA #REQUIRED
resource CDATA #REQUIRED
file CDATA #REQUIRED>
<!ELEMENT chmod EMPTY>
<!ATTLIST chmod
src CDATA #REQUIRED
perm CDATA #REQUIRED>
<!ELEMENT copydir EMPTY>
<!ATTLIST copydir
src CDATA #REQUIRED
dest CDATA #REQUIRED
ignore CDATA #IMPLIED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
defaultexcludes CDATA #IMPLIED
filtering CDATA #IMPLIED>
<!ELEMENT copyfile EMPTY>
<!ATTLIST copyfile
src CDATA #REQUIRED
dest CDATA #REQUIRED
filtering CDATA #IMPLIED>
<!ELEMENT cvs EMPTY>
<!ATTLIST cvs
cvsRoot CDATA #REQUIRED
dest CDATA #REQUIRED
package CDATA #REQUIRED
tag CDATA #IMPLIED>
<!ELEMENT delete EMPTY>
<!ATTLIST delete
file CDATA #REQUIRED>
<!ELEMENT deltree EMPTY>
<!ATTLIST deltree
dir CDATA #REQUIRED>
<!ELEMENT echo EMPTY>
<!ATTLIST echo
message CDATA #REQUIRED>
<!ELEMENT exec EMPTY>
<!ATTLIST exec
command CDATA #REQUIRED
dir CDATA #REQUIRED
os CDATA #IMPLIED
output CDATA #REQUIRED>
<!ELEMENT expand EMPTY>
<!ATTLIST expand
src CDATA #REQUIRED
dest CDATA #REQUIRED>
<!ELEMENT filter EMPTY>
<!ATTLIST filter
token CDATA #REQUIRED
value CDATA #REQUIRED>
<!ELEMENT get EMPTY>
<!ATTLIST get
src CDATA #REQUIRED
dest CDATA #REQUIRED
verbose CDATA #IMPLIED>
<!ELEMENT gzip EMPTY>
<!ATTLIST gzip
src CDATA #REQUIRED
zipfile CDATA #REQUIRED>
<!ELEMENT fixcrlf EMPTY>
<!ATTLIST fixcrlf
srcdir CDATA #REQUIRED
destDir CDATA #IMPLIED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
cr CDATA #IMPLIED
tab CDATA #IMPLIED
eof CDATA #IMPLIED>
<!ELEMENT jar EMPTY>
<!ATTLIST jar
jarfile CDATA #REQUIRED
basedir CDATA #REQUIRED
items CDATA #IMPLIED
ignore CDATA #IMPLIED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
defaultexcludes CDATA #IMPLIED
manifest CDATA #IMPLIED>
<!ELEMENT java EMPTY>
<!ATTLIST java
classname CDATA #REQUIRED
args CDATA #IMPLIED
fork CDATA #IMPLIED
jvmargs CDATA #IMPLIED>
<!ELEMENT javac EMPTY>
<!ATTLIST javac
srcdir CDATA #REQUIRED
destdir CDATA #REQUIRED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
defaultexcludes CDATA #IMPLIED
classpath CDATA #IMPLIED
bootclasspath CDATA #IMPLIED
extdirs CDATA #IMPLIED
debug CDATA #IMPLIED
optimize CDATA #IMPLIED
deprecation CDATA #IMPLIED
filtering CDATA #IMPLIED>
<!ELEMENT javadoc EMPTY>
<!ATTLIST javadoc
sourcepath CDATA #REQUIRED
destdir CDATA #REQUIRED
sourcefiles CDATA #IMPLIED
packagenames CDATA #IMPLIED
classpath CDATA #IMPLIED
bootclasspath CDATA #IMPLIED
extdirs CDATA #IMPLIED
overview CDATA #IMPLIED
public CDATA #IMPLIED
protected CDATA #IMPLIED
package CDATA #IMPLIED
private CDATA #IMPLIED
old CDATA #IMPLIED
verbose CDATA #IMPLIED
locale CDATA #IMPLIED
encoding CDATA #IMPLIED
version CDATA #IMPLIED
use CDATA #IMPLIED
author CDATA #IMPLIED
splitindex CDATA #IMPLIED
windowtitle CDATA #IMPLIED
doctitle CDATA #IMPLIED
header CDATA #IMPLIED
footer CDATA #IMPLIED
bottom CDATA #IMPLIED
link CDATA #IMPLIED
linkoffline CDATA #IMPLIED
group CDATA #IMPLIED
nodedeprecated CDATA #IMPLIED
nodedeprecatedlist CDATA #IMPLIED
notree CDATA #IMPLIED
noindex CDATA #IMPLIED
nohelp CDATA #IMPLIED
nonavbar CDATA #IMPLIED
serialwarn CDATA #IMPLIED
helpfile CDATA #IMPLIED
stylesheetfile CDATA #IMPLIED
charset CDATA #IMPLIED
docencoding CDATA #IMPLIED>
<!ELEMENT keysubst EMPTY>
<!ATTLIST keysubst
src CDATA #REQUIRED
dest CDATA #REQUIRED
sep CDATA #IMPLIED
keys CDATA #REQUIRED>
<!ELEMENT mkdir EMPTY>
<!ATTLIST mkdir
dir CDATA #REQUIRED>
<!ELEMENT rename EMPTY>
<!ATTLIST rename
src CDATA #REQUIRED
dest CDATA #REQUIRED
replace CDATA #IMPLIED>
<!ELEMENT replace EMPTY>
<!ATTLIST replace
file CDATA #REQUIRED
token CDATA #REQUIRED
value CDATA #IMPLIED>
<!ELEMENT rmic EMPTY>
<!ATTLIST rmic
base CDATA #REQUIRED
classname CDATA #REQUIRED
filtering CDATA #IMPLIED>
<!ELEMENT tar EMPTY>
<!ATTLIST tar
tarfile CDATA #REQUIRED
basedir CDATA #REQUIRED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
defaultexcludes CDATA #IMPLIED>
<!ELEMENT taskdef EMPTY>
<!ATTLIST taskdef
name CDATA #REQUIRED
classname CDATA #REQUIRED>
<!ELEMENT tstamp EMPTY>
<!ELEMENT zip EMPTY>
<!ATTLIST zip
zipfile CDATA #REQUIRED
basedir CDATA #REQUIRED
items CDATA #IMPLIED
ignore CDATA #IMPLIED
includes CDATA #IMPLIED
excludes CDATA #IMPLIED
defaultexcludes CDATA #IMPLIED>

@ -0,0 +1,96 @@
options = tabwidth,indent,style,linewidth,import,verbose,lvt,inner,anonymous,push,pretty,decrypt,onetime,immediate,verify,contrafo,debug
tabwidth.0=<n>
tabwidth.1=Set tab width to n.
tabwidth.2=This means that Jode uses tabs to replace n spaces. \
Don't confound this with the indent option. Use 0 if you don't want \
tabs. Default is 8.
indent.0=<n>
indent.1=Indent blocks by n spaces.
style.0={sun|gnu}
style.1=Specify indentation style.
linewidth.0=<n>
linewidth.1=Set maximum line width to n.
linewidth.2=Jode breaks lines that are longer than this. It tries it's best \
to make all lines fit in this limit, but sometimes this won't succeed.
import.0=<pkglimit>,<clslimit>
import.1=import classes if they occur more than clslimit times and packages \
with more than pkglimit used classes. Default is 0,1 which means that all \
used classes are imported, but never a whole package.
verbose.0=<n>
verbose.1=Be verbose (higher n means more verbose).
verbose.2=This prints some information about the currently decompiled \
class or method to the console.
debug.0=<flag>,...
debug.1=Enable debugging options. Useful to track errors in the decompiler.
debug.2=Possible flags are: \
"bytecode", to print raw bytecode. \
"lvt", dump LocalVariableTable. \
"verifier", to trace bytecode verification. \
"check", do time consuming sanity checks; useful to spot serious errors. \
"types", to see the type intersections. \
"flow", for a very verbose trace of the decompile process. \
"analyze", briefly inform about "T1/T2" analyzation. \
"inout", to view the in/out local variable analyzation. \
"locals", to see how local variable merging is done. \
"constructors", to trace constructor transformation. \
"interpreter", to follow the execution of the interpreter \
(the interpreter is used for string decryption).
inner.0={yes|no}
inner.1=(Don't) decompiler inner classes.
anonymous.0={yes|no}
anonymous.1=(Don't) decompiler method scoped classes.
contrafo.0={yes|no}
contrafo.1=(Don't) transform constructors.
lvt.0={yes|no}
lvt.1=(Don't) use the local variable table.
lvt.2=Turning it off is useful if an obfuscator filled it with bogus values.
pretty.0={yes|no}
pretty.1=(Don't) use `pretty' names for local variables.
pretty.2=The non pretty names have the advantage, that their names are \
unique. This make search & replace possible.
push.0={yes|no}
push.1=Allow PUSH pseudo instructions in output.
push.2=Sometimes, when methods were inlined, Jode can't reconstruct \
the original expression. It has to split a complex expression into \
several ones, using temporary variables. If this option is on, it won't \
use the temporary variables, but uses pseudo PUSH/POP instructions instead, \
as they are in the bytecode.
decrypt.0={yes|no}
decrypt.1=(Don't) decrypt encrypted strings.
decrypt.2=Some obfuscators encrypt all strings. To decrypt them at runtime \
they add a small decryption routine to the code. If Jode detects such a \
decryption routine it interprets it to decrypt the strings at decompile time.
onetime.0={yes|no}
onetime.1=(Don't) remove locals that written and then immediately read.
onetime.2=When javac inlines a method it uses temporary local variables for \
the parameters. Often these local variables can be removed, which makes \
the code much better to read.
immediate.0={yes|no}
immediate.1=Output the source immediately as it gets decompiled.
immediate.2=This leads to more instant output, but has many disadvantages.\
For one the import statements can't be correct. But it also may lead to \
buggy code. The advantage is, that you can get partial output even if an
exception is thrown.
verify.0={yes|no}
verify.1=(Don't) verify code before decompiling it.
verify.2=Jode assumes at many places that your byte code is legal. To \
be sure it verifies it before decompiling. If verification fails it \
rejects the code. Since verification can fail for legal code if the \
type hierarchy is not known, you can turn this option off.

@ -0,0 +1,28 @@
usage.count=3
usage.0 = usage: java jode.swingui.Main [CLASSPATH]
usage.1 = The directories in CLASSPATH should be separated by ','.
usage.2 = If no CLASSPATH is given the virtual machine classpath is used.
browse.filter.description = *.jar, *.zip Archives
browse.title = Browse
cpdialog.title = Set Class Path
button.okay=Okay
button.apply=Apply
button.cancel=Cancel
button.select=Select
button.browse=Browse...
button.add=Add
button.remove=Remove
main.decompiling=decompiling
main.exception = \nException while decompiling:
menu.file = File
menu.file.save = Save...
menu.file.save.ex = An Exception occured on filewriting!
menu.file.gc = Collect Garbage
menu.file.exit = Exit
menu.opt = Options
menu.opt.hier = Class Hierarchy
menu.opt.cp = Set Class Path...

@ -0,0 +1,28 @@
usage.count=3
usage.0 = Syntax: java jode.swingui.Main [CLASSPATH]
usage.1 = Die Verzeichnisse in CLASSPATH werden durch Kommas abgetrennt.
usage.2 = Wird kein CLASSPATH angegeben, so wird Java's standard classpath verwendet.
browse.filter.description = *.jar, *.zip Archive
browse.title = Durchsuchen
cpdialog.title = Setze Classpath
button.okay = Ok
button.apply = Anwenden
button.cancel = Abbruch
button.select = Selektieren
button.browse = Durchsuchen...
button.add = HinzufĂĽgen
button.remove = Entfernen
main.decompiling = dekompiliere
main.exception = \nBeim Dekompilieren ist ein Fehler aufgetreten:
menu.file = Datei
menu.file.save = Speichern...
menu.file.save.ex = Beim Schreiben der Datei trat eine Ausnahme auf!
menu.file.gc = Speicher freiräumen
menu.file.exit = Beenden
menu.opt = Optionen
menu.opt.hier = Klassen-Hierarchie
menu.opt.cp = Setze Classpath...

@ -0,0 +1,94 @@
#!/usr/bin/perl
# addHeader.pl 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$
# This perl script just adds the copyright header to all given java files,
# removing a possible previous header.
for (@ARGV) {
my $file = $_;
$file =~ m=([^/]*)\.java(\.in)?$= or do {
print STDERR "$file is not a java file";
next;
};
my $class = $1;
my $curyear = `date +%Y`;
chomp $curyear;
# my $firstcheckin = `rlog $file 2>/dev/null |grep date| tail -1`;
# my $firstyear =
# ($firstcheckin =~ m=date: ([0-9]+)/[0-9]+/[0-9]+=) ? $1 : $curyear;
# my $lastcheckin = `rlog $file 2>/dev/null |grep date| head -1`;
# my $lastyear =
# ($firstcheckin =~ m=date: ([0-9]+)/[0-9]+/[0-9]+=) ? $1 : $curyear;
open FILE, "<$file";
while (<FILE>) {
$firstyear = $1 if /Copyright \(C\) (\d{4})/;
last if /^package/;
}
$firstyear = $curyear if ! $firstyear;
my $lastyear = $curyear;
my $years = ($firstyear == $lastyear)
? $firstyear : "$firstyear-$lastyear";
my $lesser = "";
my $dotlesser = "";
if ($file =~ m!jode/(util|bytecode|jvm|flow|expr|decompiler
|GlobalOptions|AssertError)!x) {
$lesser = " Lesser";
$dotlesser = ".LESSER";
}
rename "$file", "$file.orig" or do {
print STDERR "Can't open file $file\n";
next;
};
open OLD, "<$file.orig";
open NEW, ">$file";
print NEW <<"EOF";
/* $class Copyright (C) $years Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU$lesser General Public License as published by
* the Free Software Foundation; either version 2, 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$lesser General Public License
* along with this program; see the file COPYING$dotlesser. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* \$Id\$
*/
EOF
while (<OLD>) {
/^package/ and last;
}
print NEW $_;
while (<OLD>) {
print NEW $_;
}
}

@ -0,0 +1,134 @@
#!/usr/bin/perl
# createStackDelta.pl 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$
# This perl script creates the stackDelta string needed by
# jode.bytecode.Instruction.
my $OPCODEFILE="jode/bytecode/Opcodes.java";
my @delta;
my $lastOpcode = 0;
my $nr;
open OPCODES, "<$OPCODEFILE";
while (<OPCODES>) {
next unless /opc_([a-z0-9_]+)\s*=\s*(\d+)/;
$_ = $1;
$nr = $2;
if (/^(nop|iinc)$/) {
# no pop, no push
$delta[$nr] = "000";
} elsif (/^([aif](const|load).*|[sb]ipush|ldc(_w)?)$/) {
# no pop, one push
$delta[$nr] = "010";
} elsif (/^([ld](const|load).*|ldc2_w)$/) {
# no pop, two push
$delta[$nr] = "020";
} elsif (/^([aif]store.*|pop)$/) {
# one pop, no push
$delta[$nr] = "001";
} elsif (/^([ld]store.*|pop2)$/) {
# two pop, no push
$delta[$nr] = "002";
} elsif (/^[aifbcs]aload$/) {
# two pop, one push
$delta[$nr] = "012";
} elsif (/^[dl]aload$/) {
# two pop, two push
$delta[$nr] = "022";
} elsif (/^[aifbcs]astore$/) {
# three pop, no push
$delta[$nr] = "003";
} elsif (/^[dl]astore$/) {
# four pop, no push
$delta[$nr] = "004";
} elsif (/^dup(2)?(_x([12]))?$/) {
$count = $1 ? 2 : 1;
$depth = $2 ? $3 : 0;
$pop = $count + $depth;
$push = $pop + $count;
$delta[$nr] = "0".$push.$pop;
} elsif (/^swap$/) {
# two pop, two push
$delta[$nr] = "022";
} elsif (/^[if](add|sub|mul|div|rem|u?sh[lr]|and|or|xor)$/) {
# two pop, one push
$delta[$nr] = "012";
} elsif (/^[ld](add|sub|mul|div|rem|and|or|xor)$/) {
# four pop, two push
$delta[$nr] = "024";
} elsif (/^[if]neg$/) {
# one pop, one push
$delta[$nr] = "011";
} elsif (/^[ld]neg$/) {
# two pop, two push
$delta[$nr] = "022";
} elsif (/^lu?sh[lr]$/) {
# 3 pop, two push
$delta[$nr] = "023";
} elsif (/^[if]2[ifbcs]$/) {
# one pop, one push
$delta[$nr] = "011";
} elsif (/^[if]2[ld]$/) {
# one pop, two push
$delta[$nr] = "021";
} elsif (/^[ld]2[if]$/) {
# two pop, one push
$delta[$nr] = "012";
} elsif (/^[ld]2[ld]$/) {
# two pop, two push
$delta[$nr] = "022";
} elsif (/^fcmp[lg]$/) {
$delta[$nr] = "012";
} elsif (/^[ld]cmp[lg]?$/) {
$delta[$nr] = "014";
} elsif (/^if_[ia]cmp(eq|ne|lt|ge|le|gt)$/) {
$delta[$nr] = "002";
} elsif (/^(if(eq|ne|lt|ge|le|gt|(non)?null)|tableswitch|lookupswitch)$/) {
# order does matter
$delta[$nr] = "001";
} elsif (/^(goto(_w)?|jsr(_w)?|ret|return)$/) {
$delta[$nr] = "000";
} elsif (/^([ifa]return)$/) {
$delta[$nr] = "001";
} elsif (/^([ld]return)$/) {
$delta[$nr] = "002";
} elsif (/^(new)$/) {
$delta[$nr] = "010";
} elsif (/^(multianewarray|(get|put|invoke).*)$/) {
# unknown
$delta[$nr] = "100";
} elsif (/^(athrow|monitor(enter|exit))$/) {
$delta[$nr] = "001";
} elsif (/^(a?newarray|arraylength|checkcast|instanceof)$/) {
$delta[$nr] = "011";
} else {
# illegal
next;
}
$lastOpcode = $nr
if ($nr > $lastOpcode);
}
print " private final static String stackDelta = \n\t\"";
for ($nr = 0; $nr <= $lastOpcode; $nr ++) {
defined $delta[$nr] or $delta[$nr] = "177";
print "\\$delta[$nr]";
}
print "\";\n";

@ -0,0 +1,184 @@
#!/usr/bin/perl -s -w
#
# javaDependencies 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$
# This scripts create Makefile dependencies out of class files. It
# simply scans the constant pool of the class files, finding all
# references to other classes and adding a dependency to that class.
#
# It doesn't do a perfect job, since it can't handle dependencies to
# constant values in different classes: The compiler inlines the
# constant and thus doesn't include a reference to the class.
#
# Usage:
# javaDependencies.pl -classpath <cp> [-dependdir <depdir> [-subdir <subdir>]]
# [-depfile <depfile>]
# <classfiles>
#
# cp: colon separated paths to the java files we should depend on.
# depdir: if set, use this path as path to the java files when printing
# dependencies, not the path where the java files were found.
# useful, if you want to make use of VPATH settings in Makefile.
# subdir: if set, this is the path from depdir to the current directory.
# Use it to remove unneccessary ../../$subdir/
# depfile: the name of the dependency file, default is "Makefile.dep".
# class: The class files (not inner classes) for which the dependencies
# should be generated. We will also look for inner and anon
# classes.
my $buff;
sub readInBuff ($) {
my $count = $_[0];
my $offset = 0;
while ($count > 0) {
my $result;
$result = read FILE, $buff, $count, $offset or return 0;
$offset += $result;
$count -= $result;
}
$offset;
}
sub readUTF () {
readInBuff 2 or die "Can't read UTF8 length";
my $ulength = unpack("n", $buff) & 0xffff;
return "" if $ulength == 0;
readInBuff $ulength or die "Can't read UTF8 string $ulength";
unpack("a$ulength", $buff);
}
$depfile = "Makefile.dep" if (!defined($depfile));
open DEPFILE, ">$depfile";
print DEPFILE <<EOF;
# This dependency file is automatically created by $0 from class files.
# Do not edit.
EOF
foreach $clazz (@ARGV) {
next if $clazz =~ (/^.*\$.*\.class/);
$clazz =~ /([^\$]*)(\$.*)?\.class/ or die "not a class file";
$base = $1;
my ($filename, %done);
%done=();
for $filename ($clazz, glob("$base\\\$*.class")) {
open FILE, $filename;
binmode FILE;
readInBuff 8 or die "Can't read header";
my ($magic, $major, $minor) = unpack("Nnn", $buff);
die "Wrong magic $magic" if $magic != 0xcafebabe;
die "Wrong major $major" if $major != 3;
die "Wrong minor $minor" if $minor < 45;
readInBuff 2 or die "Can't read cpool length";
my ($length) = unpack("n", $buff) & 0xffff;
my $number;
my @strings = ();
my @clazzes;
for ($number = 1; $number < $length; $number++) {
readInBuff 1 or die "Can't read constant tag";
my ($tag) = unpack("C", $buff);
#print STDERR "$number/$length: $tag";
tags:
for ($tag) {
/^1$/ && do {
# UTF 8
$strings[$number] = &readUTF();
#print STDERR ": $strings[$number]";
last tags;
};
/^(3|4|9|10|11|12)$/ && do {
# INTEGER, FLOAT, FIELDREF, METHODREF, IFACEREF, NAMEANDTYPE
readInBuff 4;
last tags;
};
/^(5|6)$/ && do {
# LONG, DOUBLE
readInBuff 8;
$number++;
last tags;
};
/^7$/ && do {
# CLASS
readInBuff 2;
push @clazzes, (unpack("n", $buff) & 0xffff);
last tags;
};
/^8$/ && do {
# STRING
readInBuff 2;
last tags;
};
die "Unknown tag: $tag, $number/$length, $filename";
}
#print STDERR "\n";
}
my @deplist = ();
clazz:
for $c (@clazzes) {
$clzz = $strings[$c];
next if $clzz =~ /^\[/;
next if defined $done{"$clzz"};
$done{$clzz} = 1;
my $p;
for $p (split ':', $classpath) {
if (-e "$p/$clzz.java") {
my $path="$p/";
if (defined $dependdir) {
$path = "$dependdir/";
if (defined $subdir) {
my $currsubdir = "$subdir/";
while ($currsubdir =~ m<^([A-Za-z0-9]+)/+(.*)>) {
$currsubdir = $2;
my $firstcomp = $1;
if ($clzz =~ m<$firstcomp/(.*)>) {
my $remain = $1;
if ($path =~ m<^(|.*/)\.\./+$>) {
$path = $1;
$clzz = $remain;
}
}
}
}
}
push @deplist, "$path$clzz.java";
next clazz;
}
}
}
if (@deplist) {
print DEPFILE "$clazz: " . join (" ", @deplist) . "\n";
}
}
}
close DEPFILE;

@ -0,0 +1,234 @@
#!/usr/bin/perl -w
#
# jcpp Copyright (C) 1999-2001 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$
# This is a program to allow conditional compiled code in java files.
# The key idea is, not to run the file always through the
# preprocessor, but to modify the java files directly and make use of
# comments.
#
# The comments all have the form /// and start at the beginning of the
# line to distinguish them from normal comments. You must not use
# such comments for other purposes.
#
# Usage is simple: jcpp -Ddefine1 -Ddefine2 first.java second.java
# The files should contain comments of the form
#
# ///#ifdef JDK12
# jdk1.2 code
# ///#else
# jdk1.1 code
# ///#endif
#
# After running jcpp the false branch is commented out. If the true
# branch was commented out it will get commented in.
#
# jcpp can also change definitions, useful for package renaming. The
# java file should look like this:
#
# ///#def COLLECTIONS java.util
# import java.util.Vector
# import java.util.ArrayList
# ///#enddef
#
# If jcpp is then called with -DCOLLECTIONS=gnu.java.util.collections
# it will replace every occurence of java.util (the string in the #def
# line) with the new value:
#
# ///#def COLLECTIONS gnu.java.util.collections
# import gnu.java.util.collections.Vector
# import gnu.java.util.collections.ArrayList
# ///#enddef
my @files;
my %defs;
for (@ARGV) {
if ($_ =~ /^-D([^=]*)$/) {
$defs{$1} = 1;
} elsif ($_ =~ /^-D([^=]*)=([^=]*)$/) {
$defs{$1} = $2;
} else {
push @files, $_;
}
}
for (@files) {
# Number of nested #if directives. Initially 0, will be increased
# on every #if directive and decreased on every #endif directive.
my $level = 0;
# The number of the outermost level, whose #if directive was
# false. This is 0, if there wasn't an false #if directive, yet.
# As long as it is != 0, we comment every line, and ignore
# directives except for increasing/decreasing $level.
my $falselevel = 0;
# Tells if an error occured and the transformation shouldn't
# be done.
my $error = 0;
my $changes = 0;
# The list of #def replacements, @replold is the previous value,
# @replnew the new one.
my @replold = ();
my @replnew = ();
my $file = $_;
open OLD, "<$file" or do {
print STDERR "Can't open file $file\n";
next;
};
open NEW, ">$file.tmp" or do {
print STDERR "Can't open tmp file $file.tmp\n";
next;
};
my $linenr = 0;
LINE:
while (<OLD>) {
$linenr++;
if (m'^///#') {
# This is a directive. First we print it out.
if (m'^///#\s*if') {
$level++;
if (m'^///#\s*ifdef\s+(\w+)\s*$') {
# If there was an outer false #if directive, we ignore the
# condition.
next LINE if ($falselevel);
my $label=$1;
# An ifdef directive, look if -D is defined.
$falselevel = $level
unless (defined $defs{$label});
} elsif (m'^///#\s*ifndef\s+(\w+)\s*$') {
# If there was an outer false #if directive, we ignore the
# condition.
next LINE if ($falselevel);
my $label=$1;
# An ifndef directive, look if -D is defined
$falselevel = $level
if (defined $defs{$label});
} elsif (m'^///#\s*if\s+(\w+)\s*(==|!=)\s*(\S+)\s*$') {
# If there was an outer false #if directive, we ignore the
# condition.
next LINE if ($falselevel);
my $label=$1;
my $value=$3;
# An ifdef directive, look if -D is defined.
$falselevel = $level
unless ($2 eq "==" ? $defs{$label} eq $value
: $defs{$label} ne $value);
} elsif (m'^///#\s*if\s+(\w+)\s*(>=|<=|>|<)\s*(\S+)\s*$') {
# If there was an outer false #if directive, we ignore the
# condition.
next LINE if ($falselevel);
my $label=$1;
my $value=$3;
# An ifdef directive, look if -D is defined.
$falselevel = $level
unless ($2 eq ">=" ? $defs{$label} >= $value
: $2 eq "<=" ? $defs{$label} <= $value
: $2 eq ">" ? $defs{$label} > $value
: $defs{$label} < $value);
}
} elsif (m'^///#\s*else\s*$') {
# An else directive. We switch from true to false and
# if level is falselevel we switch from false to true
if ($level == 0) {
# An else outside of any directives; warn.
print STDERR "$file: $linenr: unmatched $_";
$error = 1;
} elsif ($falselevel == $level) {
$falselevel = 0;
} elsif ($falselevel == 0) {
$falselevel = $level;
}
} elsif (m'^///#\s*endif\s*$') {
# set $falselevel to 0, if the false branch is over now.
$falselevel = 0 if ($falselevel == $level);
# decrease level.
if ($level == 0) {
print STDERR "$file: $linenr: unmatched $_";
$error = 1;
} else {
$level--;
}
} elsif (m'^///#\s*def\s+(\w+)\s+(\S*)$') {
my $label = $1;
my $old = $2;
my $new = $defs{$label};
if (defined $new && $new ne $old) {
push @replold, "$old";
push @replnew, "$new";
$changes = 1;
} else {
push @replnew, "";
push @replold, "";
}
} elsif (m'^///#\s*enddef\s*$') {
pop @replold;
pop @replnew;
} else {
print STDERR "$file: $linenr: ignoring unknown directive $_";
$error = 1;
}
} elsif (m'^///(.*)') {
$line = $1;
if ($falselevel == 0 && $level > 0) {
# remove comments in true branch, but not in outermost level.
$_ = "$line\n";
$changes = 1;
}
} else {
if ($falselevel != 0) {
# add comments in false branch
$_ = "///$_";
$changes = 1;
}
}
for ($i = 0; $i < @replold; $i++) {
$_ =~ s/\Q$replold[$i]\E/$replnew[$i]/ if ($replold[$i] ne "");
}
print NEW $_;
}
if ($level != 0 || $falselevel != 0) {
# something got wrong
print STDERR "$file: unmatched directives: level $level, ".
"falselevel $falselevel\n";
$error = 1;
}
if ($error == 0) {
if ($changes == 0) {
unlink "$file.tmp";
} else {
(unlink "$file" and rename "$file.tmp", "$file")
or print STDERR "$file: Couldn't rename files.\n";
}
} else {
print STDERR "$file: errors occured, file not transformed.\n";
}
}

@ -0,0 +1,15 @@
#!/usr/bin/perl -w
my $num = 0;
for (@ARGV) {
next if $_ !~ /\.php$/;
$html = $php = $_;
$html =~ s/\.php$/.html/;
$ENV{extension}="html";
if (! -e "$html" || (-M "$php" <= -M "$html")) {
$num++;
system "php -f $php >$html";
}
}
print $num . " html files updated.\n";

@ -0,0 +1,107 @@
/* GlobalOptions Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.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-2004 Jochen Hoenicke <"+email+">";
public final static String URL = "http://jode.sourceforge.net/";
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.
* @exception IllegalArgumentException
* if a problem occured while parsing the argument.
*/
public static boolean setDebugging(String debuggingString) {
if (debuggingString.length() == 0 || debuggingString.equals("help")) {
usageDebugging();
throw new IllegalArgumentException();
}
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;
}
}
throw new IllegalArgumentException("Illegal debugging flag: "
+token);
}
return true;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,409 @@
/* BasicBlocks Copyright (C) 2000-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.GlobalOptions;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.BitSet;
import java.util.Stack;
///#def COLLECTIONS java.util
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
///#enddef
///#def COLLECTIONEXTRA java.lang
import java.lang.UnsupportedOperationException;
///#enddef
/**
* <p>Represents the byte code of a method in form of basic blocks. A
* basic block is a bunch of instructions, that must always execute in
* sequential order. Every basic block is represented by an Block
* object.</p>
*
* <p>All jump instructions must be at the end of the block, and the
* jump instructions doesn't have to remember where they jump to.
* Instead this information is stored inside the blocks. See
* <code>Block</code> for details.</p>
*
* <p>Exception Handlers are represented by the Handler class. Their
* start/end range must span over some consecutive BasicBlocks and
* there handler must be another basic block.</p>
*
* <!-- <p>Future work: A subroutine block, i.e. a block where some jsr
* instructions may jump to, must store its return address in a local
* variable immediately. There must be exactly one block with the
* corresponding <code>opc_ret</code> instruction and all blocks that
* belong to this subroutine must point to the ret block. Bytecode
* that doesn't have this condition is automatically transformed on
* reading.</p> -->
*
* <p>When the code is written to a class file, the blocks are written
* in the given order. Goto and return instructions are inserted as
* necessary, you don't need to care about that.</p>
*
* <h3>Creating new BasicBlocks</h3>
*
* <p>If you want to create a new BasicBlocks object, first create the
* Block objects, then initialize them (you need to have all successor
* blocks created for this). Afterwards create a new BasicBlock and
* fill its sub blocks: </p>
*
* <pre>
* MethodInfo myMethod = new MethodInfo("foo", "()V", PUBLIC);
* Block blocks = new Block[10];
* for (int i = 0; i < 10; i++) blocks[i] = new Block();
* blocks[0].setCode(new Instruction[] {...},
* new Block[] {blocks[3], blocks[1]});
* ...
* Handler[] excHandlers = new Handler[1];
* excHandlers[0] = new Handler(blocks[2], blocks[5], blocks[6],
* "java.lang.NullPointerException");
* BasicBlocks bb = new BasicBlocks(myMethod);
* bb.setCode(blocks, blocks[0], excHandlers);
* classInfo.setMethods(new MethodInfo[] { myMethod });
* </pre>
*
* @see net.sf.jode.bytecode.Block
* @see net.sf.jode.bytecode.Instruction
*/
public class BasicBlocks extends BinaryInfo implements Opcodes {
/**
* The method info which contains the basic blocks.
*/
private MethodInfo methodInfo;
/**
* The maximal number of stack entries, that may be used in this
* method.
*/
int maxStack;
/**
* The maximal number of local slots, that may be used in this
* method.
*/
int maxLocals;
/**
* This is an array of blocks, which are arrays
* of Instructions.
*/
private Block[] blocks;
/**
* The start block. Normally the first block, but differs if method start
* with a goto, e.g a while. This may be null, if this method is empty.
*/
private Block startBlock;
/**
* The local variable infos for the method parameters.
*/
private LocalVariableInfo[] paramInfos;
/**
* The array of exception handlers.
*/
private Handler[] exceptionHandlers;
public BasicBlocks(MethodInfo mi) {
methodInfo = mi;
int paramSize = (mi.isStatic() ? 0 : 1)
+ TypeSignature.getParameterSize(mi.getType());
paramInfos = new LocalVariableInfo[paramSize];
for (int i=0; i< paramSize; i++)
paramInfos[i] = LocalVariableInfo.getInfo(i);
}
public int getMaxStack() {
return maxStack;
}
public int getMaxLocals() {
return maxLocals;
}
public MethodInfo getMethodInfo() {
return methodInfo;
}
public Block getStartBlock() {
return startBlock;
}
public Block[] getBlocks() {
return blocks;
}
/**
* @return the exception handlers, or null if the method has no
* exception handlers.
*/
public Handler[] getExceptionHandlers() {
return exceptionHandlers;
}
public LocalVariableInfo getParamInfo(int i) {
return paramInfos[i];
}
public int getParamCount() {
return paramInfos.length;
}
/**
* Updates the maxStack and maxLocals according to the current code.
* Call this every time you change the code.
*/
public void updateMaxStackLocals() {
maxLocals = getParamCount();
maxStack = 0;
if (startBlock == null)
return;
BitSet visited = new BitSet();
Stack todo = new Stack();
int[] poppush = new int[2];
startBlock.stackHeight = 0;
todo.push(startBlock);
while (!todo.isEmpty()) {
Block block = (Block) todo.pop();
int stackHeight = block.stackHeight;
if (stackHeight + block.maxpush > maxStack)
maxStack = stackHeight + block.maxpush;
stackHeight += block.delta;
Block[] succs = block.getSuccs();
Instruction[] instr = block.getInstructions();
for (int i = 0; i < instr.length; i++) {
if (instr[i].hasLocal()) {
int slotlimit = instr[i].getLocalSlot() + 1;
int opcode = instr[i].getOpcode();
if (opcode == opc_lstore || opcode == opc_dstore
|| opcode == opc_lload || opcode == opc_dload)
slotlimit++;
if (slotlimit > maxLocals)
maxLocals = slotlimit;
}
}
if (instr.length > 0
&& instr[instr.length-1].getOpcode() == opc_jsr) {
if (!visited.get(succs[0].blockNr)) {
succs[0].stackHeight = stackHeight + 1;
todo.push(succs[0]);
visited.set(succs[0].blockNr);
} else if (succs[0].stackHeight != stackHeight + 1)
throw new IllegalArgumentException
("Block has two different stack heights.");
if (succs[1] != null && !visited.get(succs[1].blockNr)) {
succs[1].stackHeight = stackHeight;
todo.push(succs[1]);
visited.set(succs[1].blockNr);
} else if ((succs[1] == null ? 0 : succs[1].stackHeight)
!= stackHeight)
throw new IllegalArgumentException
("Block has two different stack heights.");
} else {
for (int i = 0; i < succs.length; i++) {
if (succs[i] != null && !visited.get(succs[i].blockNr)) {
succs[i].stackHeight = stackHeight;
todo.push(succs[i]);
visited.set(succs[i].blockNr);
} else if ((succs[i] == null ? 0 : succs[i].stackHeight)
!= stackHeight)
throw new IllegalArgumentException
("Block has two different stack heights.");
}
}
Handler[] handler = block.getHandlers();
for (int i = 0; i < handler.length; i++) {
if (!visited.get(handler[i].getCatcher().blockNr)) {
handler[i].getCatcher().stackHeight = 1;
todo.push(handler[i].getCatcher());
visited.set(handler[i].getCatcher().blockNr);
} else if (handler[i].getCatcher().stackHeight != 1)
throw new IllegalArgumentException
("Block has two different stack heights.");
}
}
}
public void setBlocks(Block[] blocks, Block startBlock,
Handler[] handlers) {
this.blocks = blocks;
this.startBlock = startBlock;
exceptionHandlers = handlers.length == 0 ? Handler.EMPTY : handlers;
ArrayList activeHandlers = new ArrayList();
for (int i = 0; i < blocks.length; i++) {
blocks[i].blockNr = i;
for (int j = 0; j < handlers.length; j++) {
if (handlers[j].getStart() == blocks[i])
activeHandlers.add(handlers[j]);
}
if (activeHandlers.size() == 0)
blocks[i].catchers = Handler.EMPTY;
else
blocks[i].catchers =
(Handler[]) activeHandlers.toArray(Handler.EMPTY);
for (int j = 0; j < handlers.length; j++) {
if (handlers[j].getEnd() == blocks[i])
activeHandlers.remove(handlers[j]);
}
}
/* Check if all successor blocks are in this basic block */
for (int i = 0; i < blocks.length; i++) {
Block[] succs = blocks[i].getSuccs();
for (int j = 0; j < succs.length; j++) {
if (succs[j] != null
&& succs[j] != blocks[succs[j].blockNr])
throw new IllegalArgumentException
("Succ " + j + " of block " + i
+ " not in basicblocks");
}
}
updateMaxStackLocals();
// TransformSubroutine.createSubroutineInfo(this);
}
/**
* Sets the name and type of a method parameter. This overwrites
* any previously set parameter info for this slot.
* @param info a local variable info mapping a slot nr to a name
* and a type.
*/
public void setParamInfo(LocalVariableInfo info) {
paramInfos[info.getSlot()] = info;
}
private BasicBlockReader reader;
void read(ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.println("Reading "+methodInfo);
reader = new BasicBlockReader(this);
reader.readCode(cp, input);
readAttributes(cp, input, howMuch);
reader.convert();
reader = null;
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0)
dumpCode(GlobalOptions.err);
}
protected void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if (howMuch >= ClassInfo.ALMOSTALL
&& name.equals("LocalVariableTable")) {
reader.readLVT(length, cp, input);
} else if (howMuch >= ClassInfo.ALMOSTALL
&& name.equals("LineNumberTable")) {
reader.readLNT(length, cp, input);
} else
super.readAttribute(name, length, cp, input, howMuch);
}
void reserveSmallConstants(GrowableConstantPool gcp) {
for (int i=0; i < blocks.length; i++) {
next_instr:
for (Iterator iter
= Arrays.asList(blocks[i].getInstructions()).iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == Opcodes.opc_ldc) {
Object constant = instr.getConstant();
if (constant == null)
continue next_instr;
for (int j=1; j < Opcodes.constants.length; j++) {
if (constant.equals(Opcodes.constants[j]))
continue next_instr;
}
if (constant instanceof Integer) {
int value = ((Integer) constant).intValue();
if (value >= Short.MIN_VALUE
&& value <= Short.MAX_VALUE)
continue next_instr;
}
gcp.reserveConstant(constant);
}
}
}
}
BasicBlockWriter bbw;
void prepareWriting(GrowableConstantPool gcp) {
bbw = new BasicBlockWriter(this, gcp);
prepareAttributes(gcp);
}
protected int getAttributeCount() {
return super.getAttributeCount() + bbw.getAttributeCount();
}
protected void writeAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
super.writeAttributes(gcp, output);
bbw.writeAttributes(gcp, output);
}
void write(GrowableConstantPool gcp,
DataOutputStream output) throws IOException {
output.writeInt(bbw.getSize() + getAttributeSize());
bbw.write(gcp, output);
writeAttributes(gcp, output);
bbw = null;
}
public void dumpCode(PrintWriter output) {
output.println(methodInfo.getName()+methodInfo.getType()+":");
if (startBlock == null)
output.println("\treturn");
else if (startBlock != blocks[0])
output.println("\tgoto "+startBlock);
for (int i=0; i< blocks.length; i++) {
blocks[i].dumpCode(output);
}
for (int i=0; i< exceptionHandlers.length; i++) {
output.println("catch " + exceptionHandlers[i].type
+ " from " + exceptionHandlers[i].start
+ " to " + exceptionHandlers[i].end
+ " catcher " + exceptionHandlers[i].catcher);
}
}
public String toString() {
return "BasicBlocks["+methodInfo+"]";
}
}

@ -0,0 +1,405 @@
/* BinaryInfo Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import net.sf.jode.util.SimpleMap;
///#def COLLECTIONS java.util
import java.util.Map;
import java.util.Collections;
import java.util.Iterator;
///#enddef
/**
* <p>Represents a container for user specified attributes.</p>
*
* <p>Java bytecode is extensible: Classes, Methods and Fields may
* have any number of attributes. Every attribute has a name and some
* unformatted data.</p>
*
* <p>There are some predefined attributes, even the Code of a Method
* is an attribute. These predefined attributes are all handled by
* this package as appropriate. These methods are only useful for non
* standard attributes.</p>
*
* <p>You can provide new attributes by overriding the protected
* methods of this class. This makes it possible to use constant pool
* entries in the attributes.</p>
*
* <p>Another possibility is to add the attributes with the public
* method. This way you don't need to extend the classes, but you
* can't use a constant pool for the contents of the attributes. One
* possible application of this are installation classes. These
* classes have a special attribute containing a zip archive of the
* files that should be installed. There are other possible uses,
* e.g. putting native machine code for some architectures into the
* class.</p>
*
* @author Jochen Hoenicke
*/
public class BinaryInfo {
/**
* The bit mask representing public modifier.
*/
public static int ACC_PUBLIC = 0x0001;
/**
* The bit mask representing private modifier.
*/
public static int ACC_PRIVATE = 0x0002;
/**
* The bit mask representing protected modifier.
*/
public static int ACC_PROTECTED = 0x0004;
/**
* The bit mask representing static modifier.
*/
public static int ACC_STATIC = 0x0008;
/**
* The bit mask representing final modifier.
*/
public static int ACC_FINAL = 0x0010;
/**
* The bit mask representing the ACC_SUPER modifier for classes.
* This is a special modifier that only has historic meaning. Every
* class should have this set.
*/
public static int ACC_SUPER = 0x0020;
/**
* The bit mask representing volatile modifier for fields.
*/
public static int ACC_VOLATILE = 0x0040;
/**
* The bit mask representing synthetic bridge method. This is
* used when a non-generic method overrides a generic method of
* super class/interface.
*/
public static int ACC_BRIDGE = 0x0040;
/**
* The bit mask representing transient fields.
*/
public static int ACC_TRANSIENT = 0x0080;
/**
* The bit mask representing varargs methods.
*/
public static int ACC_VARARGS = 0x0080;
/**
* The bit mask representing enumeration fields.
*/
public static int ACC_ENUM = 0x0100;
/**
* The bit mask representing native methods.
*/
public static int ACC_NATIVE = 0x0100;
/**
* The bit mask representing interfaces.
*/
public static int ACC_INTERFACE = 0x0200;
/**
* The bit mask representing abstract modifier.
*/
public static int ACC_ABSTRACT = 0x0400;
/**
* The bit mask representing annotation classes.
*/
public static int ACC_ANNOTATION = 0x0800;
/**
* The bit mask representing strictfp modifier.
*/
public static int ACC_STRICT = 0x0800;
/**
* The bit mask representing synthetic fields/methods and classes.
*/
public static int ACC_SYNTHETIC = 0x1000;
private Map unknownAttributes = null;
void skipAttributes(DataInputStream input) throws IOException {
int count = input.readUnsignedShort();
for (int i=0; i< count; i++) {
input.readUnsignedShort(); // the name index
long length = input.readInt();
while (length > 0) {
long skipped = input.skip(length);
if (skipped == 0)
throw new EOFException("Can't skip. EOF?");
length -= skipped;
}
}
}
/**
* Reads in an attributes of this class. Overwrite this method if
* you want to handle your own attributes. If you don't know how
* to handle an attribute call this method for the super class.
* @param name the attribute name.
* @param length the length of the attribute.
* @param constantPool the constant pool of the class.
* @param input a data input stream where you can read the attribute
* from. It will protect you to read more over the attribute boundary.
* @param howMuch the constant that was given to the {@link
* ClassInfo#load} function when loading this class.
*/
protected void readAttribute(String name, int length,
ConstantPool constantPool,
DataInputStream input,
int howMuch) throws IOException {
byte[] data = new byte[length];
input.readFully(data);
if (howMuch >= ClassInfo.ALL) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
unknownAttributes.put(name, data);
}
}
static class ConstrainedInputStream extends FilterInputStream {
int length;
public ConstrainedInputStream(int attrLength, InputStream input) {
super(input);
length = attrLength;
}
public int read() throws IOException {
if (length > 0) {
int data = super.read();
length--;
return data;
}
throw new EOFException();
}
public int read(byte[] b, int off, int len) throws IOException {
if (length < len) {
len = length;
}
if (len == 0)
return -1;
int count = super.read(b, off, len);
length -= count;
return count;
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
public long skip(long count) throws IOException {
if (length < count) {
count = length;
}
count = super.skip(count);
length -= (int) count;
return count;
}
public void skipRemaining() throws IOException {
while (length > 0) {
int skipped = (int) skip(length);
if (skipped == 0)
throw new EOFException();
length -= skipped;
}
}
}
void readAttributes(ConstantPool constantPool,
DataInputStream input,
int howMuch) throws IOException {
int count = input.readUnsignedShort();
unknownAttributes = null;
for (int i=0; i< count; i++) {
String attrName =
constantPool.getUTF8(input.readUnsignedShort());
final int attrLength = input.readInt();
ConstrainedInputStream constrInput =
new ConstrainedInputStream(attrLength, input);
readAttribute(attrName, attrLength,
constantPool, new DataInputStream(constrInput),
howMuch);
constrInput.skipRemaining();
}
}
/**
* Drops information from this info. Override this to drop your
* own info and don't forget to call the method of the super class.
* @param keep the constant representing how much information we
* should keep (see {@link ClassInfo#load}).
*/
protected void drop(int keep) {
if (keep < ClassInfo.ALL)
unknownAttributes = null;
}
/**
* Returns the number of attributes of this class. Overwrite this
* method if you want to add your own attributes by providing a
* writeAttributes method. You should call this method for the
* super class and add the number of your own attributes to the
* returned value.
* @return the number of attributes of this class.
*/
protected int getAttributeCount() {
return unknownAttributes != null ? unknownAttributes.size() : 0;
}
/**
* Prepare writing your attributes. Overwrite this method if you
* want to add your own attributes, which need constants on the
* class pool. Add the necessary constants to the constant pool
* and call this method for the super class.
* @param gcp The growable constant pool.
*/
protected void prepareAttributes(GrowableConstantPool gcp) {
if (unknownAttributes == null)
return;
Iterator i = unknownAttributes.keySet().iterator();
while (i.hasNext())
gcp.putUTF8((String) i.next());
}
/**
* <p>Writes the attributes to the output stream.
* Overwrite this method if you want to add your own attributes.
* All constants you need from the growable constant pool must
* have been previously registered by the {@link #prepareAttributes}
* method. This method must not add new constants to the pool</p>
*
* First call the method of the super class. Afterwrites write
* each of your own attributes including the attribute header
* (name and length entry).
*
* @param constantPool The growable constant pool, which is not
* growable anymore (see above).
* @param output the data output stream. You must write exactly
* as many bytes to it as you have told with the {@link
* #getAttributeSize} method.
*/
protected void writeAttributes
(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
int count = getAttributeCount();
output.writeShort(count);
if (unknownAttributes != null) {
Iterator i = unknownAttributes.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
String name = (String) e.getKey();
byte[] data = (byte[]) e.getValue();
output.writeShort(constantPool.putUTF8(name));
output.writeInt(data.length);
output.write(data);
}
}
}
/**
* Gets the total length of all attributes in this binary info.
* Overwrite this method if you want to add your own attributes
* and add the size of your attributes to the value returned by
* the super class.<br>
*
* Currently you only need to write this if you extend
* BasicBlocks.
*
* @return the total length of all attributes, including their
* headers and the "number of attributes" field.
*/
protected int getAttributeSize() {
int size = 2; /* attribute count */
if (unknownAttributes != null) {
Iterator i = unknownAttributes.values().iterator();
while (i.hasNext())
size += 2 + 4 + ((byte[]) i.next()).length;
}
return size;
}
/**
* Finds a non standard attribute with the given name. You don't
* have access to the constant pool. If you need the pool don't
* use this method but extend this class and override
* readAttribute method.
* @param name the name of the attribute.
* @return the contents of the attribute, null if not found.
* @see #readAttribute
*/
public byte[] findAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.get(name);
return null;
}
/**
* Gets all non standard attributes.
* @return an iterator for all attributes. The values returned by
* the next() method of the iterator are of Map.Entry type. The
* key of the entry is the name of the attribute, while the values
* are the byte[] contents.
* @see #findAttribute
*/
public Iterator getAttributes() {
if (unknownAttributes != null)
return unknownAttributes.entrySet().iterator();
return Collections.EMPTY_SET.iterator();
}
/**
* Adds a new non standard attribute or replaces an old one with
* the same name. If it already exists, it will be overwritten.
* Note that there's now way to correlate the contents with a
* constant pool. If you need that extend this class and override
* the methods {@link #getAttributeCount}, {@link
* #prepareAttributes}, {@link #writeAttributes}, and {@link
* #getAttributeSize}.
* @param name the name of the attribute.
* @param contents the new contens.
*/
public void addAttribute(String name, byte[] contents) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
unknownAttributes.put(name, contents);
}
/**
* Removes a non standard attributes.
* @param name the name of the attribute.
* @return the old contents of the attribute.
*/
public byte[] removeAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.remove(name);
return null;
}
/**
* Removes all non standard attributes.
*/
public void removeAllAttributes() {
unknownAttributes = null;
}
}

@ -0,0 +1,296 @@
/* Block Copyright (C) 2000-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.PrintWriter;
///#def COLLECTIONS java.util
import java.util.Collection;
import java.util.Arrays;
import java.util.List;
import java.util.Iterator;
///#enddef
/**
* <p>Represents a single basic block. It contains a list of
* instructions and the successor blocks.</p>
*
* <p>All jump instructions must be at the end of the block. These
* jump instructions are <code>opc_lookupswitch</code>,
* <code>opc_if</code>xxx, <code>opc_jsr</code>, <code>opc_ret</code>,
* <code>opc_</code>x<code>return</code> and <code>opc_return</code>.
* An <code>opc_goto</code> is implicit if the basic block doesn't end
* with a jump instructions, or if it ends with an conditional jump or
* jsr.</p>
*
* <p>The jump instructions don't remember their destinations, instead
* the Block does it. This are the successor block. There are
* several cases:</p>
*
* <ul>
* <li>Block ends with <code>opc_lookupswitch</code> with
* <code>n</code> values. Then there must be <code>n+1</code>
* successors where the first <code>n</code> successors correspond to
* the values and the last successor is the default successor.</li>
* <li>Block ends with <code>opc_if</code>xxx, then there must be two
* successors: The first one is the successor if the condition evaluates
* to true, the second one is for the false branch. </li>
* <li>Block ends with <code>opc_jsr</code>, then there must be two
* successors: The first one is the subroutine, the second is the next
* block after the subroutine. </li>
* <li>Block ends with <code>opc_</code>x</code>return</code> or
* <code>opc_ret</code>, then there must no successor at all. </li>
* <li>In any other case there must be exactly one successor.</li>
* </ul>
*
* <p>If any successor is <code>null</code> it represents end of
* method, i.e. a return instruction. You can also use
* <code>null</code> successors for conditional jumps and switch
* instruction. You normally shouldn't use <code>opc_return</code>
* instructions. They are only necessary, if you want to return with
* a non-empty stack. </p>
*
* @author Jochen Hoenicke
* @see net.sf.jode.bytecode.BasicBlocks
* @see net.sf.jode.bytecode.Instruction
*/
public final class Block {
/**
* The opcodes of the instructions in this block.
*/
private Instruction[] instrs;
/**
* The blockNr of successor blocks
*/
private Block[] succs;
/**
* The catching blocks. Set by BasicBlocks.
*/
Handler[] catchers;
/**
* The blockNr of this block. Set by BasicBlocks.
*/
int blockNr;
/**
* The number of items this block takes from the stack with
* respect to the stack items at the beginning of the block.
*/
int maxpop;
/**
* The maximum number of items the stack may grow.
*/
int maxpush;
/**
* The difference stack items after the block minus stack items
* before block.
*/
int delta;
/**
* The stack height at the beginning of this block.
* Only valid after the block was inserted in a BasicBlocks and
* the updateMaxStackLocals() of BasicBlocks was called.
*/
int stackHeight;
/**
* Creates a new block uninitialized block. You mustn't really
* use it (except as successor for other blocks) until you have
* set the code.
*/
public Block() {
}
/**
* Gets the list of instructions. The returned list should not be
* modified, except that the instructions (but not their opcodes)
* may be modified.
*/
public Instruction[] getInstructions() {
return instrs;
}
/**
* Gets the successor array. The last successor is the next basic
* block that is jumped to via goto or the default part of a
* switch. For conditional jumps and jsrs the second successor gives
* the destination.
*/
public Block[] getSuccs() {
return succs;
}
/**
* Gets the exception handlers whose try region contains this
* block. You can't set them since they are calculated
* automatically.
* @return the exception handlers.
* @see BasicBlocks#setBlocks
*/
public Handler[] getHandlers() {
return catchers;
}
/**
* Gets the block number. The block numbers are consecutive number
* from 0 to the number of blocks in a method. The equation
* <pre> BasicBlocks.getBlock()[i].getBlockNr() == i </pre>
* always holds (as long as you don't do something dirty, like adding
* the same block to different BasicBlocks, or to the same but more
* than once).
* @return the block number.
*/
public int getBlockNr() {
return blockNr;
}
private void initCode() {
int size = instrs.length;
maxpop = maxpush = 0;
int depth = 0;
int poppush[] = new int[2];
boolean needGoto = true;
for (int i = 0; i < size; i++) {
instrs[i].getStackPopPush(poppush);
depth -= poppush[0];
if (maxpop < -depth)
maxpop = -depth;
depth += poppush[1];
if (maxpush < depth)
maxpush = depth;
int opcode = instrs[i].getOpcode();
switch (opcode) {
case Opcodes.opc_goto:
throw new IllegalArgumentException("goto in block");
case Opcodes.opc_lookupswitch:
if (succs.length != instrs[i].getValues().length + 1)
throw new IllegalArgumentException
("number of successors for switch doesn't match");
if (i != size - 1)
throw new IllegalArgumentException
("switch in the middle!");
needGoto = false;
break;
case Opcodes.opc_ret: case Opcodes.opc_athrow:
case Opcodes.opc_ireturn: case Opcodes.opc_lreturn:
case Opcodes.opc_freturn: case Opcodes.opc_dreturn:
case Opcodes.opc_areturn: case Opcodes.opc_return:
if (succs.length != 0)
throw new IllegalArgumentException
("throw or return with successor.");
if (i != size - 1)
throw new IllegalArgumentException
("return in the middle!");
needGoto = false;
break;
case Opcodes.opc_ifeq: case Opcodes.opc_ifne:
case Opcodes.opc_iflt: case Opcodes.opc_ifge:
case Opcodes.opc_ifgt: case Opcodes.opc_ifle:
case Opcodes.opc_if_icmpeq: case Opcodes.opc_if_icmpne:
case Opcodes.opc_if_icmplt: case Opcodes.opc_if_icmpge:
case Opcodes.opc_if_icmpgt: case Opcodes.opc_if_icmple:
case Opcodes.opc_if_acmpeq: case Opcodes.opc_if_acmpne:
case Opcodes.opc_ifnull: case Opcodes.opc_ifnonnull:
case Opcodes.opc_jsr:
if (succs.length != 2)
throw new IllegalArgumentException
("successors inappropriate for if/jsr");
if (succs[0] == null && opcode == Opcodes.opc_jsr)
throw new IllegalArgumentException
("null successors inappropriate for jsr");
if (i != size - 1)
throw new IllegalArgumentException
("if/jsr in the middle!");
needGoto = false;
}
}
delta = depth;
if (needGoto && succs.length != 1)
throw new IllegalArgumentException("no single successor block");
}
/**
* Returns the stack height at the beginning of the block. This
* is automatically calculated, when the block is inserted in a
* basic block.
*/
public int getStackHeight () {
return stackHeight;
}
public void getStackPopPush (int[] poppush) {
poppush[0] = maxpop;
poppush[1] = delta + maxpop;
return;
}
/**
* Set the code, i.e. instructions and successor blocks.
* The instructions must be valid and match the successors.
*/
public void setCode(Instruction[] instrs, Block[] succs) {
this.instrs = instrs;
this.succs = succs;
initCode();
}
public void dumpCode(PrintWriter output) {
output.println(" "+this+":");
for (int i = 0; i < instrs.length; i++) {
Instruction instr = instrs[i];
if (i == instrs.length - 1 && succs != null) {
int opcode = instr.getOpcode();
if (opcode == Opcodes.opc_lookupswitch) {
// Special case for switch:
output.println("\tswitch");
int[] values = instr.getValues();
for (int j = 0; j < values.length; j++)
output.println("\t case"+values[j]
+": goto "+succs[j]);
output.println("\t default: goto"+
succs[values.length]);
return;
} else if (succs.length > 1) {
output.println("\t"+instr.getDescription()
+" "+succs[0]);
break;
}
}
output.println("\t"+instr.getDescription());
}
if (succs != null && succs.length > 0) {
if (succs[succs.length-1] == null)
output.println("\treturn");
else
output.println("\tgoto "+succs[succs.length-1]);
}
}
public String toString() {
return "Block_"+blockNr;
}
}

@ -0,0 +1,43 @@
/* ClassFormatException Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* Thrown when a class file with an unknown or illegal format is loaded.
*
* @author Jochen Hoenicke
*/
public class ClassFormatException extends java.io.IOException{
/**
* Constructs a new class format exception with the given detail
* message.
* @param detail the detail message.
*/
public ClassFormatException(String detail) {
super(detail);
}
/**
* Constructs a new class format exception.
*/
public ClassFormatException() {
super();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,53 @@
/* ConstantInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.util.StringQuoter;
/**
* This class represents an instruction in the byte code.
*
*/
class ConstantInstruction extends Instruction {
/**
* The typesignature of the class/array.
*/
private Object constant;
ConstantInstruction(int opcode, Object constant) {
super(opcode);
this.constant = constant;
}
public final Object getConstant()
{
return constant;
}
public final void setConstant(Object constant)
{
this.constant = constant;
}
public String toString() {
return super.toString() + ' ' +
(constant instanceof String
? StringQuoter.quote((String) constant) : constant);
}
}

@ -0,0 +1,280 @@
/* ConstantPool Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.NoSuchElementException;
///#def COLLECTIONS java.util
import java.util.Iterator;
///#enddef
///#def COLLECTIONEXTRA java.lang
import java.lang.UnsupportedOperationException;
///#enddef
/**
* This class represent the constant pool. Normally you wont need to
* touch this class, as ClassInfo already does all the hard work. You
* will only need it if you want to add your own custom attributes
* that use the constant pool.
*
* @author Jochen Hoenicke
*/
public class ConstantPool {
public final static int CLASS = 7;
public final static int FIELDREF = 9;
public final static int METHODREF = 10;
public final static int INTERFACEMETHODREF = 11;
public final static int STRING = 8;
public final static int INTEGER = 3;
public final static int FLOAT = 4;
public final static int LONG = 5;
public final static int DOUBLE = 6;
public final static int NAMEANDTYPE = 12;
public final static int UTF8 = 1;
int count;
int[] tags;
int[] indices1, indices2;
Object[] constants;
public ConstantPool () {
}
public void read(DataInputStream stream)
throws IOException {
count = stream.readUnsignedShort();
tags = new int[count];
indices1 = new int[count];
indices2 = new int[count];
constants = new Object[count];
for (int i=1; i< count; i++) {
int tag = stream.readUnsignedByte();
tags[i] = tag;
switch (tag) {
case CLASS:
indices1[i] = stream.readUnsignedShort();
break;
case FIELDREF:
case METHODREF:
case INTERFACEMETHODREF:
indices1[i] = stream.readUnsignedShort();
indices2[i] = stream.readUnsignedShort();
break;
case STRING:
indices1[i] = stream.readUnsignedShort();
break;
case INTEGER:
constants[i] = new Integer(stream.readInt());
break;
case FLOAT:
constants[i] = new Float(stream.readFloat());
break;
case LONG:
constants[i] = new Long(stream.readLong());
tags[++i] = -LONG;
break;
case DOUBLE:
constants[i] = new Double(stream.readDouble());
tags[++i] = -DOUBLE;
break;
case NAMEANDTYPE:
indices1[i] = stream.readUnsignedShort();
indices2[i] = stream.readUnsignedShort();
break;
case UTF8:
constants[i] = stream.readUTF().intern();
break;
default:
throw new ClassFormatException("unknown constant tag");
}
}
}
public int getTag(int i) throws ClassFormatException {
if (i == 0)
throw new ClassFormatException("null tag");
return tags[i];
}
public String getUTF8(int i) throws ClassFormatException {
if (tags[i] != UTF8)
throw new ClassFormatException("Tag mismatch");
return (String)constants[i];
}
public Reference getRef(int i) throws ClassFormatException {
if (tags[i] != FIELDREF
&& tags[i] != METHODREF && tags[i] != INTERFACEMETHODREF)
throw new ClassFormatException("Tag mismatch");
if (constants[i] == null) {
int classIndex = indices1[i];
int nameTypeIndex = indices2[i];
if (tags[nameTypeIndex] != NAMEANDTYPE)
throw new ClassFormatException("Tag mismatch");
String type = getUTF8(indices2[nameTypeIndex]);
try {
if (tags[i] == FIELDREF)
TypeSignature.checkTypeSig(type);
else
TypeSignature.checkMethodTypeSig(type);
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
String clName = getClassType(classIndex);
constants[i] = Reference.getReference
(clName, getUTF8(indices1[nameTypeIndex]), type);
}
return (Reference) constants[i];
}
public Object getConstant(int i) throws ClassFormatException {
if (i == 0)
throw new ClassFormatException("null constant");
switch (tags[i]) {
case INTEGER:
case FLOAT:
case LONG:
case DOUBLE:
return constants[i];
case CLASS:
return Reference.getReference(getClassType(i),
"class", "Ljava/lang/Class;");
case STRING:
return getUTF8(indices1[i]);
}
throw new ClassFormatException("Tag mismatch: "+tags[i]);
}
public String getClassType(int i) throws ClassFormatException {
if (tags[i] != CLASS)
throw new ClassFormatException("Tag mismatch");
String clName = getUTF8(indices1[i]);
if (clName.charAt(0) != '[') {
clName = ("L"+clName+';').intern();
}
try {
TypeSignature.checkTypeSig(clName);
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
return clName;
}
public String getClassName(int i) throws ClassFormatException {
if (tags[i] != CLASS)
throw new ClassFormatException("Tag mismatch");
if (constants[i] == null) {
String clName = getUTF8(indices1[i]);
try {
TypeSignature.checkTypeSig("L"+clName+";");
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
constants[i] = clName.replace('/','.').intern();
}
return (String) constants[i];
}
/**
* Iterates through all class entries in the class pool and returns
* their (dot seperated) class name.
*/
public Iterator iterateClassNames() {
return new Iterator()
{
int entry = 1;
public boolean hasNext() {
try {
while (entry < count
&& (tags[entry] != CLASS
|| getUTF8(indices1[entry])
.charAt(0) == '['))
entry++;
} catch (ClassFormatException ex) {
throw new InternalError(ex.getMessage());
}
return entry < count;
}
public Object next() {
if (!hasNext())
throw new NoSuchElementException();
try {
return getClassName(entry++);
} catch (ClassFormatException ex) {
throw new InternalError(ex.getMessage());
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public String toString(int i) {
switch (tags[i]) {
case CLASS:
return "Class "+toString(indices1[i]);
case STRING:
return "String \""+toString(indices1[i])+"\"";
case INTEGER:
return "Int "+constants[i].toString();
case FLOAT:
return "Float "+constants[i].toString();
case LONG:
return "Long "+constants[i].toString();
case DOUBLE:
return "Double "+constants[i].toString();
case UTF8:
return constants[i].toString();
case FIELDREF:
return "Fieldref: "+toString(indices1[i])+"; "
+ toString(indices2[i]);
case METHODREF:
return "Methodref: "+toString(indices1[i])+"; "
+ toString(indices2[i]);
case INTERFACEMETHODREF:
return "Interfaceref: "+toString(indices1[i])+"; "
+ toString(indices2[i]);
case NAMEANDTYPE:
return "Name "+toString(indices1[i])
+"; Type "+toString(indices2[i]);
default:
return "unknown tag: "+tags[i];
}
}
public int size() {
return count;
}
public String toString() {
StringBuffer result = new StringBuffer("ConstantPool[ null");
for (int i=1; i< count; i++) {
result.append(", ").append(i).append(" = ").append(toString(i));
}
result.append(" ]");
return result.toString();
}
}

@ -0,0 +1,340 @@
/* FieldInfo Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
///#def COLLECTIONEXTRA java.lang
import java.lang.Comparable;
///#enddef
/**
* Represents a java bytecode field (class variable). A field
* consists of the following parts:
*
* <dl>
*
* <dt>name</dt><dd>The field's name</dd>
*
* <dt>type</dt><dd>The field's {@link TypeSignature type signature}
* in bytecode format.</dd>
*
* <dt>signature</dt><dd>The field's {@link TypeSignature type signature}
* in bytecode format including template information.</dd>
*
* <dt>modifiers</dt><dd>The modifiers of the field like private, public etc.
* These are created by or-ing the constants {@link Modifier#PUBLIC},
* {@link Modifier#PRIVATE}, {@link Modifier#PROTECTED},
* {@link Modifier#STATIC}, {@link Modifier#FINAL},
* {@link Modifier#VOLATILE}, {@link Modifier#TRANSIENT},
* {@link Modifier#STRICT}
* of class {@link java.lang.reflect.Modifier}. </dt>
*
* <dt>synthetic</dt><dd>true if this field is synthetic.</dd>
*
* <dt>deprecated</dt><dd>true if this field is deprecated.</dd>
*
* <dt>constant</dt> <dd>Final static fields may have a constant
* value. This is either of type String, Integer, Long, Float or
* Double. </dt>
*
* </dl>
*
* @author Jochen Hoenicke
* @see net.sf.jode.bytecode.TypeSignature
* @see net.sf.jode.bytecode.BasicBlocks
*/
public final class FieldInfo extends BinaryInfo implements Comparable {
int modifier;
String name;
String typeSig;
Object constant;
boolean deprecatedFlag;
/**
* The type signature that also contains template information.
*/
private String signature;
/**
* Creates a new empty field info.
*/
public FieldInfo() {
}
/**
* Creates a new field with given name, type and modifiers.
* @param name the name of the field.
* @param typeSig the typeSig the type signature.
* @param modifier the modifier
* @see TypeSignature
* @see Modifier
*/
public FieldInfo(String name, String typeSig, int modifier) {
this.name = name;
this.typeSig = typeSig;
this.modifier = modifier;
}
protected void readAttribute(String name, int length,
ConstantPool cp,
DataInputStream input,
int howMuch) throws IOException {
if (howMuch >= ClassInfo.DECLARATIONS
&& name.equals("ConstantValue")) {
if (length != 2)
throw new ClassFormatException
("ConstantValue attribute has wrong length");
int index = input.readUnsignedShort();
constant = cp.getConstant(index);
} else if (name.equals("Synthetic")) {
modifier |= ACC_SYNTHETIC;
if (length != 0)
throw new ClassFormatException
("Synthetic attribute has wrong length");
} else if (name.equals("Deprecated")) {
deprecatedFlag = true;
if (length != 0)
throw new ClassFormatException
("Deprecated attribute has wrong length");
} else if (name.equals("Signature")) {
signature = cp.getUTF8(input.readUnsignedShort());
} else
super.readAttribute(name, length, cp, input, howMuch);
}
void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort());
typeSig = constantPool.getUTF8(input.readUnsignedShort());
readAttributes(constantPool, input, howMuch);
}
void reserveSmallConstants(GrowableConstantPool gcp) {
}
void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name);
gcp.putUTF8(typeSig);
if (constant != null) {
gcp.putUTF8("ConstantValue");
if (typeSig.charAt(0) == 'J' || typeSig.charAt(0) == 'D')
gcp.putLongConstant(constant);
else
gcp.putConstant(constant);
}
if (isSynthetic())
gcp.putUTF8("Synthetic");
if (deprecatedFlag)
gcp.putUTF8("Deprecated");
if (signature != null) {
gcp.putUTF8("Signature");
gcp.putUTF8(signature);
}
prepareAttributes(gcp);
}
protected int getAttributeCount() {
int count = super.getAttributeCount();
if (constant != null)
count++;
if (isSynthetic())
count++;
if (deprecatedFlag)
count++;
return count;
}
protected void writeAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
super.writeAttributes(gcp, output);
if (constant != null) {
output.writeShort(gcp.putUTF8("ConstantValue"));
output.writeInt(2);
int index;
if (typeSig.charAt(0) == 'J'
|| typeSig.charAt(0) == 'D')
index = gcp.putLongConstant(constant);
else
index = gcp.putConstant(constant);
output.writeShort(index);
}
if (isSynthetic()) {
output.writeShort(gcp.putUTF8("Synthetic"));
output.writeInt(0);
}
if (deprecatedFlag) {
output.writeShort(gcp.putUTF8("Deprecated"));
output.writeInt(0);
}
if (signature != null) {
output.writeShort(gcp.putUTF8("Signature"));
output.writeInt(2);
output.writeShort(gcp.putUTF8(signature));
}
}
void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name));
output.writeShort(constantPool.putUTF8(typeSig));
writeAttributes(constantPool, output);
}
protected void drop(int keep) {
if (keep < ClassInfo.DECLARATIONS)
constant = null;
super.drop(keep);
}
/**
* Gets the name of the field.
* @return the name.
*/
public String getName() {
return name;
}
/**
* Gets the type signature of the field.
* @return the type signature.
* @see TypeSignature
*/
public String getType() {
return typeSig;
}
/**
* Gets the type signature including template information of the field.
* <b>WARNING:</b> This field may disappear and merged into getType later.
* @return the type signature.
* @see TypeSignature
*/
public String getSignature() {
return signature != null ? signature : typeSig;
}
/**
* Gets the modifier of the field.
* @return the modifiers.
* @see Modifier
*/
public int getModifiers() {
return modifier;
}
/**
* Tells whether this field is synthetic.
* @return true if the field is synthetic.
*/
public boolean isSynthetic() {
return (modifier & ACC_SYNTHETIC) != 0;
}
/**
* Tells whether this field is deprecated.
* @return true if the field is deprecated.
*/
public boolean isDeprecated() {
return deprecatedFlag;
}
/**
* Gets the constant value of the field. For static final fields
* that have a simple String, int, float, double or long constant,
* this returns the corresponding constant as String, Integer, Float
* Double or long. For other fields it returns null.
* @return The constant, or null.
*/
public Object getConstant() {
return constant;
}
/**
* Sets the name of the field.
* @param newName the name.
*/
public void setName(String newName) {
name = newName;
}
/**
* Sets the type signature of the field.
* @param newType the type signature.
* @see TypeSignature
*/
public void setType(String newType) {
typeSig = newType;
}
/**
* Sets the modifier of the field.
* @param newModifier the modifiers.
* @see Modifier
*/
public void setModifiers(int newModifier) {
modifier = newModifier;
}
public void setSynthetic(boolean flag) {
if (flag)
modifier |= ACC_SYNTHETIC;
else
modifier &= ~ACC_SYNTHETIC;
}
public void setDeprecated(boolean flag) {
deprecatedFlag = flag;
}
public void setConstant(Object newConstant) {
constant = newConstant;
}
/**
* Compares two FieldInfo objects for field order. The field
* order is as follows: First the static class intializer followed
* by constructor with type signature sorted lexicographic. Then
* all other fields sorted lexicographically by name. If two
* fields have the same name, they are sorted by type signature,
* though that can only happen for obfuscated code.
*
* @return a positive number if this field follows the other in
* field order, a negative number if it preceeds the
* other, and 0 if they are equal.
* @exception ClassCastException if other is not a ClassInfo. */
public int compareTo(Object other) {
FieldInfo fi = (FieldInfo) other;
int result = name.compareTo(fi.name);
if (result == 0)
result = typeSig.compareTo(fi.typeSig);
return result;
}
public String toString() {
return "Field "+Modifier.toString(modifier)+" "+
getSignature()+" "+name;
}
}

@ -0,0 +1,348 @@
/* GrowableConstantPool Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Hashtable;
/**
* This class represent a constant pool, where new constants can be
* added to. Normally you wont need to touch this class, as ClassInfo
* already does all the hard work. You will only need it if you want
* to add your own custom attributes that use the constant pool.
*
* @author Jochen Hoenicke
*/
public class GrowableConstantPool extends ConstantPool {
Hashtable entryToIndex = new Hashtable();
boolean written;
/**
* This class is used as key to the entryToIndex hashtable
*/
private class Key {
int tag;
Object objData;
int intData;
public Key(int tag, Object objData, int intData) {
this.tag = tag;
this.objData = objData;
this.intData = intData;
}
public int hashCode() {
return tag ^ objData.hashCode() ^ intData;
}
public boolean equals(Object o) {
if (o instanceof Key) {
Key k = (Key) o;
return tag == k.tag && intData == k.intData
&& objData.equals(k.objData);
}
return false;
}
}
/**
* Create a new growable constant pool
*/
public GrowableConstantPool () {
count = 1;
tags = new int[128];
indices1 = new int[128];
indices2 = new int[128];
constants = new Object[128];
written = false;
}
private final void grow(int wantedSize) {
if (written)
throw new IllegalStateException("adding to written ConstantPool");
if (wantedSize > 65535)
throw new IllegalArgumentException("Too many constants added");
if (tags.length < wantedSize) {
int newSize = Math.min(65535, Math.max(tags.length*2, wantedSize));
int[] tmpints = new int[newSize];
System.arraycopy(tags, 0, tmpints, 0, count);
tags = tmpints;
tmpints = new int[newSize];
System.arraycopy(indices1, 0, tmpints, 0, count);
indices1 = tmpints;
tmpints = new int[newSize];
System.arraycopy(indices2, 0, tmpints, 0, count);
indices2 = tmpints;
Object[] tmpobjs = new Object[newSize];
System.arraycopy(constants, 0, tmpobjs, 0, count);
constants = tmpobjs;
}
}
private int putConstant(int tag, Object constant) {
Key key = new Key(tag, constant, 0);
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
return index.intValue();
int newIndex = count;
grow(count + 1);
tags[newIndex] = tag;
constants[newIndex] = constant;
entryToIndex.put(key, new Integer(newIndex));
count++;
return newIndex;
}
private int putLongConstant(int tag, Object constant) {
Key key = new Key(tag, constant, 0);
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
return index.intValue();
int newIndex = count;
grow(count + 2);
tags[newIndex] = tag;
tags[newIndex+1] = -tag;
constants[newIndex] = constant;
entryToIndex.put(key, new Integer(newIndex));
count += 2;
return newIndex;
}
private int putIndexed(int tag, Object obj1, int index1, int index2) {
Key key = new Key(tag, obj1, index2);
Integer indexObj = (Integer) entryToIndex.get(key);
if (indexObj != null) {
/* Maybe this was a reserved, but not filled entry */
int index = indexObj.intValue();
indices1[index] = index1;
indices2[index] = index2;
return index;
}
grow(count+1);
tags[count] = tag;
indices1[count] = index1;
indices2[count] = index2;
entryToIndex.put(key, new Integer(count));
return count++;
}
/**
* Adds a new UTF8 entry to the constant pool and returns the index.
* If it already exists it will reuse the previous entry.
* @param utf the UTF8 string.
* @return the index of the pool entry.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public final int putUTF8(String utf) {
return putConstant(UTF8, utf);
}
/**
* Adds a new class name entry to the constant pool and returns
* the index. If it already exists it will reuse the previous
* entry.
* @param name the dot separated full qualified class name.
* @return the index of the pool entry.
* @exception IllegalArgumentException if the class name is illegal.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public int putClassName(String name) {
name = name.replace('.','/');
TypeSignature.checkTypeSig("L"+name+";");
return putIndexed(CLASS, name, putUTF8(name), 0);
}
/**
* Adds a new class entry to the constant pool and returns
* the index. If it already exists it will reuse the previous
* entry. This is the same as putClassName, except for the format
* of the parameter and that it can also handle arrays.
* @param name the type signature of the class to add.
* @return the index of the pool entry.
* @exception IllegalArgumentException if the class name is illegal.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public int putClassType(String name) {
TypeSignature.checkTypeSig(name);
if (name.charAt(0) == 'L')
name = name.substring(1, name.length()-1);
else if (name.charAt(0) != '[')
throw new IllegalArgumentException("wrong class type: "+name);
return putIndexed(CLASS, name, putUTF8(name), 0);
}
/**
* Adds a new field/method or interface reference to the constant
* pool and returns the index. If it already exists it will reuse
* the previous entry.
* @param tag the tag of the reference, one of FIELDREF, METHODREF
* or INTERFACEMETHODREF.
* @param ref the reference.
* @return the index of the pool entry.
* @exception IllegalArgumentException if the reference type or
* class name is illegal.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public int putRef(int tag, Reference ref) {
String className = ref.getClazz();
String typeSig = ref.getType();
if (tag == FIELDREF)
TypeSignature.checkTypeSig(typeSig);
else
TypeSignature.checkMethodTypeSig(typeSig);
int classIndex = putClassType(className);
int nameIndex = putUTF8(ref.getName());
int typeIndex = putUTF8(typeSig);
int nameTypeIndex = putIndexed(NAMEANDTYPE,
ref.getName(), nameIndex, typeIndex);
return putIndexed(tag, className, classIndex, nameTypeIndex);
}
/**
* Puts a "one slot" constant into this constant pool. If it
* already exists it will reuse the previous entry.
* @param c the constant; must be of type
* Integer, Float or String
* @return the index of the pool entry.
* @exception IllegalArgumentException if the constant is of wrong type.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public int putConstant(Object c) {
if (c instanceof String) {
return putIndexed(STRING, c, putUTF8((String) c), 0);
} else if (c instanceof Reference) {
return putClassType(((Reference) c).getClazz());
} else {
int tag;
if (c instanceof Integer)
tag = INTEGER;
else if (c instanceof Float)
tag = FLOAT;
else
throw new IllegalArgumentException
("illegal constant " + c + " of type: " + c.getClass());
return putConstant(tag, c);
}
}
/**
* Puts a "double slot" constant into this constant pool. If it
* already exists it will reuse the previous entry.
* @param c the constant; must be of type Long or Double
* @return the index of the pool entry.
* @exception IllegalArgumentException if the constant is of wrong type.
* @exception IllegalStateException if the pool was already written,
* but the entry was not added before.
*/
public int putLongConstant(Object c) {
int tag;
if (c instanceof Long)
tag = LONG;
else if (c instanceof Double)
tag = DOUBLE;
else
throw new IllegalArgumentException
("illegal long constant " + c + " of type: " + c.getClass());
return putLongConstant(tag, c);
}
/**
* Reserves an entry in this constant pool for a constant (for ldc).
* The constant must still be put into the pool, before the pool may
* be written.
* @param c the constant, must be of type
* Integer, Float or String
* @return the reserved index into the pool of this constant.
*/
public int reserveConstant(Object c) {
if (c instanceof String) {
return putIndexed(STRING, c, -1, 0);
} else if (c instanceof Reference) {
String name = ((Reference) c).getClazz();
if (name.charAt(0) == 'L')
name = name.substring(1, name.length()-1);
else if (name.charAt(0) != '[')
throw new IllegalArgumentException("wrong class type: "+name);
return putIndexed(CLASS, name, -1, 0);
} else {
return putConstant(c);
}
}
/**
* Writes the constant pool to the stream. This is normally called
* by {@link ClassInfo#write}.
* @param stream the stream to write to.
* @exception IOException if it occured while writing.
*/
public void write(DataOutputStream stream)
throws IOException {
written = true;
stream.writeShort(count);
for (int i=1; i< count; i++) {
int tag = tags[i];
stream.writeByte(tag);
switch (tag) {
case CLASS:
stream.writeShort(indices1[i]);
break;
case FIELDREF:
case METHODREF:
case INTERFACEMETHODREF:
stream.writeShort(indices1[i]);
stream.writeShort(indices2[i]);
break;
case STRING:
stream.writeShort(indices1[i]);
break;
case INTEGER:
stream.writeInt(((Integer)constants[i]).intValue());
break;
case FLOAT:
stream.writeFloat(((Float)constants[i]).floatValue());
break;
case LONG:
stream.writeLong(((Long)constants[i]).longValue());
i++;
break;
case DOUBLE:
stream.writeDouble(((Double)constants[i]).doubleValue());
i++;
break;
case NAMEANDTYPE:
stream.writeShort(indices1[i]);
stream.writeShort(indices2[i]);
break;
case UTF8:
stream.writeUTF((String)constants[i]);
break;
default:
throw new ClassFormatException("unknown constant tag");
}
}
}
}

@ -0,0 +1,94 @@
/* Handler Copyright (C) 2000-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* A simple class containing the info about one try-catch block.
*
* @author Jochen Hoenicke
*/
public class Handler {
Block start, end, catcher;
String type;
/**
* The empty handler array. Since handlers are often empty, we don't
* want to create a new object each time.
*/
final static Handler[] EMPTY = new Handler[0];
/**
* Creates a new handler.
*/
Handler(Block s, Block e, Block c, String t) {
start = s;
end = e;
catcher = c;
type = t;
}
/**
* Gets the first basic block of the try.
*/
public Block getStart() {
return start;
}
/**
* Gets the last basic block of the try.
*/
public Block getEnd() {
return end;
}
/**
* Gets the first basic block of the exception handler.
*/
public Block getCatcher() {
return catcher;
}
/**
* Gets the class name of the exception type.
*/
public String getType() {
return type;
}
public void setStart(Block start) {
this.start = start;
}
public void setEnd(Block end) {
this.end = end;
}
public void setCatcher(Block catcher) {
this.catcher = catcher;
}
/**
* Sets the class name of the exception type.
*/
public void setType(String type) {
this.type = type;
}
}

@ -0,0 +1,60 @@
/* IncInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This class represents an instruction in the byte code.
*
*/
class IncInstruction extends SlotInstruction {
/**
* The amount of increment.
*/
private int increment;
/**
* Creates a simple opcode, without any parameters.
*/
IncInstruction(int opcode, LocalVariableInfo lvi, int increment) {
super(opcode, lvi);
this.increment = increment;
}
/**
* Get the increment for an opc_iinc instruction.
*/
public final int getIncrement()
{
return increment;
}
/**
* Set the increment for an opc_iinc instruction.
*/
public final void setIncrement(int incr)
{
this.increment = incr;
}
public String toString() {
return super.toString()+' '+increment;
}
}

@ -0,0 +1,503 @@
/* Instruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* <p> This class represents an instruction in the byte code.
* Instructions can be created with the static {@link #forOpcode}
* methods. </p>
*
* <p> We only allow a subset of opcodes. Other opcodes are mapped to
* their simpler version. Don't worry about this, when writing the
* bytecode the shortest possible bytecode is produced. </p>
*
* The opcodes we map are:
* <pre>
* [iflda]load_x -&gt; [iflda]load
* [iflda]store_x -&gt; [iflda]store
* [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre>
*/
public class Instruction implements Opcodes{
/**
* The opcode and lineNr of the instruction.
* opcode is <code>(lineAndOpcode &amp; 0xff)</code>, while
* lineNr is <code>(lineAndOpcode &gt;&gt; 8)</code>.
* If line number is not known or unset, it is -1.
*/
private int lineAndOpcode;
/**
* Creates a new simple Instruction with no parameters. We map
* some opcodes, so you must always use the mapped opcode.
* @param opcode the opcode of this instruction.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode needs a parameter. */
public static Instruction forOpcode(int opcode) {
switch (opcode) {
case opc_nop:
case opc_iaload: case opc_laload: case opc_faload:
case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
case opc_iastore: case opc_lastore: case opc_fastore:
case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
case opc_pop: case opc_pop2:
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
case opc_swap:
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
case opc_iand: case opc_land:
case opc_ior: case opc_lor:
case opc_ixor: case opc_lxor:
case opc_i2l: case opc_i2f: case opc_i2d:
case opc_l2i: case opc_l2f: case opc_l2d:
case opc_f2i: case opc_f2l: case opc_f2d:
case opc_d2i: case opc_d2l: case opc_d2f:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn:
case opc_return:
case opc_athrow:
case opc_arraylength:
case opc_monitorenter: case opc_monitorexit:
case opc_goto:
case opc_jsr:
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull:
return new Instruction(opcode);
default:
throw new IllegalArgumentException("Instruction has a parameter");
}
}
/**
* Creates a new ldc Instruction.
* @param opcode the opcode of this instruction.
* @param constant the constant parameter.
* @exception IllegalArgumentException if opcode is not opc_ldc or
* opc_ldc2_w.
*/
public static Instruction forOpcode(int opcode, Object constant) {
if (opcode == opc_ldc || opcode == opc_ldc2_w)
return new ConstantInstruction(opcode, constant);
throw new IllegalArgumentException("Instruction has no constant");
}
/**
* Creates a new Instruction with a local variable as parameter.
* @param opcode the opcode of this instruction.
* @param lvi the local variable parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a single local variable as parameter.
*/
public static Instruction forOpcode(int opcode, LocalVariableInfo lvi) {
if (opcode == opc_ret
|| opcode >= opc_iload && opcode <= opc_aload
|| opcode >= opc_istore && opcode <= opc_astore)
return new SlotInstruction(opcode, lvi);
throw new IllegalArgumentException("Instruction has no slot");
}
/**
* Creates a new Instruction with reference as parameter.
* @param opcode the opcode of this instruction.
* @param reference the reference parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a reference as parameter.
*/
public static Instruction forOpcode(int opcode, Reference reference) {
if (opcode >= opc_getstatic && opcode <= opc_invokeinterface)
return new ReferenceInstruction(opcode, reference);
throw new IllegalArgumentException("Instruction has no reference");
}
/**
* Creates a new Instruction with type signature as parameter.
* @param opcode the opcode of this instruction.
* @param typeSig the type signature parameter.
* @exception IllegalArgumentException if opcode is not in our subset
* or if opcode doesn't need a type signature as parameter.
*/
public static Instruction forOpcode(int opcode, String typeSig) {
switch (opcode) {
case opc_new:
case opc_checkcast:
case opc_instanceof:
return new TypeInstruction(opcode, typeSig);
default:
throw new IllegalArgumentException("Instruction has no type");
}
}
/**
* Creates a new switch Instruction.
* @param opcode the opcode of this instruction must be opc_lookupswitch.
* @param values an array containing the different cases.
* @exception IllegalArgumentException if opcode is not opc_lookupswitch.
*/
public static Instruction forOpcode(int opcode, int[] values) {
if (opcode == opc_lookupswitch)
return new SwitchInstruction(opcode, values);
throw new IllegalArgumentException("Instruction has no values");
}
/**
* Creates a new increment Instruction.
* @param opcode the opcode of this instruction.
* @param lvi the local variable parameter.
* @param increment the increment parameter.
* @exception IllegalArgumentException if opcode is not opc_iinc.
*/
public static Instruction forOpcode(int opcode,
LocalVariableInfo lvi, int increment) {
if (opcode == opc_iinc)
return new IncInstruction(opcode, lvi, increment);
throw new IllegalArgumentException("Instruction has no increment");
}
/**
* Creates a new Instruction with type signature and a dimension
* as parameter.
* @param opcode the opcode of this instruction.
* @param typeSig the type signature parameter.
* @param dimension the array dimension parameter.
* @exception IllegalArgumentException if opcode is not
* opc_multianewarray.
*/
public static Instruction forOpcode(int opcode,
String typeSig, int dimension) {
if (opcode == opc_multianewarray)
return new TypeDimensionInstruction(opcode, typeSig, dimension);
throw new IllegalArgumentException("Instruction has no dimension");
}
/**
* Creates a simple opcode, without any parameters.
*/
Instruction(int opcode) {
this.lineAndOpcode = (-1 << 8) | opcode;
}
/**
* Gets the opcode of the instruction.
* @return the opcode of the instruction.
*/
public final int getOpcode() {
return lineAndOpcode & 0xff;
}
/**
* Tells whether there is a line number information for this
* instruction.
* @return true if there is a line number information for this
* instruction.
*/
public final boolean hasLineNr() {
return lineAndOpcode >= 0;
}
/**
* Gets the line number of this instruction.
* @return the line number, or -1 if there isn't one.
*/
public final int getLineNr() {
return lineAndOpcode >> 8;
}
/**
* Sets the line number of this instruction.
* @param nr the line number; use -1 to clear it.
*/
public final void setLineNr(int nr) {
lineAndOpcode = (nr << 8) | (lineAndOpcode & 0xff);
}
/**
* Checks whether this instruction is a local store instruction, i.e.
* one of <code>astore</code>, <code>istore</code>, <code>lstore</code>,
* <code>fstore</code> or <code>dstore</code>.
*/
public boolean isStore() {
return false;
}
/**
* Checks whether this instruction accesses a local slot.
*/
public boolean hasLocal() {
return false;
}
/**
* Gets the slot number of the local this instruction accesses.
* @return the slot number.
* @throws IllegalArgumentException if this instruction doesn't
* access a local slot.
*/
public int getLocalSlot()
{
throw new IllegalArgumentException();
// UnsupportedOperationException would be more appropriate
}
/**
* Gets the information of the local this instruction accesses.
* @return the local variable info.
* @throws IllegalArgumentException if this instruction doesn't
* access a local.
*/
public LocalVariableInfo getLocalInfo()
{
throw new IllegalArgumentException();
}
/**
* Sets the information of the local this instruction accesses.
* @param info the local variable info.
* @throws IllegalArgumentException if this instruction doesn't
* access a local.
*/
public void setLocalInfo(LocalVariableInfo info)
{
throw new IllegalArgumentException();
}
/**
* Sets the slot of the local this instruction accesses.
* @param slot the local slot
* @throws IllegalArgumentException if this instruction doesn't
* access a local.
*/
public void setLocalSlot(int slot)
{
throw new IllegalArgumentException();
}
/**
* Gets the increment for an opc_iinc instruction.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public int getIncrement()
{
throw new IllegalArgumentException();
}
/**
* Sets the increment for an opc_iinc instruction.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setIncrement(int incr)
{
throw new IllegalArgumentException();
}
/**
* Gets the dimensions for an opc_multianewarray opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public int getDimensions()
{
throw new IllegalArgumentException();
}
/**
* Sets the dimensions for an opc_multianewarray opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setDimensions(int dims)
{
throw new IllegalArgumentException();
}
/**
* Gets the constant for a opc_ldc or opc_ldc2_w opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public Object getConstant()
{
throw new IllegalArgumentException();
}
/**
* Sets the constant for a opc_ldc or opc_ldc2_w opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setConstant(Object constant)
{
throw new IllegalArgumentException();
}
/**
* Gets the reference of the field or method this instruction accesses.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public Reference getReference()
{
throw new IllegalArgumentException();
}
/**
* Sets the reference of the field or method this instruction accesses.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setReference(Reference ref)
{
throw new IllegalArgumentException();
}
/**
* Gets the class type this instruction uses, e.g if its a class cast.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public String getClazzType()
{
throw new IllegalArgumentException();
}
/**
* Sets the class type this instruction uses, e.g if its a class cast.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setClazzType(String type)
{
throw new IllegalArgumentException();
}
/**
* Gets the values of a opc_lookupswitch opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public int[] getValues()
{
throw new IllegalArgumentException();
}
/**
* Sets the values of a opc_lookupswitch opcode.
* @throws IllegalArgumentException if this instruction doesn't
* support this.
*/
public void setValues(int[] values)
{
throw new IllegalArgumentException();
}
/**
* Checks whether this instruction always changes program flow.
* Returns false for opc_jsr it.
* @return true if this instruction always changes flow, i.e. if
* its an unconditional jump, a return, a throw, a ret or a switch.
*/
public final boolean doesAlwaysJump() {
switch (getOpcode()) {
case opc_ret:
case opc_goto:
case opc_lookupswitch:
case opc_ireturn:
case opc_lreturn:
case opc_freturn:
case opc_dreturn:
case opc_areturn:
case opc_return:
case opc_athrow:
return true;
default:
return false;
}
}
/**
* This returns the number of stack entries this instruction
* pushes and pops from the stack. The result fills the given
* array.
*
* @param poppush an array of two ints. The first element will
* get the number of pops, the second the number of pushes.
*/
public void getStackPopPush(int[] poppush)
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
{
byte delta = (byte) stackDelta.charAt(getOpcode());
poppush[0] = delta & 7;
poppush[1] = delta >> 3;
}
/**
* Gets a printable representation of the opcode with its
* parameters. This will not include the destination for jump
* instructions, since this information is not stored inside the
* instruction.
*/
public final String getDescription() {
return toString();
}
/**
* Gets a printable representation of the opcode with its
* parameters. This will not include the destination for jump
* instructions, since this information is not stored inside the
* instruction.
*/
public String toString() {
return opcodeString[getOpcode()];
}
/**
* stackDelta contains \100 if stack count of opcode is variable
* \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise
* The string is created by scripts/createStackDelta.pl
*/
final static String stackDelta =
"\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\000\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\000";
}

@ -0,0 +1,135 @@
/* LocalVariableInfo Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.util.UnifyHash;
///#def COLLECTIONS java.util
import java.util.Iterator;
///#enddef
/**
* A simple class containing the info of the LocalVariableTable. This
* info is stored decentral: every load, store or iinc instruction contains
* the info for its local. When writing code it will automatically be
* collected again. <br>
*
* You can't modify a LocalVariableInfo, for this reason they can and
* will be shared.<br>
*
* This information consists of name, type signature and slot number.
* There is no public constructor; use the static getInfo() methods
* instead.
*/
public final class LocalVariableInfo {
private String name, type;
private int slot;
private static LocalVariableInfo anonymous[];
static {
grow(5);
}
private static final UnifyHash unifier = new UnifyHash();
private LocalVariableInfo(int slot) {
this.slot = slot;
}
private LocalVariableInfo(int slot, String name, String type) {
this.slot = slot;
this.name = name;
this.type = type;
}
private static void grow(int upper) {
LocalVariableInfo[] newAnon = new LocalVariableInfo[upper];
int start = 0;
if (anonymous != null) {
start = anonymous.length;
System.arraycopy(anonymous, 0, newAnon, 0, start);
}
anonymous = newAnon;
for (int i=start; i< upper; i++)
anonymous[i] = new LocalVariableInfo(i);
}
/**
* Creates a new local variable info, with no name or type.
* @param slot the slot number.
*/
public static LocalVariableInfo getInfo(int slot) {
if (slot >= anonymous.length)
grow(Math.max(slot + 1, anonymous.length * 2));
return anonymous[slot];
}
/**
* Creates a new local variable info, with given name and type.
* @param slot the slot number.
* @param name the name of the local.
* @param type the type signature of the local.
*/
public static LocalVariableInfo getInfo(int slot,
String name, String type) {
if (name == null && type == null)
return getInfo(slot);
int hash = slot ^ name.hashCode() ^ type.hashCode();
Iterator iter = unifier.iterateHashCode(hash);
while (iter.hasNext()) {
LocalVariableInfo lvi = (LocalVariableInfo) iter.next();
if (lvi.slot == slot
&& lvi.name.equals(name)
&& lvi.type.equals(type))
return lvi;
}
LocalVariableInfo lvi = new LocalVariableInfo(slot, name, type);
unifier.put(hash, lvi);
return lvi;
}
/**
* Gets the slot number.
*/
public int getSlot() {
return slot;
}
/**
* Gets the name.
*/
public String getName() {
return name;
}
/**
* Gets the type signature.
* @see TypeSignature
*/
public String getType() {
return type;
}
/**
* Gets a string representation for debugging purposes.
*/
public String toString() {
String result = ""+slot;
if (name != null)
result += " ["+name+","+type+"]";
return result;
}
}

@ -0,0 +1,339 @@
/* MethodInfo Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
///#def COLLECTIONEXTRA java.lang
import java.lang.Comparable;
///#enddef
/**
* Represents a java bytecode method. A method consists of the following
* parts:
*
* <dl>
*
* <dt>name</dt><dd>The method's name</dd>
*
* <dt>type</dt><dd>The method's {@link TypeSignature type signature}
* in bytecode format.</dd>
*
* <dt>signature</dt><dd>The method's {@link TypeSignature type signature}
* in bytecode format including template information.</dd>
*
* <dt>modifiers</dt><dd>The modifiers of the field like private, public etc.
* These are created by or-ing the constants {@link Modifier#PUBLIC},
* {@link Modifier#PRIVATE}, {@link Modifier#PROTECTED},
* {@link Modifier#STATIC}, {@link Modifier#FINAL},
* {@link Modifier#SYNCHRONIZED}, {@link Modifier#NATIVE},
* {@link Modifier#ABSTRACT}, {@link Modifier#STRICT}
* of class {@link java.lang.reflect.Modifier}. </dt>
*
* <dt>basicblocks</dt><dd>the bytecode of the method in form of
* {@link BasicBlocks basic blocks}, null if it is native or
* abstract.</dd>
*
* <dt>synthetic</dt><dd>true if this method is synthetic</dd>
*
* <dt>deprecated</dt><dd>true if this method is deprecated</dd>
*
* <dt>exceptions</dt> <dd>the exceptions that the method declared in
* its throws clause</dd>
*
* </dl>
*
* @author Jochen Hoenicke
* @see net.sf.jode.bytecode.TypeSignature
* @see net.sf.jode.bytecode.BasicBlocks
*/
public final class MethodInfo extends BinaryInfo implements Comparable {
int modifier;
String name;
String typeSig;
BasicBlocks basicblocks;
String[] exceptions;
boolean deprecatedFlag;
/**
* The type signature that also contains template information.
*/
private String signature;
public MethodInfo() {
}
public MethodInfo(String name, String typeSig, int modifier) {
this.name = name;
this.typeSig = typeSig;
this.modifier = modifier;
}
protected void readAttribute
(String name, int length, ConstantPool cp,
DataInputStream input, int howMuch) throws IOException {
if (howMuch >= ClassInfo.NODEBUG && name.equals("Code")) {
basicblocks = new BasicBlocks(this);
basicblocks.read(cp, input, howMuch);
} else if (howMuch >= ClassInfo.DECLARATIONS
&& name.equals("Exceptions")) {
int count = input.readUnsignedShort();
exceptions = new String[count];
for (int i = 0; i < count; i++)
exceptions[i] = cp.getClassName(input.readUnsignedShort());
if (length != 2 * (count + 1))
throw new ClassFormatException
("Exceptions attribute has wrong length");
} else if (name.equals("Synthetic")) {
modifier |= ACC_SYNTHETIC;
if (length != 0)
throw new ClassFormatException
("Synthetic attribute has wrong length");
} else if (name.equals("Deprecated")) {
deprecatedFlag = true;
if (length != 0)
throw new ClassFormatException
("Deprecated attribute has wrong length");
} else if (name.equals("Signature")) {
signature = cp.getUTF8(input.readUnsignedShort());
} else
super.readAttribute(name, length, cp, input, howMuch);
}
void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException {
modifier = input.readUnsignedShort();
name = constantPool.getUTF8(input.readUnsignedShort());
typeSig = constantPool.getUTF8(input.readUnsignedShort());
readAttributes(constantPool, input, howMuch);
}
void reserveSmallConstants(GrowableConstantPool gcp) {
if (basicblocks != null)
basicblocks.reserveSmallConstants(gcp);
}
void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name);
gcp.putUTF8(typeSig);
if (basicblocks != null) {
gcp.putUTF8("Code");
basicblocks.prepareWriting(gcp);
}
if (exceptions != null) {
gcp.putUTF8("Exceptions");
for (int i = 0; i < exceptions.length; i++)
gcp.putClassName(exceptions[i]);
}
if (isSynthetic())
gcp.putUTF8("Synthetic");
if (deprecatedFlag)
gcp.putUTF8("Deprecated");
if (signature != null) {
gcp.putUTF8("Signature");
gcp.putUTF8(signature);
}
prepareAttributes(gcp);
}
protected int getAttributeCount() {
int count = super.getAttributeCount();
if (basicblocks != null)
count++;
if (exceptions != null)
count++;
if (isSynthetic())
count++;
if (deprecatedFlag)
count++;
return count;
}
protected void writeAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
super.writeAttributes(gcp, output);
if (basicblocks != null) {
output.writeShort(gcp.putUTF8("Code"));
basicblocks.write(gcp, output);
}
if (exceptions != null) {
int count = exceptions.length;
output.writeShort(gcp.putUTF8("Exceptions"));
output.writeInt(2 + count * 2);
output.writeShort(count);
for (int i = 0; i < count; i++)
output.writeShort(gcp.putClassName(exceptions[i]));
}
if (isSynthetic()) {
output.writeShort(gcp.putUTF8("Synthetic"));
output.writeInt(0);
}
if (deprecatedFlag) {
output.writeShort(gcp.putUTF8("Deprecated"));
output.writeInt(0);
}
if (signature != null) {
output.writeShort(gcp.putUTF8("Signature"));
output.writeInt(2);
output.writeShort(gcp.putUTF8(signature));
}
}
void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
output.writeShort(modifier);
output.writeShort(constantPool.putUTF8(name));
output.writeShort(constantPool.putUTF8(typeSig));
writeAttributes(constantPool, output);
}
protected void drop(int keep) {
if (keep < ClassInfo.DECLARATIONS)
exceptions = null;
if (keep < ClassInfo.NODEBUG)
basicblocks = null;
else
basicblocks.drop(keep);
super.drop(keep);
}
public String getName() {
return name;
}
public String getType() {
return typeSig;
}
/**
* Gets the type signature including template information of the method.
* <b>WARNING:</b> This field may disappear and merged into getType later.
* @return the type signature.
* @see TypeSignature
*/
public String getSignature() {
return signature != null ? signature : typeSig;
}
public int getModifiers() {
return modifier;
}
public boolean isConstructor() {
return name.charAt(0) == '<';
}
public boolean isStatic() {
return Modifier.isStatic(modifier);
}
public boolean isSynthetic() {
return (modifier & ACC_SYNTHETIC) != 0;
}
public boolean isDeprecated() {
return deprecatedFlag;
}
public BasicBlocks getBasicBlocks() {
return basicblocks;
}
public String[] getExceptions() {
return exceptions;
}
public void setName(String newName) {
name = newName;
}
public void setType(String newType) {
typeSig = newType;
}
public void setModifiers(int newModifier) {
modifier = newModifier;
}
public void setSynthetic(boolean flag) {
if (flag)
modifier |= ACC_SYNTHETIC;
else
modifier &= ~ACC_SYNTHETIC;
}
public void setDeprecated(boolean flag) {
deprecatedFlag = flag;
}
public void setBasicBlocks(BasicBlocks newBasicblocks) {
basicblocks = newBasicblocks;
}
public void setExceptions(String[] newExceptions) {
exceptions = newExceptions;
}
/**
* Compares two MethodInfo objects for method order. The method
* order is as follows: First the static class intializer followed
* by constructor with type signature sorted lexicographic. Then
* all other methods sorted lexicographically by name. If two
* methods have the same name, they are sorted by type signature.
*
* @return a positive number if this method follows the other in
* method order, a negative number if it preceeds the
* other, and 0 if they are equal.
* @exception ClassCastException if other is not a ClassInfo.
*/
public int compareTo(Object other) {
MethodInfo mi = (MethodInfo) other;
/* Normally constructors should automatically sort themself to
* the beginning, but if method name starts with a digit, the
* order would be destroyed.
*
* The JVM explicitly forbids methods starting with digits,
* nonetheless some obfuscators break this rule.
*
* But note that <clinit> comes lexicographically before <init>.
*/
if (name.charAt(0) != mi.name.charAt(0)) {
if (name.charAt(0) == '<')
return -1;
if (mi.name.charAt(0) == '<')
return 1;
}
int result = name.compareTo(mi.name);
if (result == 0)
result = typeSig.compareTo(mi.typeSig);
return result;
}
/**
* Returns a string representation of this method. It consists
* of the method's name and type signature.
* @return a string representation of this method.
*/
public String toString() {
return "MethodInfo[name="+name+",sig="+getSignature()+"]";
}
}

@ -0,0 +1,280 @@
/* Opcodes Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This is an interface containing the constants for the byte code opcodes.
*/
public interface Opcodes {
public final static int opc_nop = 0;
public final static int opc_aconst_null = 1;
public final static int opc_iconst_m1 = 2;
public final static int opc_iconst_0 = 3;
public final static int opc_iconst_1 = 4;
public final static int opc_iconst_2 = 5;
public final static int opc_iconst_3 = 6;
public final static int opc_iconst_4 = 7;
public final static int opc_iconst_5 = 8;
public final static int opc_lconst_0 = 9;
public final static int opc_lconst_1 = 10;
public final static int opc_fconst_0 = 11;
public final static int opc_fconst_1 = 12;
public final static int opc_fconst_2 = 13;
public final static int opc_dconst_0 = 14;
public final static int opc_dconst_1 = 15;
public final static int opc_bipush = 16;
public final static int opc_sipush = 17;
public final static int opc_ldc = 18;
public final static int opc_ldc_w = 19;
public final static int opc_ldc2_w = 20;
public final static int opc_iload = 21;
public final static int opc_lload = 22;
public final static int opc_fload = 23;
public final static int opc_dload = 24;
public final static int opc_aload = 25;
public final static int opc_iload_0 = 26;
public final static int opc_iload_1 = 27;
public final static int opc_iload_2 = 28;
public final static int opc_iload_3 = 29;
public final static int opc_lload_0 = 30;
public final static int opc_lload_1 = 31;
public final static int opc_lload_2 = 32;
public final static int opc_lload_3 = 33;
public final static int opc_fload_0 = 34;
public final static int opc_fload_1 = 35;
public final static int opc_fload_2 = 36;
public final static int opc_fload_3 = 37;
public final static int opc_dload_0 = 38;
public final static int opc_dload_1 = 39;
public final static int opc_dload_2 = 40;
public final static int opc_dload_3 = 41;
public final static int opc_aload_0 = 42;
public final static int opc_aload_1 = 43;
public final static int opc_aload_2 = 44;
public final static int opc_aload_3 = 45;
public final static int opc_iaload = 46;
public final static int opc_laload = 47;
public final static int opc_faload = 48;
public final static int opc_daload = 49;
public final static int opc_aaload = 50;
public final static int opc_baload = 51;
public final static int opc_caload = 52;
public final static int opc_saload = 53;
public final static int opc_istore = 54;
public final static int opc_lstore = 55;
public final static int opc_fstore = 56;
public final static int opc_dstore = 57;
public final static int opc_astore = 58;
public final static int opc_istore_0 = 59;
public final static int opc_istore_1 = 60;
public final static int opc_istore_2 = 61;
public final static int opc_istore_3 = 62;
public final static int opc_lstore_0 = 63;
public final static int opc_lstore_1 = 64;
public final static int opc_lstore_2 = 65;
public final static int opc_lstore_3 = 66;
public final static int opc_fstore_0 = 67;
public final static int opc_fstore_1 = 68;
public final static int opc_fstore_2 = 69;
public final static int opc_fstore_3 = 70;
public final static int opc_dstore_0 = 71;
public final static int opc_dstore_1 = 72;
public final static int opc_dstore_2 = 73;
public final static int opc_dstore_3 = 74;
public final static int opc_astore_0 = 75;
public final static int opc_astore_1 = 76;
public final static int opc_astore_2 = 77;
public final static int opc_astore_3 = 78;
public final static int opc_iastore = 79;
public final static int opc_lastore = 80;
public final static int opc_fastore = 81;
public final static int opc_dastore = 82;
public final static int opc_aastore = 83;
public final static int opc_bastore = 84;
public final static int opc_castore = 85;
public final static int opc_sastore = 86;
public final static int opc_pop = 87;
public final static int opc_pop2 = 88;
public final static int opc_dup = 89;
public final static int opc_dup_x1 = 90;
public final static int opc_dup_x2 = 91;
public final static int opc_dup2 = 92;
public final static int opc_dup2_x1 = 93;
public final static int opc_dup2_x2 = 94;
public final static int opc_swap = 95;
public final static int opc_iadd = 96;
public final static int opc_ladd = 97;
public final static int opc_fadd = 98;
public final static int opc_dadd = 99;
public final static int opc_isub = 100;
public final static int opc_lsub = 101;
public final static int opc_fsub = 102;
public final static int opc_dsub = 103;
public final static int opc_imul = 104;
public final static int opc_lmul = 105;
public final static int opc_fmul = 106;
public final static int opc_dmul = 107;
public final static int opc_idiv = 108;
public final static int opc_ldiv = 109;
public final static int opc_fdiv = 110;
public final static int opc_ddiv = 111;
public final static int opc_irem = 112;
public final static int opc_lrem = 113;
public final static int opc_frem = 114;
public final static int opc_drem = 115;
public final static int opc_ineg = 116;
public final static int opc_lneg = 117;
public final static int opc_fneg = 118;
public final static int opc_dneg = 119;
public final static int opc_ishl = 120;
public final static int opc_lshl = 121;
public final static int opc_ishr = 122;
public final static int opc_lshr = 123;
public final static int opc_iushr = 124;
public final static int opc_lushr = 125;
public final static int opc_iand = 126;
public final static int opc_land = 127;
public final static int opc_ior = 128;
public final static int opc_lor = 129;
public final static int opc_ixor = 130;
public final static int opc_lxor = 131;
public final static int opc_iinc = 132;
public final static int opc_i2l = 133;
public final static int opc_i2f = 134;
public final static int opc_i2d = 135;
public final static int opc_l2i = 136;
public final static int opc_l2f = 137;
public final static int opc_l2d = 138;
public final static int opc_f2i = 139;
public final static int opc_f2l = 140;
public final static int opc_f2d = 141;
public final static int opc_d2i = 142;
public final static int opc_d2l = 143;
public final static int opc_d2f = 144;
public final static int opc_i2b = 145;
public final static int opc_i2c = 146;
public final static int opc_i2s = 147;
public final static int opc_lcmp = 148;
public final static int opc_fcmpl = 149;
public final static int opc_fcmpg = 150;
public final static int opc_dcmpl = 151;
public final static int opc_dcmpg = 152;
public final static int opc_ifeq = 153;
public final static int opc_ifne = 154;
public final static int opc_iflt = 155;
public final static int opc_ifge = 156;
public final static int opc_ifgt = 157;
public final static int opc_ifle = 158;
public final static int opc_if_icmpeq = 159;
public final static int opc_if_icmpne = 160;
public final static int opc_if_icmplt = 161;
public final static int opc_if_icmpge = 162;
public final static int opc_if_icmpgt = 163;
public final static int opc_if_icmple = 164;
public final static int opc_if_acmpeq = 165;
public final static int opc_if_acmpne = 166;
public final static int opc_goto = 167;
public final static int opc_jsr = 168;
public final static int opc_ret = 169;
public final static int opc_tableswitch = 170;
public final static int opc_lookupswitch = 171;
public final static int opc_ireturn = 172;
public final static int opc_lreturn = 173;
public final static int opc_freturn = 174;
public final static int opc_dreturn = 175;
public final static int opc_areturn = 176;
public final static int opc_return = 177;
public final static int opc_getstatic = 178;
public final static int opc_putstatic = 179;
public final static int opc_getfield = 180;
public final static int opc_putfield = 181;
public final static int opc_invokevirtual = 182;
public final static int opc_invokespecial = 183;
public final static int opc_invokestatic = 184;
public final static int opc_invokeinterface = 185;
public final static int opc_xxxunusedxxx = 186;
public final static int opc_new = 187;
public final static int opc_newarray = 188;
public final static int opc_anewarray = 189;
public final static int opc_arraylength = 190;
public final static int opc_athrow = 191;
public final static int opc_checkcast = 192;
public final static int opc_instanceof = 193;
public final static int opc_monitorenter = 194;
public final static int opc_monitorexit = 195;
public final static int opc_wide = 196;
public final static int opc_multianewarray = 197;
public final static int opc_ifnull = 198;
public final static int opc_ifnonnull = 199;
public final static int opc_goto_w = 200;
public final static int opc_jsr_w = 201;
public final static int opc_breakpoint = 202;
public final static int opc_impdep1 = 254;
public final static int opc_impdep2 = 255;
public final static String[] opcodeString = {
"nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1",
"iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0",
"lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0",
"dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w",
"iload", "lload", "fload", "dload", "aload", "iload_0",
"iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2",
"lload_3", "fload_0", "fload_1", "fload_2", "fload_3", "dload_0",
"dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2",
"aload_3", "iaload", "laload", "faload", "daload", "aaload",
"baload", "caload", "saload", "istore", "lstore", "fstore",
"dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3",
"lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0",
"fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1",
"dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2",
"astore_3", "iastore", "lastore", "fastore", "dastore", "aastore",
"bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1",
"dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd",
"fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul",
"fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem",
"frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl",
"ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor",
"ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d",
"f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s",
"lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt",
"ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt",
"if_icmpge", "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne",
"goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn",
"lreturn", "freturn", "dreturn", "areturn", "return", "getstatic",
"putstatic", "getfield", "putfield", "invokevirtual",
"invokespecial", "invokestatic", "invokeinterface", "xxxunusedxxx",
"new", "newarray", "anewarray", "arraylength", "athrow", "checkcast",
"instanceof", "monitorenter", "monitorexit", "wide", "multianewarray",
"ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint"
};
public final static String newArrayTypes = "ZCFDBSIJ";
public final static Object[] constants = {
null,
new Integer(-1), new Integer(0), new Integer(1),
new Integer(2), new Integer(3), new Integer(4), new Integer(5),
new Long(0), new Long(1),
new Float(0), new Float(1), new Float(2),
new Double(0), new Double(1)
};
}

@ -0,0 +1,79 @@
/* Reference Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.util.UnifyHash;
///#def COLLECTIONS java.util
import java.util.Iterator;
///#enddef
/**
* This class represents a field or method reference. It consists of
* the class name the method/field name and the type signature.
*/
public class Reference {
/**
* A reference consists of a class name, a member name and a type.
*/
private final String clazz, name, type;
private static final UnifyHash unifier = new UnifyHash();
public static Reference getReference(String className,
String name, String type) {
int hash = className.hashCode() ^ name.hashCode() ^ type.hashCode();
Iterator iter = unifier.iterateHashCode(hash);
while (iter.hasNext()) {
Reference ref = (Reference) iter.next();
if (ref.clazz.equals(className)
&& ref.name.equals(name)
&& ref.type.equals(type))
return ref;
}
Reference ref = new Reference(className, name, type);
unifier.put(hash, ref);
return ref;
}
private Reference(String clazz, String name, String type) {
this.clazz = clazz;
this.name = name;
this.type = type;
}
public String getClazz() {
return clazz;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String toString() {
String classStr = clazz;
if (clazz.startsWith("L"))
classStr = clazz.substring(1, clazz.length() - 1)
.replace('/', '.');
return classStr + "." + name + " " + type;
}
}

@ -0,0 +1,86 @@
/* ReferenceInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This class represents an instruction that needs a reference, i.e.
* a method invocation or field access instruction.
*/
class ReferenceInstruction extends Instruction {
private Reference reference;
public ReferenceInstruction(int opcode, Reference ref) {
super(opcode);
this.reference = ref;
}
public final Reference getReference()
{
return reference;
}
public final void setReference(Reference ref)
{
reference = ref;
}
/**
* This returns the number of stack entries this instruction
* pushes and pops from the stack. The result fills the given
* array.
*
* @param poppush an array of two ints. The first element will
* get the number of pops, the second the number of pushes.
*/
public void getStackPopPush(int[] poppush)
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
{
String typeSig = reference.getType();
int opcode = getOpcode();
switch (opcode) {
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
poppush[0] += TypeSignature.getParameterSize(typeSig);
poppush[1] = TypeSignature.getReturnSize(typeSig);
break;
case opc_putfield:
case opc_putstatic:
poppush[1] = 0;
poppush[0] = TypeSignature.getTypeSize(typeSig);
if (opcode == opc_putfield)
poppush[0]++;
break;
case opc_getstatic:
case opc_getfield:
poppush[1] = TypeSignature.getTypeSize(typeSig);
poppush[0] = opcode == opc_getfield ? 1 : 0;
break;
}
}
public String toString() {
return super.toString()+' '+reference;
}
}

@ -0,0 +1,72 @@
/* SlotInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This class represents an instruction in the byte code.
*
*/
class SlotInstruction extends Instruction {
private LocalVariableInfo lvi;
/**
*/
public SlotInstruction(int opcode, LocalVariableInfo lvi) {
super(opcode);
this.lvi = lvi;
}
public boolean isStore() {
int opcode = getOpcode();
return opcode >= opc_istore && opcode <= opc_astore;
}
public boolean hasLocal() {
return true;
}
public final int getLocalSlot()
{
return lvi.getSlot();
}
public final LocalVariableInfo getLocalInfo()
{
return lvi;
}
public final void setLocalInfo(LocalVariableInfo info)
{
this.lvi = info;
}
public final void setLocalSlot(int slot)
{
if (lvi.getName() == null)
this.lvi = LocalVariableInfo.getInfo(slot);
else
this.lvi = LocalVariableInfo.getInfo(slot,
lvi.getName(), lvi.getType());
}
public String toString() {
return super.toString()+' '+lvi;
}
}

@ -0,0 +1,58 @@
/* SwitchInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.util.StringQuoter;
/**
* This class represents an instruction in the byte code.
*
*/
class SwitchInstruction extends Instruction {
/**
* The values for this switch.
*/
private int[] values;
/**
* Standard constructor: creates an opcode with parameter and
* lineNr.
*/
SwitchInstruction(int opcode, int[] values) {
super(opcode);
this.values = values;
}
public final int[] getValues()
{
return values;
}
public final void setValues(int[] values)
{
this.values = values;
}
public String toString() {
StringBuffer sb = new StringBuffer(opcodeString[getOpcode()]);
for (int i=0; i< values.length; i++)
sb.append(' ').append(values[i]);
return sb.toString();
}
}

@ -0,0 +1,72 @@
/* TypeDimensionInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This class represents an opc_multianewarray instruction.
*
*/
class TypeDimensionInstruction extends TypeInstruction {
/**
* The dimension of this multianewarray operation.
*/
private int dimension;
public TypeDimensionInstruction(int opcode, String type, int dimension) {
super(opcode, type);
this.dimension = dimension;
}
/**
* Get the dimensions for an opc_anewarray opcode.
*/
public final int getDimensions()
{
return dimension;
}
/**
* Get the dimensions for an opc_anewarray opcode.
*/
public final void setDimensions(int dim)
{
dimension = dim;
}
/**
* This returns the number of stack entries this instruction
* pushes and pops from the stack. The result fills the given
* array.
*
* @param poppush an array of two ints. The first element will
* get the number of pops, the second the number of pushes.
*/
public void getStackPopPush(int[] poppush)
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
{
poppush[0] = dimension;
poppush[1] = 1;
}
public String toString() {
return super.toString()+' '+dimension;
}
}

@ -0,0 +1,50 @@
/* TypeInstruction Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
/**
* This class represents an instruction in the byte code.
*
*/
class TypeInstruction extends Instruction {
/**
* The typesignature of the class/array.
*/
private String typeSig;
public TypeInstruction(int opcode, String typeSig) {
super(opcode);
this.typeSig = typeSig;
}
public final String getClazzType()
{
return typeSig;
}
public final void setClazzType(String type)
{
typeSig = type;
}
public String toString() {
return super.toString()+' '+typeSig;
}
}

@ -0,0 +1,710 @@
/* TypeSignature Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.bytecode;
import net.sf.jode.util.UnifyHash;
///#def COLLECTIONS java.util
import java.util.Map;
///#enddef
/**
* This class contains some static methods to handle type signatures. <br>
*
* A type signature is a compact textual representation of a java
* types. It is described in the Java Virtual Machine Specification.
* Primitive types have a one letter type signature. Type signature
* of classes contains the class name. Type signatures for arrays and
* methods are recursively build from the type signatures of their
* elements. <br> Since java 5 there is a new class of type
* signatures supporting generics. These can be accessed with the
* getSignature methods of ClassInfo, MethodInfo and FieldInfo.
*
* Here are a few examples:
* <table><tr><th>type signature</th><th>Java type</th></tr>
* <tr><td><code>Z</code></td><td><code>boolean</code></td></tr>
* <tr><td><code>B</code></td><td><code>byte</code></td></tr>
* <tr><td><code>S</code></td><td><code>short</code></td></tr>
* <tr><td><code>C</code></td><td><code>char</code></td></tr>
* <tr><td><code>I</code></td><td><code>int</code></td></tr>
* <tr><td><code>F</code></td><td><code>float</code></td></tr>
* <tr><td><code>J</code></td><td><code>long</code></td></tr>
* <tr><td><code>D</code></td><td><code>double</code></td></tr>
* <tr><td><code>Ljava/lang/Object;</code></td>
* <td><code>java.lang.Object</code></td></tr>
* <tr><td><code>[[I</code></td><td><code>int[][]</code></td></tr>
* <tr><td><code>(Ljava/lang/Object;I)V</code></td>
* <td>method with argument types <code>Object</code> and
* <code>int</code> and <code>void</code> return type.</td></tr>
* <tr><td><code>()I</code></td>
* <td> method without arguments
* and <code>int</code> return type.</td></tr>
* <tr><td colspan="2"><code>&lt;E:Ljava/lang/Object;&gt;Ljava/lang/Object;Ljava/util/Collection&lt;TE;&gt;;</code></td>
* </tr><tr><td></td>
* <td> generic class over &lt;E extends Object&gt; extending
* Object and implementing Collections&lt;E&gt;</td></tr>
* <tr><td colspan="2"><code>&lt;T:Ljava/lang/Object;&gt;([TT;)[TT;</code></td>
* </tr><tr><td></td>
* <td> generic method over &lt;T extends Object&gt; taking an
* array of T as parameters and returning an array of T.</td></tr>
* </table>
*
*
* @author Jochen Hoenicke
*/
public class TypeSignature {
/**
* This is a private method for generating the signature of a
* given type.
*/
private static final StringBuffer appendSignature(StringBuffer sb,
Class javaType) {
if (javaType.isPrimitive()) {
if (javaType == Boolean.TYPE)
return sb.append('Z');
else if (javaType == Byte.TYPE)
return sb.append('B');
else if (javaType == Character.TYPE)
return sb.append('C');
else if (javaType == Short.TYPE)
return sb.append('S');
else if (javaType == Integer.TYPE)
return sb.append('I');
else if (javaType == Long.TYPE)
return sb.append('J');
else if (javaType == Float.TYPE)
return sb.append('F');
else if (javaType == Double.TYPE)
return sb.append('D');
else if (javaType == Void.TYPE)
return sb.append('V');
else
throw new InternalError("Unknown primitive type: "+javaType);
} else if (javaType.isArray()) {
return appendSignature(sb.append('['),
javaType.getComponentType());
} else {
return sb.append('L')
.append(javaType.getName().replace('.','/')).append(';');
}
}
/**
* Generates the type signature of the given Class.
* @param clazz a java.lang.Class, this may also be a primitive or
* array type.
* @return the type signature.
*/
public static String getSignature(Class clazz) {
return appendSignature(new StringBuffer(), clazz).toString();
}
/**
* Generates a method signature.
* @param paramT the java.lang.Class of the parameter types of the method.
* @param returnT the java.lang.Class of the return type of the method.
* @return the method type signature
*/
public static String getSignature(Class paramT[], Class returnT) {
StringBuffer sig = new StringBuffer("(");
for (int i=0; i< paramT.length; i++)
appendSignature(sig, paramT[i]);
return appendSignature(sig.append(')'), returnT).toString();
}
/**
* Generates a Class object for a type signature. This is the
* inverse function of getSignature.
* @param typeSig a single type signature
* @return the Class object representing that type.
*/
public static Class getClass(String typeSig)
throws ClassNotFoundException
{
switch(typeSig.charAt(0)) {
case 'Z':
return Boolean.TYPE;
case 'B':
return Byte.TYPE;
case 'C':
return Character.TYPE;
case 'S':
return Short.TYPE;
case 'I':
return Integer.TYPE;
case 'F':
return Float.TYPE;
case 'J':
return Long.TYPE;
case 'D':
return Double.TYPE;
case 'V':
return Void.TYPE;
case 'L':
typeSig = typeSig.substring(1, typeSig.length()-1)
.replace('/','.');
/* fall through */
case '[':
return Class.forName(typeSig);
}
throw new IllegalArgumentException(typeSig);
}
/**
* Check if the given type is a two slot type. The only two slot
* types are long and double.
*/
private static boolean usingTwoSlots(char type) {
return "JD".indexOf(type) >= 0;
}
/**
* Returns the number of words, an object of the given simple type
* signature takes. For long and double this is two, for all other
* types it is one.
*/
public static int getTypeSize(String typeSig) {
return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1;
}
/**
* Gets the element type of an array.
* @param typeSig type signature of the array.
* @return type signature for the element type.
* @exception IllegalArgumentException if typeSig is not an array
* type signature.
*/
public static String getElementType(String typeSig) {
if (typeSig.charAt(0) != '[')
throw new IllegalArgumentException();
return typeSig.substring(1);
}
/**
* Gets the ClassInfo for a class type.
* @param classpath the classpath in which the ClassInfo is searched.
* @param typeSig type signature of the class.
* @return the ClassInfo object for the class.
* @exception IllegalArgumentException if typeSig is not an class
* type signature.
*/
public static ClassInfo getClassInfo(ClassPath classpath, String typeSig) {
if (typeSig.charAt(0) != 'L')
throw new IllegalArgumentException();
return classpath.getClassInfo
(typeSig.substring(1, typeSig.length()-1).replace('/', '.'));
}
/**
* Skips the next entry of a method type signature
* @param methodTypeSig type signature of the method.
* @param position the index to the last entry.
* @return the index to the next entry.
*/
public static int skipType(String methodTypeSig, int position) {
char c = methodTypeSig.charAt(position++);
while (c == '[')
c = methodTypeSig.charAt(position++);
if (c == 'L' || c == 'T') {
int angledepth = 0;
c = methodTypeSig.charAt(position++);
while (c != ';' || angledepth > 0) {
if (c == '<')
angledepth++;
else if (c == '>')
angledepth--;
c = methodTypeSig.charAt(position++);
}
}
return position;
}
/**
* Gets the number of words the parameters for the given method
* type signature takes. This is the sum of getTypeSize() for
* each parameter type.
* @param methodTypeSig the method type signature.
* @return the number of words the parameters take.
*/
public static int getParameterSize(String methodTypeSig) {
int nargs = 0;
int i = 1;
for (;;) {
char c = methodTypeSig.charAt(i);
if (c == ')')
return nargs;
i = skipType(methodTypeSig, i);
if (usingTwoSlots(c))
nargs += 2;
else
nargs++;
}
}
/**
* Gets the size of the return type of the given method in words.
* This is zero for void return type, two for double or long return
* type and one otherwise.
* @param methodTypeSig the method type signature.
* @return the size of the return type in words.
*/
public static int getReturnSize(String methodTypeSig) {
int length = methodTypeSig.length();
if (methodTypeSig.charAt(length - 2) == ')') {
// This is a single character return type.
char returnType = methodTypeSig.charAt(length - 1);
return returnType == 'V' ? 0
: usingTwoSlots(returnType) ? 2 : 1;
} else
// All multi character return types take one parameter
return 1;
}
/**
* Gets the argument type signatures of the given template signature.
* @param templateTypeSig the template type signature.
* @return an array containing all parameter types in correct order.
*/
public static String[] getArgumentTypes(String templateTypeSig) {
System.err.println(templateTypeSig);
int pos = 1;
int count = 0;
char c;
while ((c = templateTypeSig.charAt(pos)) != '>') {
if (c == '*') {
pos++;
} else {
if (c == '+' || c == '-')
pos++;
pos = skipType(templateTypeSig, pos);
}
count++;
}
String[] params = new String[count];
pos = 1;
for (int i = 0; i < count; i++) {
int start = pos;
c = templateTypeSig.charAt(pos);
if (c == '*') {
pos++;
} else {
if (c == '+' || c == '-')
pos++;
pos = skipType(templateTypeSig, pos);
}
params[i] = templateTypeSig.substring(start, pos);
}
return params;
}
/**
* Gets the parameter type signatures of the given method signature.
* @param methodTypeSig the method type signature.
* @return an array containing all parameter types in correct order.
*/
public static String[] getParameterTypes(String methodTypeSig) {
System.err.println(methodTypeSig);
int pos = 1;
int count = 0;
while (methodTypeSig.charAt(pos) != ')') {
pos = skipType(methodTypeSig, pos);
count++;
}
String[] params = new String[count];
pos = 1;
for (int i = 0; i < count; i++) {
int start = pos;
pos = skipType(methodTypeSig, pos);
params[i] = methodTypeSig.substring(start, pos);
}
return params;
}
/**
* Gets the return type for a method signature
* @param methodTypeSig the method signature.
* @return the return type for a method signature, `V' for void methods.
*/
public static String getReturnType(String methodTypeSig) {
return methodTypeSig.substring(methodTypeSig.lastIndexOf(')')+1);
}
/**
* Gets the names of the generic parameters of the given type signature.
* @param typeSig the type signature.
* @return an array containing all generic parameter types
* in correct order, or null if there aren't any generic parameters.
*/
public static String[] getGenericNames(String typeSig) {
System.err.println(typeSig);
if (typeSig.charAt(0) != '<')
return null;
int pos = 1;
int count = 0;
while (typeSig.charAt(pos) != '>') {
while (typeSig.charAt(pos) != ':')
pos++;
/* check for empty entry */
if (typeSig.charAt(pos+1) == ':')
pos++;
while (typeSig.charAt(pos) == ':') {
/* skip colon and type */
pos = skipType(typeSig, pos + 1);
}
count++;
}
String[] params = new String[count];
pos = 1;
count = 0;
while (typeSig.charAt(pos) != '>') {
int spos = pos;
while (typeSig.charAt(pos) != ':')
pos++;
params[count++] = typeSig.substring(spos, pos);
/* check for empty entry */
if (typeSig.charAt(pos+1) == ':')
pos++;
while (typeSig.charAt(pos) == ':') {
/* skip colon and type */
pos = skipType(typeSig, pos + 1);
}
}
return params;
}
private static int mapGenericsInType(String typeSig, Map generics,
StringBuffer mapped, int spos) {
int pos = spos;
char c = typeSig.charAt(pos++);
while (c == '[')
c = typeSig.charAt(pos++);
if (c == 'T') {
int epos = typeSig.indexOf(';', pos);
String key = typeSig.substring(pos, epos);
String mapval = (String) generics.get(key);
if (mapval != null) {
mapped.append(typeSig.substring(spos, pos - 1))
.append(key);
spos = epos + 1;
}
pos = epos + 1;
} else if (c == 'L') {
c = typeSig.charAt(pos++);
while (c != ';' && c != '<')
c = typeSig.charAt(pos++);
if (c == '<') {
mapped.append(typeSig.substring(spos, pos));
while (typeSig.charAt(pos) != '>') {
pos = mapGenericsInType(typeSig, generics, mapped, pos);
}
spos = pos;
pos += 2;
}
}
mapped.append(typeSig.substring(spos, pos));
return pos;
}
/**
* Map the names of the generic parameters in the given type signature
* and return the type signature with the generic parameters mapped to
* (more or less) real types.
* @param typeSig the type signature.
* @param generics A map from generic names to type signatures.
* @return the mapped generic type signature.
*/
public static String mapGenerics(String typeSig, Map generics) {
StringBuffer mapped = new StringBuffer();
int pos = 0;
int spos = 0;
if (typeSig.length() == 0)
return "";
char c = typeSig.charAt(pos++);
if (c == '<') {
c = typeSig.charAt(pos++);
while (c != '>') {
while (c != ':') {
c = typeSig.charAt(pos++);
}
if (typeSig.charAt(pos) == ':')
pos++;
while (c == ':') {
mapped.append(typeSig.substring(spos, pos));
pos = mapGenericsInType(typeSig, generics, mapped, pos);
spos = pos;
c = typeSig.charAt(pos);
}
}
}
if (c == '(') {
while (typeSig.charAt(pos) != ')') {
mapped.append(typeSig.substring(spos, pos));
pos = mapGenericsInType(typeSig, generics, mapped, pos);
spos = pos;
}
pos++;
}
mapped.append(typeSig.substring(spos, pos));
while (pos < typeSig.length()) {
pos = mapGenericsInType(typeSig, generics, mapped, pos);
}
return mapped.toString();
}
/**
* Gets the default value an object of the given type has. It is
* null for objects and arrays, Integer(0) for boolean and short
* integer types or Long(0L), Double(0.0), Float(0.0F) for long,
* double and float. This seems strange, but this way the type
* returned is the same as for FieldInfo.getConstant().
*
* @param typeSig the type signature.
* @return the default value.
* @exception IllegalArgumentException if this is a method type signature.
*/
public static Object getDefaultValue(String typeSig) {
switch(typeSig.charAt(0)) {
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
return new Integer(0);
case 'J':
return new Long(0L);
case 'D':
return new Double(0.0);
case 'F':
return new Float(0.0F);
case 'L':
case '[':
return null;
default:
throw new IllegalArgumentException(typeSig);
}
}
/**
* Checks if there is a valid class name starting at index
* in string typeSig and ending with a semicolon.
* @return the index at which the class name ends.
* @exception IllegalArgumentException if there was an illegal character.
* @exception StringIndexOutOfBoundsException if the typeSig ended early.
*/
private static int checkClassName(String clName, int i)
throws IllegalArgumentException, StringIndexOutOfBoundsException
{
while (true) {
char c = clName.charAt(i++);
if (c == '<') {
c = clName.charAt(i++);
do {
if (c == '*')
i++;
else {
if (c == '+' || c == '-')
c = clName.charAt(i++);
if (c != 'L' && c != 'T' && c != '[')
throw new IllegalArgumentException
("Wrong class instantiation: "+clName);
i = checkTypeSig(clName, i - 1);
}
c = clName.charAt(i++);
} while (c != '>');
c = clName.charAt(i++);
if (c != ';')
throw new IllegalArgumentException
("no ; after > in "+clName);
}
if (c == ';')
return i;
if (c != '/' && !Character.isJavaIdentifierPart(c))
throw new IllegalArgumentException("Illegal java class name: "
+ clName);
}
}
/**
* Checks if there is a valid class name starting at index
* in string typeSig and ending with a semicolon.
* @return the index at which the class name ends.
* @exception IllegalArgumentException if there was an illegal character.
* @exception StringIndexOutOfBoundsException if the typeSig ended early.
*/
private static int checkTemplateName(String clName, int i)
throws IllegalArgumentException, StringIndexOutOfBoundsException
{
while (true) {
char c = clName.charAt(i++);
if (c == ';')
return i;
if (!Character.isJavaIdentifierPart(c))
throw new IllegalArgumentException("Illegal java class name: "
+ clName);
}
}
/**
* Checks if there is a valid simple type signature starting at index
* in string typeSig.
* @return the index at which the type signature ends.
* @exception IllegalArgumentException if there was an illegal character.
* @exception StringIndexOutOfBoundsException if the typeSig ended early.
*/
private static int checkTypeSig(String typeSig, int index) {
char c = typeSig.charAt(index++);
while (c == '[')
c = typeSig.charAt(index++);
if (c == 'L') {
index = checkClassName(typeSig, index);
} else if (c == 'T') {
index = checkTemplateName(typeSig, index);
} else {
if ("ZBSCIJFD".indexOf(c) == -1)
throw new IllegalArgumentException("Type sig error: "+typeSig);
}
return index;
}
/**
* Checks whether a given type signature starts with valid generic
* part and returns the index where generics end.
* @param typeSig the type signature.
* @param i the start index.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* type signature.
* @return 0 if no generics at beginning, otherwise the
* index after the &gt; sign.
*/
private static int checkGenerics(String typeSig, int i) {
if (typeSig.charAt(i) == '<') {
i++;
char c = typeSig.charAt(i++);
if (c == '>')
throw new IllegalArgumentException("Empty Generics: "+typeSig);
while (c != '>') {
if (c == ':')
throw new IllegalArgumentException("Empty type name: "+typeSig);
while (c != ':') {
if (!Character.isJavaIdentifierPart(c))
throw new IllegalArgumentException
("Illegal generic name: "+ typeSig);
c = typeSig.charAt(i++);
}
c = typeSig.charAt(i++);
if (c != 'L' && c != 'T' && c != ':')
throw new IllegalArgumentException
("Wrong generic extends: "+typeSig);
if (c != ':')
i = checkTypeSig(typeSig, i - 1);
c = typeSig.charAt(i++);
while(c == ':') {
i = checkTypeSig(typeSig, i);
c = typeSig.charAt(i++);
}
}
}
return i;
}
/**
* Checks whether a given type signature is a valid (not method)
* type signature. Throws an exception otherwise.
* @param typeSig the type signature.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* type signature or if it's a method type signature.
*/
public static void checkTypeSig(String typeSig)
throws IllegalArgumentException
{
try {
int i = checkGenerics(typeSig, 0);
if (checkTypeSig(typeSig, i) != typeSig.length())
throw new IllegalArgumentException
("Type sig too long: "+typeSig);
} catch (StringIndexOutOfBoundsException ex) {
throw new IllegalArgumentException
("Incomplete type sig: "+typeSig);
}
}
/**
* Checks whether a given type signature is a valid class
* type signature. Throws an exception otherwise.
* A class type signature starts optionally with generics,
* followed by type signature of super class, followed by
* type signature of super interfaces.
* @param typeSig the type signature.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* type signature or if it's a method type signature.
*/
public static void checkClassTypeSig(String typeSig)
throws IllegalArgumentException
{
try {
int i = checkGenerics(typeSig, 0);
i = checkTypeSig(typeSig, i);
while (i != typeSig.length()) {
i = checkTypeSig(typeSig, i);
}
} catch (StringIndexOutOfBoundsException ex) {
throw new IllegalArgumentException
("Incomplete type sig: "+typeSig);
}
}
/**
* Checks whether a given type signature is a valid method
* type signature. Throws an exception otherwise.
* @param typeSig the type signature.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* method type signature.
*/
public static void checkMethodTypeSig(String typeSig)
throws IllegalArgumentException
{
try {
int i = checkGenerics(typeSig, 0);
if (typeSig.charAt(i) != '(')
throw new IllegalArgumentException
("No method signature: "+typeSig);
i++;
while (typeSig.charAt(i) != ')')
i = checkTypeSig(typeSig, i);
// skip closing parenthesis.
i++;
if (typeSig.charAt(i) == 'V')
// accept void return type.
i++;
else
i = checkTypeSig(typeSig, i);
if (i != typeSig.length())
throw new IllegalArgumentException
("Type sig too long: "+typeSig);
} catch (StringIndexOutOfBoundsException ex) {
throw new IllegalArgumentException
("Incomplete type sig: "+typeSig);
}
}
}

@ -0,0 +1,106 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<!--
Copyright (C) 1998-1999 Jochen Hoenicke.
This documentation is free; 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.
-->
<title>Jode Bytecode Package</title>
</head>
<body>
Provides easy access to class files and their contents. To use it you
create a <code>ClassPath</code> object giving it the locations where
it should search for classes. Then you can ask this object for a
class and get a ClassInfo object. As third step you can actually load
the class.<br><br>
Please notify me if you want to use this package. I will inform you
about updates, help you with problems, etc. <b> WARNING: </b> Some
parts of this package may change in the future in incompatible ways.
Ask me for more information. <br><br>
Here is a short example, how you can use this package, see the
documentation of the classes for more details.
<pre>
...
ClassPath path = new ClassPath("/usr/lib/java/lib/classes.zip");
ClassInfo clazz = path.getClassInfo("java.util.Hashtable");
try {
clazz.load(ClassInfo.DECLARATIONS);
} catch (ClassFormatException ex) {
System.err.println("Something is wrong with HashTable, giving up!");
return;
} catch (IOException ex) {
System.err.println("Can't load HashTable, giving up!");
return;
}
MethodInfo[] methods = clazz.getMethods();
for (int i = 0; i &lt; methods.length; i++) {
String type = methods[i].getType();
if (TypeSignature.getReturnType(type) == TypeSignature.INT_TYPE)
System.out.println("Found integer method: "+method.getName());
}
...
</pre>
You can also use this package to create and write new classes:
<pre>
...
ClassPath path = new ClassPath("/usr/lib/java/lib/classes.zip");
ClassInfo clazz = path.getClassInfo("my.new.Class");
clazz.setModifiers(Modifier.PUBLIC);
clazz.setSourceFile("Class.pl");
clazz.set...
clazz.write(zipOutputStream);
...
</pre>
<h3><a name="advantages">Advantages of this bytecode package</a></h3>
<ul>
<li>You don't need to think of the constant pool, except when you want
to write your custom attributes.</li>
<li>The set of opcodes is drastically reduced: For example you don't
have to handle 20 different opcodes that all push a constant value on
the stack. When reading it will automatically convert them to
<code>ldc</code> or <code>ldc2</code> and on writing it will convert
them back.</li>
<li>Wide instructions are automatically generated when needed, large
methods are supported.</li>
<li>The code is organized in {@link net.sf.jode.bytecode.BasicBlocks}
which makes flow analysis much easier.</li>
<li>The memory consumption is quite moderate.</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>You can't change every byte. For example Jode decides itself if
a lookup switch or table switch is generated.</li>
<li>Jode does a lot of checks when reading the bytecode and it is
impossible to recover from errors. This makes it sometime hard to
find out why the bytecode of a particular class files is invalid.</li>
</ul>
<hr>
<address><a href="mailto:jochen@gnu.org">Jochen Hoenicke</a></address>
<!-- Created: Thu Jun 22 2000 -->
<!-- hhmts start -->
Last modified: Sat Aug 11 18:44:19 MEST 2001
<!-- hhmts end -->
</body>
</html>

@ -0,0 +1,26 @@
/* Analyzer Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
public interface Analyzer {
public void analyze();
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException;
}

@ -0,0 +1,124 @@
/* Applet Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
public class Applet extends java.applet.Applet {
private final int BORDER = 10;
private final int BEVEL = 2;
private Window jodeWin = new Window(this);
private Insets myInsets;
private Color pageColor;
///#ifdef AWT10
/// public boolean action(Event e, Object arg) {
/// jodeWin.action(e, arg);
/// return true;
/// }
///
/// public Insets insets() {
/// if (myInsets == null) {
/// Insets appInsets = super.insets();
///#else
public Insets getInsets() {
if (myInsets == null) {
Insets appInsets = super.getInsets();
///#endif
myInsets = new Insets
(appInsets.top+BORDER, appInsets.left+BORDER,
appInsets.bottom+BORDER, appInsets.right+BORDER);
}
return myInsets;
}
public void paint(Graphics g) {
super.paint(g);
Color back = getBackground();
Color bright = back.brighter();
Color dark = back.darker();
///#ifdef AWT10
/// Dimension size = size();
///#else
Dimension size = getSize();
///#endif
// Fill corners with page color:
g.setColor(pageColor);
g.fillRect(0 , 0 , BORDER, BORDER);
g.fillRect(size.width - BORDER, 0 , BORDER, BORDER);
g.fillRect(size.width - BORDER, size.height - BORDER, BORDER, BORDER);
g.fillRect(0 , size.height - BORDER, BORDER, BORDER);
// put filled arcs into corners with highlight color
g.setColor(bright);
g.fillArc(0, 0,
2*BORDER, 2*BORDER, 90, 90);
g.fillArc(size.width - 2*BORDER, 0,
2*BORDER, 2*BORDER, 45, 45);
g.fillArc(0, size.height - 2*BORDER,
2*BORDER, 2*BORDER, 180, 45);
// draw highlighted edges
g.fillRect(BORDER, 0, size.width - 2*BORDER, BEVEL);
g.fillRect(0, BORDER, BEVEL, size.height - 2*BORDER);
// The same as above on the other side with dark color.
g.setColor(dark);
g.fillArc(size.width - 2*BORDER, 0,
2*BORDER, 2*BORDER, 0, 45);
g.fillArc(0, size.height - 2*BORDER,
2*BORDER, 2*BORDER, 225, 45);
g.fillArc(size.width - 2*BORDER, size.height - 2*BORDER,
2*BORDER, 2*BORDER, -90, 90);
g.fillRect(BORDER, size.height - BEVEL, size.width - 2*BORDER, BEVEL);
g.fillRect(size.width - BEVEL, BORDER, BEVEL, size.height - 2*BORDER);
// Finally fill the corners with background color again.
g.setColor(back);
g.fillArc(BEVEL, BEVEL,
2*(BORDER-BEVEL), 2*(BORDER-BEVEL), 90, 90);
g.fillArc(size.width - (2*BORDER-BEVEL), BEVEL,
2*(BORDER-BEVEL), 2*(BORDER-BEVEL), 0, 90);
g.fillArc(BEVEL, size.height - 2*BORDER + BEVEL,
2*(BORDER-BEVEL), 2*(BORDER-BEVEL), 180, 90);
g.fillArc(size.width - (2*BORDER-BEVEL),
size.height - (2*BORDER-BEVEL),
2*(BORDER-BEVEL), 2*(BORDER-BEVEL), -90, 90);
}
public void init() {
String colorstr = getParameter("pagecolor");
if (colorstr == null)
colorstr = "ffffff";
this.pageColor = new Color(Integer.parseInt(colorstr, 16));
colorstr = getParameter("bgcolor");
if (colorstr != null)
setBackground(new Color(Integer.parseInt(colorstr, 16)));
String cp = getParameter("classpath");
if (cp != null)
jodeWin.setClassPath(cp);
String cls = getParameter("class");
if (cls != null)
jodeWin.setClass(cls);
}
}

@ -0,0 +1,825 @@
/* ClassAnalyzer Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
import net.sf.jode.GlobalOptions;
import net.sf.jode.type.MethodType;
import net.sf.jode.type.Type;
import net.sf.jode.bytecode.ClassFormatException;
import net.sf.jode.bytecode.ClassInfo;
import net.sf.jode.bytecode.ClassPath;
import net.sf.jode.bytecode.FieldInfo;
import net.sf.jode.bytecode.MethodInfo;
import net.sf.jode.expr.Expression;
import net.sf.jode.expr.ThisOperator;
import net.sf.jode.flow.TransformConstructors;
import net.sf.jode.flow.StructuredBlock;
import net.sf.jode.util.SimpleSet;
import java.lang.reflect.Modifier;
import java.util.NoSuchElementException;
import java.util.Vector;
import java.util.Enumeration;
import java.io.IOException;
///#def COLLECTIONS java.util
import java.util.Collection;
import java.util.Set;
///#enddef
public class ClassAnalyzer
implements Scope, Declarable, ClassDeclarer
{
ImportHandler imports;
ClassInfo clazz;
ClassDeclarer parent;
ProgressListener progressListener;
String[] generics;
Type[] genericTypes;
/**
* The complexity for initi#alizing a class.
*/
private static double INITIALIZE_COMPLEXITY = 0.03;
/**
* The minimal visible complexity.
*/
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 innerComplexity = 0.0;
String name;
StructuredBlock[] blockInitializers;
FieldAnalyzer[] fields;
MethodAnalyzer[] methods;
ClassAnalyzer[] inners;
int modifiers;
TransformConstructors constrAna;
MethodAnalyzer staticConstructor;
MethodAnalyzer[] constructors;
/**
* The outer values for method scoped classes.
*/
OuterValues outerValues;
/**
* The outer instance for non-static class scope classes.
*/
Expression outerInstance;
public ClassAnalyzer(ClassDeclarer parent,
ClassInfo clazz, ImportHandler imports,
Expression[] outerValues)
throws ClassFormatException, IOException
{
clazz.load(ClassInfo.ALL);
String signatures = clazz.getSignature();
if (signatures.charAt(0) == '<') {
String[] genericSignatures = signature.getGenericNames();
generics = new String[genericSignatures.length];
for (int i = 0; i < generics.length; i++) {
int colon = genericSignatures[i].charAt(':');
String genName;
if (colon == -1) {
generics[i] = genericSignatures[i];
genericType[i] =
new GenericParameterType(genericSignatures[i],
Type.tObject,
new ClassType[0]);
} else {
generics[i] = genericSignatures[i].substring(0, colon);
String remainder = genericSignatures[i].substring(colon+1);
int nextIndex = remainder.skipType(remainder, 0);
List superClazzes;
for (;;) {
String clazzSig = remainder.substring(0, nextIndex);
superClazzes.add(Type.tType(clazzSig));
if (nextIndex >= remainder.length())
break;
remainder = remainder.substring(nextIndex+1);
}
ClassType genSupClass = (ClassType) superClazzes.get(0);
if (!genSupClass.isInterface())
superClazzes.remove(0);
else
genSupClass = Type.tObject;
ClassType[] genSupIfaces = (ClassType[])
superClazzes.toArray(new ClassType[0]);
genericType[i] = new GenericParameterType(generics[i],
genSupClass,
genSupIfaces);
}
}
}
ClassInfo superClass = clazz.getSuperclass();
String myPackage = clazz.getName().substring
(clazz.getName().lastIndexOf('.') + 1);
while (superClass != null) {
int howMuch = (superClass.getName().startsWith(myPackage)
&& (superClass.getName().lastIndexOf('.')
< myPackage.length()))
? ClassInfo.DECLARATIONS : ClassInfo.PUBLICDECLARATIONS;
try {
superClass.load(howMuch);
} catch (IOException ex) {
GlobalOptions.err.println
("Warning: Can't get "
+ (howMuch == ClassInfo.PUBLICDECLARATIONS
? "public" : "all")
+ " information of " + superClass
+" to detect name conflicts.");
GlobalOptions.err.println(ex.toString());
superClass.guess(howMuch);
}
superClass = superClass.getSuperclass();
}
this.parent = parent;
this.clazz = clazz;
this.imports = imports;
modifiers = clazz.getModifiers();
name = clazz.getClassName();
/* Check if this is a normal non-static inner class and set
* outerInstance.
*/
if ((Options.options & Options.OPTION_INNER) != 0
&& parent instanceof ClassAnalyzer && !isStatic())
outerInstance = new ThisOperator(((ClassAnalyzer) parent).clazz);
if (outerValues != null)
this.outerValues = new OuterValues(this, outerValues);
}
public ClassAnalyzer(ClassDeclarer parent,
ClassInfo clazz, ImportHandler imports)
throws ClassFormatException, IOException
{
this(parent, clazz, imports, null);
}
public ClassAnalyzer(ClassInfo clazz, ImportHandler imports)
throws ClassFormatException, IOException
{
this(null, clazz, imports);
}
public ClassPath getClassPath() {
return clazz.getClassPath();
}
public final boolean isStatic() {
return Modifier.isStatic(modifiers);
}
public final boolean isStrictFP() {
return (modifiers & STRICTFP) != 0;
}
public FieldAnalyzer getField(int index) {
return fields[index];
}
public int getFieldIndex(String fieldName, Type fieldType) {
for (int i=0; i< fields.length; i++) {
if (fields[i].getName().equals(fieldName)
&& fields[i].getType().equals(fieldType))
return i;
}
return -1;
}
public MethodAnalyzer getMethod(String methodName, MethodType methodType) {
for (int i=0; i< methods.length; i++) {
if (methods[i].getName().equals(methodName)
&& methods[i].getType().equals(methodType))
return methods[i];
}
return null;
}
public int getModifiers() {
return modifiers;
}
public ClassDeclarer getParent() {
return parent;
}
public void setParent(ClassDeclarer newParent) {
this.parent = newParent;
}
public ClassInfo getClazz() {
return clazz;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public OuterValues getOuterValues() {
return outerValues;
}
public Expression getOuterInstance() {
return outerInstance;
}
public void addBlockInitializer(int index, StructuredBlock initializer) {
if (blockInitializers[index] == null)
blockInitializers[index] = initializer;
else
blockInitializers[index].appendBlock(initializer);
}
public void initialize() {
FieldInfo[] finfos = clazz.getFields();
MethodInfo[] minfos = clazz.getMethods();
ClassInfo[] innerInfos = clazz.getClasses();
if (finfos == null) {
/* This means that the class could not be loaded.
* give up.
*/
return;
}
if ((Options.options & Options.OPTION_INNER) != 0
&& innerInfos != null) {
/* Create inner classes */
int innerCount = innerInfos.length;
inners = new ClassAnalyzer[innerCount];
for (int i=0; i < innerCount; i++) {
try {
inners[i] = new ClassAnalyzer
(this, innerInfos[i], imports, null);
} catch (ClassFormatException ex) {
GlobalOptions.err.println("Inner class "+innerInfos[i]
+" malformed!");
ex.printStackTrace(GlobalOptions.err);
} catch (IOException ex) {
GlobalOptions.err.println("Can't read inner class "
+innerInfos[i]+".");
ex.printStackTrace(GlobalOptions.err);
}
}
} else
inners = new ClassAnalyzer[0];
fields = new FieldAnalyzer[finfos.length];
methods = new MethodAnalyzer[minfos.length];
blockInitializers = new StructuredBlock[finfos.length+1];
for (int j=0; j < finfos.length; j++)
fields[j] = new FieldAnalyzer(this, finfos[j], imports);
staticConstructor = null;
Vector constrVector = new Vector();
for (int j=0; j < methods.length; j++) {
methods[j] = new MethodAnalyzer(this, minfos[j], imports);
if (methods[j].isConstructor()) {
if (methods[j].isStatic())
staticConstructor = methods[j];
else
constrVector.addElement(methods[j]);
/* 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();
}
constructors = new MethodAnalyzer[constrVector.size()];
constrVector.copyInto(constructors);
// initialize the inner classes.
for (int j=0; j < inners.length; j++) {
if (inners[j] == null)
continue;
inners[j].initialize();
innerComplexity += inners[j].getComplexity();
}
}
/**
* Gets the complexity of this class. Must be called after it has
* been initialized. This is used for a nice progress bar.
*/
public double getComplexity() {
return (methodComplexity + innerComplexity);
}
public void analyze(ProgressListener pl, double done, double scale) {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("Class " + name);
double subScale = scale / methodComplexity;
if (pl != null)
pl.updateProgress(done, name);
imports.useClass(clazz);
if (clazz.getSuperclass() != null)
imports.useClass(clazz.getSuperclass());
ClassInfo[] interfaces = clazz.getInterfaces();
for (int j=0; j< interfaces.length; j++)
imports.useClass(interfaces[j]);
if (fields == null) {
/* This means that the class could not be loaded.
* give up.
*/
return;
}
// First analyze constructors and synthetic fields:
constrAna = null;
if (constructors.length > 0) {
for (int j=0; j< constructors.length; j++) {
if (pl != null) {
double constrCompl = constructors[j].getComplexity()
* subScale;
if (constrCompl > STEP_COMPLEXITY)
constructors[j].analyze(pl, done, constrCompl);
else {
pl.updateProgress(done, name);
constructors[j].analyze(null, 0.0, 0.0);
}
done += constrCompl;
} else
constructors[j].analyze(null, 0.0, 0.0);
}
constrAna = new TransformConstructors(this, false, constructors);
constrAna.removeSynthInitializers();
}
if (staticConstructor != null) {
if (pl != null) {
double constrCompl
= staticConstructor.getComplexity() * subScale;
if (constrCompl > STEP_COMPLEXITY)
staticConstructor.analyze(pl, done, constrCompl);
else {
pl.updateProgress(done, name);
staticConstructor.analyze(null, 0.0, 0.0);
}
done += constrCompl;
} else
staticConstructor.analyze(null, 0.0, 0.0);
}
// If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user
// has been warned.
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return;
// Analyze fields
for (int j=0; j < fields.length; j++)
fields[j].analyze();
// Now analyze remaining methods.
for (int j=0; j < methods.length; j++) {
if (!methods[j].isConstructor())
if (pl != null) {
double methodCompl = methods[j].getComplexity()
* subScale;
if (methodCompl > STEP_COMPLEXITY)
methods[j].analyze(pl, done, methodCompl);
else {
pl.updateProgress(done, methods[j].getName());
methods[j].analyze(null, 0.0, 0.0);
}
done += methodCompl;
} else
methods[j].analyze(null, 0.0, 0.0);
}
}
public void analyzeInnerClasses(ProgressListener pl,
double done, double scale) {
double subScale = scale / innerComplexity;
// If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user
// has been warned.
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return;
// Now analyze the inner classes.
for (int j=0; j < inners.length; j++) {
if (inners[j] == null)
continue;
if (pl != null) {
double innerCompl = inners[j].getComplexity() * subScale;
if (innerCompl > STEP_COMPLEXITY) {
double innerscale = subScale * inners[j].methodComplexity;
inners[j].analyze(pl, done, innerscale);
inners[j].analyzeInnerClasses(null, done + innerscale,
innerCompl - innerscale);
} else {
pl.updateProgress(done, inners[j].name);
inners[j].analyze(null, 0.0, 0.0);
inners[j].analyzeInnerClasses(null, 0.0, 0.0);
}
done += innerCompl;
} else {
inners[j].analyze(null, 0.0, 0.0);
inners[j].analyzeInnerClasses(null, 0.0, 0.0);
}
}
// Now analyze the method scoped classes.
for (int j=0; j < methods.length; j++)
methods[j].analyzeInnerClasses();
}
public void makeDeclaration(Set done) {
// First prepare constructors:
if (constrAna != null)
constrAna.transform();
if (staticConstructor != null) {
new TransformConstructors
(this, true, new MethodAnalyzer[] { staticConstructor })
.transform();
}
// If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user
// has been warned.
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return;
for (int j=0; j < fields.length; j++)
fields[j].makeDeclaration(done);
for (int j=0; j < inners.length; j++)
if (inners[j] != null)
inners[j].makeDeclaration(done);
for (int j=0; j < methods.length; j++)
methods[j].makeDeclaration(done);
}
public void dumpDeclaration(TabbedPrintWriter writer) throws IOException
{
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);
String signature = clazz.getSignature();
System.err.println("Class Signature: "+signature+ " (class "+name+")");
ClassInfo superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz.getName() != "java.lang.Object") {
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)
throws IOException
{
dumpBlock(writer, null, 0.0, 0.0);
}
public void dumpBlock(TabbedPrintWriter writer,
ProgressListener pl, double done, double scale)
throws IOException
{
double subScale = scale / getComplexity();
writer.pushScope(this);
boolean needFieldNewLine = false;
boolean needNewLine = false;
Set declared = null;
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
declared = new SimpleSet();
for (int i=0; i< fields.length; i++) {
if (blockInitializers[i] != null) {
if (needNewLine)
writer.println();
writer.openBrace();
writer.tab();
blockInitializers[i].dumpSource(writer);
writer.untab();
writer.closeBrace();
needFieldNewLine = needNewLine = true;
}
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before.
fields[i].analyze();
fields[i].makeDeclaration(declared);
}
if (fields[i].skipWriting())
continue;
if (needFieldNewLine)
writer.println();
fields[i].dumpSource(writer);
needNewLine = true;
}
if (blockInitializers[fields.length] != null) {
if (needNewLine)
writer.println();
writer.openBrace();
writer.tab();
blockInitializers[fields.length].dumpSource(writer);
writer.untab();
writer.closeBrace();
needNewLine = true;
}
for (int i=0; i< inners.length; i++) {
if (needNewLine)
writer.println();
if (inners[i] == null) {
writer.println("COULDN'T READ INNER CLASS!");
continue;
}
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before.
inners[i].analyze(null, 0.0, 0.0);
inners[i].analyzeInnerClasses(null, 0.0, 0.0);
inners[i].makeDeclaration(declared);
}
if (pl != null) {
double innerCompl = inners[i].getComplexity() * subScale;
if (innerCompl > STEP_COMPLEXITY)
inners[i].dumpSource(writer, pl, done, innerCompl);
else {
pl.updateProgress(done, name);
inners[i].dumpSource(writer);
}
done += innerCompl;
} else
inners[i].dumpSource(writer);
needNewLine = true;
}
for (int i=0; i< methods.length; i++) {
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before.
if (!methods[i].isConstructor())
methods[i].analyze(null, 0.0, 0.0);
methods[i].analyzeInnerClasses();
methods[i].makeDeclaration(declared);
}
if (methods[i].skipWriting())
continue;
if (needNewLine)
writer.println();
if (pl != null) {
double methodCompl = methods[i].getComplexity() * subScale;
pl.updateProgress(done, methods[i].getName());
methods[i].dumpSource(writer);
done += methodCompl;
} else
methods[i].dumpSource(writer);
needNewLine = true;
}
writer.popScope();
clazz.drop(clazz.DECLARATIONS);
}
public void dumpSource(TabbedPrintWriter writer)
throws IOException
{
dumpSource(writer, null, 0.0, 0.0);
}
public void dumpSource(TabbedPrintWriter writer,
ProgressListener pl, double done, double scale)
throws IOException
{
dumpDeclaration(writer, pl, done, scale);
writer.println();
}
public void dumpJavaFile(TabbedPrintWriter writer)
throws IOException {
dumpJavaFile(writer, null);
}
public void dumpJavaFile(TabbedPrintWriter writer, ProgressListener pl)
throws IOException {
imports.init(clazz.getName());
LocalInfo.init();
initialize();
double done = 0.05;
double scale = (0.75) * methodComplexity
/ (methodComplexity + innerComplexity);
analyze(pl, INITIALIZE_COMPLEXITY, scale);
done += scale;
analyzeInnerClasses(pl, done, 0.8 - done);
makeDeclaration(new SimpleSet());
imports.dumpHeader(writer);
dumpSource(writer, pl, 0.8, 0.2);
if (pl != null)
pl.updateProgress(1.0, name);
}
public boolean isScopeOf(Object obj, int scopeType) {
if (clazz.equals(obj) && scopeType == CLASSSCOPE)
return true;
return false;
}
static int serialnr = 0;
public void makeNameUnique() {
name = name + "_" + serialnr++ + "_";
}
public boolean conflicts(String name, int usageType) {
return conflicts(clazz, name, usageType);
}
private static boolean conflicts(ClassInfo info,
String name, int usageType) {
while (info != null) {
if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) {
MethodInfo[] minfos = info.getMethods();
for (int i = 0; i< minfos.length; i++)
if (minfos[i].getName().equals(name))
return true;
}
if (usageType == NOSUPERFIELDNAME || usageType == FIELDNAME
|| usageType == AMBIGUOUSNAME) {
FieldInfo[] finfos = info.getFields();
for (int i=0; i < finfos.length; i++) {
if (finfos[i].getName().equals(name))
return true;
}
}
if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) {
try {
info.load(info.DECLARATIONS);
} catch (IOException ex) {
info.guess(info.DECLARATIONS);
}
ClassInfo[] iinfos = info.getClasses();
if (iinfos != null) {
for (int i=0; i < iinfos.length; i++) {
if (iinfos[i].getClassName().equals(name))
return true;
}
}
}
if (usageType == NOSUPERFIELDNAME
|| usageType == NOSUPERMETHODNAME)
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();
}
return false;
}
/**
* Get the class analyzer for the given class info. This searches
* the method scoped/anonymous classes in this method and all
* outer methods and the outer classes for the class analyzer.
* @param cinfo the classinfo for which the analyzer is searched.
* @return the class analyzer, or null if there is not an outer
* class that equals cinfo, and not a method scope/inner class in
* an outer method.
*/
public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) {
if (cinfo == getClazz())
return this;
if (parent == null)
return null;
return getParent().getClassAnalyzer(cinfo);
}
/**
* Get the class analyzer for the given inner class.
* @param name the short name of the inner class
* @return the class analyzer, or null if there is no inner
* class with the given name.
*/
public ClassAnalyzer getInnerClassAnalyzer(String name) {
/** require name != null; **/
int innerCount = inners.length;
for (int i=0; i < innerCount; i++) {
if (inners[i] != null && inners[i].name.equals(name))
return inners[i];
}
return null;
}
/**
* We add the named method scoped classes to the declarables.
*/
public void fillDeclarables(Collection used) {
for (int j=0; j < methods.length; j++)
methods[j].fillDeclarables(used);
}
public void addClassAnalyzer(ClassAnalyzer clazzAna) {
if (parent != null)
parent.addClassAnalyzer(clazzAna);
}
public String toString() {
return getClass().getName()+"["+getClazz()+"]";
}
}

@ -0,0 +1,42 @@
/* ClassDeclarer Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
import net.sf.jode.bytecode.ClassInfo;
/**
* This is the interface for objects, that a method can declare
*/
public interface ClassDeclarer {
/**
* Get the parent of this ClassDeclarer.
* @return null if this is the outermost instance.
*/
public ClassDeclarer getParent();
/**
* Get the class analyzer for the given anonymous class info. It
* will search it in the classes we declare and in the parent
* class declarer.
* @return null if the class analyzer doesn't yet exists.
*/
public ClassAnalyzer getClassAnalyzer(ClassInfo ci);
public void addClassAnalyzer(ClassAnalyzer classAna);
}

@ -0,0 +1,38 @@
/* Declarable Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
/**
* This is the interface for objects, that a method can declare
*/
public interface Declarable {
/**
* Get the name of this declarable.
*/
public String getName();
/**
* Set the name of this local.
*/
public void makeNameUnique();
public void dumpDeclaration(TabbedPrintWriter writer)
throws java.io.IOException;
}

@ -0,0 +1,233 @@
/* Decompiler Copyright (C) 2000-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
import net.sf.jode.GlobalOptions;
import net.sf.jode.bytecode.ClassPath;
import net.sf.jode.bytecode.ClassInfo;
import java.io.File;
import java.io.PrintWriter;
import java.io.Writer;
import java.io.BufferedWriter;
/**
* This is the interface that other java classes may use to decompile
* classes. Feel free to use it in your own GNU GPL'ed project.
* Please tell me about your project.<br>
*
* Note that the GNU GPL doesn't allow you to use this interface in
* commercial programs.
*
* @author <a href="mailto:jochen@gnu.org">Jochen Hoenicke</a>
* @version 1.0
*/
public class Decompiler {
private ClassPath classPath = null;
private int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
private int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;
private int tabWidth = 8;
private int indentSize = 4;
private int outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
private int lineWidth = 79;
/**
* We need a different pathSeparatorChar, since ':' (used for most
* UNIX System) is used a protocol separator in URLs.
*
* We currently allow both pathSeparatorChar and
* altPathSeparatorChar and decide if it is a protocol separator
* by context.
*/
public static final char altPathSeparatorChar
= ClassPath.altPathSeparatorChar;
/**
* Create a new decompiler. Normally you need only one, but you
* can have more around, with different options and different
* class paths.
*/
public Decompiler() {
}
/**
* Sets the class path. Should be called once before decompile is
* called, otherwise the system class path is used.
* @param classpath A comma separated classpath.
* @exception NullPointerException if classpath is null.
* @see #setClassPath(String[])
*/
public void setClassPath(String classpath) {
this.classPath = new ClassPath(classpath);
}
/**
* Set the class path. Should be called once before decompile is
* called, otherwise the system class path is used.
* @param classpath a non empty array of jar files and directories;
* URLs are allowed, too.
* @exception NullPointerException if classpath is null.
* @exception IndexOutOfBoundsException if classpath array is empty.
* @see #setClassPath(String)
*/
public void setClassPath(String[] classpath) {
this.classPath = new ClassPath(classpath);
}
/**
* Set the class path. Should be called once before decompile is
* called, otherwise the system class path is used.
* @param classpath a classpath object.
* @exception NullPointerException if classpath is null.
* @exception IndexOutOfBoundsException if classpath array is empty.
* @see #setClassPath(String)
*/
public void setClassPath(ClassPath classpath) {
this.classPath = classpath;
}
private static final String[] optionStrings = {
"lvt", "inner", "anonymous", "push", "pretty", "decrypt",
"onetime", "immediate", "verify", "contrafo"
};
/**
* Set an option.
* @param option the option (pretty, style, decrypt, verify, etc.)
* @param value ("1"/"0" for on/off, "sun"/"gnu" for style)
* @exception IllegalArgumentException if option or value is invalid.
*/
public void setOption(String option, String value) {
if (option.equals("style")) {
if (value.equals("gnu")) {
outputStyle = TabbedPrintWriter.GNU_SPACING
| TabbedPrintWriter.INDENT_BRACES;
indentSize = 2;
} else if (value.equals("sun")) {
outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
indentSize = 4;
} else if (value.equals("pascal")) {
outputStyle = 0;
indentSize = 4;
} else
throw new IllegalArgumentException("Invalid style "+value);
return;
}
if (option.equals("tabwidth")) {
tabWidth = Integer.parseInt(value);
return;
}
if (option.equals("indent")) {
indentSize = Integer.parseInt(value);
return;
}
if (option.equals("linewidth")) {
lineWidth = Integer.parseInt(value);
return;
}
if (option.equals("import")) {
int comma = value.indexOf(',');
int packLimit = Integer.parseInt(value.substring(0, comma));
if (packLimit == 0)
packLimit = Integer.MAX_VALUE;
int clazzLimit = Integer.parseInt(value.substring(comma+1));
if (clazzLimit == 0)
clazzLimit = Integer.MAX_VALUE;
if (clazzLimit < 0 || packLimit < 0)
throw new IllegalArgumentException
("Option import doesn't allow negative parameters");
importPackageLimit = packLimit;
importClassLimit = clazzLimit;
return;
}
if (option.equals("verbose")) {
GlobalOptions.verboseLevel = Integer.parseInt(value);
return;
}
if (option.equals("debug")) {
GlobalOptions.setDebugging(value);
return;
}
for (int i=0; i < optionStrings.length; i++) {
if (option.equals(optionStrings[i])) {
if (value.equals("0")
|| value.equals("off")
|| value.equals("no"))
Options.options &= ~(1 << i);
else if (value.equals("1")
|| value.equals("on")
|| value.equals("yes"))
Options.options |= 1 << i;
else
throw new IllegalArgumentException("Illegal value for "+
option);
return;
}
}
throw new IllegalArgumentException("Illegal option: "+option);
}
/**
* Set the stream where copyright and warnings/errors are printed
* to.
* @param errorStream the error stream. Note that this is a
* PrintWriter, not a PrintStream (which are deprecated since 1.1).
*/
public void setErr(PrintWriter errorStream) {
GlobalOptions.err = errorStream;
}
/**
* Decompile a class.
* @param className full-qualified classname, dot separated, e.g.
* "java.lang.Object"
* @param writer The stream where the decompiled code should be
* written. Hint: Use a BufferedWriter for good performance.
* @param progress A progress listener (see below). Null if you
* don't need information about progress.
* @exception IllegalArgumentException if className isn't correct.
* @exception IOException if writer throws an exception.
* @exception RuntimeException If jode has a bug ;-)
*/
public void decompile(String className, Writer writer,
ProgressListener progress)
throws java.io.IOException {
if (classPath == null) {
String cp = System.getProperty("java.class.path");
String bootcp = System.getProperty("sun.boot.class.path");
if (bootcp != null)
cp = bootcp + altPathSeparatorChar + cp;
cp = cp.replace(File.pathSeparatorChar, altPathSeparatorChar);
classPath = new ClassPath(cp);
}
ClassInfo clazz = classPath.getClassInfo(className);
ImportHandler imports = new ImportHandler(classPath,
importPackageLimit,
importClassLimit);
TabbedPrintWriter tabbedWriter =
new TabbedPrintWriter(writer, imports, false,
outputStyle, indentSize,
tabWidth, lineWidth);
ClassAnalyzer clazzAna = new ClassAnalyzer(null, clazz, imports);
clazzAna.dumpJavaFile(tabbedWriter, progress);
writer.flush();
}
}

@ -0,0 +1,206 @@
/* FieldAnalyzer Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.decompiler;
import net.sf.jode.type.Type;
import net.sf.jode.bytecode.FieldInfo;
import net.sf.jode.expr.Expression;
import net.sf.jode.expr.ThisOperator;
import net.sf.jode.expr.LocalLoadOperator;
import net.sf.jode.expr.ConstOperator;
import net.sf.jode.expr.OuterLocalOperator;
import java.lang.reflect.Modifier;
import java.io.IOException;
///#def COLLECTIONS java.util
import java.util.Set;
///#enddef
public class FieldAnalyzer implements Analyzer {
ClassAnalyzer clazz;
ImportHandler imports;
int modifiers;
Type type;
String fieldName;
Expression constant;
boolean isSynthetic;
boolean isDeprecated;
boolean analyzedSynthetic = false;
public FieldAnalyzer(ClassAnalyzer cla, FieldInfo fd,
ImportHandler i)
{
clazz = cla;
imports = i;
modifiers = fd.getModifiers();
type = Type.tType(cla.getClassPath(), fd.getType());
fieldName = fd.getName();
constant = null;
this.isSynthetic = fd.isSynthetic();
this.isDeprecated = fd.isDeprecated();
if (fd.getConstant() != null) {
if (fd.getConstant() instanceof String) {
constant = new ConstOperator(cla.getClassPath(),
(String) fd.getConstant());
} else {
constant = new ConstOperator(fd.getConstant());
}
constant.setType(type);
constant.makeInitializer(type);
}
}
public String getName() {
return fieldName;
}
public Type getType() {
return type;
}
public ClassAnalyzer getClassAnalyzer() {
return clazz;
}
public Expression getConstant() {
return constant;
}
public boolean isSynthetic() {
return isSynthetic;
}
public boolean isFinal() {
return Modifier.isFinal(modifiers);
}
public void analyzedSynthetic() {
analyzedSynthetic = true;
}
public boolean setInitializer(Expression expr) {
if (constant != null)
return constant.equals(expr);
/* This should check for isFinal(), but sadly, sometimes jikes
* doesn't make a val$ field final. I don't know when, or why,
* so I currently ignore isFinal.
*/
if (isSynthetic
&& (fieldName.startsWith("this$")
|| fieldName.startsWith("val$"))) {
if (fieldName.startsWith("val$") && fieldName.length() > 4
&& expr instanceof OuterLocalOperator) {
LocalInfo li = ((OuterLocalOperator) expr).getLocalInfo();
li.addHint(fieldName.substring(4), type);
}
analyzedSynthetic();
} else
expr.makeInitializer(type);
constant = expr;
return true;
}
public boolean setClassConstant(String clazzName) {
if (constant != null)
return false;
if (clazzName.charAt(0) == '[') {
if (clazzName.charAt(clazzName.length()-1) == ';')
clazzName = clazzName.substring(0, clazzName.length()-1);
if (fieldName.equals("array"+ (clazzName.replace('[', '$')
.replace('.', '$')))) {
analyzedSynthetic();
return true;
}
} else {
if (fieldName.equals("class$" + clazzName.replace('.', '$'))
|| fieldName.equals("class$L" + clazzName.replace('.', '$'))) {
analyzedSynthetic();
return true;
}
}
return false;
}
public void analyze() {
imports.useType(type);
}
public void makeDeclaration(Set done) {
if (constant != null) {
constant.makeDeclaration(done);
constant = constant.simplify();
}
}
public boolean skipWriting() {
return analyzedSynthetic;
}
public void dumpSource(TabbedPrintWriter writer) throws IOException
{
if (isDeprecated) {
writer.println("/**");
writer.println(" * @deprecated");
writer.println(" */");
}
if (isSynthetic)
writer.print("/*synthetic*/ ");
int modifiedModifiers = modifiers;
/*
* JLS-1.0, section 9.3:
*
* Every field declaration in the body of an interface is
* implicitly public, static, and final. It is permitted, but
* strongly discouraged as a matter of style, to redundantly
* specify any or all of these modifiers for such fields.
*
* But I personally don't like this style..., move the
* comment mark if you think different.
if (clazz.getClazz().isInterface())
modifiedModifiers &= ~(Modifier.PUBLIC
| Modifier.STATIC
| Modifier.FINAL);
*/
writer.startOp(writer.NO_PAREN, 0);
String modif = Modifier.toString(modifiedModifiers);
if (modif.length() > 0)
writer.print(modif+" ");
writer.printType(type);
writer.print(" " + fieldName);
if (constant != null) {
writer.breakOp();
writer.print(" = ");
constant.dumpExpression(writer.IMPL_PAREN, writer);
}
writer.endOp();
writer.println(";");
}
public String toString() {
return getClass().getName()+"["+clazz.getClazz()+"."+getName()+"]";
}
}

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

Loading…
Cancel
Save