/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dexfuzz.rawdex; import dexfuzz.Log; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class MapList implements RawDexObject { private RawDexFile rawDexFile; public int size; public List mapItems; public MapList(RawDexFile rawDexFile) { this.rawDexFile = rawDexFile; } @Override public void read(DexRandomAccessFile file) throws IOException { // Find the map list. file.seek(rawDexFile.header.mapOff.getOriginalOffset()); file.getOffsetTracker().getNewOffsettable(file, this); // Get the number of entries. size = file.readUInt(); // Allocate and populate the array. mapItems = new ArrayList(size); for (int i = 0; i < size; i++) { MapItem mapItem = new MapItem(); mapItems.add(mapItem); mapItem.read(file); } file.getOffsetTracker().rememberPointAfterMapList(); // NB: We track the current index into the MapList, so when we encounter the DebugInfoItem // MapItem, we know how to find the next MapItem, so we know how large the DebugInfo // area is, so we can copy it as a blob. int mapItemIdx = 0; // Iterate through the list, and create all the other data structures. for (MapItem mapItem : mapItems) { file.seek(mapItem.offset.getOriginalOffset()); switch (mapItem.type) { case MapItem.TYPE_HEADER_ITEM: // Already read it; skip. break; case MapItem.TYPE_STRING_ID_ITEM: for (int i = 0; i < mapItem.size; i++) { StringIdItem newStringId = new StringIdItem(); rawDexFile.stringIds.add(newStringId); newStringId.read(file); } break; case MapItem.TYPE_TYPE_ID_ITEM: for (int i = 0; i < mapItem.size; i++) { TypeIdItem newTypeId = new TypeIdItem(); rawDexFile.typeIds.add(newTypeId); newTypeId.read(file); } break; case MapItem.TYPE_PROTO_ID_ITEM: for (int i = 0; i < mapItem.size; i++) { ProtoIdItem newProtoId = new ProtoIdItem(); rawDexFile.protoIds.add(newProtoId); newProtoId.read(file); } break; case MapItem.TYPE_FIELD_ID_ITEM: for (int i = 0; i < mapItem.size; i++) { FieldIdItem newFieldId = new FieldIdItem(); rawDexFile.fieldIds.add(newFieldId); newFieldId.read(file); } break; case MapItem.TYPE_METHOD_ID_ITEM: for (int i = 0; i < mapItem.size; i++) { MethodIdItem newMethodId = new MethodIdItem(); rawDexFile.methodIds.add(newMethodId); newMethodId.read(file); } break; case MapItem.TYPE_CLASS_DEF_ITEM: for (int i = 0; i < mapItem.size; i++) { ClassDefItem newClassDef = new ClassDefItem(); rawDexFile.classDefs.add(newClassDef); newClassDef.read(file); } break; case MapItem.TYPE_MAP_LIST: // Already read it; skip. break; case MapItem.TYPE_TYPE_LIST: rawDexFile.typeLists = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { TypeList newTypeList = new TypeList(); rawDexFile.typeLists.add(newTypeList); newTypeList.read(file); } break; case MapItem.TYPE_ANNOTATION_SET_REF_LIST: rawDexFile.annotationSetRefLists = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { AnnotationSetRefList newAnnotationSetRefList = new AnnotationSetRefList(); rawDexFile.annotationSetRefLists.add(newAnnotationSetRefList); newAnnotationSetRefList.read(file); } break; case MapItem.TYPE_ANNOTATION_SET_ITEM: rawDexFile.annotationSetItems = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { AnnotationSetItem newAnnotationSetItem = new AnnotationSetItem(); rawDexFile.annotationSetItems.add(newAnnotationSetItem); newAnnotationSetItem.read(file); } break; case MapItem.TYPE_CLASS_DATA_ITEM: rawDexFile.classDatas = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { ClassDataItem newClassData = new ClassDataItem(); rawDexFile.classDatas.add(newClassData); newClassData.read(file); } break; case MapItem.TYPE_CODE_ITEM: rawDexFile.codeItems = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { CodeItem newCodeItem = new CodeItem(); rawDexFile.codeItems.add(newCodeItem); newCodeItem.read(file); } break; case MapItem.TYPE_STRING_DATA_ITEM: rawDexFile.stringDatas = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { StringDataItem newStringData = new StringDataItem(); rawDexFile.stringDatas.add(newStringData); newStringData.read(file); } break; case MapItem.TYPE_DEBUG_INFO_ITEM: { // We aren't interested in updating the debug data, so just read it as a blob. int start = mapItem.offset.getOriginalOffset(); int end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset(); int size = end - start; rawDexFile.debugInfoItem = new DebugInfoItem(size); rawDexFile.debugInfoItem.read(file); break; } case MapItem.TYPE_ANNOTATION_ITEM: rawDexFile.annotationItems = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { AnnotationItem newAnnotationItem = new AnnotationItem(); rawDexFile.annotationItems.add(newAnnotationItem); newAnnotationItem.read(file); } break; case MapItem.TYPE_ENCODED_ARRAY_ITEM: rawDexFile.encodedArrayItems = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { EncodedArrayItem newEncodedArrayItem = new EncodedArrayItem(); rawDexFile.encodedArrayItems.add(newEncodedArrayItem); newEncodedArrayItem.read(file); } break; case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM: rawDexFile.annotationsDirectoryItems = new ArrayList(mapItem.size); for (int i = 0; i < mapItem.size; i++) { AnnotationsDirectoryItem newAnnotationsDirectoryItem = new AnnotationsDirectoryItem(); rawDexFile.annotationsDirectoryItems.add(newAnnotationsDirectoryItem); newAnnotationsDirectoryItem.read(file); } break; default: Log.errorAndQuit("Encountered unknown map item when reading map item list."); } mapItemIdx++; } } @Override public void write(DexRandomAccessFile file) throws IOException { file.alignForwards(4); file.getOffsetTracker().updatePositionOfNextOffsettable(file); file.writeUInt(mapItems.size()); for (MapItem mapItem : mapItems) { mapItem.write(file); } } @Override public void incrementIndex(IndexUpdateKind kind, int insertedIdx) { // Do nothing. } }