Commit 42eb3197 authored by Skylot's avatar Skylot

fix issues reported by Coverity

parent 343bddc6
## JADX
## JADX
[![Build Status](https://travis-ci.org/skylot/jadx.png?branch=master)](https://travis-ci.org/skylot/jadx)
[![Build Status](https://drone.io/github.com/skylot/jadx/status.png)](https://drone.io/github.com/skylot/jadx/latest)
[![Coverage Status](https://coveralls.io/repos/skylot/jadx/badge.png)](https://coveralls.io/r/skylot/jadx)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/2166/badge.svg)](https://scan.coverity.com/projects/2166)
**jadx** - Dex to Java decompiler
......@@ -12,14 +13,14 @@ Command line and GUI tools for produce Java source code from Android Dex and Apk
### Downloads
- [unstable](https://drone.io/github.com/skylot/jadx/files)
- from [github](https://github.com/skylot/jadx/releases)
- from [sourceforge](http://sourceforge.net/projects/jadx/files/)
- from [sourceforge](http://sourceforge.net/projects/jadx/files/)
### Building from source
### Building from source
git clone https://github.com/skylot/jadx.git
cd jadx
./gradlew dist
(on Windows, use `gradlew.bat` instead of `./gradlew`)
Scripts for run jadx will be placed in `build/jadx/bin`
......
......@@ -16,7 +16,7 @@ subprojects {
gradle.projectsEvaluated {
tasks.withType(Compile) {
if (!"${it}".contains(':jadx-samples:')) {
if (!"$it".contains(':jadx-samples:')) {
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
}
}
......
......@@ -14,37 +14,41 @@ public class JadxCLI {
public static void main(String[] args) {
try {
JadxCLIArgs jadxArgs = new JadxCLIArgs(args);
checkArgs(jadxArgs);
processAndSave(jadxArgs);
} catch (Exception e) {
JadxCLIArgs jadxArgs = new JadxCLIArgs();
if (processArgs(jadxArgs, args)) {
processAndSave(jadxArgs);
}
} catch (JadxException e) {
LOG.error(e.getMessage());
System.exit(1);
}
}
private static void processAndSave(JadxCLIArgs jadxArgs) {
static void processAndSave(JadxCLIArgs jadxArgs) throws JadxException {
try {
Decompiler jadx = new Decompiler(jadxArgs);
jadx.loadFiles(jadxArgs.getInput());
jadx.setOutputDir(jadxArgs.getOutDir());
jadx.save();
LOG.info("done");
} catch (Throwable e) {
LOG.error("jadx error:", e);
throw new JadxException("jadx error: " + e.getMessage(), e);
}
int errorsCount = ErrorsCounter.getErrorCount();
if (errorsCount != 0) {
if (ErrorsCounter.getErrorCount() != 0) {
ErrorsCounter.printReport();
throw new JadxException("finished with errors");
}
System.exit(errorsCount);
LOG.info("done");
}
private static void checkArgs(JadxCLIArgs jadxArgs) throws JadxException {
static boolean processArgs(JadxCLIArgs jadxArgs, String[] args) throws JadxException {
if (!jadxArgs.processArgs(args)) {
return false;
}
if (jadxArgs.getInput().isEmpty()) {
LOG.error("Please specify input file");
jadxArgs.printUsage();
System.exit(1);
return false;
}
File outputDir = jadxArgs.getOutDir();
if (outputDir == null) {
......@@ -64,5 +68,6 @@ public class JadxCLI {
if (outputDir.exists() && !outputDir.isDirectory()) {
throw new JadxException("Output directory exists as file " + outputDir);
}
return true;
}
}
......@@ -47,25 +47,25 @@ public final class JadxCLIArgs implements IJadxArgs {
private final List<File> input = new ArrayList<File>(1);
private File outputDir;
public JadxCLIArgs(String[] args) {
parse(args);
processArgs();
public boolean processArgs(String[] args) {
return parse(args) && process();
}
private void parse(String[] args) {
private boolean parse(String[] args) {
try {
new JCommander(this, args);
return true;
} catch (ParameterException e) {
System.err.println("Arguments parse error: " + e.getMessage());
printUsage();
System.exit(1);
return false;
}
}
public void processArgs() {
private boolean process() {
if (isPrintHelp()) {
printUsage();
System.exit(0);
return false;
}
try {
if (threadsCount <= 0) {
......@@ -95,8 +95,9 @@ public final class JadxCLIArgs implements IJadxArgs {
} catch (JadxException e) {
System.err.println("ERROR: " + e.getMessage());
printUsage();
System.exit(1);
return false;
}
return true;
}
public void printUsage() {
......
......@@ -25,7 +25,6 @@ import jadx.core.dex.visitors.typeinference.TypeInference;
import jadx.core.utils.Utils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
......@@ -95,15 +94,18 @@ public class Jadx {
public static String getVersion() {
try {
Enumeration<URL> resources = Utils.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
Manifest manifest = new Manifest(resources.nextElement().openStream());
String ver = manifest.getMainAttributes().getValue("jadx-version");
if (ver != null) {
return ver;
ClassLoader classLoader = Utils.class.getClassLoader();
if (classLoader != null) {
Enumeration<URL> resources = classLoader.getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
Manifest manifest = new Manifest(resources.nextElement().openStream());
String ver = manifest.getMainAttributes().getValue("jadx-version");
if (ver != null) {
return ver;
}
}
}
} catch (IOException e) {
} catch (Exception e) {
LOG.error("Can't get manifest file", e);
}
return "dev";
......
......@@ -65,6 +65,9 @@ public class ClsSet {
for (ClassNode cls : list) {
if (cls.getAccessFlags().isPublic()) {
NClass nClass = getCls(cls.getRawName(), names);
if (nClass == null) {
throw new JadxRuntimeException("Missing class: " + cls);
}
nClass.setParents(makeParentsArray(cls, names));
classes[k] = nClass;
k++;
......@@ -102,40 +105,47 @@ public class ClsSet {
Utils.makeDirsForFile(output);
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output));
String outputName = output.getName();
if (outputName.endsWith(CLST_EXTENSION)) {
save(outputStream);
} else if (outputName.endsWith(".jar")) {
ZipOutputStream out = new ZipOutputStream(outputStream);
try {
out.putNextEntry(new ZipEntry(CLST_PKG_PATH + "/" + CLST_FILENAME));
save(out);
out.closeEntry();
} finally {
out.close();
outputStream.close();
try {
String outputName = output.getName();
if (outputName.endsWith(CLST_EXTENSION)) {
save(outputStream);
} else if (outputName.endsWith(".jar")) {
ZipOutputStream out = new ZipOutputStream(outputStream);
try {
out.putNextEntry(new ZipEntry(CLST_PKG_PATH + "/" + CLST_FILENAME));
save(out);
out.closeEntry();
} finally {
out.close();
}
} else {
throw new JadxRuntimeException("Unknown file format: " + outputName);
}
} else {
throw new JadxRuntimeException("Unknown file format: " + outputName);
} finally {
outputStream.close();
}
}
public void save(OutputStream output) throws IOException {
DataOutputStream out = new DataOutputStream(output);
out.writeBytes(JADX_CLS_SET_HEADER);
out.writeByte(VERSION);
LOG.info("Classes count: " + classes.length);
out.writeInt(classes.length);
for (NClass cls : classes) {
writeString(out, cls.getName());
}
for (NClass cls : classes) {
NClass[] parents = cls.getParents();
out.writeByte(parents.length);
for (NClass parent : parents) {
out.writeInt(parent.getId());
try {
out.writeBytes(JADX_CLS_SET_HEADER);
out.writeByte(VERSION);
LOG.info("Classes count: " + classes.length);
out.writeInt(classes.length);
for (NClass cls : classes) {
writeString(out, cls.getName());
}
for (NClass cls : classes) {
NClass[] parents = cls.getParents();
out.writeByte(parents.length);
for (NClass parent : parents) {
out.writeInt(parent.getId());
}
}
} finally {
out.close();
}
}
......@@ -144,55 +154,67 @@ public class ClsSet {
if (input == null) {
throw new JadxRuntimeException("Can't load classpath file: " + CLST_FILENAME);
}
load(input);
try {
load(input);
} finally {
input.close();
}
}
public void load(File input) throws IOException, DecodeException {
String name = input.getName();
InputStream inputStream = new FileInputStream(input);
if (name.endsWith(CLST_EXTENSION)) {
load(inputStream);
} else if (name.endsWith(".jar")) {
ZipInputStream in = new ZipInputStream(inputStream);
try {
ZipEntry entry = in.getNextEntry();
while (entry != null) {
if (entry.getName().endsWith(CLST_EXTENSION)) {
load(in);
try {
if (name.endsWith(CLST_EXTENSION)) {
load(inputStream);
} else if (name.endsWith(".jar")) {
ZipInputStream in = new ZipInputStream(inputStream);
try {
ZipEntry entry = in.getNextEntry();
while (entry != null) {
if (entry.getName().endsWith(CLST_EXTENSION)) {
load(in);
}
entry = in.getNextEntry();
}
entry = in.getNextEntry();
} finally {
in.close();
}
} finally {
in.close();
} else {
throw new JadxRuntimeException("Unknown file format: " + name);
}
} else {
throw new JadxRuntimeException("Unknown file format: " + name);
} finally {
inputStream.close();
}
}
public void load(InputStream input) throws IOException, DecodeException {
DataInputStream in = new DataInputStream(input);
byte[] header = new byte[JADX_CLS_SET_HEADER.length()];
int readHeaderLength = in.read(header);
int version = in.readByte();
if (readHeaderLength != JADX_CLS_SET_HEADER.length()
|| !JADX_CLS_SET_HEADER.equals(new String(header, STRING_CHARSET))
|| version != VERSION) {
throw new DecodeException("Wrong jadx class set header");
}
int count = in.readInt();
classes = new NClass[count];
for (int i = 0; i < count; i++) {
String name = readString(in);
classes[i] = new NClass(name, i);
}
for (int i = 0; i < count; i++) {
int pCount = in.readByte();
NClass[] parents = new NClass[pCount];
for (int j = 0; j < pCount; j++) {
parents[j] = classes[in.readInt()];
try {
byte[] header = new byte[JADX_CLS_SET_HEADER.length()];
int readHeaderLength = in.read(header);
int version = in.readByte();
if (readHeaderLength != JADX_CLS_SET_HEADER.length()
|| !JADX_CLS_SET_HEADER.equals(new String(header, STRING_CHARSET))
|| version != VERSION) {
throw new DecodeException("Wrong jadx class set header");
}
int count = in.readInt();
classes = new NClass[count];
for (int i = 0; i < count; i++) {
String name = readString(in);
classes[i] = new NClass(name, i);
}
for (int i = 0; i < count; i++) {
int pCount = in.readByte();
NClass[] parents = new NClass[pCount];
for (int j = 0; j < pCount; j++) {
parents[j] = classes[in.readInt()];
}
classes[i].setParents(parents);
}
classes[i].setParents(parents);
} finally {
in.close();
}
}
......
......@@ -54,6 +54,9 @@ public class ConvertToClsSet {
private static void addFilesFromDirectory(File dir, List<InputFile> inputFiles) throws IOException, DecodeException {
File[] files = dir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
addFilesFromDirectory(file, inputFiles);
......
......@@ -555,10 +555,12 @@ public class InsnGen {
}
cls.getAttributes().add(AttributeFlag.DONT_GENERATE);
MethodNode defCtr = cls.getDefaultConstructor();
if (RegionUtils.notEmpty(defCtr.getRegion())) {
defCtr.getAttributes().add(AttributeFlag.ANONYMOUS_CONSTRUCTOR);
} else {
defCtr.getAttributes().add(AttributeFlag.DONT_GENERATE);
if (defCtr != null) {
if (RegionUtils.notEmpty(defCtr.getRegion())) {
defCtr.getAttributes().add(AttributeFlag.ANONYMOUS_CONSTRUCTOR);
} else {
defCtr.getAttributes().add(AttributeFlag.DONT_GENERATE);
}
}
code.add("new ").add(parent == null ? "Object" : useClass(parent)).add("() ");
new ClassGen(cls, mgen.getClassGen().getParentGen(), fallback).addClassBody(code);
......
......@@ -312,6 +312,7 @@ public class MethodGen {
}
}
} catch (CodegenException e) {
LOG.debug("Error generate fallback instruction: ", e.getCause());
code.startLine("// error: " + insn);
}
}
......
......@@ -62,6 +62,23 @@ public class ArithNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ArithNode) || !super.equals(obj)) {
return false;
}
ArithNode that = (ArithNode) obj;
return op == that.op;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + op.hashCode();
}
@Override
public String toString() {
return InsnUtils.formatOffset(offset) + ": "
+ InsnUtils.insnTypeToString(insnType)
......
......@@ -3,7 +3,7 @@ package jadx.core.dex.instructions;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.InsnNode;
public class ConstClassNode extends InsnNode {
public final class ConstClassNode extends InsnNode {
private final ArgType clsType;
......@@ -17,6 +17,23 @@ public class ConstClassNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ConstClassNode) || !super.equals(obj)) {
return false;
}
ConstClassNode that = (ConstClassNode) obj;
return clsType.equals(that.clsType);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + clsType.hashCode();
}
@Override
public String toString() {
return super.toString() + " " + clsType;
}
......
......@@ -2,7 +2,7 @@ package jadx.core.dex.instructions;
import jadx.core.dex.nodes.InsnNode;
public class ConstStringNode extends InsnNode {
public final class ConstStringNode extends InsnNode {
private final String str;
......@@ -16,6 +16,23 @@ public class ConstStringNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ConstStringNode) || !super.equals(obj)) {
return false;
}
ConstStringNode that = (ConstStringNode) obj;
return str.equals(that.str);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + str.hashCode();
}
@Override
public String toString() {
return super.toString() + " \"" + str + "\"";
}
......
......@@ -8,7 +8,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction;
public class FillArrayNode extends InsnNode {
public final class FillArrayNode extends InsnNode {
private final Object data;
private ArgType elemType;
......@@ -53,4 +53,21 @@ public class FillArrayNode extends InsnNode {
elemType = r;
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FillArrayNode) || !super.equals(obj)) {
return false;
}
FillArrayNode that = (FillArrayNode) obj;
return elemType.equals(that.elemType) && data == that.data;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + elemType.hashCode() + data.hashCode();
}
}
......@@ -21,6 +21,23 @@ public class GotoNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof GotoNode) || !super.equals(obj)) {
return false;
}
GotoNode gotoNode = (GotoNode) obj;
return target == gotoNode.target;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + target;
}
@Override
public String toString() {
return super.toString() + "-> " + InsnUtils.formatOffset(target);
}
......
......@@ -71,6 +71,23 @@ public class IfNode extends GotoNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof IfNode) || !super.equals(obj)) {
return false;
}
IfNode ifNode = (IfNode) obj;
return op == ifNode.op;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + op.hashCode();
}
@Override
public String toString() {
return InsnUtils.formatOffset(offset) + ": "
+ InsnUtils.insnTypeToString(insnType)
......
......@@ -17,6 +17,23 @@ public class IndexInsnNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof IndexInsnNode) || !super.equals(obj)) {
return false;
}
IndexInsnNode that = (IndexInsnNode) obj;
return index == null ? that.index == null : index.equals(that.index);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + (index != null ? index.hashCode() : 0);
}
@Override
public String toString() {
return super.toString() + " " + InsnUtils.indexToString(index);
}
......
......@@ -45,6 +45,26 @@ public class InvokeNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof InvokeNode) || !super.equals(obj)) {
return false;
}
InvokeNode that = (InvokeNode) obj;
return type == that.type && mth.equals(that.mth);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + type.hashCode();
result = 31 * result + mth.hashCode();
return result;
}
@Override
public String toString() {
return InsnUtils.formatOffset(offset) + ": "
+ InsnUtils.insnTypeToString(insnType)
......
......@@ -37,6 +37,29 @@ public class SwitchNode extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof SwitchNode) || !super.equals(obj)) {
return false;
}
SwitchNode that = (SwitchNode) obj;
return def == that.def
&& Arrays.equals(keys, that.keys)
&& Arrays.equals(targets, that.targets);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + Arrays.hashCode(keys);
result = 31 * result + Arrays.hashCode(targets);
result = 31 * result + def;
return result;
}
@Override
public String toString() {
StringBuilder targ = new StringBuilder();
targ.append('[');
......
......@@ -43,6 +43,32 @@ public final class FieldArg extends RegisterArg {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FieldArg) || !super.equals(obj)) {
return false;
}
FieldArg fieldArg = (FieldArg) obj;
if (!field.equals(fieldArg.field)) {
return false;
}
if (regArg != null ? !regArg.equals(fieldArg.regArg) : fieldArg.regArg != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + field.hashCode();
result = 31 * result + (regArg != null ? regArg.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "(" + field + ")";
}
......
......@@ -126,6 +126,9 @@ public class RegisterArg extends InsnArg implements Named {
}
public InsnNode getAssignInsn() {
if (sVar == null) {
return null;
}
RegisterArg assign = sVar.getAssign();
if (assign != null) {
return assign.getParentInsn();
......
......@@ -76,6 +76,29 @@ public class ConstructorInsn extends InsnNode {
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ConstructorInsn) || !super.equals(o)) {
return false;
}
ConstructorInsn that = (ConstructorInsn) o;
return callMth.equals(that.callMth)
&& callType == that.callType
&& instanceArg.equals(that.instanceArg);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + callMth.hashCode();
result = 31 * result + callType.hashCode();
result = 31 * result + instanceArg.hashCode();
return result;
}
@Override
public String toString() {
return super.toString() + " " + callMth + " " + callType;
}
......
......@@ -34,6 +34,23 @@ public class TernaryInsn extends InsnNode {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof TernaryInsn) || !super.equals(obj)) {
return false;
}
TernaryInsn that = (TernaryInsn) obj;
return condition.equals(that.condition);
}
@Override
public int hashCode() {
return 31 * super.hashCode() + condition.hashCode();
}
@Override
public String toString() {
return InsnUtils.formatOffset(offset) + ": TERNARY"
+ getResult() + " = "
......
......@@ -61,9 +61,17 @@ public class BlockNode extends AttrNode implements IBlock {
}
public void lock() {
cleanSuccessors = Collections.unmodifiableList(cleanSuccessors);
successors = Collections.unmodifiableList(successors);
predecessors = Collections.unmodifiableList(predecessors);
cleanSuccessors = lockList(cleanSuccessors);
successors = lockList(successors);
predecessors = lockList(predecessors);
dominatesOn = lockList(dominatesOn);
}
List<BlockNode> lockList(List<BlockNode> list) {
if (list.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(list);
}
/**
......
......@@ -86,6 +86,16 @@ final class LocalVar extends RegisterArg {
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return super.toString() + " " + (isEnd
? "end: " + InsnUtils.formatOffset(startAddr) + "-" + InsnUtils.formatOffset(endAddr)
......
......@@ -13,7 +13,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignatureParser {
private static final Logger LOG = LoggerFactory.getLogger(SignatureParser.class);
private static final char STOP_CHAR = 0;
private final String sign;
......@@ -217,6 +222,10 @@ public class SignatureParser {
break;
}
String id = consumeUntil(':');
if (id == null) {
LOG.error("Can't parse generic map: {}", sign);
return Collections.emptyMap();
}
tryConsume(':');
List<ArgType> types = consumeExtendsTypesList();
map.put(ArgType.genericType(id), types);
......
......@@ -73,7 +73,7 @@ public class ClassModifier extends AbstractVisitor {
}
private static boolean removeFieldUsageFromConstructor(MethodNode mth, FieldNode field, ClassNode fieldsCls) {
if (!mth.getAccessFlags().isConstructor()) {
if (mth.isNoCode() || !mth.getAccessFlags().isConstructor()) {
return false;
}
List<RegisterArg> args = mth.getArguments(false);
......@@ -114,6 +114,9 @@ public class ClassModifier extends AbstractVisitor {
private static void removeSyntheticMethods(ClassNode cls) {
for (MethodNode mth : cls.getMethods()) {
if (mth.isNoCode()) {
continue;
}
AccessInfo af = mth.getAccessFlags();
// remove bridge methods
if (af.isBridge() && af.isSynthetic() && !isMethodUniq(cls, mth)) {
......
......@@ -97,7 +97,7 @@ public class Utils {
public static void makeDirsForFile(File file) {
File dir = file.getParentFile();
if (!dir.exists()) {
if (dir != null && !dir.exists()) {
// if directory already created in other thread mkdirs will return false,
// so check dir existence again
if (!dir.mkdirs() && !dir.exists()) {
......
......@@ -2,6 +2,7 @@ package jadx.core.utils.files;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.io.ByteArrayOutputStream;
import java.io.File;
......@@ -56,17 +57,23 @@ public class InputFile {
private byte[] openDexFromApk(File file) throws IOException {
ZipFile zf = new ZipFile(file);
ZipEntry dex = zf.getEntry("classes.dex");
if (dex == null) {
zf.close();
throw new JadxRuntimeException("File 'classes.dex' not found in apk file: " + file);
}
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
InputStream in = null;
try {
InputStream in = zf.getInputStream(dex);
in = zf.getInputStream(dex);
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) != -1) {
bytesOut.write(buffer, 0, count);
}
in.close();
} finally {
if (in != null) {
in.close();
}
zf.close();
}
return bytesOut.toByteArray();
......
......@@ -4,6 +4,7 @@ import jadx.core.utils.exceptions.JadxException;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import com.android.dx.command.DxConsole;
import com.android.dx.command.dexer.Main;
......@@ -11,6 +12,8 @@ import com.android.dx.command.dexer.Main.Arguments;
public class JavaToDex {
private static final String CHARSET_NAME = "UTF-8";
public static class DxArgs extends Arguments {
public DxArgs(String dexFile, String[] input) {
outName = dexFile;
......@@ -27,12 +30,15 @@ public class JavaToDex {
public byte[] convert(String javaFile) throws JadxException {
ByteArrayOutputStream errOut = new ByteArrayOutputStream();
DxConsole.err = new PrintStream(errOut);
try {
DxConsole.err = new PrintStream(errOut, true, CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
throw new JadxException(e.getMessage(), e);
}
PrintStream oldOut = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
System.setOut(new PrintStream(baos));
System.setOut(new PrintStream(baos, true, CHARSET_NAME));
DxArgs args = new DxArgs("-", new String[]{javaFile});
Main.run(args);
baos.close();
......@@ -41,8 +47,12 @@ public class JavaToDex {
} finally {
System.setOut(oldOut);
}
// errOut also contains warnings
dxErrors = errOut.toString();
try {
// errOut also contains warnings
dxErrors = errOut.toString(CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
throw new JadxException("Can't save error output", e);
}
return baos.toByteArray();
}
......
package jadx.tests
import jadx.core.dex.instructions.args.ArgType
import jadx.core.dex.nodes.parser.SignatureParser
import spock.lang.Specification
......@@ -84,4 +83,12 @@ class TestSignatureParser extends Specification {
argTypes.size() == 1
argTypes.get(0) == generic("Ljava/util/List;", wildcard())
}
def "generic map: bad signature"() {
when:
def map = new SignatureParser("<A:Ljava/lang/Object;B").consumeGenericMap()
then:
notThrown(NullPointerException)
map.isEmpty()
}
}
......@@ -15,7 +15,10 @@ public class JadxGUI {
public static void main(String[] args) {
try {
final JadxCLIArgs jadxArgs = new JadxCLIArgs(args);
final JadxCLIArgs jadxArgs = new JadxCLIArgs();
if (!jadxArgs.processArgs(args)) {
return;
}
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
......@@ -25,7 +28,7 @@ public class JadxGUI {
window.setLocationAndPosition();
window.setVisible(true);
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
if (jadxArgs.getInput().isEmpty()) {
window.openFile();
......
......@@ -135,7 +135,10 @@ public class MainWindow extends JFrame {
}
private void toggleSearch() {
tabbedPane.getSelectedCodePanel().getSearchBar().toggle();
CodePanel codePanel = tabbedPane.getSelectedCodePanel();
if (codePanel != null) {
codePanel.getSearchBar().toggle();
}
}
private void initMenuAndToolbar() {
......@@ -148,7 +151,7 @@ public class MainWindow extends JFrame {
exit.setMnemonic(KeyEvent.VK_E);
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
dispose();
}
});
......
......@@ -145,8 +145,10 @@ class SearchBar extends JToolBar {
}
private void search(int direction) {
String text = searchField.getText();
if (text.length() == 0) {
String searchText = searchField.getText();
if (searchText == null
|| searchText.length() == 0
|| rTextArea.getText() == null) {
return;
}
......@@ -156,20 +158,20 @@ class SearchBar extends JToolBar {
boolean wholeWord = wholeWordCB.isSelected();
if (markAllCB.isSelected()) {
rTextArea.markAll(text, matchCase, wholeWord, regex);
rTextArea.markAll(searchText, matchCase, wholeWord, regex);
} else {
rTextArea.clearMarkAllHighlights();
}
SearchContext context = new SearchContext();
context.setSearchFor(text);
context.setSearchFor(searchText);
context.setMatchCase(matchCase);
context.setRegularExpression(regex);
context.setSearchForward(forward);
context.setWholeWord(wholeWord);
// TODO hack: move cursor before previous search for not jump to next occurrence
if (direction == 0 && !searchField.getBackground().equals(COLOR_BG_ERROR)) {
if (direction == 0 && !COLOR_BG_ERROR.equals(searchField.getBackground())) {
try {
int caretPos = rTextArea.getCaretPosition();
int lineNum = rTextArea.getLineOfOffset(caretPos) - 1;
......@@ -183,7 +185,7 @@ class SearchBar extends JToolBar {
boolean found = SearchEngine.find(rTextArea, context);
if (!found) {
int pos = SearchEngine.getNextMatchPos(text, rTextArea.getText(), forward, matchCase, wholeWord);
int pos = SearchEngine.getNextMatchPos(searchText, rTextArea.getText(), forward, matchCase, wholeWord);
if (pos != -1) {
rTextArea.setCaretPosition(forward ? 0 : rTextArea.getDocument().getLength() - 1);
search(direction);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment