1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexFormat;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexOptions;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.Constant;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstBaseMethodRef;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstEnumRef;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstFieldRef;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ByteArrayAnnotatedOutput;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ExceptionWithContext;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.OutputStream;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.Writer;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.security.DigestException;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.security.MessageDigest;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.security.NoSuchAlgorithmException;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.zip.Adler32;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport static com.android.dx.dex.file.MixedItemSection.SortType;
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Representation of an entire {@code .dex} (Dalvik EXecutable)
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * file, which itself consists of a set of Dalvik classes.
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class DexFile {
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** options controlling the creation of the file */
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private DexOptions dexOptions;
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} word data section */
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection wordData;
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code non-null;} type lists section. This is word data, but separating
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * it from {@link #wordData} helps break what would otherwise be a
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * circular dependency between the that and {@link #protoIds}.
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection typeLists;
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code non-null;} map section. The map needs to be in a section by itself
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * for the self-reference mechanics to work in a reasonably
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * straightforward way. See {@link MapItem#addMap} for more detail.
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection map;
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} string data section */
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection stringData;
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} string identifiers section */
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final StringIdsSection stringIds;
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} type identifiers section */
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final TypeIdsSection typeIds;
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} prototype identifiers section */
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final ProtoIdsSection protoIds;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} field identifiers section */
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final FieldIdsSection fieldIds;
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} method identifiers section */
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MethodIdsSection methodIds;
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} class definitions section */
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final ClassDefsSection classDefs;
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} class data section */
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection classData;
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} byte data section */
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MixedItemSection byteData;
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} file header */
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final HeaderSection header;
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code non-null;} array of sections in the order they will appear in the
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * final output file
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Section[] sections;
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code >= -1;} total file size or {@code -1} if unknown */
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int fileSize;
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code >= 40;} maximum width of the file dump */
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int dumpWidth;
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. It is initially empty.
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DexFile(DexOptions dexOptions) {
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.dexOptions = dexOptions;
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        header = new HeaderSection(this);
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeLists = new MixedItemSection(null, this, 4, SortType.NONE);
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE);
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        stringData =
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            new MixedItemSection("string_data", this, 1, SortType.INSTANCE);
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        classData = new MixedItemSection(null, this, 1, SortType.NONE);
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE);
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        stringIds = new StringIdsSection(this);
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeIds = new TypeIdsSection(this);
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protoIds = new ProtoIdsSection(this);
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fieldIds = new FieldIdsSection(this);
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        methodIds = new MethodIdsSection(this);
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        classDefs = new ClassDefsSection(this);
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        map = new MixedItemSection("map", this, 4, SortType.NONE);
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * This is the list of sections in the order they appear in
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the final output.
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sections = new Section[] {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            header, stringIds, typeIds, protoIds, fieldIds, methodIds,
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            classDefs, wordData, typeLists, stringData, byteData,
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            classData, map };
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fileSize = -1;
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        dumpWidth = 79;
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns true if this dex doesn't contain any class defs.
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean isEmpty() {
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return classDefs.items().isEmpty();
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the dex-creation options object.
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DexOptions getDexOptions() {
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return dexOptions;
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Adds a class to this instance. It is illegal to attempt to add more
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * than one class with the same name.
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param clazz {@code non-null;} the class to add
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void add(ClassDefItem clazz) {
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        classDefs.add(clazz);
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the class definition with the given name, if any.
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param name {@code non-null;} the class name to look for
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the class with the given name, or {@code null}
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * if there is no such class
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public ClassDefItem getClassOrNull(String name) {
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Type type = Type.internClassName(name);
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return (ClassDefItem) classDefs.get(new CstType(type));
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException ex) {
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Translate exception, per contract.
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Writes the contents of this instance as either a binary or a
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * human-readable form, or both.
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code null-ok;} where to write to
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param humanOut {@code null-ok;} where to write human-oriented output to
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param verbose whether to be verbose when writing human-oriented output
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void writeTo(OutputStream out, Writer humanOut, boolean verbose)
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throws IOException {
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean annotate = (humanOut != null);
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (out != null) {
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.write(result.getArray());
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotate) {
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.writeAnnotationsTo(humanOut);
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the contents of this instance as a {@code .dex} file,
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in {@code byte[]} form.
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param humanOut {@code null-ok;} where to write human-oriented output to
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param verbose whether to be verbose when writing human-oriented output
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} a {@code .dex} file for this instance
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public byte[] toDex(Writer humanOut, boolean verbose)
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throws IOException {
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean annotate = (humanOut != null);
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotate) {
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.writeAnnotationsTo(humanOut);
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result.getArray();
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Sets the maximum width of the human-oriented dump of the instance.
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dumpWidth {@code >= 40;} the width
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void setDumpWidth(int dumpWidth) {
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (dumpWidth < 40) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("dumpWidth < 40");
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.dumpWidth = dumpWidth;
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the total file size, if known.
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the {@link HeaderSection} to set itself up properly.</p>
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the total file size
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws RuntimeException thrown if the file size is not yet known
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ int getFileSize() {
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (fileSize < 0) {
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("file size not yet known");
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return fileSize;
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the string data section.
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the string data section
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getStringData() {
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return stringData;
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the word data section.
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the word data section
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getWordData() {
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return wordData;
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the type lists section.
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the word data section
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getTypeLists() {
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return typeLists;
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the map section.
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow the header section
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to query it.</p>
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the map section
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getMap() {
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return map;
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the string identifiers section.
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the string identifiers section
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ StringIdsSection getStringIds() {
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return stringIds;
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the class definitions section.
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the class definitions section
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ ClassDefsSection getClassDefs() {
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return classDefs;
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the class data section.
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the class data section
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getClassData() {
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return classData;
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the type identifiers section.
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the class identifiers section
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ TypeIdsSection getTypeIds() {
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return typeIds;
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the prototype identifiers section.
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the prototype identifiers section
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ ProtoIdsSection getProtoIds() {
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return protoIds;
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the field identifiers section.
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the field identifiers section
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ FieldIdsSection getFieldIds() {
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return fieldIds;
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the method identifiers section.
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the method identifiers section
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MethodIdsSection getMethodIds() {
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return methodIds;
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the byte data section.
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the various {@link Item} instances to add items to the
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance.</p>
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the byte data section
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ MixedItemSection getByteData() {
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return byteData;
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the first section of the file that is to be considered
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * part of the data section.
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow the header section
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to query it.</p>
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the section
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ Section getFirstDataSection() {
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return wordData;
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the last section of the file that is to be considered
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * part of the data section.
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>This is package-scope in order to allow the header section
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to query it.</p>
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the section
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ Section getLastDataSection() {
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return map;
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Interns the given constant in the appropriate section of this
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance, or do nothing if the given constant isn't the sort
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * that should be interned.
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param cst {@code non-null;} constant to possibly intern
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ void internIfAppropriate(Constant cst) {
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (cst instanceof CstString) {
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            stringIds.intern((CstString) cst);
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstType) {
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            typeIds.intern((CstType) cst);
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstBaseMethodRef) {
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            methodIds.intern((CstBaseMethodRef) cst);
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstFieldRef) {
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fieldIds.intern((CstFieldRef) cst);
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstEnumRef) {
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fieldIds.intern(((CstEnumRef) cst).getFieldRef());
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst == null) {
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("cst == null");
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the {@link IndexedItem} corresponding to the given constant,
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * if it is a constant that has such a correspondence, or return
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null} if it isn't such a constant. This will throw
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * an exception if the given constant <i>should</i> have been found
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * but wasn't.
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param cst {@code non-null;} the constant to look up
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} its corresponding item, if it has a corresponding
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * item, or {@code null} if it's not that sort of constant
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /*package*/ IndexedItem findItemOrNull(Constant cst) {
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        IndexedItem item;
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (cst instanceof CstString) {
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return stringIds.get(cst);
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstType) {
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return typeIds.get(cst);
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstBaseMethodRef) {
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return methodIds.get(cst);
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (cst instanceof CstFieldRef) {
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return fieldIds.get(cst);
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the contents of this instance as a {@code .dex} file,
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in a {@link ByteArrayAnnotatedOutput} instance.
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotate whether or not to keep annotations
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param verbose if annotating, whether to be verbose
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} a {@code .dex} file for this instance
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private ByteArrayAnnotatedOutput toDex0(boolean annotate,
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean verbose) {
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * The following is ordered so that the prepare() calls which
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * add items happen before the calls to the sections that get
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * added to.
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        classDefs.prepare();
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        classData.prepare();
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        wordData.prepare();
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byteData.prepare();
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        methodIds.prepare();
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fieldIds.prepare();
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protoIds.prepare();
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeLists.prepare();
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeIds.prepare();
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        stringIds.prepare();
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        stringData.prepare();
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        header.prepare();
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Place the sections within the file.
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int count = sections.length;
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int offset = 0;
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < count; i++) {
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Section one = sections[i];
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int placedAt = one.setFileOffset(offset);
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (placedAt < offset) {
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("bogus placement for section " + i);
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            try {
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (one == map) {
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * Inform the map of all the sections, and add it
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * to the file. This can only be done after all
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * the other items have been sorted and placed.
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    MapItem.addMap(sections, map);
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    map.prepare();
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (one instanceof MixedItemSection) {
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * Place the items of a MixedItemSection that just
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * got placed.
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ((MixedItemSection) one).placeItems();
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                offset = placedAt + one.writeSize();
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } catch (RuntimeException ex) {
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw ExceptionWithContext.withContext(ex,
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        "...while writing section " + i);
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Write out all the sections.
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fileSize = offset;
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byte[] barr = new byte[fileSize];
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr);
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotate) {
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.enableAnnotations(dumpWidth, verbose);
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < count; i++) {
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            try {
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Section one = sections[i];
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int zeroCount = one.getFileOffset() - out.getCursor();
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (zeroCount < 0) {
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new ExceptionWithContext("excess write of " +
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            (-zeroCount));
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeZeroes(one.getFileOffset() - out.getCursor());
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                one.writeTo(out);
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } catch (RuntimeException ex) {
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                ExceptionWithContext ec;
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (ex instanceof ExceptionWithContext) {
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ec = (ExceptionWithContext) ex;
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else {
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ec = new ExceptionWithContext(ex);
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                ec.addContext("...while writing section " + i);
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw ec;
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (out.getCursor() != fileSize) {
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("foreshortened write");
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Perform final bookkeeping.
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        calcSignature(barr);
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        calcChecksum(barr);
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotate) {
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM,
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "\nmethod code index:\n\n");
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            getStatistics().writeAnnotation(out);
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.finishAnnotating();
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return out;
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Generates and returns statistics for all the items in the file.
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the statistics
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Statistics getStatistics() {
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Statistics stats = new Statistics();
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Section s : sections) {
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            stats.addAll(s);
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return stats;
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Calculates the signature for the {@code .dex} file in the
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given array, and modify the array to contain it.
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param bytes {@code non-null;} the bytes of the file
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void calcSignature(byte[] bytes) {
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MessageDigest md;
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            md = MessageDigest.getInstance("SHA-1");
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (NoSuchAlgorithmException ex) {
631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(ex);
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        md.update(bytes, 32, bytes.length - 32);
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int amt = md.digest(bytes, 12, 20);
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (amt != 20) {
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("unexpected digest write: " + amt +
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                           " bytes");
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (DigestException ex) {
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(ex);
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Calculates the checksum for the {@code .dex} file in the
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given array, and modify the array to contain it.
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param bytes {@code non-null;} the bytes of the file
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void calcChecksum(byte[] bytes) {
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Adler32 a32 = new Adler32();
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        a32.update(bytes, 12, bytes.length - 12);
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sum = (int) a32.getValue();
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        bytes[8]  = (byte) sum;
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        bytes[9]  = (byte) (sum >> 8);
662579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        bytes[10] = (byte) (sum >> 16);
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        bytes[11] = (byte) (sum >> 24);
664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
666