Home | History | Annotate | Download | only in grep
      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 
     17 package com.android.dx.command.grep;
     18 
     19 import com.android.dex.ClassData;
     20 import com.android.dex.ClassDef;
     21 import com.android.dex.Dex;
     22 import com.android.dex.EncodedValueReader;
     23 import com.android.dex.MethodId;
     24 import com.android.dx.io.CodeReader;
     25 import com.android.dx.io.instructions.DecodedInstruction;
     26 import java.io.PrintWriter;
     27 import java.util.HashSet;
     28 import java.util.Set;
     29 import java.util.regex.Pattern;
     30 
     31 public final class Grep {
     32     private final Dex 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 Dex 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             @Override
     50             public void visit(DecodedInstruction[] all, DecodedInstruction one) {
     51                 encounterString(one.getIndex());
     52             }
     53         });
     54     }
     55 
     56     private void readArray(EncodedValueReader reader) {
     57         for (int i = 0, size = reader.readArray(); i < size; i++) {
     58             switch (reader.peek()) {
     59             case EncodedValueReader.ENCODED_STRING:
     60                 encounterString(reader.readString());
     61                 break;
     62             case EncodedValueReader.ENCODED_ARRAY:
     63                 readArray(reader);
     64                 break;
     65             }
     66         }
     67     }
     68 
     69     private void encounterString(int index) {
     70         if (stringIds.contains(index)) {
     71             out.println(location() + " " + dex.strings().get(index));
     72             count++;
     73         }
     74     }
     75 
     76     private String location() {
     77         String className = dex.typeNames().get(currentClass.getTypeIndex());
     78         if (currentMethod != null) {
     79             MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex());
     80             return className + "." + dex.strings().get(methodId.getNameIndex());
     81         } else {
     82             return className;
     83         }
     84     }
     85 
     86     /**
     87      * Prints usages to out. Returns the number of matches found.
     88      */
     89     public int grep() {
     90         for (ClassDef classDef : dex.classDefs()) {
     91             currentClass = classDef;
     92             currentMethod = null;
     93 
     94             if (classDef.getClassDataOffset() == 0) {
     95                 continue;
     96             }
     97 
     98             ClassData classData = dex.readClassData(classDef);
     99 
    100             // find the strings in encoded constants
    101             int staticValuesOffset = classDef.getStaticValuesOffset();
    102             if (staticValuesOffset != 0) {
    103                 readArray(new EncodedValueReader(dex.open(staticValuesOffset)));
    104             }
    105 
    106             // find the strings in method bodies
    107             for (ClassData.Method method : classData.allMethods()) {
    108                 currentMethod = method;
    109                 if (method.getCodeOffset() != 0) {
    110                     codeReader.visitAll(dex.readCode(method).getInstructions());
    111                 }
    112             }
    113         }
    114 
    115         currentClass = null;
    116         currentMethod = null;
    117         return count;
    118     }
    119 
    120     private Set<Integer> getStringIds(Dex dex, Pattern pattern) {
    121         Set<Integer> stringIds = new HashSet<Integer>();
    122         int stringIndex = 0;
    123         for (String s : dex.strings()) {
    124             if (pattern.matcher(s).find()) {
    125                 stringIds.add(stringIndex);
    126             }
    127             stringIndex++;
    128         }
    129         return stringIds;
    130     }
    131 }
    132