blob: 492155ddb591036de3ecdce2e44b7f55ff1d5c3f [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 Lesinskie78fd612015-10-22 12:48:43 -070021#include "util/Util.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070022
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070023#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include <androidfw/ResourceTypes.h>
25#include <limits>
Adam Lesinski8197cc462016-08-19 12:16:49 -070026#include <set>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027
28namespace aapt {
29
Adam Lesinski1ab598f2015-08-14 14:26:04 -070030template <typename Derived>
31void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
32 visitor->visit(static_cast<Derived*>(this));
33}
34
35template <typename Derived>
36void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
37 visitor->visit(static_cast<Derived*>(this));
38}
39
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080040RawString::RawString(const StringPool::Ref& ref) : value(ref) {
41}
42
Adam Lesinski458b8772016-04-25 14:20:21 -070043bool RawString::equals(const Value* value) const {
44 const RawString* other = valueCast<RawString>(value);
45 if (!other) {
46 return false;
47 }
48 return *this->value == *other->value;
49}
50
Adam Lesinski769de982015-04-10 19:43:55 -070051RawString* RawString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -080052 RawString* rs = new RawString(newPool->makeRef(*value));
53 rs->mComment = mComment;
54 rs->mSource = mSource;
55 return rs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080056}
57
Adam Lesinski1ab598f2015-08-14 14:26:04 -070058bool RawString::flatten(android::Res_value* outValue) const {
Adam Lesinski59e04c62016-02-04 15:59:23 -080059 outValue->dataType = android::Res_value::TYPE_STRING;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070060 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061 return true;
62}
63
Adam Lesinski1ab598f2015-08-14 14:26:04 -070064void RawString::print(std::ostream* out) const {
65 *out << "(raw string) " << *value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080066}
67
Adam Lesinski5c3464c2016-08-24 16:03:48 -070068Reference::Reference() : referenceType(Type::kResource) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080069}
70
71Reference::Reference(const ResourceNameRef& n, Type t) :
72 name(n.toResourceName()), referenceType(t) {
73}
74
75Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
76}
77
Adam Lesinski5c3464c2016-08-24 16:03:48 -070078Reference::Reference(const ResourceNameRef& n, const ResourceId& i) :
79 name(n.toResourceName()), id(i), referenceType(Type::kResource) {
80}
81
Adam Lesinski458b8772016-04-25 14:20:21 -070082bool Reference::equals(const Value* value) const {
83 const Reference* other = valueCast<Reference>(value);
84 if (!other) {
85 return false;
86 }
87 return referenceType == other->referenceType && privateReference == other->privateReference &&
88 id == other->id && name == other->name;
89}
90
Adam Lesinski1ab598f2015-08-14 14:26:04 -070091bool Reference::flatten(android::Res_value* outValue) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080092 outValue->dataType = (referenceType == Reference::Type::kResource) ?
93 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070094 outValue->data = util::hostToDevice32(id ? id.value().id : 0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080095 return true;
96}
97
Adam Lesinski769de982015-04-10 19:43:55 -070098Reference* Reference::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080099 return new Reference(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800100}
101
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700102void Reference::print(std::ostream* out) const {
103 *out << "(reference) ";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800104 if (referenceType == Reference::Type::kResource) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700105 *out << "@";
Adam Lesinski467f1712015-11-16 17:35:44 -0800106 if (privateReference) {
107 *out << "*";
108 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800109 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700110 *out << "?";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800111 }
112
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700113 if (name) {
114 *out << name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800115 }
116
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700117 if (id && !Res_INTERNALID(id.value().id)) {
118 *out << " " << id.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119 }
120}
121
Adam Lesinski458b8772016-04-25 14:20:21 -0700122bool Id::equals(const Value* value) const {
123 return valueCast<Id>(value) != nullptr;
124}
125
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700126bool Id::flatten(android::Res_value* out) const {
127 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
128 out->data = util::hostToDevice32(0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800129 return true;
130}
131
Adam Lesinski769de982015-04-10 19:43:55 -0700132Id* Id::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800133 return new Id(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800134}
135
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700136void Id::print(std::ostream* out) const {
137 *out << "(id)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800138}
139
Adam Lesinski458b8772016-04-25 14:20:21 -0700140String::String(const StringPool::Ref& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800141}
142
Adam Lesinski458b8772016-04-25 14:20:21 -0700143bool String::equals(const Value* value) const {
144 const String* other = valueCast<String>(value);
145 if (!other) {
146 return false;
147 }
148 return *this->value == *other->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800149}
150
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700151bool String::flatten(android::Res_value* outValue) const {
152 // Verify that our StringPool index is within encode-able limits.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800153 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
154 return false;
155 }
156
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700157 outValue->dataType = android::Res_value::TYPE_STRING;
158 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800159 return true;
160}
161
Adam Lesinski769de982015-04-10 19:43:55 -0700162String* String::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800163 String* str = new String(newPool->makeRef(*value));
164 str->mComment = mComment;
165 str->mSource = mSource;
166 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800167}
168
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700169void String::print(std::ostream* out) const {
170 *out << "(string) \"" << *value << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800171}
172
Adam Lesinski458b8772016-04-25 14:20:21 -0700173StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800174}
175
Adam Lesinski458b8772016-04-25 14:20:21 -0700176bool StyledString::equals(const Value* value) const {
177 const StyledString* other = valueCast<StyledString>(value);
178 if (!other) {
179 return false;
180 }
Adam Lesinski393b5f02015-12-17 13:03:11 -0800181
Adam Lesinski458b8772016-04-25 14:20:21 -0700182 if (*this->value->str == *other->value->str) {
183 const std::vector<StringPool::Span>& spansA = this->value->spans;
184 const std::vector<StringPool::Span>& spansB = other->value->spans;
185 return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
186 [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
187 return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
188 });
189 }
190 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800191}
192
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700193bool StyledString::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800194 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
195 return false;
196 }
197
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700198 outValue->dataType = android::Res_value::TYPE_STRING;
199 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800200 return true;
201}
202
Adam Lesinski769de982015-04-10 19:43:55 -0700203StyledString* StyledString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800204 StyledString* str = new StyledString(newPool->makeRef(value));
205 str->mComment = mComment;
206 str->mSource = mSource;
207 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800208}
209
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700210void StyledString::print(std::ostream* out) const {
211 *out << "(styled string) \"" << *value->str << "\"";
Adam Lesinski458b8772016-04-25 14:20:21 -0700212 for (const StringPool::Span& span : value->spans) {
213 *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
214 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800215}
216
217FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
218}
219
Adam Lesinski458b8772016-04-25 14:20:21 -0700220bool FileReference::equals(const Value* value) const {
221 const FileReference* other = valueCast<FileReference>(value);
222 if (!other) {
223 return false;
224 }
225 return *path == *other->path;
226}
227
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700228bool FileReference::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800229 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
230 return false;
231 }
232
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700233 outValue->dataType = android::Res_value::TYPE_STRING;
234 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800235 return true;
236}
237
Adam Lesinski769de982015-04-10 19:43:55 -0700238FileReference* FileReference::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800239 FileReference* fr = new FileReference(newPool->makeRef(*path));
Adam Lesinski355f2852016-02-13 20:26:45 -0800240 fr->file = file;
Adam Lesinskib274e352015-11-06 15:14:35 -0800241 fr->mComment = mComment;
242 fr->mSource = mSource;
243 return fr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800244}
245
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700246void FileReference::print(std::ostream* out) const {
247 *out << "(file) " << *path;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800248}
249
250BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
251}
252
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700253BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
254 value.dataType = dataType;
255 value.data = data;
256}
257
Adam Lesinski458b8772016-04-25 14:20:21 -0700258bool BinaryPrimitive::equals(const Value* value) const {
259 const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
260 if (!other) {
261 return false;
262 }
263 return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
264}
265
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700266bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
267 outValue->dataType = value.dataType;
268 outValue->data = util::hostToDevice32(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800269 return true;
270}
271
Adam Lesinski769de982015-04-10 19:43:55 -0700272BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800273 return new BinaryPrimitive(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800274}
275
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700276void BinaryPrimitive::print(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277 switch (value.dataType) {
278 case android::Res_value::TYPE_NULL:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700279 *out << "(null)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800280 break;
281 case android::Res_value::TYPE_INT_DEC:
Adam Lesinskia5870652015-11-20 15:32:30 -0800282 *out << "(integer) " << static_cast<int32_t>(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800283 break;
284 case android::Res_value::TYPE_INT_HEX:
Adam Lesinski458b8772016-04-25 14:20:21 -0700285 *out << "(integer) 0x" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800286 break;
287 case android::Res_value::TYPE_INT_BOOLEAN:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700288 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800289 break;
290 case android::Res_value::TYPE_INT_COLOR_ARGB8:
291 case android::Res_value::TYPE_INT_COLOR_RGB8:
292 case android::Res_value::TYPE_INT_COLOR_ARGB4:
293 case android::Res_value::TYPE_INT_COLOR_RGB4:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700294 *out << "(color) #" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800295 break;
296 default:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700297 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
298 << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800299 break;
300 }
301}
302
Adam Lesinskia5870652015-11-20 15:32:30 -0800303Attribute::Attribute(bool w, uint32_t t) :
Adam Lesinski393b5f02015-12-17 13:03:11 -0800304 typeMask(t),
Adam Lesinskia5870652015-11-20 15:32:30 -0800305 minInt(std::numeric_limits<int32_t>::min()),
306 maxInt(std::numeric_limits<int32_t>::max()) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800307 mWeak = w;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800308}
309
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700310template <typename T>
311T* addPointer(T& val) {
312 return &val;
313}
314
Adam Lesinski458b8772016-04-25 14:20:21 -0700315bool Attribute::equals(const Value* value) const {
316 const Attribute* other = valueCast<Attribute>(value);
317 if (!other) {
318 return false;
319 }
320
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700321 if (symbols.size() != other->symbols.size()) {
322 return false;
323 }
324
325 if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) {
326 return false;
327 }
328
329 std::vector<const Symbol*> sortedA;
330 std::transform(symbols.begin(), symbols.end(),
331 std::back_inserter(sortedA), addPointer<const Symbol>);
332 std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool {
333 return a->symbol.name < b->symbol.name;
334 });
335
336 std::vector<const Symbol*> sortedB;
337 std::transform(other->symbols.begin(), other->symbols.end(),
338 std::back_inserter(sortedB), addPointer<const Symbol>);
339 std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool {
340 return a->symbol.name < b->symbol.name;
341 });
342
343 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
344 [](const Symbol* a, const Symbol* b) -> bool {
345 return a->symbol.equals(&b->symbol) && a->value == b->value;
Adam Lesinski458b8772016-04-25 14:20:21 -0700346 });
347}
348
Adam Lesinski769de982015-04-10 19:43:55 -0700349Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800350 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800351}
352
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700353void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800354 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700355 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800356 return;
357 }
358
359 bool set = false;
360 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
361 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800362 set = true;
363 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700364 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800365 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700366 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800367 }
368
369 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
370 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800371 set = true;
372 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700373 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800374 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700375 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800376 }
377
378 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
379 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800380 set = true;
381 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700382 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800383 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700384 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800385 }
386
387 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
388 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800389 set = true;
390 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700391 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800392 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700393 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800394 }
395
396 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
397 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800398 set = true;
399 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700400 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800401 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700402 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800403 }
404
405 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
406 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800407 set = true;
408 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700409 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800410 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700411 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800412 }
413
414 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
415 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800416 set = true;
417 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700418 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800419 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700420 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800421 }
422
423 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
424 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800425 set = true;
426 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700427 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800428 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700429 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800430 }
431
432 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
433 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800434 set = true;
435 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700436 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800437 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700438 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439 }
440
441 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
442 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800443 set = true;
444 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700445 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800446 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700447 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800448 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700449}
450
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700451void Attribute::print(std::ostream* out) const {
452 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700453 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800454
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700455 if (!symbols.empty()) {
Adam Lesinski36c73a52016-08-11 13:39:24 -0700456 *out << " [" << util::joiner(symbols, ", ") << "]";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700457 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800458
Adam Lesinski458b8772016-04-25 14:20:21 -0700459 if (minInt != std::numeric_limits<int32_t>::min()) {
460 *out << " min=" << minInt;
461 }
462
463 if (maxInt != std::numeric_limits<int32_t>::max()) {
464 *out << " max=" << maxInt;
465 }
466
Adam Lesinski393b5f02015-12-17 13:03:11 -0800467 if (isWeak()) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700468 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800469 }
470}
471
Adam Lesinskia5870652015-11-20 15:32:30 -0800472static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
473 const Item* value) {
474 *msg << "expected";
475 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
476 *msg << " boolean";
477 }
478
479 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
480 *msg << " color";
481 }
482
483 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
484 *msg << " dimension";
485 }
486
487 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
488 *msg << " enum";
489 }
490
491 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
492 *msg << " flags";
493 }
494
495 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
496 *msg << " float";
497 }
498
499 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
500 *msg << " fraction";
501 }
502
503 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
504 *msg << " integer";
505 }
506
507 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
508 *msg << " reference";
509 }
510
511 if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
512 *msg << " string";
513 }
514
515 *msg << " but got " << *value;
516}
517
518bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
519 android::Res_value val = {};
520 item->flatten(&val);
521
522 // Always allow references.
523 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
524 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
525 if (outMsg) {
526 buildAttributeMismatchMessage(outMsg, this, item);
527 }
528 return false;
529
530 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
531 android::ResTable_map::TYPE_INTEGER) {
532 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
533 if (outMsg) {
534 *outMsg << *item << " is less than minimum integer " << minInt;
535 }
536 return false;
537 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
538 if (outMsg) {
539 *outMsg << *item << " is greater than maximum integer " << maxInt;
540 }
541 return false;
542 }
543 }
544 return true;
545}
546
Adam Lesinski458b8772016-04-25 14:20:21 -0700547bool Style::equals(const Value* value) const {
548 const Style* other = valueCast<Style>(value);
549 if (!other) {
550 return false;
551 }
552 if (bool(parent) != bool(other->parent) ||
553 (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
554 return false;
555 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700556
557 if (entries.size() != other->entries.size()) {
558 return false;
559 }
560
561 std::vector<const Entry*> sortedA;
562 std::transform(entries.begin(), entries.end(),
563 std::back_inserter(sortedA), addPointer<const Entry>);
564 std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool {
565 return a->key.name < b->key.name;
566 });
567
568 std::vector<const Entry*> sortedB;
569 std::transform(other->entries.begin(), other->entries.end(),
570 std::back_inserter(sortedB), addPointer<const Entry>);
571 std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool {
572 return a->key.name < b->key.name;
573 });
574
575 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
576 [](const Entry* a, const Entry* b) -> bool {
577 return a->key.equals(&b->key) && a->value->equals(b->value.get());
Adam Lesinski458b8772016-04-25 14:20:21 -0700578 });
579}
580
Adam Lesinski769de982015-04-10 19:43:55 -0700581Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700582 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800583 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700584 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800585 style->mComment = mComment;
586 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800587 for (auto& entry : entries) {
588 style->entries.push_back(Entry{
589 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700590 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800591 });
592 }
593 return style;
594}
595
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700596void Style::print(std::ostream* out) const {
597 *out << "(style) ";
598 if (parent && parent.value().name) {
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800599 if (parent.value().privateReference) {
600 *out << "*";
601 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700602 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800603 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700604 *out << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700605 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800606 << "]";
607}
608
609static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700610 if (value.key.name) {
611 out << value.key.name.value();
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700612 } else if (value.key.id) {
613 out << value.key.id.value();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700614 } else {
615 out << "???";
616 }
617 out << " = ";
618 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800619 return out;
620}
621
Adam Lesinski458b8772016-04-25 14:20:21 -0700622bool Array::equals(const Value* value) const {
623 const Array* other = valueCast<Array>(value);
624 if (!other) {
625 return false;
626 }
627
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700628 if (items.size() != other->items.size()) {
629 return false;
630 }
631
Adam Lesinski458b8772016-04-25 14:20:21 -0700632 return std::equal(items.begin(), items.end(), other->items.begin(),
633 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
634 return a->equals(b.get());
635 });
636}
637
Adam Lesinski769de982015-04-10 19:43:55 -0700638Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800639 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800640 array->mComment = mComment;
641 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800642 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700643 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800644 }
645 return array;
646}
647
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700648void Array::print(std::ostream* out) const {
649 *out << "(array) ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700650 << util::joiner(items, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800651 << "]";
652}
653
Adam Lesinski458b8772016-04-25 14:20:21 -0700654bool Plural::equals(const Value* value) const {
655 const Plural* other = valueCast<Plural>(value);
656 if (!other) {
657 return false;
658 }
659
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700660 if (values.size() != other->values.size()) {
661 return false;
662 }
663
Adam Lesinski458b8772016-04-25 14:20:21 -0700664 return std::equal(values.begin(), values.end(), other->values.begin(),
665 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
666 if (bool(a) != bool(b)) {
667 return false;
668 }
669 return bool(a) == bool(b) || a->equals(b.get());
670 });
671}
672
Adam Lesinski769de982015-04-10 19:43:55 -0700673Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800674 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800675 p->mComment = mComment;
676 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800677 const size_t count = values.size();
678 for (size_t i = 0; i < count; i++) {
679 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700680 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800681 }
682 }
683 return p;
684}
685
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700686void Plural::print(std::ostream* out) const {
687 *out << "(plural)";
Adam Lesinski458b8772016-04-25 14:20:21 -0700688 if (values[Zero]) {
689 *out << " zero=" << *values[Zero];
690 }
691
692 if (values[One]) {
693 *out << " one=" << *values[One];
694 }
695
696 if (values[Two]) {
697 *out << " two=" << *values[Two];
698 }
699
700 if (values[Few]) {
701 *out << " few=" << *values[Few];
702 }
703
704 if (values[Many]) {
705 *out << " many=" << *values[Many];
706 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800707}
708
709static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
710 return out << *item;
711}
712
Adam Lesinski458b8772016-04-25 14:20:21 -0700713bool Styleable::equals(const Value* value) const {
714 const Styleable* other = valueCast<Styleable>(value);
715 if (!other) {
716 return false;
717 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700718
719 if (entries.size() != other->entries.size()) {
720 return false;
721 }
722
Adam Lesinski458b8772016-04-25 14:20:21 -0700723 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
724 [](const Reference& a, const Reference& b) -> bool {
725 return a.equals(&b);
726 });
727}
728
Adam Lesinski769de982015-04-10 19:43:55 -0700729Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800730 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800731}
732
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700733void Styleable::print(std::ostream* out) const {
734 *out << "(styleable) " << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700735 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800736 << "]";
737}
738
Adam Lesinski8197cc462016-08-19 12:16:49 -0700739bool operator<(const Reference& a, const Reference& b) {
740 int cmp = a.name.valueOrDefault({}).compare(b.name.valueOrDefault({}));
741 if (cmp != 0) return cmp < 0;
742 return a.id < b.id;
743}
744
745bool operator==(const Reference& a, const Reference& b) {
746 return a.name == b.name && a.id == b.id;
747}
748
749bool operator!=(const Reference& a, const Reference& b) {
750 return a.name != b.name || a.id != b.id;
751}
752
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700753struct NameOnlyComparator {
754 bool operator()(const Reference& a, const Reference& b) const {
755 return a.name < b.name;
756 }
757};
758
Adam Lesinski8197cc462016-08-19 12:16:49 -0700759void Styleable::mergeWith(Styleable* other) {
Adam Lesinski5c3464c2016-08-24 16:03:48 -0700760 // Compare only names, because some References may already have their IDs assigned
761 // (framework IDs that don't change).
762 std::set<Reference, NameOnlyComparator> references;
Adam Lesinski8197cc462016-08-19 12:16:49 -0700763 references.insert(entries.begin(), entries.end());
764 references.insert(other->entries.begin(), other->entries.end());
765 entries.clear();
766 entries.reserve(references.size());
767 entries.insert(entries.end(), references.begin(), references.end());
768}
769
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800770} // namespace aapt