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 // Returns true if the ID is a valid ID that is not dynamic (package ID cannot be 0)
151 bool is_valid_static() const;
152
153 // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
154 bool is_valid() const;
155
156 uint8_t package_id() const;
157 uint8_t type_id() const;
158 uint16_t entry_id() const;
159
160 std::string to_string() const;
161 };
162
163 struct SourcedResourceName {
164 ResourceName name;
165 size_t line;
166 };
167
168 struct ResourceFile {
169 enum class Type {
170 kUnknown,
171 kPng,
172 kBinaryXml,
173 kProtoXml,
174 };
175
176 // Name
177 ResourceName name;
178
179 // Configuration
180 android::ConfigDescription config;
181
182 // Type
183 Type type;
184
185 // Source
186 Source source;
187
188 // Exported symbols
189 std::vector<SourcedResourceName> exported_symbols;
190 };
191
192 /**
193 * Useful struct used as a key to represent a unique resource in associative
194 * containers.
195 */
196 struct ResourceKey {
197 ResourceName name;
198 android::ConfigDescription config;
199 };
200
201 bool operator<(const ResourceKey& a, const ResourceKey& b);
202
203 /**
204 * Useful struct used as a key to represent a unique resource in associative
205 * containers.
206 * Holds a reference to the name, so that name better live longer than this key!
207 */
208 struct ResourceKeyRef {
209 ResourceNameRef name;
210 android::ConfigDescription config;
211
212 ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef213 ResourceKeyRef(const ResourceNameRef& n, const android::ConfigDescription& c)
214 : name(n), config(c) {}
215
216 /**
217 * Prevent taking a reference to a temporary. This is bad.
218 */
219 ResourceKeyRef(ResourceName&& n, const android::ConfigDescription& c) = delete;
220 };
221
222 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
223
224 //
225 // ResourceId implementation.
226 //
227
ResourceId()228 inline ResourceId::ResourceId() : id(0) {}
229
ResourceId(const ResourceId & rhs)230 inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {}
231
ResourceId(uint32_t res_id)232 inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
233
ResourceId(uint8_t p,uint8_t t,uint16_t e)234 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
235 : id((p << 24) | (t << 16) | e) {}
236
is_valid_static()237 inline bool ResourceId::is_valid_static() const {
238 return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
239 }
240
is_valid()241 inline bool ResourceId::is_valid() const {
242 return (id & 0x00ff0000u) != 0;
243 }
244
package_id()245 inline uint8_t ResourceId::package_id() const {
246 return static_cast<uint8_t>(id >> 24);
247 }
248
type_id()249 inline uint8_t ResourceId::type_id() const {
250 return static_cast<uint8_t>(id >> 16);
251 }
252
entry_id()253 inline uint16_t ResourceId::entry_id() const {
254 return static_cast<uint16_t>(id);
255 }
256
257 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
258 return lhs.id < rhs.id;
259 }
260
261 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
262 return lhs.id > rhs.id;
263 }
264
265 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
266 return lhs.id == rhs.id;
267 }
268
269 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
270 return lhs.id != rhs.id;
271 }
272
273 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
274 return out << res_id.to_string();
275 }
276
277 // For generic code to call 'using std::to_string; to_string(T);'.
to_string(const ResourceId & id)278 inline std::string to_string(const ResourceId& id) {
279 return id.to_string();
280 }
281
282 //
283 // ResourceType implementation.
284 //
285
286 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
287 return out << to_string(val);
288 }
289
290 //
291 // ResourceName implementation.
292 //
293
ResourceName(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)294 inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
295 const android::StringPiece& e)
296 : package(p.to_string()), type(t), entry(e.to_string()) {}
297
compare(const ResourceName & other)298 inline int ResourceName::compare(const ResourceName& other) const {
299 int cmp = package.compare(other.package);
300 if (cmp != 0) return cmp;
301 cmp = static_cast<int>(type) - static_cast<int>(other.type);
302 if (cmp != 0) return cmp;
303 cmp = entry.compare(other.entry);
304 return cmp;
305 }
306
is_valid()307 inline bool ResourceName::is_valid() const {
308 return !package.empty() && !entry.empty();
309 }
310
311 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
312 return std::tie(lhs.package, lhs.type, lhs.entry) <
313 std::tie(rhs.package, rhs.type, rhs.entry);
314 }
315
316 inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
317 return std::tie(lhs.package, lhs.type, lhs.entry) ==
318 std::tie(rhs.package, rhs.type, rhs.entry);
319 }
320
321 inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
322 return std::tie(lhs.package, lhs.type, lhs.entry) !=
323 std::tie(rhs.package, rhs.type, rhs.entry);
324 }
325
326 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
327 return out << name.to_string();
328 }
329
330 //
331 // ResourceNameRef implementation.
332 //
333
ResourceNameRef(const ResourceName & rhs)334 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
335 : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
336
ResourceNameRef(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)337 inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
338 const android::StringPiece& e)
339 : package(p), type(t), entry(e) {}
340
341 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
342 package = rhs.package;
343 type = rhs.type;
344 entry = rhs.entry;
345 return *this;
346 }
347
ToResourceName()348 inline ResourceName ResourceNameRef::ToResourceName() const {
349 return ResourceName(package, type, entry);
350 }
351
is_valid()352 inline bool ResourceNameRef::is_valid() const {
353 return !package.empty() && !entry.empty();
354 }
355
356 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
357 return std::tie(lhs.package, lhs.type, lhs.entry) <
358 std::tie(rhs.package, rhs.type, rhs.entry);
359 }
360
361 inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
362 return std::tie(lhs.package, lhs.type, lhs.entry) ==
363 std::tie(rhs.package, rhs.type, rhs.entry);
364 }
365
366 inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
367 return std::tie(lhs.package, lhs.type, lhs.entry) !=
368 std::tie(rhs.package, rhs.type, rhs.entry);
369 }
370
371 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
372 return out << name.to_string();
373 }
374
375 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
376 return ResourceNameRef(lhs) < b;
377 }
378
379 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
380 return ResourceNameRef(lhs) != rhs;
381 }
382
383 inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
384 return lhs.name == rhs.name && lhs.line == rhs.line;
385 }
386
387 } // namespace aapt
388
389 namespace std {
390
391 template <>
392 struct hash<aapt::ResourceName> {
393 size_t operator()(const aapt::ResourceName& name) const {
394 android::hash_t h = 0;
395 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
396 h = android::JenkinsHashMix(h, static_cast<uint32_t>(name.type));
397 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
398 return static_cast<size_t>(h);
399 }
400 };
401
402 template <>
403 struct hash<aapt::ResourceId> {
404 size_t operator()(const aapt::ResourceId& id) const {
405 return id.id;
406 }
407 };
408
409 } // namespace std
410
411 #endif // AAPT_RESOURCE_H
412