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