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.io;
18
19import com.android.dex.DexException;
20import com.android.dx.io.instructions.DecodedInstruction;
21
22/**
23 * Walks through a block of code and calls visitor call backs.
24 */
25public final class CodeReader {
26    private Visitor fallbackVisitor = null;
27    private Visitor stringVisitor = null;
28    private Visitor typeVisitor = null;
29    private Visitor fieldVisitor = null;
30    private Visitor methodVisitor = null;
31    private Visitor methodAndProtoVisitor = null;
32    private Visitor callSiteVisitor = null;
33
34    /**
35     * Sets {@code visitor} as the visitor for all instructions.
36     */
37    public void setAllVisitors(Visitor visitor) {
38        fallbackVisitor = visitor;
39        stringVisitor = visitor;
40        typeVisitor = visitor;
41        fieldVisitor = visitor;
42        methodVisitor = visitor;
43        methodAndProtoVisitor = visitor;
44        callSiteVisitor = visitor;
45    }
46
47    /**
48     * Sets {@code visitor} as the visitor for all instructions not
49     * otherwise handled.
50     */
51    public void setFallbackVisitor(Visitor visitor) {
52        fallbackVisitor = visitor;
53    }
54
55    /**
56     * Sets {@code visitor} as the visitor for all string instructions.
57     */
58    public void setStringVisitor(Visitor visitor) {
59        stringVisitor = visitor;
60    }
61
62    /**
63     * Sets {@code visitor} as the visitor for all type instructions.
64     */
65    public void setTypeVisitor(Visitor visitor) {
66        typeVisitor = visitor;
67    }
68
69    /**
70     * Sets {@code visitor} as the visitor for all field instructions.
71     */
72    public void setFieldVisitor(Visitor visitor) {
73        fieldVisitor = visitor;
74    }
75
76    /**
77     * Sets {@code visitor} as the visitor for all method instructions.
78     */
79    public void setMethodVisitor(Visitor visitor) {
80        methodVisitor = visitor;
81    }
82
83    /** Sets {@code visitor} as the visitor for all method and proto instructions. */
84    public void setMethodAndProtoVisitor(Visitor visitor) {
85        methodAndProtoVisitor = visitor;
86    }
87
88    /** Sets {@code visitor} as the visitor for all call site instructions. */
89    public void setCallSiteVisitor(Visitor visitor) {
90        callSiteVisitor = visitor;
91    }
92
93    public void visitAll(DecodedInstruction[] decodedInstructions)
94            throws DexException {
95        int size = decodedInstructions.length;
96
97        for (int i = 0; i < size; i++) {
98            DecodedInstruction one = decodedInstructions[i];
99            if (one == null) {
100                continue;
101            }
102
103            callVisit(decodedInstructions, one);
104        }
105    }
106
107    public void visitAll(short[] encodedInstructions) throws DexException {
108        DecodedInstruction[] decodedInstructions =
109            DecodedInstruction.decodeAll(encodedInstructions);
110        visitAll(decodedInstructions);
111    }
112
113    private void callVisit(DecodedInstruction[] all, DecodedInstruction one) {
114        Visitor visitor = null;
115
116        switch (OpcodeInfo.getIndexType(one.getOpcode())) {
117            case STRING_REF:           visitor = stringVisitor;         break;
118            case TYPE_REF:             visitor = typeVisitor;           break;
119            case FIELD_REF:            visitor = fieldVisitor;          break;
120            case METHOD_REF:           visitor = methodVisitor;         break;
121            case METHOD_AND_PROTO_REF: visitor = methodAndProtoVisitor; break;
122            case CALL_SITE_REF:        visitor = callSiteVisitor;       break;
123        }
124
125        if (visitor == null) {
126            visitor = fallbackVisitor;
127        }
128
129        if (visitor != null) {
130            visitor.visit(all, one);
131        }
132    }
133
134    public interface Visitor {
135        void visit(DecodedInstruction[] all, DecodedInstruction one);
136    }
137}
138