• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   bool uses_readwrite_feature_flags = false;
254 };
255 
256 /**
257  * Useful struct used as a key to represent a unique resource in associative
258  * containers.
259  */
260 struct ResourceKey {
261   ResourceName name;
262   android::ConfigDescription config;
263 };
264 
265 bool operator<(const ResourceKey& a, const ResourceKey& b);
266 
267 /**
268  * Useful struct used as a key to represent a unique resource in associative
269  * containers.
270  * Holds a reference to the name, so that name better live longer than this key!
271  */
272 struct ResourceKeyRef {
273   ResourceNameRef name;
274   android::ConfigDescription config;
275 
276   ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef277   ResourceKeyRef(const ResourceNameRef& n, const android::ConfigDescription& c)
278       : name(n), config(c) {}
279 
280   /**
281    * Prevent taking a reference to a temporary. This is bad.
282    */
283   ResourceKeyRef(ResourceName&& n, const android::ConfigDescription& c) = delete;
284 };
285 
286 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
287 
288 //
289 // ResourceId implementation.
290 //
291 
ResourceId()292 inline ResourceId::ResourceId() : id(0) {}
293 
ResourceId(uint32_t res_id)294 inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
295 
ResourceId(uint8_t p,uint8_t t,uint16_t e)296 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
297     : id((p << 24) | (t << 16) | e) {}
298 
is_valid_static()299 inline bool ResourceId::is_valid_static() const {
300   return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
301 }
302 
is_valid()303 inline bool ResourceId::is_valid() const {
304   return (id & 0x00ff0000u) != 0;
305 }
306 
package_id()307 inline uint8_t ResourceId::package_id() const {
308   return static_cast<uint8_t>(id >> 24);
309 }
310 
type_id()311 inline uint8_t ResourceId::type_id() const {
312   return static_cast<uint8_t>(id >> 16);
313 }
314 
entry_id()315 inline uint16_t ResourceId::entry_id() const {
316   return static_cast<uint16_t>(id);
317 }
318 
319 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
320   return lhs.id < rhs.id;
321 }
322 
323 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
324   return lhs.id > rhs.id;
325 }
326 
327 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
328   return lhs.id == rhs.id;
329 }
330 
331 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
332   return lhs.id != rhs.id;
333 }
334 
335 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
336   return out << res_id.to_string();
337 }
338 
339 // For generic code to call 'using std::to_string; to_string(T);'.
to_string(const ResourceId & id)340 inline std::string to_string(const ResourceId& id) {
341   return id.to_string();
342 }
343 
344 // Helper to compare resource IDs, moving dynamic IDs after framework IDs.
cmp_ids_dynamic_after_framework(const ResourceId & a,const ResourceId & b)345 inline bool cmp_ids_dynamic_after_framework(const ResourceId& a, const ResourceId& b) {
346   // If one of a and b is from the framework package (package ID 0x01), and the
347   // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
348   // framework ID. This ensures that when AssetManager resolves the dynamic IDs,
349   // they will be in sorted order as expected by AssetManager.
350   if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
351       (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
352     return b < a;
353   }
354   return a < b;
355 }
356 
357 //
358 // ResourceType implementation.
359 //
360 
361 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
362   return out << to_string(val);
363 }
364 
365 //
366 // ResourceNamedType implementation.
367 //
ResourceNamedType(android::StringPiece n,ResourceType t)368 inline ResourceNamedType::ResourceNamedType(android::StringPiece n, ResourceType t)
369     : name(n), type(t) {
370 }
371 
compare(const ResourceNamedType & other)372 inline int ResourceNamedType::compare(const ResourceNamedType& other) const {
373   int cmp = static_cast<int>(type) - static_cast<int>(other.type);
374   if (cmp != 0) return cmp;
375   cmp = name.compare(other.name);
376   return cmp;
377 }
378 
to_string()379 inline const std::string& ResourceNamedType::to_string() const {
380   return name;
381 }
382 
383 inline bool operator<(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
384   return lhs.compare(rhs) < 0;
385 }
386 
387 inline bool operator==(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
388   return lhs.compare(rhs) == 0;
389 }
390 
391 inline bool operator!=(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
392   return lhs.compare(rhs) != 0;
393 }
394 
395 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedType& val) {
396   return out << val.to_string();
397 }
398 
399 //
400 // ResourceNamedTypeRef implementation.
401 //
ResourceNamedTypeRef(android::StringPiece n,ResourceType t)402 inline ResourceNamedTypeRef::ResourceNamedTypeRef(android::StringPiece n, ResourceType t)
403     : name(n), type(t) {
404 }
405 
ResourceNamedTypeRef(const ResourceNamedType & rhs)406 inline ResourceNamedTypeRef::ResourceNamedTypeRef(const ResourceNamedType& rhs)
407     : name(rhs.name), type(rhs.type) {
408 }
409 
410 inline ResourceNamedTypeRef& ResourceNamedTypeRef::operator=(const ResourceNamedType& rhs) {
411   name = rhs.name;
412   type = rhs.type;
413   return *this;
414 }
415 
ToResourceNamedType()416 inline ResourceNamedType ResourceNamedTypeRef::ToResourceNamedType() const {
417   return ResourceNamedType(name, type);
418 }
419 
to_string()420 inline std::string_view ResourceNamedTypeRef::to_string() const {
421   return name;
422 }
423 
424 inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
425   return std::tie(lhs.type, lhs.name) < std::tie(rhs.type, rhs.name);
426 }
427 
428 inline bool operator==(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
429   return std::tie(lhs.type, lhs.name) == std::tie(rhs.type, rhs.name);
430 }
431 
432 inline bool operator!=(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
433   return std::tie(lhs.type, lhs.name) != std::tie(rhs.type, rhs.name);
434 }
435 
436 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRef& val) {
437   return out << val.name;
438 }
439 
440 //
441 // ResourceName implementation.
442 //
443 
ResourceName(android::StringPiece p,const ResourceNamedTypeRef & t,android::StringPiece e)444 inline ResourceName::ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t,
445                                   android::StringPiece e)
446     : package(p), type(t.ToResourceNamedType()), entry(e) {
447 }
448 
ResourceName(android::StringPiece p,ResourceType t,android::StringPiece e)449 inline ResourceName::ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e)
450     : ResourceName(p, ResourceNamedTypeWithDefaultName(t), e) {
451 }
452 
compare(const ResourceName & other)453 inline int ResourceName::compare(const ResourceName& other) const {
454   int cmp = package.compare(other.package);
455   if (cmp != 0) return cmp;
456   cmp = type.compare(other.type);
457   if (cmp != 0) return cmp;
458   cmp = entry.compare(other.entry);
459   return cmp;
460 }
461 
is_valid()462 inline bool ResourceName::is_valid() const {
463   return !package.empty() && !entry.empty();
464 }
465 
466 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
467   return std::tie(lhs.package, lhs.type, lhs.entry) <
468          std::tie(rhs.package, rhs.type, rhs.entry);
469 }
470 
471 inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
472   return std::tie(lhs.package, lhs.type, lhs.entry) ==
473          std::tie(rhs.package, rhs.type, rhs.entry);
474 }
475 
476 inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
477   return std::tie(lhs.package, lhs.type, lhs.entry) !=
478          std::tie(rhs.package, rhs.type, rhs.entry);
479 }
480 
481 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
482   return out << name.to_string();
483 }
484 
485 //
486 // ResourceNameRef implementation.
487 //
488 
ResourceNameRef(const ResourceName & rhs)489 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
490     : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
491 
ResourceNameRef(android::StringPiece p,const ResourceNamedTypeRef & t,android::StringPiece e)492 inline ResourceNameRef::ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t,
493                                         android::StringPiece e)
494     : package(p), type(t), entry(e) {
495 }
496 
ResourceNameRef(android::StringPiece p,ResourceType t,android::StringPiece e)497 inline ResourceNameRef::ResourceNameRef(android::StringPiece p, ResourceType t,
498                                         android::StringPiece e)
499     : ResourceNameRef(p, ResourceNamedTypeWithDefaultName(t), e) {
500 }
501 
502 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
503   package = rhs.package;
504   type = rhs.type;
505   entry = rhs.entry;
506   return *this;
507 }
508 
ToResourceName()509 inline ResourceName ResourceNameRef::ToResourceName() const {
510   return ResourceName(package, type, entry);
511 }
512 
is_valid()513 inline bool ResourceNameRef::is_valid() const {
514   return !package.empty() && !entry.empty();
515 }
516 
517 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
518   return std::tie(lhs.package, lhs.type, lhs.entry) <
519          std::tie(rhs.package, rhs.type, rhs.entry);
520 }
521 
522 inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
523   return std::tie(lhs.package, lhs.type, lhs.entry) ==
524          std::tie(rhs.package, rhs.type, rhs.entry);
525 }
526 
527 inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
528   return std::tie(lhs.package, lhs.type, lhs.entry) !=
529          std::tie(rhs.package, rhs.type, rhs.entry);
530 }
531 
532 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
533   return out << name.to_string();
534 }
535 
536 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
537   return ResourceNameRef(lhs) < b;
538 }
539 
540 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
541   return ResourceNameRef(lhs) != rhs;
542 }
543 
544 inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
545   return lhs.name == rhs.name && lhs.line == rhs.line;
546 }
547 
548 }  // namespace aapt
549 
550 namespace std {
551 
552 template <>
553 struct hash<aapt::ResourceName> {
554   size_t operator()(const aapt::ResourceName& name) const {
555     android::hash_t h = 0;
556     h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
557     h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.type.name)));
558     h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
559     return static_cast<size_t>(h);
560   }
561 };
562 
563 template <>
564 struct hash<aapt::ResourceId> {
565   size_t operator()(const aapt::ResourceId& id) const {
566     return id.id;
567   }
568 };
569 
570 }  // namespace std
571 
572 #endif  // AAPT_RESOURCE_H
573