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