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.MAP_LIST,
57
58                ItemType.HEADER_ITEM,
59                ItemType.STRING_ID_ITEM,
60                ItemType.TYPE_ID_ITEM,
61                ItemType.PROTO_ID_ITEM,
62                ItemType.FIELD_ID_ITEM,
63                ItemType.METHOD_ID_ITEM,
64
65                // these need to be ordered like this, so the item identities can be propagated
66                ItemType.CLASS_DEF_ITEM,
67                ItemType.CLASS_DATA_ITEM,
68                ItemType.CODE_ITEM,
69                ItemType.DEBUG_INFO_ITEM,
70
71                ItemType.TYPE_LIST,
72                ItemType.ANNOTATION_SET_REF_LIST,
73                ItemType.ANNOTATION_SET_ITEM,
74                ItemType.STRING_DATA_ITEM,
75                ItemType.ANNOTATION_ITEM,
76                ItemType.ENCODED_ARRAY_ITEM,
77                ItemType.ANNOTATION_DIRECTORY_ITEM
78        };
79
80        for (int i=0; i<sectionOrder.length; i++) {
81            sectionAnnotationOrder.put(sectionOrder[i], i);
82        }
83    }
84
85    public DexAnnotator(@Nonnull RawDexFile dexFile, int width) {
86        super(width);
87
88        this.dexFile = dexFile;
89
90        for (MapItem mapItem: dexFile.getMapItems()) {
91            switch (mapItem.getType()) {
92                case ItemType.HEADER_ITEM:
93                    annotators.put(mapItem.getType(), HeaderItem.makeAnnotator(this, mapItem));
94                    break;
95                case ItemType.STRING_ID_ITEM:
96                    annotators.put(mapItem.getType(), StringIdItem.makeAnnotator(this, mapItem));
97                    break;
98                case ItemType.TYPE_ID_ITEM:
99                    annotators.put(mapItem.getType(), TypeIdItem.makeAnnotator(this, mapItem));
100                    break;
101                case ItemType.PROTO_ID_ITEM:
102                    annotators.put(mapItem.getType(), ProtoIdItem.makeAnnotator(this, mapItem));
103                    break;
104                case ItemType.FIELD_ID_ITEM:
105                    annotators.put(mapItem.getType(), FieldIdItem.makeAnnotator(this, mapItem));
106                    break;
107                case ItemType.METHOD_ID_ITEM:
108                    annotators.put(mapItem.getType(), MethodIdItem.makeAnnotator(this, mapItem));
109                    break;
110                case ItemType.CLASS_DEF_ITEM:
111                    annotators.put(mapItem.getType(), ClassDefItem.makeAnnotator(this, mapItem));
112                    break;
113                case ItemType.MAP_LIST:
114                    annotators.put(mapItem.getType(), MapItem.makeAnnotator(this, mapItem));
115                    break;
116                case ItemType.TYPE_LIST:
117                    annotators.put(mapItem.getType(), TypeListItem.makeAnnotator(this, mapItem));
118                    break;
119                case ItemType.ANNOTATION_SET_REF_LIST:
120                    annotators.put(mapItem.getType(), AnnotationSetRefList.makeAnnotator(this, mapItem));
121                    break;
122                case ItemType.ANNOTATION_SET_ITEM:
123                    annotators.put(mapItem.getType(), AnnotationSetItem.makeAnnotator(this, mapItem));
124                    break;
125                case ItemType.CLASS_DATA_ITEM:
126                    annotators.put(mapItem.getType(), ClassDataItem.makeAnnotator(this, mapItem));
127                    break;
128                case ItemType.CODE_ITEM:
129                    annotators.put(mapItem.getType(), CodeItem.makeAnnotator(this, mapItem));
130                    break;
131                case ItemType.STRING_DATA_ITEM:
132                    annotators.put(mapItem.getType(), StringDataItem.makeAnnotator(this, mapItem));
133                    break;
134                case ItemType.DEBUG_INFO_ITEM:
135                    annotators.put(mapItem.getType(), DebugInfoItem.makeAnnotator(this, mapItem));
136                    break;
137                case ItemType.ANNOTATION_ITEM:
138                    annotators.put(mapItem.getType(), AnnotationItem.makeAnnotator(this, mapItem));
139                    break;
140                case ItemType.ENCODED_ARRAY_ITEM:
141                    annotators.put(mapItem.getType(), EncodedArrayItem.makeAnnotator(this, mapItem));
142                    break;
143                case ItemType.ANNOTATION_DIRECTORY_ITEM:
144                    annotators.put(mapItem.getType(), AnnotationDirectoryItem.makeAnnotator(this, mapItem));
145                    break;
146                default:
147                    throw new RuntimeException(String.format("Unrecognized item type: 0x%x", mapItem.getType()));
148            }
149        }
150    }
151
152    public void writeAnnotations(Writer out) throws IOException {
153        List<MapItem> mapItems = dexFile.getMapItems();
154        // sort the map items based on the order defined by sectionAnnotationOrder
155        Ordering<MapItem> ordering = Ordering.from(new Comparator<MapItem>() {
156            @Override public int compare(MapItem o1, MapItem o2) {
157                return Ints.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
158            }
159        });
160
161        mapItems = ordering.immutableSortedCopy(mapItems);
162
163        try {
164            for (MapItem mapItem: mapItems) {
165                SectionAnnotator annotator = annotators.get(mapItem.getType());
166                annotator.annotateSection(this);
167            }
168        } finally {
169            dexFile.writeAnnotations(out, this);
170        }
171    }
172
173    @Nullable
174    public SectionAnnotator getAnnotator(int itemType) {
175        return annotators.get(itemType);
176    }
177}
178