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 <optional>
23 #include <sstream>
24 #include <string>
25 #include <tuple>
26 #include <vector>
27
28 #include "androidfw/ConfigDescription.h"
29 #include "androidfw/Source.h"
30 #include "androidfw/StringPiece.h"
31 #include "utils/JenkinsHash.h"
32
33 namespace aapt {
34
35 /**
36 * The various types of resource types available.
37 */
38 enum class ResourceType {
39 kAnim,
40 kAnimator,
41 kArray,
42 kAttr,
43 kAttrPrivate,
44 kBool,
45 kColor,
46
47 // Not really a type, but it shows up in some CTS tests and
48 // we need to continue respecting it.
49 kConfigVarying,
50
51 kDimen,
52 kDrawable,
53 kFont,
54 kFraction,
55 kId,
56 kInteger,
57 kInterpolator,
58 kLayout,
59 kMacro,
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 to_string(ResourceType type);
73
74 /**
75 * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
76 */
77 const ResourceType* ParseResourceType(android::StringPiece str);
78
79 /**
80 * Pair of type name as in ResourceTable and actual resource type.
81 * Corresponds to the 'type' in package:type/entry.
82 *
83 * This is to support resource types with custom names inside resource tables.
84 */
85 struct ResourceNamedType {
86 std::string name;
87 ResourceType type = ResourceType::kRaw;
88
89 ResourceNamedType() = default;
90 ResourceNamedType(android::StringPiece n, ResourceType t);
91
92 int compare(const ResourceNamedType& other) const;
93
94 const std::string& to_string() const;
95 };
96
97 /**
98 * Same as ResourceNamedType, but uses StringPieces instead.
99 * Use this if you need to avoid copying and know that
100 * the lifetime of this object is shorter than that
101 * of the original string.
102 */
103 struct ResourceNamedTypeRef {
104 android::StringPiece name;
105 ResourceType type = ResourceType::kRaw;
106
107 ResourceNamedTypeRef() = default;
108 ResourceNamedTypeRef(const ResourceNamedTypeRef&) = default;
109 ResourceNamedTypeRef(ResourceNamedTypeRef&&) = default;
110 ResourceNamedTypeRef(const ResourceNamedType& rhs); // NOLINT(google-explicit-constructor)
111 ResourceNamedTypeRef(android::StringPiece n, ResourceType t);
112 ResourceNamedTypeRef& operator=(const ResourceNamedTypeRef& rhs) = default;
113 ResourceNamedTypeRef& operator=(ResourceNamedTypeRef&& rhs) = default;
114 ResourceNamedTypeRef& operator=(const ResourceNamedType& rhs);
115
116 ResourceNamedType ToResourceNamedType() const;
117
118 std::string_view to_string() const;
119 };
120
121 ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t);
122
123 std::optional<ResourceNamedTypeRef> ParseResourceNamedType(android::StringPiece s);
124
125 /**
126 * A resource's name. This can uniquely identify
127 * a resource in the ResourceTable.
128 */
129 struct ResourceName {
130 std::string package;
131 ResourceNamedType type;
132 std::string entry;
133
134 ResourceName() = default;
135 ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
136 ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e);
137
138 int compare(const ResourceName& other) const;
139
140 bool is_valid() const;
141 std::string to_string() const;
142 };
143
144 /**
145 * Same as ResourceName, but uses StringPieces instead.
146 * Use this if you need to avoid copying and know that
147 * the lifetime of this object is shorter than that
148 * of the original string.
149 */
150 struct ResourceNameRef {
151 android::StringPiece package;
152 ResourceNamedTypeRef type;
153 android::StringPiece entry;
154
155 ResourceNameRef() = default;
156 ResourceNameRef(const ResourceNameRef&) = default;
157 ResourceNameRef(ResourceNameRef&&) = default;
158 ResourceNameRef(const ResourceName& rhs); // NOLINT(google-explicit-constructor)
159 ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
160 ResourceNameRef(android::StringPiece p, ResourceType t, android::StringPiece e);
161 ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
162 ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
163 ResourceNameRef& operator=(const ResourceName& rhs);
164
165 bool is_valid() const;
166
167 ResourceName ToResourceName() const;
168 std::string to_string() const;
169 };
170
171 constexpr const uint8_t kAppPackageId = 0x7fu;
172 constexpr const uint8_t kFrameworkPackageId = 0x01u;
173
174 /**
175 * A binary identifier representing a resource. Internally it
176 * is a 32bit integer split as follows:
177 *
178 * 0xPPTTEEEE
179 *
180 * PP: 8 bit package identifier. 0x01 is reserved for system
181 * and 0x7f is reserved for the running app.
182 * TT: 8 bit type identifier. 0x00 is invalid.
183 * EEEE: 16 bit entry identifier.
184 */
185 struct ResourceId {
186 uint32_t id;
187
188 ResourceId();
189 ResourceId(const ResourceId& rhs) = default;
190 ResourceId(uint32_t res_id); // NOLINT(google-explicit-constructor)
191 ResourceId(uint8_t p, uint8_t t, uint16_t e);
192
193 // Returns true if the ID is a valid ID that is not dynamic (package ID cannot be 0)
194 bool is_valid_static() const;
195
196 // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
197 bool is_valid() const;
198
199 uint8_t package_id() const;
200 uint8_t type_id() const;
201 uint16_t entry_id() const;
202
203 std::string to_string() const;
204 };
205
206 struct SourcedResourceName {
207 ResourceName name;
208 size_t line;
209 };
210
211 struct ResourceFile {
212 enum class Type {
213 kUnknown,
214 kPng,
215 kBinaryXml,
216 kProtoXml,
217 };
218
219 // Name
220 ResourceName name;
221
222 // Configuration
223 android::ConfigDescription config;
224
225 // Type
226 Type type;
227
228 // Source
229 android::Source source;
230
231 // Exported symbols
232 std::vector<SourcedResourceName> exported_symbols;
233 };
234
235 /**
236 * Useful struct used as a key to represent a unique resource in associative
237 * containers.
238 */
239 struct ResourceKey {
240 ResourceName name;
241 android::ConfigDescription config;
242 };
243
244 bool operator<(const ResourceKey& a, const ResourceKey& b);
245
246 /**
247 * Useful struct used as a key to represent a unique resource in associative
248 * containers.
249 * Holds a reference to the name, so that name better live longer than this key!
250 */
251 struct ResourceKeyRef {
252 ResourceNameRef name;
253 android::ConfigDescription config;
254
255 ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef256 ResourceKeyRef(const ResourceNameRef& n, const android::ConfigDescription& c)
257 : name(n), config(c) {}
258
259 /**
260 * Prevent taking a reference to a temporary. This is bad.
261 */
262 ResourceKeyRef(ResourceName&& n, const android::ConfigDescription& c) = delete;
263 };
264
265 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
266
267 //
268 // ResourceId implementation.
269 //
270
ResourceId()271 inline ResourceId::ResourceId() : id(0) {}
272
ResourceId(uint32_t res_id)273 inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
274
ResourceId(uint8_t p,uint8_t t,uint16_t e)275 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
276 : id((p << 24) | (t << 16) | e) {}
277
is_valid_static()278 inline bool ResourceId::is_valid_static() const {
279 return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
280 }
281
is_valid()282 inline bool ResourceId::is_valid() const {
283 return (id & 0x00ff0000u) != 0;
284 }
285
package_id()286 inline uint8_t ResourceId::package_id() const {
287 return static_cast<uint8_t>(id >> 24);
288 }
289
type_id()290 inline uint8_t ResourceId::type_id() const {
291 return static_cast<uint8_t>(id >> 16);
292 }
293
entry_id()294 inline uint16_t ResourceId::entry_id() const {
295 return static_cast<uint16_t>(id);
296 }
297
298 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
299 return lhs.id < rhs.id;
300 }
301
302 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
303 return lhs.id > rhs.id;
304 }
305
306 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
307 return lhs.id == rhs.id;
308 }
309
310 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
311 return lhs.id != rhs.id;
312 }
313
314 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
315 return out << res_id.to_string();
316 }
317
318 // For generic code to call 'using std::to_string; to_string(T);'.
to_string(const ResourceId & id)319 inline std::string to_string(const ResourceId& id) {
320 return id.to_string();
321 }
322
323 // Helper to compare resource IDs, moving dynamic IDs after framework IDs.
cmp_ids_dynamic_after_framework(const ResourceId & a,const ResourceId & b)324 inline bool cmp_ids_dynamic_after_framework(const ResourceId& a, const ResourceId& b) {
325 // If one of a and b is from the framework package (package ID 0x01), and the
326 // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
327 // framework ID. This ensures that when AssetManager resolves the dynamic IDs,
328 // they will be in sorted order as expected by AssetManager.
329 if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
330 (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
331 return b < a;
332 }
333 return a < b;
334 }
335
336 //
337 // ResourceType implementation.
338 //
339
340 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
341 return out << to_string(val);
342 }
343
344 //
345 // ResourceNamedType implementation.
346 //
ResourceNamedType(android::StringPiece n,ResourceType t)347 inline ResourceNamedType::ResourceNamedType(android::StringPiece n, ResourceType t)
348 : name(n), type(t) {
349 }
350
compare(const ResourceNamedType & other)351 inline int ResourceNamedType::compare(const ResourceNamedType& other) const {
352 int cmp = static_cast<int>(type) - static_cast<int>(other.type);
353 if (cmp != 0) return cmp;
354 cmp = name.compare(other.name);
355 return cmp;
356 }
357
to_string()358 inline const std::string& ResourceNamedType::to_string() const {
359 return name;
360 }
361
362 inline bool operator<(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
363 return lhs.compare(rhs) < 0;
364 }
365
366 inline bool operator==(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
367 return lhs.compare(rhs) == 0;
368 }
369
370 inline bool operator!=(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
371 return lhs.compare(rhs) != 0;
372 }
373
374 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedType& val) {
375 return out << val.to_string();
376 }
377
378 //
379 // ResourceNamedTypeRef implementation.
380 //
ResourceNamedTypeRef(android::StringPiece n,ResourceType t)381 inline ResourceNamedTypeRef::ResourceNamedTypeRef(android::StringPiece n, ResourceType t)
382 : name(n), type(t) {
383 }
384
ResourceNamedTypeRef(const ResourceNamedType & rhs)385 inline ResourceNamedTypeRef::ResourceNamedTypeRef(const ResourceNamedType& rhs)
386 : name(rhs.name), type(rhs.type) {
387 }
388
389 inline ResourceNamedTypeRef& ResourceNamedTypeRef::operator=(const ResourceNamedType& rhs) {
390 name = rhs.name;
391 type = rhs.type;
392 return *this;
393 }
394
ToResourceNamedType()395 inline ResourceNamedType ResourceNamedTypeRef::ToResourceNamedType() const {
396 return ResourceNamedType(name, type);
397 }
398
to_string()399 inline std::string_view ResourceNamedTypeRef::to_string() const {
400 return name;
401 }
402
403 inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
404 return std::tie(lhs.type, lhs.name) < std::tie(rhs.type, rhs.name);
405 }
406
407 inline bool operator==(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
408 return std::tie(lhs.type, lhs.name) == std::tie(rhs.type, rhs.name);
409 }
410
411 inline bool operator!=(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
412 return std::tie(lhs.type, lhs.name) != std::tie(rhs.type, rhs.name);
413 }
414
415 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRef& val) {
416 return out << val.name;
417 }
418
419 //
420 // ResourceName implementation.
421 //
422
ResourceName(android::StringPiece p,const ResourceNamedTypeRef & t,android::StringPiece e)423 inline ResourceName::ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t,
424 android::StringPiece e)
425 : package(p), type(t.ToResourceNamedType()), entry(e) {
426 }
427
ResourceName(android::StringPiece p,ResourceType t,android::StringPiece e)428 inline ResourceName::ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e)
429 : ResourceName(p, ResourceNamedTypeWithDefaultName(t), e) {
430 }
431
compare(const ResourceName & other)432 inline int ResourceName::compare(const ResourceName& other) const {
433 int cmp = package.compare(other.package);
434 if (cmp != 0) return cmp;
435 cmp = type.compare(other.type);
436 if (cmp != 0) return cmp;
437 cmp = entry.compare(other.entry);
438 return cmp;
439 }
440
is_valid()441 inline bool ResourceName::is_valid() const {
442 return !package.empty() && !entry.empty();
443 }
444
445 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
446 return std::tie(lhs.package, lhs.type, lhs.entry) <
447 std::tie(rhs.package, rhs.type, rhs.entry);
448 }
449
450 inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
451 return std::tie(lhs.package, lhs.type, lhs.entry) ==
452 std::tie(rhs.package, rhs.type, rhs.entry);
453 }
454
455 inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
456 return std::tie(lhs.package, lhs.type, lhs.entry) !=
457 std::tie(rhs.package, rhs.type, rhs.entry);
458 }
459
460 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
461 return out << name.to_string();
462 }
463
464 //
465 // ResourceNameRef implementation.
466 //
467
ResourceNameRef(const ResourceName & rhs)468 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
469 : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
470
ResourceNameRef(android::StringPiece p,const ResourceNamedTypeRef & t,android::StringPiece e)471 inline ResourceNameRef::ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t,
472 android::StringPiece e)
473 : package(p), type(t), entry(e) {
474 }
475
ResourceNameRef(android::StringPiece p,ResourceType t,android::StringPiece e)476 inline ResourceNameRef::ResourceNameRef(android::StringPiece p, ResourceType t,
477 android::StringPiece e)
478 : ResourceNameRef(p, ResourceNamedTypeWithDefaultName(t), e) {
479 }
480
481 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
482 package = rhs.package;
483 type = rhs.type;
484 entry = rhs.entry;
485 return *this;
486 }
487
ToResourceName()488 inline ResourceName ResourceNameRef::ToResourceName() const {
489 return ResourceName(package, type, entry);
490 }
491
is_valid()492 inline bool ResourceNameRef::is_valid() const {
493 return !package.empty() && !entry.empty();
494 }
495
496 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
497 return std::tie(lhs.package, lhs.type, lhs.entry) <
498 std::tie(rhs.package, rhs.type, rhs.entry);
499 }
500
501 inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
502 return std::tie(lhs.package, lhs.type, lhs.entry) ==
503 std::tie(rhs.package, rhs.type, rhs.entry);
504 }
505
506 inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
507 return std::tie(lhs.package, lhs.type, lhs.entry) !=
508 std::tie(rhs.package, rhs.type, rhs.entry);
509 }
510
511 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
512 return out << name.to_string();
513 }
514
515 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
516 return ResourceNameRef(lhs) < b;
517 }
518
519 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
520 return ResourceNameRef(lhs) != rhs;
521 }
522
523 inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
524 return lhs.name == rhs.name && lhs.line == rhs.line;
525 }
526
527 } // namespace aapt
528
529 namespace std {
530
531 template <>
532 struct hash<aapt::ResourceName> {
533 size_t operator()(const aapt::ResourceName& name) const {
534 android::hash_t h = 0;
535 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
536 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.type.name)));
537 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
538 return static_cast<size_t>(h);
539 }
540 };
541
542 template <>
543 struct hash<aapt::ResourceId> {
544 size_t operator()(const aapt::ResourceId& id) const {
545 return id.id;
546 }
547 };
548
549 } // namespace std
550
551 #endif // AAPT_RESOURCE_H
552