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  kPlurals,
63  kRaw,
64  kString,
65  kStyle,
66  kStyleable,
67  kTransition,
68  kXml,
69};
70
71android::StringPiece ToString(ResourceType type);
72
73/**
74 * Returns a pointer to a valid ResourceType, or nullptr if
75 * 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 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 */
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  ResourceName ToResourceName() const;
118  bool is_valid() const;
119};
120
121constexpr const uint8_t kAppPackageId = 0x7fu;
122constexpr 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 */
135struct 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
153struct SourcedResourceName {
154  ResourceName name;
155  size_t line;
156};
157
158struct 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 */
176struct ResourceKey {
177  ResourceName name;
178  ConfigDescription config;
179};
180
181bool 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 */
188struct ResourceKeyRef {
189  ResourceNameRef name;
190  ConfigDescription config;
191
192  ResourceKeyRef() = default;
193  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
202bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
203
204//
205// ResourceId implementation.
206//
207
208inline ResourceId::ResourceId() : id(0) {}
209
210inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {}
211
212inline ResourceId::ResourceId(uint32_t res_id) : id(res_id) {}
213
214inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
215    : id((p << 24) | (t << 16) | e) {}
216
217inline bool ResourceId::is_valid() const {
218  return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
219}
220
221inline bool ResourceId::is_valid_dynamic() const { return (id & 0x00ff0000u) != 0; }
222
223inline uint8_t ResourceId::package_id() const {
224  return static_cast<uint8_t>(id >> 24);
225}
226
227inline uint8_t ResourceId::type_id() const {
228  return static_cast<uint8_t>(id >> 16);
229}
230
231inline uint16_t ResourceId::entry_id() const {
232  return static_cast<uint16_t>(id);
233}
234
235inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
236  return lhs.id < rhs.id;
237}
238
239inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
240  return lhs.id > rhs.id;
241}
242
243inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
244  return lhs.id == rhs.id;
245}
246
247inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
248  return lhs.id != rhs.id;
249}
250
251inline ::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
266inline ::std::ostream& operator<<(::std::ostream& out,
267                                  const ResourceType& val) {
268  return out << ToString(val);
269}
270
271//
272// ResourceName implementation.
273//
274
275inline 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
279inline 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
288inline bool ResourceName::is_valid() const {
289  return !package.empty() && !entry.empty();
290}
291
292inline 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
297inline 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
302inline 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
307inline ::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
315inline std::string ResourceName::ToString() const {
316  std::stringstream stream;
317  stream << *this;
318  return stream.str();
319}
320
321//
322// ResourceNameRef implementation.
323//
324
325inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
326    : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
327
328inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
329                                        const android::StringPiece& e)
330    : package(p), type(t), entry(e) {}
331
332inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
333  package = rhs.package;
334  type = rhs.type;
335  entry = rhs.entry;
336  return *this;
337}
338
339inline ResourceName ResourceNameRef::ToResourceName() const {
340  return ResourceName(package, type, entry);
341}
342
343inline bool ResourceNameRef::is_valid() const {
344  return !package.empty() && !entry.empty();
345}
346
347inline 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
352inline 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
357inline 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
362inline ::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
370inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
371  return ResourceNameRef(lhs) < b;
372}
373
374inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
375  return ResourceNameRef(lhs) != rhs;
376}
377
378inline 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
385namespace std {
386
387template <>
388struct 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
398template <>
399struct 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