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