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/StringPiece.h"
28 #include "utils/JenkinsHash.h"
29
30 #include "ConfigDescription.h"
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 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 * A resource's name. This can uniquely identify
81 * a resource in the ResourceTable.
82 */
83 struct ResourceName {
84 std::string package;
85 ResourceType type = ResourceType::kRaw;
86 std::string entry;
87
88 ResourceName() = default;
89 ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
90
91 int compare(const ResourceName& other) const;
92
93 bool is_valid() const;
94 std::string to_string() const;
95 };
96
97 /**
98 * Same as ResourceName, 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 ResourceNameRef {
104 android::StringPiece package;
105 ResourceType type = ResourceType::kRaw;
106 android::StringPiece entry;
107
108 ResourceNameRef() = default;
109 ResourceNameRef(const ResourceNameRef&) = default;
110 ResourceNameRef(ResourceNameRef&&) = default;
111 ResourceNameRef(const ResourceName& rhs); // NOLINT(implicit)
112 ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
113 ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
114 ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
115 ResourceNameRef& operator=(const ResourceName& rhs);
116
117 bool is_valid() const;
118
119 ResourceName ToResourceName() const;
120 std::string to_string() const;
121 };
122
123 constexpr const uint8_t kAppPackageId = 0x7fu;
124 constexpr const uint8_t kFrameworkPackageId = 0x01u;
125
126 /**
127 * A binary identifier representing a resource. Internally it
128 * is a 32bit integer split as follows:
129 *
130 * 0xPPTTEEEE
131 *
132 * PP: 8 bit package identifier. 0x01 is reserved for system
133 * and 0x7f is reserved for the running app.
134 * TT: 8 bit type identifier. 0x00 is invalid.
135 * EEEE: 16 bit entry identifier.
136 */
137 struct ResourceId {
138 uint32_t id;
139
140 ResourceId();
141 ResourceId(const ResourceId& rhs);
142 ResourceId(uint32_t res_id); // NOLINT(implicit)
143 ResourceId(uint8_t p, uint8_t t, uint16_t e);
144
145 bool is_valid() const;
146
147 // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
148 bool is_valid_dynamic() const;
149
150 uint8_t package_id() const;
151 uint8_t type_id() const;
152 uint16_t entry_id() const;
153
154 std::string to_string() const;
155 };
156
157 struct SourcedResourceName {
158 ResourceName name;
159 size_t line;
160 };
161
162 struct ResourceFile {
163 enum class Type {
164 kUnknown,
165 kPng,
166 kBinaryXml,
167 kProtoXml,
168 };
169
170 // Name
171 ResourceName name;
172
173 // Configuration
174 ConfigDescription config;
175
176 // Type
177 Type type;
178
179 // Source
180 Source source;
181
182 // Exported symbols
183 std::vector<SourcedResourceName> exported_symbols;
184 };
185
186 /**
187 * Useful struct used as a key to represent a unique resource in associative
188 * containers.
189 */
190 struct ResourceKey {
191 ResourceName name;
192 ConfigDescription config;
193 };
194
195 bool operator<(const ResourceKey& a, const ResourceKey& b);
196
197 /**
198 * Useful struct used as a key to represent a unique resource in associative
199 * containers.
200 * Holds a reference to the name, so that name better live longer than this key!
201 */
202 struct ResourceKeyRef {
203 ResourceNameRef name;
204 ConfigDescription config;
205
206 ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef207 ResourceKeyRef(const ResourceNameRef& n, const ConfigDescription& c)
208 : name(n), config(c) {}
209
210 /**
211 * Prevent taking a reference to a temporary. This is bad.
212 */
213 ResourceKeyRef(ResourceName&& n, const ConfigDescription& c) = delete;
214 };
215
216 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
217
218 //
219 // ResourceId implementation.
220 //
221
ResourceId()222 inline ResourceId::ResourceId() : id(0) {}
223
ResourceId(const ResourceId & rhs)224 inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {}
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()231 inline bool ResourceId::is_valid() const {
232 return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
233 }
234
is_valid_dynamic()235 inline bool ResourceId::is_valid_dynamic() 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 //
277 // ResourceType implementation.
278 //
279
280 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
281 return out << to_string(val);
282 }
283
284 //
285 // ResourceName implementation.
286 //
287
ResourceName(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)288 inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
289 const android::StringPiece& e)
290 : package(p.to_string()), type(t), entry(e.to_string()) {}
291
compare(const ResourceName & other)292 inline int ResourceName::compare(const ResourceName& other) const {
293 int cmp = package.compare(other.package);
294 if (cmp != 0) return cmp;
295 cmp = static_cast<int>(type) - static_cast<int>(other.type);
296 if (cmp != 0) return cmp;
297 cmp = entry.compare(other.entry);
298 return cmp;
299 }
300
is_valid()301 inline bool ResourceName::is_valid() const {
302 return !package.empty() && !entry.empty();
303 }
304
305 inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
306 return std::tie(lhs.package, lhs.type, lhs.entry) <
307 std::tie(rhs.package, rhs.type, rhs.entry);
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 ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
321 return out << name.to_string();
322 }
323
324 //
325 // ResourceNameRef implementation.
326 //
327
ResourceNameRef(const ResourceName & rhs)328 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
329 : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
330
ResourceNameRef(const android::StringPiece & p,ResourceType t,const android::StringPiece & e)331 inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
332 const android::StringPiece& e)
333 : package(p), type(t), entry(e) {}
334
335 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
336 package = rhs.package;
337 type = rhs.type;
338 entry = rhs.entry;
339 return *this;
340 }
341
ToResourceName()342 inline ResourceName ResourceNameRef::ToResourceName() const {
343 return ResourceName(package, type, entry);
344 }
345
is_valid()346 inline bool ResourceNameRef::is_valid() const {
347 return !package.empty() && !entry.empty();
348 }
349
350 inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
351 return std::tie(lhs.package, lhs.type, lhs.entry) <
352 std::tie(rhs.package, rhs.type, rhs.entry);
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 ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
366 return out << name.to_string();
367 }
368
369 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
370 return ResourceNameRef(lhs) < b;
371 }
372
373 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
374 return ResourceNameRef(lhs) != rhs;
375 }
376
377 inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
378 return lhs.name == rhs.name && lhs.line == rhs.line;
379 }
380
381 } // namespace aapt
382
383 namespace std {
384
385 template <>
386 struct hash<aapt::ResourceName> {
387 size_t operator()(const aapt::ResourceName& name) const {
388 android::hash_t h = 0;
389 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.package)));
390 h = android::JenkinsHashMix(h, static_cast<uint32_t>(name.type));
391 h = android::JenkinsHashMix(h, static_cast<uint32_t>(hash<string>()(name.entry)));
392 return static_cast<size_t>(h);
393 }
394 };
395
396 template <>
397 struct hash<aapt::ResourceId> {
398 size_t operator()(const aapt::ResourceId& id) const {
399 return id.id;
400 }
401 };
402
403 } // namespace std
404
405 #endif // AAPT_RESOURCE_H
406