How to decompile .class and jar file using Storyyeller/Krakatau - java

I am trying to decompile a file using Storyyeller/Krakatau decompiler. I have already downloaded the relevant file and placed it inside a folder. I tried decompile the file using below syntax using command prompt.
=== Decompilation ===
Usage:
python Krakatau\decompile.py [-nauto] [-path PATH] [-out OUT] [-r] [-skip]
target
PATH: An optional list of directories, jars, or zipfiles to search for
classes in. Krakatau will attempt to automatically detect and add the
jar containing core language classes, but you can disable this with
the -nauto option. For multiple jars, you can either pass a semicolon
seperated list of jars or pass the -path option multiple times.
OUT: Directory name where source files are to be written. Defaults to the
current directory. If the name ends in .zip or .jar, the output will be a
zip file instead.
-r: Decompiles all .class files found in the directory target (recursively)
-skip: Continue upon errors. If an error occurs while decompiling a specific
method, the trace back will be printed as comments in the source file. If the
error occurs while decompiling at the class level, no source file will be
emitted and an error message will be printed to the console.
target: Class name or jar name to decompile. If a jar is specified, all
classes in the jar will be decompiled. If -r is specified, this should
be a directory.
But I always get errors.I don't understand the above syntax.
Please explain this syntax
python Krakatau\decompile.py [-nauto] [-path PATH] [-out OUT] [-r] [-skip]
target
using a simple example.

The easiest and normal way to decompile with Krakatau is to decompile a jar.
Say you have a jar file named Luyten.jar in the current directory and you want to decompile every class in the jar and output it to the directory temp. Then you'd do something like
pypy -O Krakatau\decompile.py -skip -out temp Luyten.jar
Depending on whether you have JDK installed and where, you may need to explicitly pass the location of the jre in the path argument. For example
pypy -O Krakatau\decompile.py -skip -out temp -path "C:\Program Files (x86)\Java\jre7\lib\rt.jar" Luyten.jar
If you want to decompile a specific class within the jar, you can add the jar to the path and specify the classname. If you need to specify a path to rt.jar as in the previous example, you can pass the -path argument multiple times or a single time separated by semicolons. For example to decompile only the class com.beust.jcommander.FuzzyMap$IKey,
pypy -O Krakatau\decompile.py -skip -out temp -path Luyten.jar com.beust.jcommander.FuzzyMap$IKey
You can also decompile classfiles that are outside of a jar, but it's a lot more annoying, because you have to make sure the directory layout is correct. You need to specify the directory that is the root relative to where the classes will be found.
For example, suppose you have a classfile located at ./Foo/Bar/com/beust/jcommander/FuzzyMap$IKey.class
pypy -O Krakatau\decompile.py -skip -out temp -path Foo/Bar com.beust.jcommander.FuzzyMap$IKey
In this case, the directory has to match the fully qualified classname exactly. A common mistake is to try to decompile with the wrong root directory. The nice thing about jars is that having the correct directory structure is automatic.

Related

Running Java command including all JARs in current folder

