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