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 
31 namespace aapt {
32 
33 /**
34  * The various types of resource types available. Corresponds
35  * to the 'type' in package:type/entry.
36  */
37 enum 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 
63 StringPiece16 toString(ResourceType type);
64 
65 /**
66  * Returns a pointer to a valid ResourceType, or nullptr if
67  * the string was invalid.
68  */
69 const ResourceType* parseResourceType(const StringPiece16& str);
70 
71 /**
72  * A resource's name. This can uniquely identify
73  * a resource in the ResourceTable.
74  */
75 struct ResourceName {
76     std::u16string package;
77     ResourceType type;
78     std::u16string entry;
79 
ResourceNameResourceName80     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  */
93 struct 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  */
122 struct 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 
136 struct SourcedResourceName {
137     ResourceName name;
138     size_t line;
139 };
140 
141 struct 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  */
158 struct ResourceKey {
159     ResourceName name;
160     ConfigDescription config;
161 };
162 
163 bool 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  */
169 struct ResourceKeyRef {
170     ResourceNameRef name;
171     ConfigDescription config;
172 
173     ResourceKeyRef() = default;
ResourceKeyRefResourceKeyRef174     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 
183 bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
184 
185 //
186 // ResourceId implementation.
187 //
188 
ResourceId()189 inline ResourceId::ResourceId() : id(0) {
190 }
191 
ResourceId(const ResourceId & rhs)192 inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {
193 }
194 
ResourceId(uint32_t resId)195 inline ResourceId::ResourceId(uint32_t resId) : id(resId) {
196 }
197 
ResourceId(uint8_t p,uint8_t t,uint16_t e)198 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e) : id((p << 24) | (t << 16) | e) {
199 }
200 
isValid()201 inline bool ResourceId::isValid() const {
202     return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
203 }
204 
packageId()205 inline uint8_t ResourceId::packageId() const {
206     return static_cast<uint8_t>(id >> 24);
207 }
208 
typeId()209 inline uint8_t ResourceId::typeId() const {
210     return static_cast<uint8_t>(id >> 16);
211 }
212 
entryId()213 inline uint16_t ResourceId::entryId() const {
214     return static_cast<uint16_t>(id);
215 }
216 
217 inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
218     return lhs.id < rhs.id;
219 }
220 
221 inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
222     return lhs.id > rhs.id;
223 }
224 
225 inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
226     return lhs.id == rhs.id;
227 }
228 
229 inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
230     return lhs.id != rhs.id;
231 }
232 
233 inline ::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 
247 inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
248     return out << toString(val);
249 }
250 
251 //
252 // ResourceName implementation.
253 //
254 
ResourceName(const StringPiece16 & p,ResourceType t,const StringPiece16 & e)255 inline ResourceName::ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e) :
256         package(p.toString()), type(t), entry(e.toString()) {
257 }
258 
isValid()259 inline bool ResourceName::isValid() const {
260     return !package.empty() && !entry.empty();
261 }
262 
263 inline 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 
268 inline 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 
273 inline 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 
toString()278 inline 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 
286 inline ::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 
ResourceNameRef(const ResourceName & rhs)298 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs) :
299         package(rhs.package), type(rhs.type), entry(rhs.entry) {
300 }
301 
ResourceNameRef(const StringPiece16 & p,ResourceType t,const StringPiece16 & e)302 inline ResourceNameRef::ResourceNameRef(const StringPiece16& p, ResourceType t,
303                                         const StringPiece16& e) :
304         package(p), type(t), entry(e) {
305 }
306 
307 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
308     package = rhs.package;
309     type = rhs.type;
310     entry = rhs.entry;
311     return *this;
312 }
313 
toResourceName()314 inline ResourceName ResourceNameRef::toResourceName() const {
315     return { package.toString(), type, entry.toString() };
316 }
317 
isValid()318 inline bool ResourceNameRef::isValid() const {
319     return !package.empty() && !entry.empty();
320 }
321 
322 inline 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 
327 inline 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 
332 inline 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 
337 inline ::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 
344 inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
345     return ResourceNameRef(lhs) < b;
346 }
347 
348 inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
349     return ResourceNameRef(lhs) != rhs;
350 }
351 
352 inline 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