blob: c10b134cb36ec3e0e0b452c17675243c9971e38c [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
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#include "Resource.h"
Adam Lesinskia5870652015-11-20 15:32:30 -080018#include "ResourceUtils.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080019#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "ValueVisitor.h"
Adam Lesinski355f2852016-02-13 20:26:45 -080021#include "io/File.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070022#include "util/Util.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070023
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include <androidfw/ResourceTypes.h>
25#include <limits>
26
27namespace aapt {
28
Adam Lesinski1ab598f2015-08-14 14:26:04 -070029template <typename Derived>
30void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
31 visitor->visit(static_cast<Derived*>(this));
32}
33
34template <typename Derived>
35void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
36 visitor->visit(static_cast<Derived*>(this));
37}
38
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080039RawString::RawString(const StringPool::Ref& ref) : value(ref) {
40}
41
Adam Lesinski458b8772016-04-25 14:20:21 -070042bool RawString::equals(const Value* value) const {
43 const RawString* other = valueCast<RawString>(value);
44 if (!other) {
45 return false;
46 }
47 return *this->value == *other->value;
48}
49
Adam Lesinski769de982015-04-10 19:43:55 -070050RawString* RawString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -080051 RawString* rs = new RawString(newPool->makeRef(*value));
52 rs->mComment = mComment;
53 rs->mSource = mSource;
54 return rs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080055}
56
Adam Lesinski1ab598f2015-08-14 14:26:04 -070057bool RawString::flatten(android::Res_value* outValue) const {
Adam Lesinski59e04c62016-02-04 15:59:23 -080058 outValue->dataType = android::Res_value::TYPE_STRING;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080060 return true;
61}
62
Adam Lesinski1ab598f2015-08-14 14:26:04 -070063void RawString::print(std::ostream* out) const {
64 *out << "(raw string) " << *value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080065}
66
67Reference::Reference() : referenceType(Reference::Type::kResource) {
68}
69
70Reference::Reference(const ResourceNameRef& n, Type t) :
71 name(n.toResourceName()), referenceType(t) {
72}
73
74Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
75}
76
Adam Lesinski458b8772016-04-25 14:20:21 -070077bool Reference::equals(const Value* value) const {
78 const Reference* other = valueCast<Reference>(value);
79 if (!other) {
80 return false;
81 }
82 return referenceType == other->referenceType && privateReference == other->privateReference &&
83 id == other->id && name == other->name;
84}
85
Adam Lesinski1ab598f2015-08-14 14:26:04 -070086bool Reference::flatten(android::Res_value* outValue) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080087 outValue->dataType = (referenceType == Reference::Type::kResource) ?
88 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070089 outValue->data = util::hostToDevice32(id ? id.value().id : 0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080090 return true;
91}
92
Adam Lesinski769de982015-04-10 19:43:55 -070093Reference* Reference::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080094 return new Reference(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080095}
96
Adam Lesinski1ab598f2015-08-14 14:26:04 -070097void Reference::print(std::ostream* out) const {
98 *out << "(reference) ";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080099 if (referenceType == Reference::Type::kResource) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700100 *out << "@";
Adam Lesinski467f1712015-11-16 17:35:44 -0800101 if (privateReference) {
102 *out << "*";
103 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800104 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700105 *out << "?";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800106 }
107
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700108 if (name) {
109 *out << name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800110 }
111
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700112 if (id && !Res_INTERNALID(id.value().id)) {
113 *out << " " << id.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114 }
115}
116
Adam Lesinski458b8772016-04-25 14:20:21 -0700117bool Id::equals(const Value* value) const {
118 return valueCast<Id>(value) != nullptr;
119}
120
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700121bool Id::flatten(android::Res_value* out) const {
122 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
123 out->data = util::hostToDevice32(0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800124 return true;
125}
126
Adam Lesinski769de982015-04-10 19:43:55 -0700127Id* Id::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800128 return new Id(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800129}
130
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700131void Id::print(std::ostream* out) const {
132 *out << "(id)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800133}
134
Adam Lesinski458b8772016-04-25 14:20:21 -0700135String::String(const StringPool::Ref& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800136}
137
Adam Lesinski458b8772016-04-25 14:20:21 -0700138bool String::equals(const Value* value) const {
139 const String* other = valueCast<String>(value);
140 if (!other) {
141 return false;
142 }
143 return *this->value == *other->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800144}
145
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146bool String::flatten(android::Res_value* outValue) const {
147 // Verify that our StringPool index is within encode-able limits.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800148 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
149 return false;
150 }
151
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700152 outValue->dataType = android::Res_value::TYPE_STRING;
153 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800154 return true;
155}
156
Adam Lesinski769de982015-04-10 19:43:55 -0700157String* String::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800158 String* str = new String(newPool->makeRef(*value));
159 str->mComment = mComment;
160 str->mSource = mSource;
161 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800162}
163
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700164void String::print(std::ostream* out) const {
165 *out << "(string) \"" << *value << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800166}
167
Adam Lesinski458b8772016-04-25 14:20:21 -0700168StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800169}
170
Adam Lesinski458b8772016-04-25 14:20:21 -0700171bool StyledString::equals(const Value* value) const {
172 const StyledString* other = valueCast<StyledString>(value);
173 if (!other) {
174 return false;
175 }
Adam Lesinski393b5f02015-12-17 13:03:11 -0800176
Adam Lesinski458b8772016-04-25 14:20:21 -0700177 if (*this->value->str == *other->value->str) {
178 const std::vector<StringPool::Span>& spansA = this->value->spans;
179 const std::vector<StringPool::Span>& spansB = other->value->spans;
180 return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
181 [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
182 return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
183 });
184 }
185 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800186}
187
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700188bool StyledString::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800189 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
190 return false;
191 }
192
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700193 outValue->dataType = android::Res_value::TYPE_STRING;
194 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800195 return true;
196}
197
Adam Lesinski769de982015-04-10 19:43:55 -0700198StyledString* StyledString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800199 StyledString* str = new StyledString(newPool->makeRef(value));
200 str->mComment = mComment;
201 str->mSource = mSource;
202 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800203}
204
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700205void StyledString::print(std::ostream* out) const {
206 *out << "(styled string) \"" << *value->str << "\"";
Adam Lesinski458b8772016-04-25 14:20:21 -0700207 for (const StringPool::Span& span : value->spans) {
208 *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
209 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800210}
211
212FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
213}
214
Adam Lesinski458b8772016-04-25 14:20:21 -0700215bool FileReference::equals(const Value* value) const {
216 const FileReference* other = valueCast<FileReference>(value);
217 if (!other) {
218 return false;
219 }
220 return *path == *other->path;
221}
222
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700223bool FileReference::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800224 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
225 return false;
226 }
227
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700228 outValue->dataType = android::Res_value::TYPE_STRING;
229 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800230 return true;
231}
232
Adam Lesinski769de982015-04-10 19:43:55 -0700233FileReference* FileReference::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800234 FileReference* fr = new FileReference(newPool->makeRef(*path));
Adam Lesinski355f2852016-02-13 20:26:45 -0800235 fr->file = file;
Adam Lesinskib274e352015-11-06 15:14:35 -0800236 fr->mComment = mComment;
237 fr->mSource = mSource;
238 return fr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800239}
240
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700241void FileReference::print(std::ostream* out) const {
242 *out << "(file) " << *path;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800243}
244
245BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
246}
247
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700248BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
249 value.dataType = dataType;
250 value.data = data;
251}
252
Adam Lesinski458b8772016-04-25 14:20:21 -0700253bool BinaryPrimitive::equals(const Value* value) const {
254 const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
255 if (!other) {
256 return false;
257 }
258 return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
259}
260
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700261bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
262 outValue->dataType = value.dataType;
263 outValue->data = util::hostToDevice32(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800264 return true;
265}
266
Adam Lesinski769de982015-04-10 19:43:55 -0700267BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800268 return new BinaryPrimitive(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800269}
270
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700271void BinaryPrimitive::print(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800272 switch (value.dataType) {
273 case android::Res_value::TYPE_NULL:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700274 *out << "(null)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800275 break;
276 case android::Res_value::TYPE_INT_DEC:
Adam Lesinskia5870652015-11-20 15:32:30 -0800277 *out << "(integer) " << static_cast<int32_t>(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800278 break;
279 case android::Res_value::TYPE_INT_HEX:
Adam Lesinski458b8772016-04-25 14:20:21 -0700280 *out << "(integer) 0x" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281 break;
282 case android::Res_value::TYPE_INT_BOOLEAN:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700283 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284 break;
285 case android::Res_value::TYPE_INT_COLOR_ARGB8:
286 case android::Res_value::TYPE_INT_COLOR_RGB8:
287 case android::Res_value::TYPE_INT_COLOR_ARGB4:
288 case android::Res_value::TYPE_INT_COLOR_RGB4:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700289 *out << "(color) #" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800290 break;
291 default:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700292 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
293 << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800294 break;
295 }
296}
297
Adam Lesinskia5870652015-11-20 15:32:30 -0800298Attribute::Attribute(bool w, uint32_t t) :
Adam Lesinski393b5f02015-12-17 13:03:11 -0800299 typeMask(t),
Adam Lesinskia5870652015-11-20 15:32:30 -0800300 minInt(std::numeric_limits<int32_t>::min()),
301 maxInt(std::numeric_limits<int32_t>::max()) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800302 mWeak = w;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800303}
304
Adam Lesinski458b8772016-04-25 14:20:21 -0700305bool Attribute::equals(const Value* value) const {
306 const Attribute* other = valueCast<Attribute>(value);
307 if (!other) {
308 return false;
309 }
310
311 return this->typeMask == other->typeMask && this->minInt == other->minInt &&
312 this->maxInt == other->maxInt &&
313 std::equal(this->symbols.begin(), this->symbols.end(),
314 other->symbols.begin(),
315 [](const Symbol& a, const Symbol& b) -> bool {
316 return a.symbol.equals(&b.symbol) && a.value == b.value;
317 });
318}
319
Adam Lesinski769de982015-04-10 19:43:55 -0700320Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800321 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800322}
323
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700324void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800325 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700326 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800327 return;
328 }
329
330 bool set = false;
331 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
332 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800333 set = true;
334 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700335 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800336 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700337 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800338 }
339
340 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
341 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800342 set = true;
343 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700344 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800345 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700346 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800347 }
348
349 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
350 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800351 set = true;
352 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700353 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800354 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700355 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800356 }
357
358 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
359 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800360 set = true;
361 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700362 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800363 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700364 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800365 }
366
367 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
368 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800369 set = true;
370 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700371 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800372 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700373 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800374 }
375
376 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
377 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800378 set = true;
379 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700380 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800381 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700382 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800383 }
384
385 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
386 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800387 set = true;
388 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700389 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800390 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700391 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800392 }
393
394 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
395 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800396 set = true;
397 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700398 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800399 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700400 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800401 }
402
403 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
404 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800405 set = true;
406 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700407 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800408 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700409 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800410 }
411
412 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
413 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800414 set = true;
415 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700416 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800417 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700418 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800419 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700420}
421
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700422void Attribute::print(std::ostream* out) const {
423 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700424 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800425
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700426 if (!symbols.empty()) {
427 *out << " ["
428 << util::joiner(symbols.begin(), symbols.end(), ", ")
429 << "]";
430 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800431
Adam Lesinski458b8772016-04-25 14:20:21 -0700432 if (minInt != std::numeric_limits<int32_t>::min()) {
433 *out << " min=" << minInt;
434 }
435
436 if (maxInt != std::numeric_limits<int32_t>::max()) {
437 *out << " max=" << maxInt;
438 }
439
Adam Lesinski393b5f02015-12-17 13:03:11 -0800440 if (isWeak()) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700441 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800442 }
443}
444
Adam Lesinskia5870652015-11-20 15:32:30 -0800445static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
446 const Item* value) {
447 *msg << "expected";
448 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
449 *msg << " boolean";
450 }
451
452 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
453 *msg << " color";
454 }
455
456 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
457 *msg << " dimension";
458 }
459
460 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
461 *msg << " enum";
462 }
463
464 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
465 *msg << " flags";
466 }
467
468 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
469 *msg << " float";
470 }
471
472 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
473 *msg << " fraction";
474 }
475
476 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
477 *msg << " integer";
478 }
479
480 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
481 *msg << " reference";
482 }
483
484 if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
485 *msg << " string";
486 }
487
488 *msg << " but got " << *value;
489}
490
491bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
492 android::Res_value val = {};
493 item->flatten(&val);
494
495 // Always allow references.
496 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
497 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
498 if (outMsg) {
499 buildAttributeMismatchMessage(outMsg, this, item);
500 }
501 return false;
502
503 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
504 android::ResTable_map::TYPE_INTEGER) {
505 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
506 if (outMsg) {
507 *outMsg << *item << " is less than minimum integer " << minInt;
508 }
509 return false;
510 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
511 if (outMsg) {
512 *outMsg << *item << " is greater than maximum integer " << maxInt;
513 }
514 return false;
515 }
516 }
517 return true;
518}
519
Adam Lesinski458b8772016-04-25 14:20:21 -0700520bool Style::equals(const Value* value) const {
521 const Style* other = valueCast<Style>(value);
522 if (!other) {
523 return false;
524 }
525 if (bool(parent) != bool(other->parent) ||
526 (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
527 return false;
528 }
529 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
530 [](const Entry& a, const Entry& b) -> bool {
531 return a.key.equals(&b.key) && a.value->equals(b.value.get());
532 });
533}
534
Adam Lesinski769de982015-04-10 19:43:55 -0700535Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700536 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800537 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700538 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800539 style->mComment = mComment;
540 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800541 for (auto& entry : entries) {
542 style->entries.push_back(Entry{
543 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700544 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800545 });
546 }
547 return style;
548}
549
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700550void Style::print(std::ostream* out) const {
551 *out << "(style) ";
552 if (parent && parent.value().name) {
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800553 if (parent.value().privateReference) {
554 *out << "*";
555 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700556 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800557 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700558 *out << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800559 << util::joiner(entries.begin(), entries.end(), ", ")
560 << "]";
561}
562
563static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700564 if (value.key.name) {
565 out << value.key.name.value();
566 } else {
567 out << "???";
568 }
569 out << " = ";
570 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800571 return out;
572}
573
Adam Lesinski458b8772016-04-25 14:20:21 -0700574bool Array::equals(const Value* value) const {
575 const Array* other = valueCast<Array>(value);
576 if (!other) {
577 return false;
578 }
579
580 return std::equal(items.begin(), items.end(), other->items.begin(),
581 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
582 return a->equals(b.get());
583 });
584}
585
Adam Lesinski769de982015-04-10 19:43:55 -0700586Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800587 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800588 array->mComment = mComment;
589 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800590 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700591 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800592 }
593 return array;
594}
595
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700596void Array::print(std::ostream* out) const {
597 *out << "(array) ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800598 << util::joiner(items.begin(), items.end(), ", ")
599 << "]";
600}
601
Adam Lesinski458b8772016-04-25 14:20:21 -0700602bool Plural::equals(const Value* value) const {
603 const Plural* other = valueCast<Plural>(value);
604 if (!other) {
605 return false;
606 }
607
608 return std::equal(values.begin(), values.end(), other->values.begin(),
609 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
610 if (bool(a) != bool(b)) {
611 return false;
612 }
613 return bool(a) == bool(b) || a->equals(b.get());
614 });
615}
616
Adam Lesinski769de982015-04-10 19:43:55 -0700617Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800618 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800619 p->mComment = mComment;
620 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800621 const size_t count = values.size();
622 for (size_t i = 0; i < count; i++) {
623 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700624 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800625 }
626 }
627 return p;
628}
629
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700630void Plural::print(std::ostream* out) const {
631 *out << "(plural)";
Adam Lesinski458b8772016-04-25 14:20:21 -0700632 if (values[Zero]) {
633 *out << " zero=" << *values[Zero];
634 }
635
636 if (values[One]) {
637 *out << " one=" << *values[One];
638 }
639
640 if (values[Two]) {
641 *out << " two=" << *values[Two];
642 }
643
644 if (values[Few]) {
645 *out << " few=" << *values[Few];
646 }
647
648 if (values[Many]) {
649 *out << " many=" << *values[Many];
650 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800651}
652
653static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
654 return out << *item;
655}
656
Adam Lesinski458b8772016-04-25 14:20:21 -0700657bool Styleable::equals(const Value* value) const {
658 const Styleable* other = valueCast<Styleable>(value);
659 if (!other) {
660 return false;
661 }
662 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
663 [](const Reference& a, const Reference& b) -> bool {
664 return a.equals(&b);
665 });
666}
667
Adam Lesinski769de982015-04-10 19:43:55 -0700668Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800669 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800670}
671
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700672void Styleable::print(std::ostream* out) const {
673 *out << "(styleable) " << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800674 << util::joiner(entries.begin(), entries.end(), ", ")
675 << "]";
676}
677
678} // namespace aapt