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 "ConfigDescription.h"
21#include "Source.h"
22
23#include "util/StringPiece.h"
24
25#include <iomanip>
26#include <limits>
27#include <string>
28#include <tuple>
29#include <vector>
30
31namespace aapt {
32
33/**
34 * The various types of resource types available. Corresponds
35 * to the 'type' in package:type/entry.
36 */
37enum class ResourceType {
38    kAnim,
39    kAnimator,
40    kArray,
41    kAttr,
42    kAttrPrivate,
43    kBool,
44    kColor,
45    kDimen,
46    kDrawable,
47    kFraction,
48    kId,
49    kInteger,
50    kInterpolator,
51    kLayout,
52    kMenu,
53    kMipmap,
54    kPlurals,
55    kRaw,
56    kString,
57    kStyle,
58    kStyleable,
59    kTransition,
60    kXml,
61};
62
63StringPiece16 toString(ResourceType type);
64
65/**
66 * Returns a pointer to a valid ResourceType, or nullptr if
67 * the string was invalid.
68 */
69const ResourceType* parseResourceType(const StringPiece16& str);
70
71/**
72 * A resource's name. This can uniquely identify
73 * a resource in the ResourceTable.
74 */
75struct ResourceName {
76    std::u16string package;
77    ResourceType type;
78    std::u16string entry;
79
80    ResourceName() : type(ResourceType::kRaw) {}
81    ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);
82
83    bool isValid() const;
84    std::u16string toString() const;
85};
86
87/**
88 * Same as ResourceName, but uses StringPieces instead.
89 * Use this if you need to avoid copying and know that
90 * the lifetime of this object is shorter than that
91 * of the original string.
92 */
93struct ResourceNameRef {
94    StringPiece16 package;
95    ResourceType type;
96    StringPiece16 entry;
97
98    ResourceNameRef() = default;
99    ResourceNameRef(const ResourceNameRef&) = default;
100    ResourceNameRef(ResourceNameRef&&) = default;
101    ResourceNameRef(const ResourceName& rhs);
102    ResourceNameRef(const StringPiece16& p, ResourceType t, const StringPiece16& e);
103    ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
104    ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
105    ResourceNameRef& operator=(const ResourceName& rhs);
106
107    ResourceName toResourceName() const;
108    bool isValid() const;
109};
110
111/**
112 * A binary identifier representing a resource. Internally it
113 * is a 32bit integer split as follows:
114 *
115 * 0xPPTTEEEE
116 *
117 * PP: 8 bit package identifier. 0x01 is reserved for system
118 *     and 0x7f is reserved for the running app.
119 * TT: 8 bit type identifier. 0x00 is invalid.
120 * EEEE: 16 bit entry identifier.
121 */
122struct ResourceId {
123    uint32_t id;
124
125    ResourceId();
126    ResourceId(const ResourceId& rhs);
127    ResourceId(uint32_t resId);
128    ResourceId(uint8_t p, uint8_t t, uint16_t e);
129
130    bool isValid() const;
131    uint8_t packageId() const;
132    uint8_t typeId() const;
133    uint16_t entryId() const;
134};
135
136struct SourcedResourceName {
137    ResourceName name;
138    size_t line;
139};
140
141struct ResourceFile {
142    // Name
143    ResourceName name;
144
145    // Configuration
146    ConfigDescription config;
147
148    // Source
149    Source source;
150
151    // Exported symbols
152    std::vector<SourcedResourceName> exportedSymbols;
153};
154
155/**
156 * Useful struct used as a key to represent a unique resource in associative containers.
157 */
158struct ResourceKey {
159    ResourceName name;
160    ConfigDescription config;
161};
162
163bool operator<(const ResourceKey& a, const ResourceKey& b);
164
165/**
166 * Useful struct used as a key to represent a unique resource in associative containers.
167 * Holds a reference to the name, so that name better live longer than this key!
168 */
169struct ResourceKeyRef {
170    ResourceNameRef name;
171    ConfigDescription config;
172
173    ResourceKeyRef() = default;
174    ResourceKeyRef(const ResourceNameRef& n, const ConfigDescription& c) : name(n), config(c) {
175    }
176
177    /**
178     * Prevent taking a reference to a temporary. This is bad.
179     */
180    ResourceKeyRef(ResourceName&& n, const ConfigDescription& c) = delete;
181};
182
183bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
184
185//
186// ResourceId implementation.
187//
188
189inline ResourceId::ResourceId() : id(0) {
190}
191
192inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {
193}
194
195inline ResourceId::ResourceId(uint32_t resId) : id(resId) {
196}
197
198inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e) : id((p << 24) | (t << 16) | e) {
199}
200
201inline bool ResourceId::isValid() const {
202    return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
203}
204
205inline uint8_t ResourceId::packageId() const {
206    return static_cast<uint8_t>(id >> 24);
207}
208
209inline uint8_t ResourceId::typeId() const {
210    return static_cast<uint8_t>(id >> 16);
211}
212
213inline uint16_t ResourceId::entryId() const {
214    return static_cast<uint16_t>(id);
215}
216
217inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
218    return lhs.id < rhs.id;
219}
220
221inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
222    return lhs.id > rhs.id;
223}
224
225inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
226    return lhs.id == rhs.id;
227}
228
229inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
230    return lhs.id != rhs.id;
231}
232
233inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& resId) {
234    std::ios_base::fmtflags oldFlags = out.flags();
235    char oldFill = out.fill();
236    out << "0x" << std::internal << std::setfill('0') << std::setw(8)
237        << std::hex << resId.id;
238    out.flags(oldFlags);
239    out.fill(oldFill);
240    return out;
241}
242
243//
244// ResourceType implementation.
245//
246
247inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
248    return out << toString(val);
249}
250
251//
252// ResourceName implementation.
253//
254
255inline ResourceName::ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e) :
256        package(p.toString()), type(t), entry(e.toString()) {
257}
258
259inline bool ResourceName::isValid() const {
260    return !package.empty() && !entry.empty();
261}
262
263inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
264    return std::tie(lhs.package, lhs.type, lhs.entry)
265            < std::tie(rhs.package, rhs.type, rhs.entry);
266}
267
268inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
269    return std::tie(lhs.package, lhs.type, lhs.entry)
270            == std::tie(rhs.package, rhs.type, rhs.entry);
271}
272
273inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
274    return std::tie(lhs.package, lhs.type, lhs.entry)
275            != std::tie(rhs.package, rhs.type, rhs.entry);
276}
277
278inline std::u16string ResourceName::toString() const {
279    std::u16string result;
280    if (!package.empty()) {
281        result = package + u":";
282    }
283    return result + aapt::toString(type).toString() + u"/" + entry;
284}
285
286inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
287    if (!name.package.empty()) {
288        out << name.package << ":";
289    }
290    return out << name.type << "/" << name.entry;
291}
292
293
294//
295// ResourceNameRef implementation.
296//
297
298inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs) :
299        package(rhs.package), type(rhs.type), entry(rhs.entry) {
300}
301
302inline ResourceNameRef::ResourceNameRef(const StringPiece16& p, ResourceType t,
303                                        const StringPiece16& e) :
304        package(p), type(t), entry(e) {
305}
306
307inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
308    package = rhs.package;
309    type = rhs.type;
310    entry = rhs.entry;
311    return *this;
312}
313
314inline ResourceName ResourceNameRef::toResourceName() const {
315    return { package.toString(), type, entry.toString() };
316}
317
318inline bool ResourceNameRef::isValid() const {
319    return !package.empty() && !entry.empty();
320}
321
322inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
323    return std::tie(lhs.package, lhs.type, lhs.entry)
324            < std::tie(rhs.package, rhs.type, rhs.entry);
325}
326
327inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
328    return std::tie(lhs.package, lhs.type, lhs.entry)
329            == std::tie(rhs.package, rhs.type, rhs.entry);
330}
331
332inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
333    return std::tie(lhs.package, lhs.type, lhs.entry)
334            != std::tie(rhs.package, rhs.type, rhs.entry);
335}
336
337inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
338    if (!name.package.empty()) {
339        out << name.package << ":";
340    }
341    return out << name.type << "/" << name.entry;
342}
343
344inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
345    return ResourceNameRef(lhs) < b;
346}
347
348inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
349    return ResourceNameRef(lhs) != rhs;
350}
351
352inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
353    return lhs.name == rhs.name && lhs.line == rhs.line;
354}
355
356} // namespace aapt
357
358#endif // AAPT_RESOURCE_H
359