blob: 741de975098980e4730f68fb7d7e7d514afcce4b [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.command.grep;
import com.android.dx.io.ClassData;
import com.android.dx.io.ClassDef;
import com.android.dx.io.CodeReader;
import com.android.dx.io.DexBuffer;
import com.android.dx.io.EncodedValueReader;
import com.android.dx.io.MethodId;
import com.android.dx.io.instructions.DecodedInstruction;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
public final class Grep {
private final DexBuffer dex;
private final CodeReader codeReader = new CodeReader();
private final Set<Integer> stringIds;
private final PrintWriter out;
private int count = 0;
private ClassDef currentClass;
private ClassData.Method currentMethod;
public Grep(final DexBuffer dex, Pattern pattern, final PrintWriter out) {
this.dex = dex;
this.out = out;
stringIds = getStringIds(dex, pattern);
codeReader.setStringVisitor(new CodeReader.Visitor() {
public void visit(DecodedInstruction[] all, DecodedInstruction one) {
encounterString(one.getIndex());
}
});
}
private EncodedValueReader newEncodedValueReader(DexBuffer.Section section) {
return new EncodedValueReader(section) {
@Override protected void visitString(int type, int index) {
encounterString(index);
}
};
}
private void encounterString(int index) {
if (stringIds.contains(index)) {
out.println(location() + " " + dex.strings().get(index));
count++;
}
}
private String location() {
String className = dex.typeNames().get(currentClass.getTypeIndex());
if (currentMethod != null) {
MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex());
return className + "." + dex.strings().get(methodId.getNameIndex());
} else {
return className;
}
}
/**
* Prints usages to out. Returns the number of matches found.
*/
public int grep() {
for (ClassDef classDef : dex.classDefs()) {
currentClass = classDef;
currentMethod = null;
if (classDef.getClassDataOffset() == 0) {
continue;
}
ClassData classData = dex.readClassData(classDef);
// find the strings in encoded constants
int staticValuesOffset = classDef.getStaticValuesOffset();
if (staticValuesOffset != 0) {
newEncodedValueReader(dex.open(staticValuesOffset)).readArray();
}
// find the strings in method bodies
for (ClassData.Method method : classData.allMethods()) {
currentMethod = method;
if (method.getCodeOffset() != 0) {
codeReader.visitAll(dex.readCode(method).getInstructions());
}
}
}
currentClass = null;
currentMethod = null;
return count;
}
private Set<Integer> getStringIds(DexBuffer dex, Pattern pattern) {
Set<Integer> stringIds = new HashSet<Integer>();
int stringIndex = 0;
for (String s : dex.strings()) {
if (pattern.matcher(s).find()) {
stringIds.add(stringIndex);
}
stringIndex++;
}
return stringIds;
}
}