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