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.dx.dex.file;
18 
19 import com.android.dx.rop.cst.Constant;
20 import com.android.dx.rop.cst.CstNat;
21 import com.android.dx.rop.cst.CstString;
22 import com.android.dx.util.AnnotatedOutput;
23 import com.android.dx.util.Hex;
24 import java.util.Collection;
25 import java.util.TreeMap;
26 
27 /**
28  * Strings list section of a {@code .dex} file.
29  */
30 public final class StringIdsSection
31         extends UniformItemSection {
32     /**
33      * {@code non-null;} map from string constants to {@link
34      * StringIdItem} instances
35      */
36     private final TreeMap<CstString, StringIdItem> strings;
37 
38     /**
39      * Constructs an instance. The file offset is initially unknown.
40      *
41      * @param file {@code non-null;} file that this instance is part of
42      */
StringIdsSection(DexFile file)43     public StringIdsSection(DexFile file) {
44         super("string_ids", file, 4);
45 
46         strings = new TreeMap<CstString, StringIdItem>();
47     }
48 
49     /** {@inheritDoc} */
50     @Override
items()51     public Collection<? extends Item> items() {
52         return strings.values();
53     }
54 
55     /** {@inheritDoc} */
56     @Override
get(Constant cst)57     public IndexedItem get(Constant cst) {
58         if (cst == null) {
59             throw new NullPointerException("cst == null");
60         }
61 
62         throwIfNotPrepared();
63 
64         IndexedItem result = strings.get((CstString) cst);
65 
66         if (result == null) {
67             throw new IllegalArgumentException("not found");
68         }
69 
70         return result;
71     }
72 
73     /**
74      * Writes the portion of the file header that refers to this instance.
75      *
76      * @param out {@code non-null;} where to write
77      */
writeHeaderPart(AnnotatedOutput out)78     public void writeHeaderPart(AnnotatedOutput out) {
79         throwIfNotPrepared();
80 
81         int sz = strings.size();
82         int offset = (sz == 0) ? 0 : getFileOffset();
83 
84         if (out.annotates()) {
85             out.annotate(4, "string_ids_size: " + Hex.u4(sz));
86             out.annotate(4, "string_ids_off:  " + Hex.u4(offset));
87         }
88 
89         out.writeInt(sz);
90         out.writeInt(offset);
91     }
92 
93     /**
94      * Interns an element into this instance.
95      *
96      * @param string {@code non-null;} the string to intern, as a regular Java
97      * {@code String}
98      * @return {@code non-null;} the interned string
99      */
intern(String string)100     public StringIdItem intern(String string) {
101         return intern(new StringIdItem(new CstString(string)));
102     }
103 
104     /**
105      * Interns an element into this instance.
106      *
107      * @param string {@code non-null;} the string to intern, as a constant
108      * @return {@code non-null;} the interned string
109      */
intern(CstString string)110     public StringIdItem intern(CstString string) {
111         return intern(new StringIdItem(string));
112     }
113 
114     /**
115      * Interns an element into this instance.
116      *
117      * @param string {@code non-null;} the string to intern
118      * @return {@code non-null;} the interned string
119      */
intern(StringIdItem string)120     public synchronized StringIdItem intern(StringIdItem string) {
121         if (string == null) {
122             throw new NullPointerException("string == null");
123         }
124 
125         throwIfPrepared();
126 
127         CstString value = string.getValue();
128         StringIdItem already = strings.get(value);
129 
130         if (already != null) {
131             return already;
132         }
133 
134         strings.put(value, string);
135         return string;
136     }
137 
138     /**
139      * Interns the components of a name-and-type into this instance.
140      *
141      * @param nat {@code non-null;} the name-and-type
142      */
intern(CstNat nat)143     public synchronized void intern(CstNat nat) {
144         intern(nat.getName());
145         intern(nat.getDescriptor());
146     }
147 
148     /**
149      * Gets the index of the given string, which must have been added
150      * to this instance.
151      *
152      * @param string {@code non-null;} the string to look up
153      * @return {@code >= 0;} the string's index
154      */
indexOf(CstString string)155     public int indexOf(CstString string) {
156         if (string == null) {
157             throw new NullPointerException("string == null");
158         }
159 
160         throwIfNotPrepared();
161 
162         StringIdItem s = strings.get(string);
163 
164         if (s == null) {
165             throw new IllegalArgumentException("not found");
166         }
167 
168         return s.getIndex();
169     }
170 
171     /** {@inheritDoc} */
172     @Override
orderItems()173     protected void orderItems() {
174         int idx = 0;
175 
176         for (StringIdItem s : strings.values()) {
177             s.setIndex(idx);
178             idx++;
179         }
180     }
181 }
182