• 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 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