1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dexfuzz.rawdex; 18 19 import dexfuzz.Log; 20 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.List; 24 25 public class MapList implements RawDexObject { 26 27 private RawDexFile rawDexFile; 28 29 public int size; 30 public List<MapItem> mapItems; 31 MapList(RawDexFile rawDexFile)32 public MapList(RawDexFile rawDexFile) { 33 this.rawDexFile = rawDexFile; 34 } 35 36 @Override read(DexRandomAccessFile file)37 public void read(DexRandomAccessFile file) throws IOException { 38 // Find the map list. 39 file.seek(rawDexFile.header.mapOff.getOriginalOffset()); 40 41 file.getOffsetTracker().getNewOffsettable(file, this); 42 43 // Get the number of entries. 44 size = file.readUInt(); 45 46 // Allocate and populate the array. 47 mapItems = new ArrayList<MapItem>(size); 48 for (int i = 0; i < size; i++) { 49 MapItem mapItem = new MapItem(); 50 mapItems.add(mapItem); 51 mapItem.read(file); 52 } 53 54 file.getOffsetTracker().rememberPointAfterMapList(); 55 56 // NB: We track the current index into the MapList, so when we encounter the DebugInfoItem 57 // MapItem, we know how to find the next MapItem, so we know how large the DebugInfo 58 // area is, so we can copy it as a blob. 59 int mapItemIdx = 0; 60 61 // Iterate through the list, and create all the other data structures. 62 for (MapItem mapItem : mapItems) { 63 file.seek(mapItem.offset.getOriginalOffset()); 64 switch (mapItem.type) { 65 case MapItem.TYPE_HEADER_ITEM: 66 // Already read it; skip. 67 break; 68 case MapItem.TYPE_STRING_ID_ITEM: 69 for (int i = 0; i < mapItem.size; i++) { 70 StringIdItem newStringId = new StringIdItem(); 71 rawDexFile.stringIds.add(newStringId); 72 newStringId.read(file); 73 } 74 break; 75 case MapItem.TYPE_TYPE_ID_ITEM: 76 for (int i = 0; i < mapItem.size; i++) { 77 TypeIdItem newTypeId = new TypeIdItem(); 78 rawDexFile.typeIds.add(newTypeId); 79 newTypeId.read(file); 80 } 81 break; 82 case MapItem.TYPE_PROTO_ID_ITEM: 83 for (int i = 0; i < mapItem.size; i++) { 84 ProtoIdItem newProtoId = new ProtoIdItem(); 85 rawDexFile.protoIds.add(newProtoId); 86 newProtoId.read(file); 87 } 88 break; 89 case MapItem.TYPE_FIELD_ID_ITEM: 90 for (int i = 0; i < mapItem.size; i++) { 91 FieldIdItem newFieldId = new FieldIdItem(); 92 rawDexFile.fieldIds.add(newFieldId); 93 newFieldId.read(file); 94 } 95 break; 96 case MapItem.TYPE_METHOD_ID_ITEM: 97 for (int i = 0; i < mapItem.size; i++) { 98 MethodIdItem newMethodId = new MethodIdItem(); 99 rawDexFile.methodIds.add(newMethodId); 100 newMethodId.read(file); 101 } 102 break; 103 case MapItem.TYPE_CLASS_DEF_ITEM: 104 for (int i = 0; i < mapItem.size; i++) { 105 ClassDefItem newClassDef = new ClassDefItem(); 106 rawDexFile.classDefs.add(newClassDef); 107 newClassDef.read(file); 108 } 109 break; 110 case MapItem.TYPE_MAP_LIST: 111 // Already read it; skip. 112 break; 113 case MapItem.TYPE_TYPE_LIST: 114 rawDexFile.typeLists = new ArrayList<TypeList>(mapItem.size); 115 for (int i = 0; i < mapItem.size; i++) { 116 TypeList newTypeList = new TypeList(); 117 rawDexFile.typeLists.add(newTypeList); 118 newTypeList.read(file); 119 } 120 break; 121 case MapItem.TYPE_ANNOTATION_SET_REF_LIST: 122 rawDexFile.annotationSetRefLists = 123 new ArrayList<AnnotationSetRefList>(mapItem.size); 124 for (int i = 0; i < mapItem.size; i++) { 125 AnnotationSetRefList newAnnotationSetRefList = new AnnotationSetRefList(); 126 rawDexFile.annotationSetRefLists.add(newAnnotationSetRefList); 127 newAnnotationSetRefList.read(file); 128 } 129 break; 130 case MapItem.TYPE_ANNOTATION_SET_ITEM: 131 rawDexFile.annotationSetItems = new ArrayList<AnnotationSetItem>(mapItem.size); 132 for (int i = 0; i < mapItem.size; i++) { 133 AnnotationSetItem newAnnotationSetItem = new AnnotationSetItem(); 134 rawDexFile.annotationSetItems.add(newAnnotationSetItem); 135 newAnnotationSetItem.read(file); 136 } 137 break; 138 case MapItem.TYPE_CLASS_DATA_ITEM: 139 rawDexFile.classDatas = new ArrayList<ClassDataItem>(mapItem.size); 140 for (int i = 0; i < mapItem.size; i++) { 141 ClassDataItem newClassData = new ClassDataItem(); 142 rawDexFile.classDatas.add(newClassData); 143 newClassData.read(file); 144 } 145 break; 146 case MapItem.TYPE_CODE_ITEM: 147 rawDexFile.codeItems = new ArrayList<CodeItem>(mapItem.size); 148 for (int i = 0; i < mapItem.size; i++) { 149 CodeItem newCodeItem = new CodeItem(); 150 rawDexFile.codeItems.add(newCodeItem); 151 newCodeItem.read(file); 152 } 153 break; 154 case MapItem.TYPE_STRING_DATA_ITEM: 155 rawDexFile.stringDatas = new ArrayList<StringDataItem>(mapItem.size); 156 for (int i = 0; i < mapItem.size; i++) { 157 StringDataItem newStringData = new StringDataItem(); 158 rawDexFile.stringDatas.add(newStringData); 159 newStringData.read(file); 160 } 161 break; 162 case MapItem.TYPE_DEBUG_INFO_ITEM: 163 { 164 // We aren't interested in updating the debug data, so just read it as a blob. 165 int start = mapItem.offset.getOriginalOffset(); 166 int end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset(); 167 int size = end - start; 168 rawDexFile.debugInfoItem = new DebugInfoItem(size); 169 rawDexFile.debugInfoItem.read(file); 170 break; 171 } 172 case MapItem.TYPE_ANNOTATION_ITEM: 173 rawDexFile.annotationItems = new ArrayList<AnnotationItem>(mapItem.size); 174 for (int i = 0; i < mapItem.size; i++) { 175 AnnotationItem newAnnotationItem = new AnnotationItem(); 176 rawDexFile.annotationItems.add(newAnnotationItem); 177 newAnnotationItem.read(file); 178 } 179 break; 180 case MapItem.TYPE_ENCODED_ARRAY_ITEM: 181 rawDexFile.encodedArrayItems = new ArrayList<EncodedArrayItem>(mapItem.size); 182 for (int i = 0; i < mapItem.size; i++) { 183 EncodedArrayItem newEncodedArrayItem = new EncodedArrayItem(); 184 rawDexFile.encodedArrayItems.add(newEncodedArrayItem); 185 newEncodedArrayItem.read(file); 186 } 187 break; 188 case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM: 189 rawDexFile.annotationsDirectoryItems = 190 new ArrayList<AnnotationsDirectoryItem>(mapItem.size); 191 for (int i = 0; i < mapItem.size; i++) { 192 AnnotationsDirectoryItem newAnnotationsDirectoryItem = new AnnotationsDirectoryItem(); 193 rawDexFile.annotationsDirectoryItems.add(newAnnotationsDirectoryItem); 194 newAnnotationsDirectoryItem.read(file); 195 } 196 break; 197 default: 198 Log.errorAndQuit("Encountered unknown map item when reading map item list."); 199 } 200 mapItemIdx++; 201 } 202 } 203 204 @Override write(DexRandomAccessFile file)205 public void write(DexRandomAccessFile file) throws IOException { 206 file.alignForwards(4); 207 file.getOffsetTracker().updatePositionOfNextOffsettable(file); 208 file.writeUInt(mapItems.size()); 209 for (MapItem mapItem : mapItems) { 210 mapItem.write(file); 211 } 212 } 213 214 @Override incrementIndex(IndexUpdateKind kind, int insertedIdx)215 public void incrementIndex(IndexUpdateKind kind, int insertedIdx) { 216 // Do nothing. 217 } 218 } 219