Home | History | Annotate | Download | only in util
      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 
     32 package org.jf.dexlib2.dexbacked.raw.util;
     33 
     34 import com.google.common.collect.Maps;
     35 import com.google.common.collect.Ordering;
     36 import com.google.common.primitives.Ints;
     37 import org.jf.dexlib2.dexbacked.raw.*;
     38 import org.jf.dexlib2.util.AnnotatedBytes;
     39 
     40 import javax.annotation.Nonnull;
     41 import javax.annotation.Nullable;
     42 import java.io.IOException;
     43 import java.io.Writer;
     44 import java.util.Comparator;
     45 import java.util.List;
     46 import java.util.Map;
     47 
     48 public 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