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
17package dexfuzz.rawdex;
18
19import dexfuzz.Log;
20
21import java.io.IOException;
22import java.util.ArrayList;
23import java.util.List;
24
25public class MapList implements RawDexObject {
26
27  private RawDexFile rawDexFile;
28
29  public int size;
30  public List<MapItem> mapItems;
31
32  public MapList(RawDexFile rawDexFile) {
33    this.rawDexFile = rawDexFile;
34  }
35
36  @Override
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
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
215  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
216    // Do nothing.
217  }
218}
219