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