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