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 
17 package com.android.dexgen.dex.file;
18 
19 import com.android.dexgen.rop.cst.Constant;
20 import com.android.dexgen.rop.cst.CstNat;
21 import com.android.dexgen.rop.cst.CstString;
22 import com.android.dexgen.rop.cst.CstUtf8;
23 import com.android.dexgen.util.AnnotatedOutput;
24 import com.android.dexgen.util.Hex;
25 
26 import java.util.Collection;
27 import java.util.TreeMap;
28 
29 /**
30  * Strings list section of a {@code .dex} file.
31  */
32 public 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      */
StringIdsSection(DexFile file)45     public StringIdsSection(DexFile file) {
46         super("string_ids", file, 4);
47 
48         strings = new TreeMap<CstUtf8, StringIdItem>();
49     }
50 
51     /** {@inheritDoc} */
52     @Override
items()53     public Collection<? extends Item> items() {
54         return strings.values();
55     }
56 
57     /** {@inheritDoc} */
58     @Override
get(Constant cst)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      */
writeHeaderPart(AnnotatedOutput out)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      */
intern(String string)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      */
intern(CstString string)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      */
intern(CstUtf8 string)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      */
intern(StringIdItem string)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      */
intern(CstNat nat)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      */
indexOf(CstUtf8 string)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      */
indexOf(CstString string)196     public int indexOf(CstString string) {
197         return indexOf(string.getString());
198     }
199 
200     /** {@inheritDoc} */
201     @Override
orderItems()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