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 long start = mapItem.offset.getOriginalOffset(); 166 long end = 0; 167 if (mapItemIdx + 1 == mapItems.size()) { 168 end = file.length(); 169 } else { 170 end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset(); 171 } 172 long size = end - start; 173 rawDexFile.debugInfoItem = new DebugInfoItem((int)size); 174 rawDexFile.debugInfoItem.read(file); 175 break; 176 } 177 case MapItem.TYPE_ANNOTATION_ITEM: 178 rawDexFile.annotationItems = new ArrayList<AnnotationItem>(mapItem.size); 179 for (int i = 0; i < mapItem.size; i++) { 180 AnnotationItem newAnnotationItem = new AnnotationItem(); 181 rawDexFile.annotationItems.add(newAnnotationItem); 182 newAnnotationItem.read(file); 183 } 184 break; 185 case MapItem.TYPE_ENCODED_ARRAY_ITEM: 186 rawDexFile.encodedArrayItems = new ArrayList<EncodedArrayItem>(mapItem.size); 187 for (int i = 0; i < mapItem.size; i++) { 188 EncodedArrayItem newEncodedArrayItem = new EncodedArrayItem(); 189 rawDexFile.encodedArrayItems.add(newEncodedArrayItem); 190 newEncodedArrayItem.read(file); 191 } 192 break; 193 case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM: 194 rawDexFile.annotationsDirectoryItems = 195 new ArrayList<AnnotationsDirectoryItem>(mapItem.size); 196 for (int i = 0; i < mapItem.size; i++) { 197 AnnotationsDirectoryItem newAnnotationsDirectoryItem = new AnnotationsDirectoryItem(); 198 rawDexFile.annotationsDirectoryItems.add(newAnnotationsDirectoryItem); 199 newAnnotationsDirectoryItem.read(file); 200 } 201 break; 202 default: 203 Log.errorAndQuit("Encountered unknown map item when reading map item list."); 204 } 205 mapItemIdx++; 206 } 207 } 208 209 @Override write(DexRandomAccessFile file)210 public void write(DexRandomAccessFile file) throws IOException { 211 file.alignForwards(4); 212 file.getOffsetTracker().updatePositionOfNextOffsettable(file); 213 file.writeUInt(mapItems.size()); 214 for (MapItem mapItem : mapItems) { 215 mapItem.write(file); 216 } 217 } 218 219 @Override incrementIndex(IndexUpdateKind kind, int insertedIdx)220 public void incrementIndex(IndexUpdateKind kind, int insertedIdx) { 221 // Do nothing. 222 } 223 } 224