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