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