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