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