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