18f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver/*
28f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * Copyright 2013, Google Inc.
38f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * All rights reserved.
48f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *
58f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * Redistribution and use in source and binary forms, with or without
68f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * modification, are permitted provided that the following conditions are
78f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * met:
88f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *
98f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *     * Redistributions of source code must retain the above copyright
108f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * notice, this list of conditions and the following disclaimer.
118f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *     * Redistributions in binary form must reproduce the above
128f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * copyright notice, this list of conditions and the following disclaimer
138f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * in the documentation and/or other materials provided with the
148f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * distribution.
158f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *     * Neither the name of Google Inc. nor the names of its
168f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * contributors may be used to endorse or promote products derived from
178f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * this software without specific prior written permission.
188f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver *
198f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
208f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
218f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
228f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
238f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
248f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
258f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
268f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
278f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
288f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
298f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
308f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver */
318f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
328f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverpackage org.jf.dexlib2.dexbacked.raw.util;
338f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
348f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport com.google.common.collect.Maps;
358f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport com.google.common.collect.Ordering;
368f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport com.google.common.primitives.Ints;
378f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport org.jf.dexlib2.dexbacked.raw.*;
388f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport org.jf.dexlib2.util.AnnotatedBytes;
398f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
408f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport javax.annotation.Nonnull;
418f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport javax.annotation.Nullable;
428f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport java.io.IOException;
438f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport java.io.Writer;
448f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport java.util.Comparator;
458f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport java.util.List;
468f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverimport java.util.Map;
478f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
488f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruverpublic class DexAnnotator extends AnnotatedBytes {
498f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    @Nonnull public final RawDexFile dexFile;
508f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
518f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    private final Map<Integer, SectionAnnotator> annotators = Maps.newHashMap();
528f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    private static final Map<Integer, Integer> sectionAnnotationOrder = Maps.newHashMap();
538f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
548f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    static {
558f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        int[] sectionOrder = new int[] {
569a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver                ItemType.MAP_LIST,
579a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver
588f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.HEADER_ITEM,
598f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.STRING_ID_ITEM,
608f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.TYPE_ID_ITEM,
618f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.PROTO_ID_ITEM,
628f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.FIELD_ID_ITEM,
638f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.METHOD_ID_ITEM,
648f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
658f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                // these need to be ordered like this, so the item identities can be propagated
668f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.CLASS_DEF_ITEM,
678f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.CLASS_DATA_ITEM,
688f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.CODE_ITEM,
698f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.DEBUG_INFO_ITEM,
708f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
718f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.TYPE_LIST,
728f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.ANNOTATION_SET_REF_LIST,
738f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.ANNOTATION_SET_ITEM,
748f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.STRING_DATA_ITEM,
758f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.ANNOTATION_ITEM,
768f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.ENCODED_ARRAY_ITEM,
778f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                ItemType.ANNOTATION_DIRECTORY_ITEM
788f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        };
798f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
808f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        for (int i=0; i<sectionOrder.length; i++) {
818f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver            sectionAnnotationOrder.put(sectionOrder[i], i);
828f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        }
838f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    }
848f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
858f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    public DexAnnotator(@Nonnull RawDexFile dexFile, int width) {
868f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        super(width);
878f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
888f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        this.dexFile = dexFile;
898f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
908f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        for (MapItem mapItem: dexFile.getMapItems()) {
918f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver            switch (mapItem.getType()) {
928f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.HEADER_ITEM:
938f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), HeaderItem.makeAnnotator(this, mapItem));
948f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
958f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.STRING_ID_ITEM:
968f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), StringIdItem.makeAnnotator(this, mapItem));
978f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
988f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.TYPE_ID_ITEM:
998f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), TypeIdItem.makeAnnotator(this, mapItem));
1008f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1018f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.PROTO_ID_ITEM:
1028f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), ProtoIdItem.makeAnnotator(this, mapItem));
1038f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1048f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.FIELD_ID_ITEM:
1058f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), FieldIdItem.makeAnnotator(this, mapItem));
1068f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1078f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.METHOD_ID_ITEM:
1088f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), MethodIdItem.makeAnnotator(this, mapItem));
1098f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1108f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.CLASS_DEF_ITEM:
1118f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), ClassDefItem.makeAnnotator(this, mapItem));
1128f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1138f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.MAP_LIST:
1148f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), MapItem.makeAnnotator(this, mapItem));
1158f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1168f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.TYPE_LIST:
1178f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), TypeListItem.makeAnnotator(this, mapItem));
1188f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1198f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.ANNOTATION_SET_REF_LIST:
1208f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), AnnotationSetRefList.makeAnnotator(this, mapItem));
1218f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1228f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.ANNOTATION_SET_ITEM:
1238f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), AnnotationSetItem.makeAnnotator(this, mapItem));
1248f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1258f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.CLASS_DATA_ITEM:
1268f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), ClassDataItem.makeAnnotator(this, mapItem));
1278f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1288f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.CODE_ITEM:
1298f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), CodeItem.makeAnnotator(this, mapItem));
1308f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1318f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.STRING_DATA_ITEM:
1328f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), StringDataItem.makeAnnotator(this, mapItem));
1338f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
134063ec54b929a38f6b56cb667f8d08e23f92b62f7Ben Gruver                case ItemType.DEBUG_INFO_ITEM:
135063ec54b929a38f6b56cb667f8d08e23f92b62f7Ben Gruver                    annotators.put(mapItem.getType(), DebugInfoItem.makeAnnotator(this, mapItem));
136063ec54b929a38f6b56cb667f8d08e23f92b62f7Ben Gruver                    break;
1378f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                case ItemType.ANNOTATION_ITEM:
1388f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    annotators.put(mapItem.getType(), AnnotationItem.makeAnnotator(this, mapItem));
1398f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                    break;
1406fa5eab85755ce9e0ec680670dde0b6c1f35f11fBen Gruver                case ItemType.ENCODED_ARRAY_ITEM:
1416fa5eab85755ce9e0ec680670dde0b6c1f35f11fBen Gruver                    annotators.put(mapItem.getType(), EncodedArrayItem.makeAnnotator(this, mapItem));
1426fa5eab85755ce9e0ec680670dde0b6c1f35f11fBen Gruver                    break;
143c5abfe4cea91f7ffcbaaa72b8f636534a12629d0Ben Gruver                case ItemType.ANNOTATION_DIRECTORY_ITEM:
144c5abfe4cea91f7ffcbaaa72b8f636534a12629d0Ben Gruver                    annotators.put(mapItem.getType(), AnnotationDirectoryItem.makeAnnotator(this, mapItem));
145c5abfe4cea91f7ffcbaaa72b8f636534a12629d0Ben Gruver                    break;
146c5abfe4cea91f7ffcbaaa72b8f636534a12629d0Ben Gruver                default:
147c5abfe4cea91f7ffcbaaa72b8f636534a12629d0Ben Gruver                    throw new RuntimeException(String.format("Unrecognized item type: 0x%x", mapItem.getType()));
1488f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver            }
1498f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        }
1508f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    }
1518f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
1528f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    public void writeAnnotations(Writer out) throws IOException {
1538f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        List<MapItem> mapItems = dexFile.getMapItems();
1548f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        // sort the map items based on the order defined by sectionAnnotationOrder
1558f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        Ordering<MapItem> ordering = Ordering.from(new Comparator<MapItem>() {
1568f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver            @Override public int compare(MapItem o1, MapItem o2) {
1578f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver                return Ints.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
1588f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver            }
1598f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        });
1608f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
1618f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        mapItems = ordering.immutableSortedCopy(mapItems);
1628f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
163afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver        try {
164afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver            for (MapItem mapItem: mapItems) {
165afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver                SectionAnnotator annotator = annotators.get(mapItem.getType());
166afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver                annotator.annotateSection(this);
167afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver            }
168afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver        } finally {
169afc0a7d325f4d2d278630089e85b86129df353e7Ben Gruver            dexFile.writeAnnotations(out, this);
1708f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        }
1718f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    }
1728f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver
1738f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    @Nullable
1748f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    public SectionAnnotator getAnnotator(int itemType) {
1758f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver        return annotators.get(itemType);
1768f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver    }
1778f8b67f65ec3390e92cce7d710e5b1eaabd4e248Ben Gruver}
178