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_TABLE_H
18#define AAPT_RESOURCE_TABLE_H
19
20#include "ConfigDescription.h"
21#include "Resource.h"
22#include "ResourceValues.h"
23#include "Source.h"
24#include "StringPool.h"
25
26#include <memory>
27#include <string>
28#include <tuple>
29#include <vector>
30
31namespace aapt {
32
33/**
34 * The Public status of a resource.
35 */
36struct Public {
37    bool isPublic = false;
38    SourceLine source;
39    std::u16string comment;
40};
41
42/**
43 * The resource value for a specific configuration.
44 */
45struct ResourceConfigValue {
46    ConfigDescription config;
47    SourceLine source;
48    std::u16string comment;
49    std::unique_ptr<Value> value;
50};
51
52/**
53 * Represents a resource entry, which may have
54 * varying values for each defined configuration.
55 */
56struct ResourceEntry {
57    enum {
58        kUnsetEntryId = 0xffffffffu
59    };
60
61    /**
62     * The name of the resource. Immutable, as
63     * this determines the order of this resource
64     * when doing lookups.
65     */
66    const std::u16string name;
67
68    /**
69     * The entry ID for this resource.
70     */
71    size_t entryId;
72
73    /**
74     * Whether this resource is public (and must maintain the same
75     * entry ID across builds).
76     */
77    Public publicStatus;
78
79    /**
80     * The resource's values for each configuration.
81     */
82    std::vector<ResourceConfigValue> values;
83
84    inline ResourceEntry(const StringPiece16& _name);
85    inline ResourceEntry(const ResourceEntry* rhs);
86};
87
88/**
89 * Represents a resource type, which holds entries defined
90 * for this type.
91 */
92struct ResourceTableType {
93    enum {
94        kUnsetTypeId = 0xffffffffu
95    };
96
97    /**
98     * The logical type of resource (string, drawable, layout, etc.).
99     */
100    const ResourceType type;
101
102    /**
103     * The type ID for this resource.
104     */
105    size_t typeId;
106
107    /**
108     * Whether this type is public (and must maintain the same
109     * type ID across builds).
110     */
111    Public publicStatus;
112
113    /**
114     * List of resources for this type.
115     */
116    std::vector<std::unique_ptr<ResourceEntry>> entries;
117
118    ResourceTableType(const ResourceType _type);
119    ResourceTableType(const ResourceTableType* rhs);
120};
121
122/**
123 * The container and index for all resources defined for an app. This gets
124 * flattened into a binary resource table (resources.arsc).
125 */
126class ResourceTable {
127public:
128    using iterator = std::vector<std::unique_ptr<ResourceTableType>>::iterator;
129    using const_iterator = std::vector<std::unique_ptr<ResourceTableType>>::const_iterator;
130
131    enum {
132        kUnsetPackageId = 0xffffffff
133    };
134
135    ResourceTable();
136
137    size_t getPackageId() const;
138    void setPackageId(size_t packageId);
139
140    const std::u16string& getPackage() const;
141    void setPackage(const StringPiece16& package);
142
143    bool addResource(const ResourceNameRef& name, const ConfigDescription& config,
144                     const SourceLine& source, std::unique_ptr<Value> value);
145
146    /**
147     * Same as addResource, but doesn't verify the validity of the name. This is used
148     * when loading resources from an existing binary resource table that may have mangled
149     * names.
150     */
151    bool addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config,
152                                 const SourceLine& source, std::unique_ptr<Value> value);
153
154    bool addResource(const ResourceNameRef& name, const ResourceId resId,
155                     const ConfigDescription& config, const SourceLine& source,
156                     std::unique_ptr<Value> value);
157
158    bool markPublic(const ResourceNameRef& name, const ResourceId resId, const SourceLine& source);
159    bool markPublicAllowMangled(const ResourceNameRef& name, const ResourceId resId,
160                                const SourceLine& source);
161
162    /*
163     * Merges the resources from `other` into this table, mangling the names of the resources
164     * if `other` has a different package name.
165     */
166    bool merge(ResourceTable&& other);
167
168    /**
169     * Returns the string pool used by this ResourceTable.
170     * Values that reference strings should use this pool to create
171     * their strings.
172     */
173    StringPool& getValueStringPool();
174    const StringPool& getValueStringPool() const;
175
176    std::tuple<const ResourceTableType*, const ResourceEntry*>
177    findResource(const ResourceNameRef& name) const;
178
179    iterator begin();
180    iterator end();
181    const_iterator begin() const;
182    const_iterator end() const;
183
184private:
185    std::unique_ptr<ResourceTableType>& findOrCreateType(ResourceType type);
186    std::unique_ptr<ResourceEntry>& findOrCreateEntry(std::unique_ptr<ResourceTableType>& type,
187                                                      const StringPiece16& name);
188
189    bool addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
190                         const ConfigDescription& config, const SourceLine& source,
191                         std::unique_ptr<Value> value, const char16_t* validChars);
192    bool markPublicImpl(const ResourceNameRef& name, const ResourceId resId,
193                        const SourceLine& source, const char16_t* validChars);
194
195    std::u16string mPackage;
196    size_t mPackageId;
197
198    // StringPool must come before mTypes so that it is destroyed after.
199    // When StringPool references are destroyed (as they will be when mTypes
200    // is destroyed), they decrement a refCount, which would cause invalid
201    // memory access if the pool was already destroyed.
202    StringPool mValuePool;
203
204    std::vector<std::unique_ptr<ResourceTableType>> mTypes;
205};
206
207//
208// ResourceEntry implementation.
209//
210
211inline ResourceEntry::ResourceEntry(const StringPiece16& _name) :
212        name(_name.toString()), entryId(kUnsetEntryId) {
213}
214
215inline ResourceEntry::ResourceEntry(const ResourceEntry* rhs) :
216        name(rhs->name), entryId(rhs->entryId), publicStatus(rhs->publicStatus) {
217}
218
219//
220// ResourceTableType implementation.
221//
222
223inline ResourceTableType::ResourceTableType(const ResourceType _type) :
224        type(_type), typeId(kUnsetTypeId) {
225}
226
227inline ResourceTableType::ResourceTableType(const ResourceTableType* rhs) :
228        type(rhs->type), typeId(rhs->typeId), publicStatus(rhs->publicStatus) {
229}
230
231//
232// ResourceTable implementation.
233//
234
235inline StringPool& ResourceTable::getValueStringPool() {
236    return mValuePool;
237}
238
239inline const StringPool& ResourceTable::getValueStringPool() const {
240    return mValuePool;
241}
242
243inline ResourceTable::iterator ResourceTable::begin() {
244    return mTypes.begin();
245}
246
247inline ResourceTable::iterator ResourceTable::end() {
248    return mTypes.end();
249}
250
251inline ResourceTable::const_iterator ResourceTable::begin() const {
252    return mTypes.begin();
253}
254
255inline ResourceTable::const_iterator ResourceTable::end() const {
256    return mTypes.end();
257}
258
259inline const std::u16string& ResourceTable::getPackage() const {
260    return mPackage;
261}
262
263inline size_t ResourceTable::getPackageId() const {
264    return mPackageId;
265}
266
267inline void ResourceTable::setPackage(const StringPiece16& package) {
268    mPackage = package.toString();
269}
270
271inline void ResourceTable::setPackageId(size_t packageId) {
272    mPackageId = packageId;
273}
274
275} // namespace aapt
276
277#endif // AAPT_RESOURCE_TABLE_H
278