1 /*
2 * Copyright (C) 2015 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 #ifndef AAPT_RESOURCE_H
18 #define AAPT_RESOURCE_H
19
20 #include <iomanip>
21 #include <limits>
22 #include <sstream>
23 #include <string>
24 #include <tuple>
25 #include <vector>
26
27 #include "androidfw/StringPiece.h"
28 #include "utils/JenkinsHash.h"
29
30 #include "ConfigDescription.h"
31 #include "Source.h"
32
33 namespace aapt {
34
35 /**
36 * The various types of resource types available. Corresponds
37 * to the 'type' in package:type/entry.
38 */
39 enum class ResourceType {
40 kAnim,
41 kAnimator,
42 kArray,
43 kAttr,
44 kAttrPrivate,
45 kBool,
46 kColor,
47
48 // Not really a type, but it shows up in some CTS tests and
49 // we need to continue respecting it.
50 kConfigVarying,
51
52 kDimen,
53 kDrawable,
54 kFont,
55 kFraction,
56 kId,
57 kInteger,
58 kInterpolator,
59 kLayout,
60 kMenu,
61 kMipmap,
62 kNavigation,
63 kPlurals,
64 kRaw,
65 kString,
66 kStyle,
67 kStyleable,
68 kTransition,
69 kXml,
70 };
71
72 android::StringPiece ToString(ResourceType type);
73
74 /**
75 * Returns a pointer to a valid ResourceType, or nullptr if
76 * the string was invalid.
77 */
78 const ResourceType* ParseResourceType(const android::StringPiece& str);
79
80 /**
81 * A resource's name. This can uniquely identify
82 * a resource in the ResourceTable.
83 */
84 struct ResourceName {
85 std::string package;
86 ResourceType type = ResourceType::kRaw;
87 std::string entry;
88
89 ResourceName() = default;
90 ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
91
92 int compare(const ResourceName& other) const;
93
94 bool is_valid() const;
95 std::string ToString() const;
96 };
97
98 /**
99 * Same as ResourceName, but uses StringPieces instead.
100 * Use this if you need to avoid copying and know that
101 * the lifetime of this object is shorter than that
102 * of the original string.
103 */
104 struct ResourceNameRef {
105 android::StringPiece package;
106 ResourceType type = ResourceType::kRaw;
107 android::StringPiece entry;
108
109 ResourceNameRef() = default;
110 ResourceNameRef(const ResourceNameRef&) = default;
111 ResourceNameRef(ResourceNameRef&&) = default;
112 ResourceNameRef(const ResourceName& rhs); // NOLINT(implicit)
113 ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
114 ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
115 ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
116 ResourceNameRef& operator=(const ResourceName& rhs);
117
118 ResourceName ToResourceName() const;
119 bool is_valid() const;
120 };
121
122 constexpr const uint8_t kAppPackageId = 0x7fu;
123 constexpr const uint8_t kFrameworkPackageId = 0x01u;
124
125 /**
126 * A binary identifier representing a resource. Internally it
127 * is a 32bit integer split as follows:
128 *
129 * 0xPPTTEEEE
130 *
131 * PP: 8 bit package identifier. 0x01 is reserved for system
132 * and 0x7f is reserved for the running app.
133 * TT: 8 bit type identifier. 0x00 is invalid.
134 * EEEE: 16 bit entry identifier.
135 */
136 struct ResourceId {
137 uint32_t id;
138
139 ResourceId();
140 ResourceId(const ResourceId& rhs);
141 ResourceId(uint32_t res_id); // NOLINT(implicit)
142 ResourceId(uint8_t p, uint8_t t, uint16_t e);
143
144 bool is_valid() const;
145
146 // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
147 bool is_valid_dynamic() const;
148
149 uint8_t package_id() const;
150 uint8_t type_id() const;
151 uint16_t entry_id() const;
152 };
153
154 struct SourcedResourceName {
155 ResourceName name;
156 size_t line;
157 };
158
159 struct ResourceFile {
160 // Name
161 ResourceName name;
162
163 // Configuration
164 ConfigDescription config;
165
166 // Source
167 Source source;
168
169 // Exported symbols
170 std::vector<SourcedResourceName> exported_symbols;
171 };
172
173 /**
174 * Useful struct used as a key to represent a unique resource in associative
175 * containers.
176 */
177 struct ResourceKey {
178 ResourceName name;
179 ConfigDescription config;
180 };
181
182 bool operator<(const ResourceKey& a, const ResourceKey& b);
183
184 /**
185 * Useful struct used as a key to represent a unique resource in associative
186 * containers.
187 * Holds a reference to the name, so that name better live longer than this key!
188 */
189 struct ResourceKeyRef {
190 ResourceNameRef name;
191 ConfigDescription config;
192
193 ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef194 ResourceKeyRef(const ResourceNameRef& n, const ConfigDescription& c)
195 : name(n), config(c) {}
196
197 /**
198 * Prevent taking a reference to a temporary. This is bad.
199 */
200 ResourceKeyRef(ResourceName&& n, const ConfigDescription& c) = delete;
201 };
202
203 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
204
205 //
206 // ResourceId implementation.
207 //
208
ResourceId()209 inline ResourceId::ResourceId() : id(0) {}
210
ResourceId(const ResourceId & rhs)211 inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {}
212
ResourceId(uint32_t res_id)213 inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
214
ResourceId(uint8_t p,uint8_t t,uint16_t e)215 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
216 : id((p << 24) | (t << 16) | e) {}
217
is_valid()218 inline bool ResourceId::is_valid() const {
219 return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
220 }
221
is_valid_dynamic()222 inline bool ResourceId::is_valid_dynamic() const { return (id & 0x00ff0000u) != 0; }
223
package_id()224 inline uint8_t ResourceId::package_id() const {
225 return static_cast<uint8_t>(id >> 24);
226 }
227
type_id()228 inline uint8_t ResourceId::type_id() const {
229 return static_cast<uint8_t>(id >> 16);
230 }
231
entry_id()232 inline uint16_t ResourceId::entry_id() const {
233 return static_cast<uint16_t>(id);
234 }
235
236 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
237 return lhs.id < rhs.id;
238 }
239
240 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
241 return lhs.id > rhs.id;
242 }
243
244 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
245 return lhs.id == rhs.id;
246 }
247
248 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
249 return lhs.id != rhs.id;
250 }
251
252 inline ::std::ostream& operator<<(::std::ostream& out,
253 const ResourceId& res_id) {
254 std::ios_base::fmtflags old_flags = out.flags();
255 char old_fill = out.fill();
256 out << "0x" << std::internal << std::setfill('0') << std::setw(8) << std::hex
257 << res_id.id;
258 out.flags(old_flags);
259 out.fill(old_fill);
260 return out;
261 }
262
263 //
264 // ResourceType implementation.
265 //
266
267 inline ::std::ostream& operator<<(::std::ostream& out,
268 const ResourceType& val) {
269 return out << ToString(val);
270 }
271
272 //
273 // ResourceName implementation.
274 //
275
ResourceName(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)276 inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
277 const android::StringPiece& e)
278 : package(p.to_string()), type(t), entry(e.to_string()) {}
279
compare(const ResourceName & other)280 inline int ResourceName::compare(const ResourceName& other) const {
281 int cmp = package.compare(other.package);
282 if (cmp != 0) return cmp;
283 cmp = static_cast<int>(type) - static_cast<int>(other.type);
284 if (cmp != 0) return cmp;
285 cmp = entry.compare(other.entry);
286 return cmp;
287 }
288
is_valid()289 inline bool ResourceName::is_valid() const {
290 return !package.empty() && !entry.empty();
291 }
292
293 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
294 return std::tie(lhs.package, lhs.type, lhs.entry) <
295 std::tie(rhs.package, rhs.type, rhs.entry);
296 }
297
298 inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
299 return std::tie(lhs.package, lhs.type, lhs.entry) ==
300 std::tie(rhs.package, rhs.type, rhs.entry);
301 }
302
303 inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
304 return std::tie(lhs.package, lhs.type, lhs.entry) !=
305 std::tie(rhs.package, rhs.type, rhs.entry);
306 }
307
308 inline ::std::ostream& operator<<(::std::ostream& out,
309 const ResourceName& name) {
310 if (!name.package.empty()) {
311 out << name.package << ":";
312 }
313 return out << name.type << "/" << name.entry;
314 }
315
ToString()316 inline std::string ResourceName::ToString() const {
317 std::stringstream stream;
318 stream << *this;
319 return stream.str();
320 }
321
322 //
323 // ResourceNameRef implementation.
324 //
325
ResourceNameRef(const ResourceName & rhs)326 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
327 : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
328
ResourceNameRef(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)329 inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
330 const android::StringPiece& e)
331 : package(p), type(t), entry(e) {}
332
333 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
334 package = rhs.package;
335 type = rhs.type;
336 entry = rhs.entry;
337 return *this;
338 }
339
ToResourceName()340 inline ResourceName ResourceNameRef::ToResourceName() const {
341 return ResourceName(package, type, entry);
342 }
343
is_valid()344 inline bool ResourceNameRef::is_valid() const {
345 return !package.empty() && !entry.empty();
346 }
347
348 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
349 return std::tie(lhs.package, lhs.type, lhs.entry) <
350 std::tie(rhs.package, rhs.type, rhs.entry);
351 }
352
353 inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
354 return std::tie(lhs.package, lhs.type, lhs.entry) ==
355 std::tie(rhs.package, rhs.type, rhs.entry);
356 }
357
358 inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
359 return std::tie(lhs.package, lhs.type, lhs.entry) !=
360 std::tie(rhs.package, rhs.type, rhs.entry);
361 }
362
363 inline ::std::ostream& operator<<(::std::ostream& out,
364 const ResourceNameRef& name) {
365 if (!name.package.empty()) {
366 out << name.package << ":";
367 }
368 return out << name.type << "/" << name.entry;
369 }
370
371 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
372 return ResourceNameRef(lhs) < b;
373 }
374
375 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
376 return ResourceNameRef(lhs) != rhs;
377 }
378
379 inline bool operator==(const SourcedResourceName& lhs,
380 const SourcedResourceName& rhs) {
381 return lhs.name == rhs.name && lhs.line == rhs.line;
382 }
383
384 } // namespace aapt
385
386 namespace std {
387
388 template <>
389 struct hash<aapt::ResourceName> {
390 size_t operator()(const aapt::ResourceName& name) const {
391 android::hash_t h = 0;
392 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
393 h = android::JenkinsHashMix(h, static_cast<uint32_t>(name.type));
394 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
395 return static_cast<size_t>(h);
396 }
397 };
398
399 template <>
400 struct hash<aapt::ResourceId> {
401 size_t operator()(const aapt::ResourceId& id) const {
402 return id.id;
403 }
404 };
405
406 } // namespace std
407
408 #endif // AAPT_RESOURCE_H
409