Grep.java revision 6bf7f30e6968d9917eb4d0ca2280df96a8096134
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.command.grep;
18
19import com.android.dx.io.ClassData;
20import com.android.dx.io.ClassDef;
21import com.android.dx.io.CodeReader;
22import com.android.dx.io.DexBuffer;
23import com.android.dx.io.EncodedValueReader;
24import com.android.dx.io.MethodId;
25import com.android.dx.io.instructions.DecodedInstruction;
26import java.io.PrintWriter;
27import java.util.HashSet;
28import java.util.Set;
29import java.util.regex.Pattern;
30
31public final class Grep {
32    private final DexBuffer dex;
33    private final CodeReader codeReader = new CodeReader();
34    private final Set<Integer> stringIds;
35
36    private final PrintWriter out;
37    private int count = 0;
38
39    private ClassDef currentClass;
40    private ClassData.Method currentMethod;
41
42    public Grep(final DexBuffer dex, Pattern pattern, final PrintWriter out) {
43        this.dex = dex;
44        this.out = out;
45
46        stringIds = getStringIds(dex, pattern);
47
48        codeReader.setStringVisitor(new CodeReader.Visitor() {
49            public void visit(DecodedInstruction[] all, DecodedInstruction one) {
50                encounterString(one.getIndex());
51            }
52        });
53    }
54
55    private EncodedValueReader newEncodedValueReader(DexBuffer.Section section) {
56        return new EncodedValueReader(section) {
57            @Override protected void visitString(int type, int index) {
58                encounterString(index);
59            }
60        };
61    }
62
63    private void encounterString(int index) {
64        if (stringIds.contains(index)) {
65            out.println(location() + " " + dex.strings().get(index));
66            count++;
67        }
68    }
69
70    private String location() {
71        String className = dex.typeNames().get(currentClass.getTypeIndex());
72        if (currentMethod != null) {
73            MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex());
74            return className + "." + dex.strings().get(methodId.getNameIndex());
75        } else {
76            return className;
77        }
78    }
79
80    /**
81     * Prints usages to out. Returns the number of matches found.
82     */
83    public int grep() {
84        for (ClassDef classDef : dex.classDefs()) {
85            currentClass = classDef;
86            currentMethod = null;
87
88            if (classDef.getClassDataOffset() == 0) {
89                continue;
90            }
91
92            ClassData classData = dex.readClassData(classDef);
93
94            // find the strings in encoded constants
95            int staticValuesOffset = classDef.getStaticValuesOffset();
96            if (staticValuesOffset != 0) {
97                newEncodedValueReader(dex.open(staticValuesOffset)).readArray();
98            }
99
100            // find the strings in method bodies
101            for (ClassData.Method method : classData.allMethods()) {
102                currentMethod = method;
103                if (method.getCodeOffset() != 0) {
104                    codeReader.visitAll(dex.readCode(method).getInstructions());
105                }
106            }
107        }
108
109        currentClass = null;
110        currentMethod = null;
111        return count;
112    }
113
114    private Set<Integer> getStringIds(DexBuffer dex, Pattern pattern) {
115        Set<Integer> stringIds = new HashSet<Integer>();
116        int stringIndex = 0;
117        for (String s : dex.strings()) {
118            if (pattern.matcher(s).find()) {
119                stringIds.add(stringIndex);
120            }
121            stringIndex++;
122        }
123        return stringIds;
124    }
125}
126