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