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