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
33namespace aapt {
34
35/**
36 * The various types of resource types available. Corresponds
37 * to the 'type' in package:type/entry.
38 */
39enum 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
72android::StringPiece to_string(ResourceType type);
73
74/**
75 * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
76 */
77const ResourceType* ParseResourceType(const android::StringPiece& str);
78
79/**
80 * A resource's name. This can uniquely identify
81 * a resource in the ResourceTable.
82 */
83struct 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 */
103struct 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
123constexpr const uint8_t kAppPackageId = 0x7fu;
124constexpr 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 */
137struct 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
157struct SourcedResourceName {
158  ResourceName name;
159  size_t line;
160};
161
162struct 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 */
190struct ResourceKey {
191  ResourceName name;
192  ConfigDescription config;
193};
194
195bool 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 */
202struct ResourceKeyRef {
203  ResourceNameRef name;
204  ConfigDescription config;
205
206  ResourceKeyRef() = default;
207  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
216bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
217
218//
219// ResourceId implementation.
220//
221
222inline ResourceId::ResourceId() : id(0) {}
223
224inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {}
225
226inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
227
228inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
229    : id((p << 24) | (t << 16) | e) {}
230
231inline bool ResourceId::is_valid() const {
232  return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
233}
234
235inline bool ResourceId::is_valid_dynamic() const {
236  return (id & 0x00ff0000u) != 0;
237}
238
239inline uint8_t ResourceId::package_id() const {
240  return static_cast<uint8_t>(id >> 24);
241}
242
243inline uint8_t ResourceId::type_id() const {
244  return static_cast<uint8_t>(id >> 16);
245}
246
247inline uint16_t ResourceId::entry_id() const {
248  return static_cast<uint16_t>(id);
249}
250
251inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
252  return lhs.id < rhs.id;
253}
254
255inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
256  return lhs.id > rhs.id;
257}
258
259inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
260  return lhs.id == rhs.id;
261}
262
263inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
264  return lhs.id != rhs.id;
265}
266
267inline ::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);'.
272inline std::string to_string(const ResourceId& id) {
273  return id.to_string();
274}
275
276//
277// ResourceType implementation.
278//
279
280inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
281  return out << to_string(val);
282}
283
284//
285// ResourceName implementation.
286//
287
288inline 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
292inline 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
301inline bool ResourceName::is_valid() const {
302  return !package.empty() && !entry.empty();
303}
304
305inline 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
310inline 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
315inline 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
320inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
321  return out << name.to_string();
322}
323
324//
325// ResourceNameRef implementation.
326//
327
328inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
329    : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
330
331inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
332                                        const android::StringPiece& e)
333    : package(p), type(t), entry(e) {}
334
335inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
336  package = rhs.package;
337  type = rhs.type;
338  entry = rhs.entry;
339  return *this;
340}
341
342inline ResourceName ResourceNameRef::ToResourceName() const {
343  return ResourceName(package, type, entry);
344}
345
346inline bool ResourceNameRef::is_valid() const {
347  return !package.empty() && !entry.empty();
348}
349
350inline 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
355inline 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
360inline 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
365inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
366  return out << name.to_string();
367}
368
369inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
370  return ResourceNameRef(lhs) < b;
371}
372
373inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
374  return ResourceNameRef(lhs) != rhs;
375}
376
377inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
378  return lhs.name == rhs.name && lhs.line == rhs.line;
379}
380
381}  // namespace aapt
382
383namespace std {
384
385template <>
386struct 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
396template <>
397struct 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