I have just shifted back from an IDE to Notepad to write a Java program. The program is using 20 JARs. I compiled successfully. When I decided to run the Java class file using
java -cp ".\\*" MyProgram
it was giving the standard error "Couldn't find or load main class....".
I was confused because when I used to run the java command with all files in an existing folder, it would just get those JARs as the current folder is already in the classpath. As the program is running from the current folder, I tried using -cp "." to include it explicitly in the classpath but that didn't work either.
Finally I was able to run the program with this command:
java -cp ".\\*;." MyProgram.java
I am asking this question to understand the actual logic behind Java's classpath.
Correct me if I am wrong, but I think that the JAR is just a standard archive in which all the packages are encapsulated in respective folders. If all the JARs are in my current folder including my main class file then why can't I run it with:
java -cp "." MyProgram
or simply:
java MyProgram
If the problem is with the multiple JAR files to include and that's why we used ".\\*" to include all the JARs in the classpath, then why do we have to explicitly include the current folder again in the classpath using:
java ".\\*;." MyProgram
To include all jar required to run your program in command prompt use wildcard *:
java -classpath E:\lib\* HelloWorld
You are using "." that defines current directory and "./*" defines all files in current directory.
The class path is a list of jar files and directories containing the classes and resources of your program. Mentioning a jar file adds its contents to the class path.
"./*" will get you only the jar files in the current directory, "." adds the current directory to the class path. This allows to access all classes (and the jar files as raw file resources but not its contents, i.e. the classes contained in them).
If you need both in the class path, you have to specify both.
You've answered your own question, sort of.
. means that it will look for .class files in the current directory.
JARs act just like a directory. So to have the abc.jar "directory" you would specify abc.jar in your classpath.
If you need both the .class files present in the current directory, and the .class files packaged into JARs found in the current directory, you would have the following classpath: -cp ".:*.jar
All the answers here are telling you to use the wildcard without extension (* or ./*) but this is a bad practice, you don't want Java to go look into irrelevant files, so specify the extension: *.jar.
"." means current directory not files in the directory
"./*" means all files in current directory.
So you want to use all jars in current directory so 2nd will work

Create jar command doesn't find file

build> jar cvfe test\MyJavaLibrary.jar Main -C test\java Main.class foo\SomeClass.class
foo\SomeClass.class : no such file or directory
added manifest
adding: Main.class(in = 444) (out= 308)(deflated 30%)
The corresponding directory structure is
build/
test/
java/
foo/
SomeClass.class
Main.class
It is very strange that it works correctly when using test\java\foo\SomeClass.class as the last argument instead. Fine, but that doesn't work when I do the same for the first argument, that is test\java\Main.class. The behaviour appears to be very inconsistent.
Why can it not find foo\SomeClass.class, or better, what is the right way to create the Jar?
java version "1.8.0_102"
The executable that you're running from the command-line appears to start in the build directory, and as such, it doesn't know where the foo\SomeClass.class file is relative to build - this would also explain why test\java\foo\SomeClass.class works (it knows how to find the file relative to the execution directory).
If you were to have the foo folder on the top level inside build, I believe it would work correctly, but because foo is nested within two layers of directories, the executable has no idea where to look for a folder with that name in its current directory.
I just found the answer in a documentation page I haven't seen before.
-C dir
Temporarily changes directories to dir while processing the following inputfiles argument. Multiple -C dir inputfiles sets are allowed.
So apparently the -C argument would need to be placed for every input, not just specified once.
Source: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jar.html

java command line argument to make jar find files in two directories?

I have a jar file which I do not have the source code but want to use.
The jar file prompts for a file to read and generates an output file using a combinatin of the input file and a number of 'helper' files it uses for data. It works perfecty fine if run from its expected home directory, but I'm trying to write a script which will allow running the jar from anywhere.
The problem is that if I try running the jar file from anywhere other then its home directories it fails to find the support files it needs to properly generate its data.
If I run the file from its expected home directory I have to give the full address of the input file or it won't find it. I would prefer to be able to give just the relative path and Java know to look at whatever directory the person calling my script is in.
Is there a way I can have a bash script pass a command line argument to Java that would ensure that this jar looks at both of the relevant directories (directory of the helper files and the current dir of the person calling the script) when trying to resolve a relative file path? Something like the -classpath argument?
With the --classpath (or -cp) you can tell your Java program where it should take the dependency classes. So, probably if you do like in your files directory
$JAVA_HOME/bin/java -cp '.:/path/to/the/original/program' My.class myfile.txt
then it will wind the program, and find your files as well.
UPDATE
If it doesn't work, you can try to force the file loading some other way. The Javadoc says:
By default the classes in the java.io package always
resolve relative pathnames against the current user directory. This
directory is named by the system property user.dir, and
is typically the directory in which the Java virtual machine was
invoked.
So, you can try running the program from the original directory this way:
$JAVA_HOME/bin/java -Duser.dir=/path/to/the/files/directory My.class myfile.txt
UPDATE2:
As I wrote in a comment, you can try symlinks. Execute the following commands in the original directory:
ln -s /path/to/the/files/directory datafiles
$JAVA_HOME/bin/java My.class datafiles/myfile.txt
Sorry - ignore. I missed the first line of your question.
You could pass the two paths as an argument to the jar file - then append the path location at runtime. Many ways to do that, here is one:
java -DdirectoryA="/somewhere" -DdirectoryB="/elsewhere" -jar program.jar
and in your code
String pathA = System.getProperty("directoryA");

java compiler options i.e. javac -d

I'm compiling a program that has a package statement.
e.g.
package APPC_LU62.Runtime ;
I also have a pre-existing directory structure that matches the package statement.
C:\APPC_LU62\Runtime
How do I keep the javac compiler from creating the same directory structure within the pre-existing one ? i.e.
C:\APPC_LU62\Runtime\APPC_LU62\Runtime
It seems to me the compiler ought to be "smart" enough to check first for an existing directory structure before creating one.
Thanks
In general, the compiler expects the source files and outputs the class files according to the package structure.
If you don't give any -sourcepath (or -classpath if no sourcepath is given) options, the source files are searched relative to the current directory. If a source path is given, the source files are searched relative to this path (in addition to any file directly specified on the command line).
Similarly, if you don't specify any -d options, the class files will be put into directories according to the package structure, relative to the current directory. If you give an -d option, the class files will be put relative to the directory given by the option. Non-existing directories will be created here.
Thus, if you want to create the output in the same directory tree as your source files are, the usual way to go would be to change into the root of this tree (C:\ in your case), and from there call javac:
javac -classpath ... -sourcepath . APPC_LU62\Runtime\*.java
(or list only the java files you actually want to compile). Alternatively, you could add the -d C:\ and -sourcepath C:\ options, and then call the command from whereever you want:
javac -classpath ... -sourcepath C:\ -d C:\ C:\APPC_LU62\Runtime\*.java
The same is valid later for executing the classes with the java command: This also expects the classes in directories according to the package structure, with the root being a directory or jar file mentioned in the class path. Thus you will have to add C:\ to the -classpath for your java call.
(By the way, I would not use the root of some drive as the root of the package hierarchy - better move everything one directory down.)
Would have been better if you had actually posted your javac command and stated clearly where your sources are located, but here goes anyway: when you issue javac -d somedir blahblah.java, javac will create the appropriate directory structure (matching package name hierarchy) starting at directory somedir.
So in your case, you simply need to do:
javac -d c:\ your_files.java

prog.java and prog.class in Prog.jar file - How can I easily update this code?

Back story:
Long ago, before dinosaurs were around, there was a contractor that wrote a small Java program, that does some stuff, and prints some stuff to the screen.
Current: No one here knows much about Java but me - and I am not fluent.
The program works, but we kind of need just a bit more information on the screen. From the documentation available, I think I know how to go about that, and I definitely know how to print stuff, as it's simply using System.out.println() for this.
I have a .jar file, which I'm 99% certain is being loaded/used, which contains .java files matching every .class file within.
Is there an easy way to (and how might I) slightly modify one of the .java files, and "compile" the new version to replace the current matching .class file within the .jar?
I'm able to open and read the java source file, of course, but don't remember to procedures to turn java into "class" files, and especially not sure if I can just drop the resulting .class file into the .jar file as a replacement.
at the basic level, javac is the compiler; that will produce the .class files. There is also a "jar" command that will regenerate your jar file. Depending on the number of dependencies, that can get complicated quick. You can just type "javac" and "jar" (w/o quotes) to get the args to run it. Another option is to setup an ant build script...
so you could do something like (assuming windows OS):
javac -cp %MY_CLS_PTH% *.java
where MY_CLS_PTH is where any dependent classes are. If you have a package structure, this gets a little more complicated.
jar -cvf .\my_class_dir MyJarFile.jar
where my_class_dir is the directory that contains the .class files.
I think that is right (didn't run it myself) but that should be about the basics...
EDIT: There is a way to just add/re-add a single .class file to an existing jar file. Check out the "jar" command's usage, looks like "-u" will update it (of course you have to pass in the .class file). Also remember that any package structure you have in these classes, you need that directory structure and you reference the class via that dir structure. (Hope that is clear...)
Add myclass.class to the top level directory in myjar.jar:
jar uf myjar.jar myclass.class
Add myclass.class to the subdir directory in myjar.jar:
jar uf myjar.jar -C subdir myclass.class
Add a Version attribute to the manifest of myjar.jar:
First create a file somefile containing the line Version: "X.Y.Z", then
jar umf somefile myjar.jar

Categories