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 <sstream>
23 #include <string>
24 #include <tuple>
25 #include <vector>
26
27 #include "androidfw/ConfigDescription.h"
28 #include "androidfw/StringPiece.h"
29 #include "utils/JenkinsHash.h"
30
31 #include "Source.h"
32
33 namespace aapt {
34
35 /**
36 * The various types of resource types available. Corresponds
37 * to the 'type' in package:type/entry.
38 */
39 enum class ResourceType {
40 kAnim,
41 kAnimator,
42 kArray,
43 kAttr,
44 kAttrPrivate,
45 kBool,
46 kColor,
47
48 // Not really a type, but it shows up in some CTS tests and
49 // we need to continue respecting it.
50 kConfigVarying,
51
52 kDimen,
53 kDrawable,
54 kFont,
55 kFraction,
56 kId,
57 kInteger,
58 kInterpolator,
59 kLayout,
60 kMacro,
61 kMenu,
62 kMipmap,
63 kNavigation,
64 kPlurals,
65 kRaw,
66 kString,
67 kStyle,
68 kStyleable,
69 kTransition,
70 kXml,
71 };
72
73 android::StringPiece to_string(ResourceType type);
74
75 /**
76 * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
77 */
78 const ResourceType* ParseResourceType(const android::StringPiece& str);
79
80 /**
81 * A resource's name. This can uniquely identify
82 * a resource in the ResourceTable.
83 */
84 struct ResourceName {
85 std::string package;
86 ResourceType type = ResourceType::kRaw;
87 std::string entry;
88
89 ResourceName() = default;
90 ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
91
92 int compare(const ResourceName& other) const;
93
94 bool is_valid() const;
95 std::string to_string() const;
96 };
97
98 /**
99 * Same as ResourceName, but uses StringPieces instead.
100 * Use this if you need to avoid copying and know that
101 * the lifetime of this object is shorter than that
102 * of the original string.
103 */
104 struct ResourceNameRef {
105 android::StringPiece package;
106 ResourceType type = ResourceType::kRaw;
107 android::StringPiece entry;
108
109 ResourceNameRef() = default;
110 ResourceNameRef(const ResourceNameRef&) = default;
111 ResourceNameRef(ResourceNameRef&&) = default;
112 ResourceNameRef(const ResourceName& rhs); // NOLINT(google-explicit-constructor)
113 ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
114 ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
115 ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
116 ResourceNameRef& operator=(const ResourceName& rhs);
117
118 bool is_valid() const;
119
120 ResourceName ToResourceName() const;
121 std::string to_string() const;
122 };
123
124 constexpr const uint8_t kAppPackageId = 0x7fu;
125 constexpr const uint8_t kFrameworkPackageId = 0x01u;
126
127 /**
128 * A binary identifier representing a resource. Internally it
129 * is a 32bit integer split as follows:
130 *
131 * 0xPPTTEEEE
132 *
133 * PP: 8 bit package identifier. 0x01 is reserved for system
134 * and 0x7f is reserved for the running app.
135 * TT: 8 bit type identifier. 0x00 is invalid.
136 * EEEE: 16 bit entry identifier.
137 */
138 struct ResourceId {
139 uint32_t id;
140
141 ResourceId();
142 ResourceId(const ResourceId& rhs) = default;
143 ResourceId(uint32_t res_id); // NOLINT(google-explicit-constructor)
144 ResourceId(uint8_t p, uint8_t t, uint16_t e);
145
146 // Returns true if the ID is a valid ID that is not dynamic (package ID cannot be 0)
147 bool is_valid_static() const;
148
149 // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
150 bool is_valid() const;
151
152 uint8_t package_id() const;
153 uint8_t type_id() const;
154 uint16_t entry_id() const;
155
156 std::string to_string() const;
157 };
158
159 struct SourcedResourceName {
160 ResourceName name;
161 size_t line;
162 };
163
164 struct ResourceFile {
165 enum class Type {
166 kUnknown,
167 kPng,
168 kBinaryXml,
169 kProtoXml,
170 };
171
172 // Name
173 ResourceName name;
174
175 // Configuration
176 android::ConfigDescription config;
177
178 // Type
179 Type type;
180
181 // Source
182 Source source;
183
184 // Exported symbols
185 std::vector<SourcedResourceName> exported_symbols;
186 };
187
188 /**
189 * Useful struct used as a key to represent a unique resource in associative
190 * containers.
191 */
192 struct ResourceKey {
193 ResourceName name;
194 android::ConfigDescription config;
195 };
196
197 bool operator<(const ResourceKey& a, const ResourceKey& b);
198
199 /**
200 * Useful struct used as a key to represent a unique resource in associative
201 * containers.
202 * Holds a reference to the name, so that name better live longer than this key!
203 */
204 struct ResourceKeyRef {
205 ResourceNameRef name;
206 android::ConfigDescription config;
207
208 ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef209 ResourceKeyRef(const ResourceNameRef& n, const android::ConfigDescription& c)
210 : name(n), config(c) {}
211
212 /**
213 * Prevent taking a reference to a temporary. This is bad.
214 */
215 ResourceKeyRef(ResourceName&& n, const android::ConfigDescription& c) = delete;
216 };
217
218 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
219
220 //
221 // ResourceId implementation.
222 //
223
ResourceId()224 inline ResourceId::ResourceId() : id(0) {}
225
ResourceId(uint32_t res_id)226 inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
227
ResourceId(uint8_t p,uint8_t t,uint16_t e)228 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
229 : id((p << 24) | (t << 16) | e) {}
230
is_valid_static()231 inline bool ResourceId::is_valid_static() const {
232 return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
233 }
234
is_valid()235 inline bool ResourceId::is_valid() const {
236 return (id & 0x00ff0000u) != 0;
237 }
238
package_id()239 inline uint8_t ResourceId::package_id() const {
240 return static_cast<uint8_t>(id >> 24);
241 }
242
type_id()243 inline uint8_t ResourceId::type_id() const {
244 return static_cast<uint8_t>(id >> 16);
245 }
246
entry_id()247 inline uint16_t ResourceId::entry_id() const {
248 return static_cast<uint16_t>(id);
249 }
250
251 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
252 return lhs.id < rhs.id;
253 }
254
255 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
256 return lhs.id > rhs.id;
257 }
258
259 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
260 return lhs.id == rhs.id;
261 }
262
263 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
264 return lhs.id != rhs.id;
265 }
266
267 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
268 return out << res_id.to_string();
269 }
270
271 // For generic code to call 'using std::to_string; to_string(T);'.
to_string(const ResourceId & id)272 inline std::string to_string(const ResourceId& id) {
273 return id.to_string();
274 }
275
276 // Helper to compare resource IDs, moving dynamic IDs after framework IDs.
cmp_ids_dynamic_after_framework(const ResourceId & a,const ResourceId & b)277 inline bool cmp_ids_dynamic_after_framework(const ResourceId& a, const ResourceId& b) {
278 // If one of a and b is from the framework package (package ID 0x01), and the
279 // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
280 // framework ID. This ensures that when AssetManager resolves the dynamic IDs,
281 // they will be in sorted order as expected by AssetManager.
282 if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
283 (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
284 return b < a;
285 }
286 return a < b;
287 }
288
289 //
290 // ResourceType implementation.
291 //
292
293 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
294 return out << to_string(val);
295 }
296
297 //
298 // ResourceName implementation.
299 //
300
ResourceName(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)301 inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
302 const android::StringPiece& e)
303 : package(p.to_string()), type(t), entry(e.to_string()) {}
304
compare(const ResourceName & other)305 inline int ResourceName::compare(const ResourceName& other) const {
306 int cmp = package.compare(other.package);
307 if (cmp != 0) return cmp;
308 cmp = static_cast<int>(type) - static_cast<int>(other.type);
309 if (cmp != 0) return cmp;
310 cmp = entry.compare(other.entry);
311 return cmp;
312 }
313
is_valid()314 inline bool ResourceName::is_valid() const {
315 return !package.empty() && !entry.empty();
316 }
317
318 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
319 return std::tie(lhs.package, lhs.type, lhs.entry) <
320 std::tie(rhs.package, rhs.type, rhs.entry);
321 }
322
323 inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
324 return std::tie(lhs.package, lhs.type, lhs.entry) ==
325 std::tie(rhs.package, rhs.type, rhs.entry);
326 }
327
328 inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
329 return std::tie(lhs.package, lhs.type, lhs.entry) !=
330 std::tie(rhs.package, rhs.type, rhs.entry);
331 }
332
333 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
334 return out << name.to_string();
335 }
336
337 //
338 // ResourceNameRef implementation.
339 //
340
ResourceNameRef(const ResourceName & rhs)341 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
342 : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
343
ResourceNameRef(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)344 inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
345 const android::StringPiece& e)
346 : package(p), type(t), entry(e) {}
347
348 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
349 package = rhs.package;
350 type = rhs.type;
351 entry = rhs.entry;
352 return *this;
353 }
354
ToResourceName()355 inline ResourceName ResourceNameRef::ToResourceName() const {
356 return ResourceName(package, type, entry);
357 }
358
is_valid()359 inline bool ResourceNameRef::is_valid() const {
360 return !package.empty() && !entry.empty();
361 }
362
363 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
364 return std::tie(lhs.package, lhs.type, lhs.entry) <
365 std::tie(rhs.package, rhs.type, rhs.entry);
366 }
367
368 inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
369 return std::tie(lhs.package, lhs.type, lhs.entry) ==
370 std::tie(rhs.package, rhs.type, rhs.entry);
371 }
372
373 inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
374 return std::tie(lhs.package, lhs.type, lhs.entry) !=
375 std::tie(rhs.package, rhs.type, rhs.entry);
376 }
377
378 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
379 return out << name.to_string();
380 }
381
382 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
383 return ResourceNameRef(lhs) < b;
384 }
385
386 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
387 return ResourceNameRef(lhs) != rhs;
388 }
389
390 inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
391 return lhs.name == rhs.name && lhs.line == rhs.line;
392 }
393
394 } // namespace aapt
395
396 namespace std {
397
398 template <>
399 struct hash<aapt::ResourceName> {
400 size_t operator()(const aapt::ResourceName& name) const {
401 android::hash_t h = 0;
402 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
403 h = android::JenkinsHashMix(h, static_cast<uint32_t>(name.type));
404 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
405 return static_cast<size_t>(h);
406 }
407 };
408
409 template <>
410 struct hash<aapt::ResourceId> {
411 size_t operator()(const aapt::ResourceId& id) const {
412 return id.id;
413 }
414 };
415
416 } // namespace std
417
418 #endif // AAPT_RESOURCE_H
419