1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/*
2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project
3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License");
5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License.
6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at
7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *      http://www.apache.org/licenses/LICENSE-2.0
9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software
11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS,
12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and
14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License.
15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */
16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.rawdex;
18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log;
20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.IOException;
22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList;
23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List;
24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class RawDexFile implements RawDexObject {
26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private OffsetTracker offsetTracker;
27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public HeaderItem header;
29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public MapList mapList;
31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // Can be allocated after reading the header.
33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<StringIdItem> stringIds;
34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<TypeIdItem> typeIds;
35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<ProtoIdItem> protoIds;
36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<FieldIdItem> fieldIds;
37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<MethodIdItem> methodIds;
38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<ClassDefItem> classDefs;
39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // Need to be allocated later (will be allocated in MapList.java)
41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<StringDataItem> stringDatas;
42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<ClassDataItem> classDatas;
43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<TypeList> typeLists;
44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<CodeItem> codeItems;
45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public DebugInfoItem debugInfoItem;
46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<AnnotationsDirectoryItem> annotationsDirectoryItems;
47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<AnnotationSetRefList> annotationSetRefLists;
48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<AnnotationSetItem> annotationSetItems;
49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<AnnotationItem> annotationItems;
50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<EncodedArrayItem> encodedArrayItems;
51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void read(DexRandomAccessFile file) throws IOException {
54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Get a reference to the OffsetTracker, so that IdCreator can use it.
55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    offsetTracker = file.getOffsetTracker();
56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(0);
58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Read header.
60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    (header = new HeaderItem()).read(file);
61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // We can allocate all of these now.
63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    stringIds = new ArrayList<StringIdItem>(header.stringIdsSize);
64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    typeIds = new ArrayList<TypeIdItem>(header.typeIdsSize);
65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    protoIds = new ArrayList<ProtoIdItem>(header.protoIdsSize);
66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    fieldIds = new ArrayList<FieldIdItem>(header.fieldIdsSize);
67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    methodIds = new ArrayList<MethodIdItem>(header.methodIdsSize);
68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    classDefs = new ArrayList<ClassDefItem>(header.classDefsSize);
69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mapList = new MapList(this);
71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mapList.read(file);
72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.getOffsetTracker().associateOffsets();
74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void write(DexRandomAccessFile file) throws IOException {
78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(0);
79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // We read the header first, and then the map list, and then everything
81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // else. Therefore, when we get to the end of the header, tell OffsetTracker
82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // to skip past the map list offsets, and then when we get to the map list,
83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // tell OffsetTracker to skip back there, and then return to where it was previously.
84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Update the map items' sizes first
86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // - but only update the items that we expect to have changed size.
87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // ALSO update the header's table sizes!
88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MapItem mapItem : mapList.mapItems) {
89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      switch (mapItem.type) {
90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_STRING_ID_ITEM:
91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != stringIds.size()) {
92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating StringIDs List size: " + stringIds.size());
93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = stringIds.size();
94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            header.stringIdsSize = stringIds.size();
95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_STRING_DATA_ITEM:
98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != stringDatas.size()) {
99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating StringDatas List size: " + stringDatas.size());
100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = stringDatas.size();
101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_METHOD_ID_ITEM:
104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != methodIds.size()) {
105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating MethodIDs List size: " + methodIds.size());
106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = methodIds.size();
107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            header.methodIdsSize = methodIds.size();
108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_FIELD_ID_ITEM:
111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != fieldIds.size()) {
112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating FieldIDs List size: " + fieldIds.size());
113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = fieldIds.size();
114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            header.fieldIdsSize = fieldIds.size();
115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_PROTO_ID_ITEM:
118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != protoIds.size()) {
119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating ProtoIDs List size: " + protoIds.size());
120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = protoIds.size();
121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            header.protoIdsSize = protoIds.size();
122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_TYPE_ID_ITEM:
125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != typeIds.size()) {
126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating TypeIDs List size: " + typeIds.size());
127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = typeIds.size();
128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            header.typeIdsSize = typeIds.size();
129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_TYPE_LIST:
132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != typeLists.size()) {
133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.debug("Updating TypeLists List size: " + typeLists.size());
134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mapItem.size = typeLists.size();
135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        default:
138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Use the map list to write the file.
142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MapItem mapItem : mapList.mapItems) {
143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      switch (mapItem.type) {
144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_HEADER_ITEM:
145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          header.write(file);
146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          file.getOffsetTracker().skipToAfterMapList();
147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_STRING_ID_ITEM:
149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != stringIds.size()) {
150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches StringIDs table size " + stringIds.size());
152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (StringIdItem stringId : stringIds) {
154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            stringId.write(file);
155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_TYPE_ID_ITEM:
158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != typeIds.size()) {
159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches TypeIDs table size " + typeIds.size());
161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (TypeIdItem typeId : typeIds) {
163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            typeId.write(file);
164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_PROTO_ID_ITEM:
167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != protoIds.size()) {
168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches ProtoIDs table size " + protoIds.size());
170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (ProtoIdItem protoId : protoIds) {
172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            protoId.write(file);
173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_FIELD_ID_ITEM:
176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != fieldIds.size()) {
177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches FieldIDs table size " + fieldIds.size());
179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (FieldIdItem fieldId : fieldIds) {
181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            fieldId.write(file);
182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_METHOD_ID_ITEM:
185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != methodIds.size()) {
186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches MethodIDs table size " + methodIds.size());
188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (MethodIdItem methodId : methodIds) {
190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            methodId.write(file);
191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_CLASS_DEF_ITEM:
194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != classDefs.size()) {
195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches ClassDefs table size " + classDefs.size());
197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (ClassDefItem classDef : classDefs) {
199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            classDef.write(file);
200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_MAP_LIST:
203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          file.getOffsetTracker().goBackToMapList();
204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          mapList.write(file);
205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          file.getOffsetTracker().goBackToPreviousPoint();
206959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
207959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_TYPE_LIST:
208959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != typeLists.size()) {
209959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
210959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches TypeLists table size " + typeLists.size());
211959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
212959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (TypeList typeList : typeLists) {
213959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            typeList.write(file);
214959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
215959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
216959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_ANNOTATION_SET_REF_LIST:
217959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != annotationSetRefLists.size()) {
218959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
219959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches AnnotationSetRefLists table size "
220959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + annotationSetRefLists.size());
221959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
222959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (AnnotationSetRefList annotationSetRefList : annotationSetRefLists) {
223959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            annotationSetRefList.write(file);
224959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
225959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
226959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_ANNOTATION_SET_ITEM:
227959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != annotationSetItems.size()) {
228959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
229959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches AnnotationSetItems table size "
230959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + annotationSetItems.size());
231959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
232959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (AnnotationSetItem annotationSetItem : annotationSetItems) {
233959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            annotationSetItem.write(file);
234959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
235959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
236959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_CLASS_DATA_ITEM:
237959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != classDatas.size()) {
238959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
239959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches ClassDataItems table size " + classDatas.size());
240959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
241959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (ClassDataItem classData : classDatas) {
242959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            classData.write(file);
243959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
244959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
245959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_CODE_ITEM:
246959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != codeItems.size()) {
247959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
248959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches CodeItems table size " + codeItems.size());
249959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
250959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (CodeItem codeItem : codeItems) {
251959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            codeItem.write(file);
252959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
253959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
254959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_STRING_DATA_ITEM:
255959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != stringDatas.size()) {
256959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
257959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches StringDataItems table size "
258959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + stringDatas.size());
259959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
260959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (StringDataItem stringDataItem : stringDatas) {
261959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            stringDataItem.write(file);
262959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
263959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
264959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_DEBUG_INFO_ITEM:
265959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          debugInfoItem.write(file);
266959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
267959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_ANNOTATION_ITEM:
268959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != annotationItems.size()) {
269959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
270959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches AnnotationItems table size "
271959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + annotationItems.size());
272959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
273959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (AnnotationItem annotationItem : annotationItems) {
274959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            annotationItem.write(file);
275959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
276959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
277959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_ENCODED_ARRAY_ITEM:
278959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != encodedArrayItems.size()) {
279959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
280959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches EncodedArrayItems table size "
281959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + encodedArrayItems.size());
282959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
283959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (EncodedArrayItem encodedArrayItem : encodedArrayItems) {
284959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            encodedArrayItem.write(file);
285959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
286959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
287959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM:
288959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (mapItem.size != annotationsDirectoryItems.size()) {
289959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            Log.errorAndQuit("MapItem's size " + mapItem.size
290959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + " no longer matches AnnotationDirectoryItems table size "
291959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                + annotationsDirectoryItems.size());
292959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
293959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          for (AnnotationsDirectoryItem annotationsDirectory : annotationsDirectoryItems) {
294959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            annotationsDirectory.write(file);
295959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
296959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
297959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        default:
298959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit("Encountered unknown map item in map item list.");
299959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
300959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
301959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
302959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.getOffsetTracker().updateOffsets(file);
303959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
304959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
305959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
306959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a DexRandomAccessFile, calculate the correct adler32 checksum for it.
307959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
308959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private int calculateAdler32Checksum(DexRandomAccessFile file) throws IOException {
309959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Skip magic + checksum.
310959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(12);
311959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int a = 1;
312959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b = 0;
313959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (file.getFilePointer() < file.length()) {
314959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      a = (a + file.readUnsignedByte()) % 65521;
315959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      b = (b + a) % 65521;
316959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
317959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return (b << 16) | a;
318959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
319959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
320959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
321959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a DexRandomAccessFile, update the file size, data size, and checksum.
322959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
323959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void updateHeader(DexRandomAccessFile file) throws IOException {
324959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // File size must be updated before checksum.
325959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int newFileSize = (int) file.length();
326959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(32);
327959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUInt(newFileSize);
328959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
329959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Data size must be updated before checksum.
330959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int newDataSize = newFileSize - header.dataOff.getNewPositionOfItem();
331959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(104);
332959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUInt(newDataSize);
333959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
334959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now update the checksum.
335959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int newChecksum = calculateAdler32Checksum(file);
336959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.seek(8);
337959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUInt(newChecksum);
338959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
339959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    header.fileSize = newFileSize;
340959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    header.dataSize = newDataSize;
341959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    header.checksum = newChecksum;
342959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
343959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
344959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
345959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * This should only be called from NewItemCreator.
346959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
347959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public OffsetTracker getOffsetTracker() {
348959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return offsetTracker;
349959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
350959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
351959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
352959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
353959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (TypeIdItem typeId : typeIds) {
354959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      typeId.incrementIndex(kind, insertedIdx);
355959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
356959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (ProtoIdItem protoId : protoIds) {
357959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      protoId.incrementIndex(kind, insertedIdx);
358959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
359959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (FieldIdItem fieldId : fieldIds) {
360959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      fieldId.incrementIndex(kind, insertedIdx);
361959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
362959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MethodIdItem methodId : methodIds) {
363959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      methodId.incrementIndex(kind, insertedIdx);
364959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
365959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (ClassDefItem classDef : classDefs) {
366959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      classDef.incrementIndex(kind, insertedIdx);
367959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
368959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (ClassDataItem classData : classDatas) {
369959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      classData.incrementIndex(kind, insertedIdx);
370959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
371959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (typeLists != null) {
372959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (TypeList typeList : typeLists) {
373959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        typeList.incrementIndex(kind, insertedIdx);
374959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
375959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
376959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (CodeItem codeItem : codeItems) {
377959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      codeItem.incrementIndex(kind, insertedIdx);
378959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
379959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (annotationsDirectoryItems != null) {
380959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (AnnotationsDirectoryItem annotationsDirectoryItem : annotationsDirectoryItems) {
381959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        annotationsDirectoryItem.incrementIndex(kind, insertedIdx);
382959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
383959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
384959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (annotationItems != null) {
385959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (AnnotationItem annotationItem : annotationItems) {
386959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        annotationItem.incrementIndex(kind, insertedIdx);
387959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
388959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
389959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
390959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle}
391