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