1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.dex.file;
18
19import com.android.dx.rop.cst.Constant;
20import com.android.dx.rop.cst.CstNat;
21import com.android.dx.rop.cst.CstString;
22import com.android.dx.rop.cst.CstUtf8;
23import com.android.dx.util.AnnotatedOutput;
24import com.android.dx.util.Hex;
25
26import java.util.Collection;
27import java.util.TreeMap;
28
29/**
30 * Strings list section of a {@code .dex} file.
31 */
32public final class StringIdsSection
33        extends UniformItemSection {
34    /**
35     * {@code non-null;} map from string constants to {@link
36     * StringIdItem} instances
37     */
38    private final TreeMap<CstUtf8, StringIdItem> strings;
39
40    /**
41     * Constructs an instance. The file offset is initially unknown.
42     *
43     * @param file {@code non-null;} file that this instance is part of
44     */
45    public StringIdsSection(DexFile file) {
46        super("string_ids", file, 4);
47
48        strings = new TreeMap<CstUtf8, StringIdItem>();
49    }
50
51    /** {@inheritDoc} */
52    @Override
53    public Collection<? extends Item> items() {
54        return strings.values();
55    }
56
57    /** {@inheritDoc} */
58    @Override
59    public IndexedItem get(Constant cst) {
60        if (cst == null) {
61            throw new NullPointerException("cst == null");
62        }
63
64        throwIfNotPrepared();
65
66        if (cst instanceof CstString) {
67            cst = ((CstString) cst).getString();
68        }
69
70        IndexedItem result = strings.get((CstUtf8) cst);
71
72        if (result == null) {
73            throw new IllegalArgumentException("not found");
74        }
75
76        return result;
77    }
78
79    /**
80     * Writes the portion of the file header that refers to this instance.
81     *
82     * @param out {@code non-null;} where to write
83     */
84    public void writeHeaderPart(AnnotatedOutput out) {
85        throwIfNotPrepared();
86
87        int sz = strings.size();
88        int offset = (sz == 0) ? 0 : getFileOffset();
89
90        if (out.annotates()) {
91            out.annotate(4, "string_ids_size: " + Hex.u4(sz));
92            out.annotate(4, "string_ids_off:  " + Hex.u4(offset));
93        }
94
95        out.writeInt(sz);
96        out.writeInt(offset);
97    }
98
99    /**
100     * Interns an element into this instance.
101     *
102     * @param string {@code non-null;} the string to intern, as a regular Java
103     * {@code String}
104     * @return {@code non-null;} the interned string
105     */
106    public StringIdItem intern(String string) {
107        CstUtf8 utf8 = new CstUtf8(string);
108        return intern(new StringIdItem(utf8));
109    }
110
111    /**
112     * Interns an element into this instance.
113     *
114     * @param string {@code non-null;} the string to intern, as a {@link CstString}
115     * @return {@code non-null;} the interned string
116     */
117    public StringIdItem intern(CstString string) {
118        CstUtf8 utf8 = string.getString();
119        return intern(new StringIdItem(utf8));
120    }
121
122    /**
123     * Interns an element into this instance.
124     *
125     * @param string {@code non-null;} the string to intern, as a constant
126     * @return {@code non-null;} the interned string
127     */
128    public StringIdItem intern(CstUtf8 string) {
129        return intern(new StringIdItem(string));
130    }
131
132    /**
133     * Interns an element into this instance.
134     *
135     * @param string {@code non-null;} the string to intern
136     * @return {@code non-null;} the interned string
137     */
138    public StringIdItem intern(StringIdItem string) {
139        if (string == null) {
140            throw new NullPointerException("string == null");
141        }
142
143        throwIfPrepared();
144
145        CstUtf8 value = string.getValue();
146        StringIdItem already = strings.get(value);
147
148        if (already != null) {
149            return already;
150        }
151
152        strings.put(value, string);
153        return string;
154    }
155
156    /**
157     * Interns the components of a name-and-type into this instance.
158     *
159     * @param nat {@code non-null;} the name-and-type
160     */
161    public void intern(CstNat nat) {
162        intern(nat.getName());
163        intern(nat.getDescriptor());
164    }
165
166    /**
167     * Gets the index of the given string, which must have been added
168     * to this instance.
169     *
170     * @param string {@code non-null;} the string to look up
171     * @return {@code >= 0;} the string's index
172     */
173    public int indexOf(CstUtf8 string) {
174        if (string == null) {
175            throw new NullPointerException("string == null");
176        }
177
178        throwIfNotPrepared();
179
180        StringIdItem s = strings.get(string);
181
182        if (s == null) {
183            throw new IllegalArgumentException("not found");
184        }
185
186        return s.getIndex();
187    }
188
189    /**
190     * Gets the index of the given string, which must have been added
191     * to this instance.
192     *
193     * @param string {@code non-null;} the string to look up
194     * @return {@code >= 0;} the string's index
195     */
196    public int indexOf(CstString string) {
197        return indexOf(string.getString());
198    }
199
200    /** {@inheritDoc} */
201    @Override
202    protected void orderItems() {
203        int idx = 0;
204
205        for (StringIdItem s : strings.values()) {
206            s.setIndex(idx);
207            idx++;
208        }
209    }
210}
211