DexAnnotator.java revision afc0a7d325f4d2d278630089e85b86129df353e7
1/*
2 * Copyright 2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked.raw.util;
33
34import com.google.common.collect.Maps;
35import com.google.common.collect.Ordering;
36import com.google.common.primitives.Ints;
37import org.jf.dexlib2.dexbacked.raw.*;
38import org.jf.dexlib2.util.AnnotatedBytes;
39
40import javax.annotation.Nonnull;
41import javax.annotation.Nullable;
42import java.io.IOException;
43import java.io.Writer;
44import java.util.Comparator;
45import java.util.List;
46import java.util.Map;
47
48public class DexAnnotator extends AnnotatedBytes {
49    @Nonnull public final RawDexFile dexFile;
50
51    private final Map<Integer, SectionAnnotator> annotators = Maps.newHashMap();
52    private static final Map<Integer, Integer> sectionAnnotationOrder = Maps.newHashMap();
53
54    static {
55        int[] sectionOrder = new int[] {
56                ItemType.HEADER_ITEM,
57                ItemType.STRING_ID_ITEM,
58                ItemType.TYPE_ID_ITEM,
59                ItemType.PROTO_ID_ITEM,
60                ItemType.FIELD_ID_ITEM,
61                ItemType.METHOD_ID_ITEM,
62
63                // these need to be ordered like this, so the item identities can be propagated
64                ItemType.CLASS_DEF_ITEM,
65                ItemType.CLASS_DATA_ITEM,
66                ItemType.CODE_ITEM,
67                ItemType.DEBUG_INFO_ITEM,
68
69                ItemType.MAP_LIST,
70                ItemType.TYPE_LIST,
71                ItemType.ANNOTATION_SET_REF_LIST,
72                ItemType.ANNOTATION_SET_ITEM,
73                ItemType.STRING_DATA_ITEM,
74                ItemType.ANNOTATION_ITEM,
75                ItemType.ENCODED_ARRAY_ITEM,
76                ItemType.ANNOTATION_DIRECTORY_ITEM
77        };
78
79        for (int i=0; i<sectionOrder.length; i++) {
80            sectionAnnotationOrder.put(sectionOrder[i], i);
81        }
82    }
83
84    public DexAnnotator(@Nonnull RawDexFile dexFile, int width) {
85        super(width);
86
87        this.dexFile = dexFile;
88
89        for (MapItem mapItem: dexFile.getMapItems()) {
90            switch (mapItem.getType()) {
91                case ItemType.HEADER_ITEM:
92                    annotators.put(mapItem.getType(), HeaderItem.makeAnnotator(this, mapItem));
93                    break;
94                case ItemType.STRING_ID_ITEM:
95                    annotators.put(mapItem.getType(), StringIdItem.makeAnnotator(this, mapItem));
96                    break;
97                case ItemType.TYPE_ID_ITEM:
98                    annotators.put(mapItem.getType(), TypeIdItem.makeAnnotator(this, mapItem));
99                    break;
100                case ItemType.PROTO_ID_ITEM:
101                    annotators.put(mapItem.getType(), ProtoIdItem.makeAnnotator(this, mapItem));
102                    break;
103                case ItemType.FIELD_ID_ITEM:
104                    annotators.put(mapItem.getType(), FieldIdItem.makeAnnotator(this, mapItem));
105                    break;
106                case ItemType.METHOD_ID_ITEM:
107                    annotators.put(mapItem.getType(), MethodIdItem.makeAnnotator(this, mapItem));
108                    break;
109                case ItemType.CLASS_DEF_ITEM:
110                    annotators.put(mapItem.getType(), ClassDefItem.makeAnnotator(this, mapItem));
111                    break;
112                case ItemType.MAP_LIST:
113                    annotators.put(mapItem.getType(), MapItem.makeAnnotator(this, mapItem));
114                    break;
115                case ItemType.TYPE_LIST:
116                    annotators.put(mapItem.getType(), TypeListItem.makeAnnotator(this, mapItem));
117                    break;
118                case ItemType.ANNOTATION_SET_REF_LIST:
119                    annotators.put(mapItem.getType(), AnnotationSetRefList.makeAnnotator(this, mapItem));
120                    break;
121                case ItemType.ANNOTATION_SET_ITEM:
122                    annotators.put(mapItem.getType(), AnnotationSetItem.makeAnnotator(this, mapItem));
123                    break;
124                case ItemType.CLASS_DATA_ITEM:
125                    annotators.put(mapItem.getType(), ClassDataItem.makeAnnotator(this, mapItem));
126                    break;
127                case ItemType.CODE_ITEM:
128                    annotators.put(mapItem.getType(), CodeItem.makeAnnotator(this, mapItem));
129                    break;
130                case ItemType.STRING_DATA_ITEM:
131                    annotators.put(mapItem.getType(), StringDataItem.makeAnnotator(this, mapItem));
132                    break;
133                case ItemType.DEBUG_INFO_ITEM:
134                    annotators.put(mapItem.getType(), DebugInfoItem.makeAnnotator(this, mapItem));
135                    break;
136                case ItemType.ANNOTATION_ITEM:
137                    annotators.put(mapItem.getType(), AnnotationItem.makeAnnotator(this, mapItem));
138                    break;
139                case ItemType.ENCODED_ARRAY_ITEM:
140                    annotators.put(mapItem.getType(), EncodedArrayItem.makeAnnotator(this, mapItem));
141                    break;
142                case ItemType.ANNOTATION_DIRECTORY_ITEM:
143                    annotators.put(mapItem.getType(), AnnotationDirectoryItem.makeAnnotator(this, mapItem));
144                    break;
145                default:
146                    throw new RuntimeException(String.format("Unrecognized item type: 0x%x", mapItem.getType()));
147            }
148        }
149    }
150
151    public void writeAnnotations(Writer out) throws IOException {
152        List<MapItem> mapItems = dexFile.getMapItems();
153        // sort the map items based on the order defined by sectionAnnotationOrder
154        Ordering<MapItem> ordering = Ordering.from(new Comparator<MapItem>() {
155            @Override public int compare(MapItem o1, MapItem o2) {
156                return Ints.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
157            }
158        });
159
160        mapItems = ordering.immutableSortedCopy(mapItems);
161
162        try {
163            for (MapItem mapItem: mapItems) {
164                SectionAnnotator annotator = annotators.get(mapItem.getType());
165                annotator.annotateSection(this);
166            }
167        } finally {
168            dexFile.writeAnnotations(out, this);
169        }
170    }
171
172    @Nullable
173    public SectionAnnotator getAnnotator(int itemType) {
174        return annotators.get(itemType);
175    }
176}
177