blob: 73682ab110c73d93350a5af1d927556cb78ae432 [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 Lesinski5e8fa3a2016-06-27 16:21:42 -070024#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080025#include <androidfw/ResourceTypes.h>
26#include <limits>
27
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
68Reference::Reference() : referenceType(Reference::Type::kResource) {
69}
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 Lesinski458b8772016-04-25 14:20:21 -070078bool Reference::equals(const Value* value) const {
79 const Reference* other = valueCast<Reference>(value);
80 if (!other) {
81 return false;
82 }
83 return referenceType == other->referenceType && privateReference == other->privateReference &&
84 id == other->id && name == other->name;
85}
86
Adam Lesinski1ab598f2015-08-14 14:26:04 -070087bool Reference::flatten(android::Res_value* outValue) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080088 outValue->dataType = (referenceType == Reference::Type::kResource) ?
89 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070090 outValue->data = util::hostToDevice32(id ? id.value().id : 0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091 return true;
92}
93
Adam Lesinski769de982015-04-10 19:43:55 -070094Reference* Reference::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080095 return new Reference(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080096}
97
Adam Lesinski1ab598f2015-08-14 14:26:04 -070098void Reference::print(std::ostream* out) const {
99 *out << "(reference) ";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800100 if (referenceType == Reference::Type::kResource) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700101 *out << "@";
Adam Lesinski467f1712015-11-16 17:35:44 -0800102 if (privateReference) {
103 *out << "*";
104 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800105 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700106 *out << "?";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800107 }
108
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700109 if (name) {
110 *out << name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800111 }
112
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700113 if (id && !Res_INTERNALID(id.value().id)) {
114 *out << " " << id.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800115 }
116}
117
Adam Lesinski458b8772016-04-25 14:20:21 -0700118bool Id::equals(const Value* value) const {
119 return valueCast<Id>(value) != nullptr;
120}
121
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700122bool Id::flatten(android::Res_value* out) const {
123 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
124 out->data = util::hostToDevice32(0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800125 return true;
126}
127
Adam Lesinski769de982015-04-10 19:43:55 -0700128Id* Id::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800129 return new Id(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800130}
131
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700132void Id::print(std::ostream* out) const {
133 *out << "(id)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800134}
135
Adam Lesinski458b8772016-04-25 14:20:21 -0700136String::String(const StringPool::Ref& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800137}
138
Adam Lesinski458b8772016-04-25 14:20:21 -0700139bool String::equals(const Value* value) const {
140 const String* other = valueCast<String>(value);
141 if (!other) {
142 return false;
143 }
144 return *this->value == *other->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800145}
146
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147bool String::flatten(android::Res_value* outValue) const {
148 // Verify that our StringPool index is within encode-able limits.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800149 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
150 return false;
151 }
152
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700153 outValue->dataType = android::Res_value::TYPE_STRING;
154 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800155 return true;
156}
157
Adam Lesinski769de982015-04-10 19:43:55 -0700158String* String::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800159 String* str = new String(newPool->makeRef(*value));
160 str->mComment = mComment;
161 str->mSource = mSource;
162 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800163}
164
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700165void String::print(std::ostream* out) const {
166 *out << "(string) \"" << *value << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800167}
168
Adam Lesinski458b8772016-04-25 14:20:21 -0700169StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800170}
171
Adam Lesinski458b8772016-04-25 14:20:21 -0700172bool StyledString::equals(const Value* value) const {
173 const StyledString* other = valueCast<StyledString>(value);
174 if (!other) {
175 return false;
176 }
Adam Lesinski393b5f02015-12-17 13:03:11 -0800177
Adam Lesinski458b8772016-04-25 14:20:21 -0700178 if (*this->value->str == *other->value->str) {
179 const std::vector<StringPool::Span>& spansA = this->value->spans;
180 const std::vector<StringPool::Span>& spansB = other->value->spans;
181 return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
182 [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
183 return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
184 });
185 }
186 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800187}
188
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700189bool StyledString::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800190 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
191 return false;
192 }
193
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700194 outValue->dataType = android::Res_value::TYPE_STRING;
195 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800196 return true;
197}
198
Adam Lesinski769de982015-04-10 19:43:55 -0700199StyledString* StyledString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800200 StyledString* str = new StyledString(newPool->makeRef(value));
201 str->mComment = mComment;
202 str->mSource = mSource;
203 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800204}
205
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700206void StyledString::print(std::ostream* out) const {
207 *out << "(styled string) \"" << *value->str << "\"";
Adam Lesinski458b8772016-04-25 14:20:21 -0700208 for (const StringPool::Span& span : value->spans) {
209 *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
210 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800211}
212
213FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
214}
215
Adam Lesinski458b8772016-04-25 14:20:21 -0700216bool FileReference::equals(const Value* value) const {
217 const FileReference* other = valueCast<FileReference>(value);
218 if (!other) {
219 return false;
220 }
221 return *path == *other->path;
222}
223
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700224bool FileReference::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800225 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
226 return false;
227 }
228
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700229 outValue->dataType = android::Res_value::TYPE_STRING;
230 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800231 return true;
232}
233
Adam Lesinski769de982015-04-10 19:43:55 -0700234FileReference* FileReference::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800235 FileReference* fr = new FileReference(newPool->makeRef(*path));
Adam Lesinski355f2852016-02-13 20:26:45 -0800236 fr->file = file;
Adam Lesinskib274e352015-11-06 15:14:35 -0800237 fr->mComment = mComment;
238 fr->mSource = mSource;
239 return fr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800240}
241
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700242void FileReference::print(std::ostream* out) const {
243 *out << "(file) " << *path;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800244}
245
246BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
247}
248
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700249BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
250 value.dataType = dataType;
251 value.data = data;
252}
253
Adam Lesinski458b8772016-04-25 14:20:21 -0700254bool BinaryPrimitive::equals(const Value* value) const {
255 const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
256 if (!other) {
257 return false;
258 }
259 return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
260}
261
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700262bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
263 outValue->dataType = value.dataType;
264 outValue->data = util::hostToDevice32(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800265 return true;
266}
267
Adam Lesinski769de982015-04-10 19:43:55 -0700268BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800269 return new BinaryPrimitive(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800270}
271
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700272void BinaryPrimitive::print(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800273 switch (value.dataType) {
274 case android::Res_value::TYPE_NULL:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700275 *out << "(null)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800276 break;
277 case android::Res_value::TYPE_INT_DEC:
Adam Lesinskia5870652015-11-20 15:32:30 -0800278 *out << "(integer) " << static_cast<int32_t>(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800279 break;
280 case android::Res_value::TYPE_INT_HEX:
Adam Lesinski458b8772016-04-25 14:20:21 -0700281 *out << "(integer) 0x" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800282 break;
283 case android::Res_value::TYPE_INT_BOOLEAN:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700284 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800285 break;
286 case android::Res_value::TYPE_INT_COLOR_ARGB8:
287 case android::Res_value::TYPE_INT_COLOR_RGB8:
288 case android::Res_value::TYPE_INT_COLOR_ARGB4:
289 case android::Res_value::TYPE_INT_COLOR_RGB4:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700290 *out << "(color) #" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800291 break;
292 default:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700293 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
294 << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800295 break;
296 }
297}
298
Adam Lesinskia5870652015-11-20 15:32:30 -0800299Attribute::Attribute(bool w, uint32_t t) :
Adam Lesinski393b5f02015-12-17 13:03:11 -0800300 typeMask(t),
Adam Lesinskia5870652015-11-20 15:32:30 -0800301 minInt(std::numeric_limits<int32_t>::min()),
302 maxInt(std::numeric_limits<int32_t>::max()) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800303 mWeak = w;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800304}
305
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700306template <typename T>
307T* addPointer(T& val) {
308 return &val;
309}
310
Adam Lesinski458b8772016-04-25 14:20:21 -0700311bool Attribute::equals(const Value* value) const {
312 const Attribute* other = valueCast<Attribute>(value);
313 if (!other) {
314 return false;
315 }
316
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700317 if (symbols.size() != other->symbols.size()) {
318 return false;
319 }
320
321 if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) {
322 return false;
323 }
324
325 std::vector<const Symbol*> sortedA;
326 std::transform(symbols.begin(), symbols.end(),
327 std::back_inserter(sortedA), addPointer<const Symbol>);
328 std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool {
329 return a->symbol.name < b->symbol.name;
330 });
331
332 std::vector<const Symbol*> sortedB;
333 std::transform(other->symbols.begin(), other->symbols.end(),
334 std::back_inserter(sortedB), addPointer<const Symbol>);
335 std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool {
336 return a->symbol.name < b->symbol.name;
337 });
338
339 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
340 [](const Symbol* a, const Symbol* b) -> bool {
341 return a->symbol.equals(&b->symbol) && a->value == b->value;
Adam Lesinski458b8772016-04-25 14:20:21 -0700342 });
343}
344
Adam Lesinski769de982015-04-10 19:43:55 -0700345Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800346 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800347}
348
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700349void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800350 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700351 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800352 return;
353 }
354
355 bool set = false;
356 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
357 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800358 set = true;
359 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700360 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800361 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700362 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800363 }
364
365 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
366 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800367 set = true;
368 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700369 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800370 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700371 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800372 }
373
374 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
375 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800376 set = true;
377 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700378 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800379 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700380 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800381 }
382
383 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
384 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800385 set = true;
386 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700387 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800388 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700389 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800390 }
391
392 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
393 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800394 set = true;
395 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700396 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800397 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700398 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800399 }
400
401 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
402 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800403 set = true;
404 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700405 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800406 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700407 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800408 }
409
410 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
411 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800412 set = true;
413 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700414 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800415 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700416 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800417 }
418
419 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
420 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800421 set = true;
422 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700423 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800424 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700425 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800426 }
427
428 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
429 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800430 set = true;
431 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700432 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800433 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700434 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800435 }
436
437 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
438 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439 set = true;
440 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700441 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800442 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700443 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800444 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700445}
446
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700447void Attribute::print(std::ostream* out) const {
448 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700449 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800450
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700451 if (!symbols.empty()) {
Adam Lesinski36c73a52016-08-11 13:39:24 -0700452 *out << " [" << util::joiner(symbols, ", ") << "]";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700453 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800454
Adam Lesinski458b8772016-04-25 14:20:21 -0700455 if (minInt != std::numeric_limits<int32_t>::min()) {
456 *out << " min=" << minInt;
457 }
458
459 if (maxInt != std::numeric_limits<int32_t>::max()) {
460 *out << " max=" << maxInt;
461 }
462
Adam Lesinski393b5f02015-12-17 13:03:11 -0800463 if (isWeak()) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700464 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800465 }
466}
467
Adam Lesinskia5870652015-11-20 15:32:30 -0800468static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
469 const Item* value) {
470 *msg << "expected";
471 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
472 *msg << " boolean";
473 }
474
475 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
476 *msg << " color";
477 }
478
479 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
480 *msg << " dimension";
481 }
482
483 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
484 *msg << " enum";
485 }
486
487 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
488 *msg << " flags";
489 }
490
491 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
492 *msg << " float";
493 }
494
495 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
496 *msg << " fraction";
497 }
498
499 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
500 *msg << " integer";
501 }
502
503 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
504 *msg << " reference";
505 }
506
507 if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
508 *msg << " string";
509 }
510
511 *msg << " but got " << *value;
512}
513
514bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
515 android::Res_value val = {};
516 item->flatten(&val);
517
518 // Always allow references.
519 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
520 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
521 if (outMsg) {
522 buildAttributeMismatchMessage(outMsg, this, item);
523 }
524 return false;
525
526 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
527 android::ResTable_map::TYPE_INTEGER) {
528 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
529 if (outMsg) {
530 *outMsg << *item << " is less than minimum integer " << minInt;
531 }
532 return false;
533 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
534 if (outMsg) {
535 *outMsg << *item << " is greater than maximum integer " << maxInt;
536 }
537 return false;
538 }
539 }
540 return true;
541}
542
Adam Lesinski458b8772016-04-25 14:20:21 -0700543bool Style::equals(const Value* value) const {
544 const Style* other = valueCast<Style>(value);
545 if (!other) {
546 return false;
547 }
548 if (bool(parent) != bool(other->parent) ||
549 (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
550 return false;
551 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700552
553 if (entries.size() != other->entries.size()) {
554 return false;
555 }
556
557 std::vector<const Entry*> sortedA;
558 std::transform(entries.begin(), entries.end(),
559 std::back_inserter(sortedA), addPointer<const Entry>);
560 std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool {
561 return a->key.name < b->key.name;
562 });
563
564 std::vector<const Entry*> sortedB;
565 std::transform(other->entries.begin(), other->entries.end(),
566 std::back_inserter(sortedB), addPointer<const Entry>);
567 std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool {
568 return a->key.name < b->key.name;
569 });
570
571 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
572 [](const Entry* a, const Entry* b) -> bool {
573 return a->key.equals(&b->key) && a->value->equals(b->value.get());
Adam Lesinski458b8772016-04-25 14:20:21 -0700574 });
575}
576
Adam Lesinski769de982015-04-10 19:43:55 -0700577Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700578 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800579 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700580 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800581 style->mComment = mComment;
582 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800583 for (auto& entry : entries) {
584 style->entries.push_back(Entry{
585 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700586 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800587 });
588 }
589 return style;
590}
591
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700592void Style::print(std::ostream* out) const {
593 *out << "(style) ";
594 if (parent && parent.value().name) {
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800595 if (parent.value().privateReference) {
596 *out << "*";
597 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700598 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800599 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700600 *out << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700601 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800602 << "]";
603}
604
605static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700606 if (value.key.name) {
607 out << value.key.name.value();
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700608 } else if (value.key.id) {
609 out << value.key.id.value();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700610 } else {
611 out << "???";
612 }
613 out << " = ";
614 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800615 return out;
616}
617
Adam Lesinski458b8772016-04-25 14:20:21 -0700618bool Array::equals(const Value* value) const {
619 const Array* other = valueCast<Array>(value);
620 if (!other) {
621 return false;
622 }
623
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700624 if (items.size() != other->items.size()) {
625 return false;
626 }
627
Adam Lesinski458b8772016-04-25 14:20:21 -0700628 return std::equal(items.begin(), items.end(), other->items.begin(),
629 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
630 return a->equals(b.get());
631 });
632}
633
Adam Lesinski769de982015-04-10 19:43:55 -0700634Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800635 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800636 array->mComment = mComment;
637 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800638 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700639 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800640 }
641 return array;
642}
643
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700644void Array::print(std::ostream* out) const {
645 *out << "(array) ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700646 << util::joiner(items, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800647 << "]";
648}
649
Adam Lesinski458b8772016-04-25 14:20:21 -0700650bool Plural::equals(const Value* value) const {
651 const Plural* other = valueCast<Plural>(value);
652 if (!other) {
653 return false;
654 }
655
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700656 if (values.size() != other->values.size()) {
657 return false;
658 }
659
Adam Lesinski458b8772016-04-25 14:20:21 -0700660 return std::equal(values.begin(), values.end(), other->values.begin(),
661 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
662 if (bool(a) != bool(b)) {
663 return false;
664 }
665 return bool(a) == bool(b) || a->equals(b.get());
666 });
667}
668
Adam Lesinski769de982015-04-10 19:43:55 -0700669Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800670 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800671 p->mComment = mComment;
672 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800673 const size_t count = values.size();
674 for (size_t i = 0; i < count; i++) {
675 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700676 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800677 }
678 }
679 return p;
680}
681
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700682void Plural::print(std::ostream* out) const {
683 *out << "(plural)";
Adam Lesinski458b8772016-04-25 14:20:21 -0700684 if (values[Zero]) {
685 *out << " zero=" << *values[Zero];
686 }
687
688 if (values[One]) {
689 *out << " one=" << *values[One];
690 }
691
692 if (values[Two]) {
693 *out << " two=" << *values[Two];
694 }
695
696 if (values[Few]) {
697 *out << " few=" << *values[Few];
698 }
699
700 if (values[Many]) {
701 *out << " many=" << *values[Many];
702 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800703}
704
705static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
706 return out << *item;
707}
708
Adam Lesinski458b8772016-04-25 14:20:21 -0700709bool Styleable::equals(const Value* value) const {
710 const Styleable* other = valueCast<Styleable>(value);
711 if (!other) {
712 return false;
713 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700714
715 if (entries.size() != other->entries.size()) {
716 return false;
717 }
718
Adam Lesinski458b8772016-04-25 14:20:21 -0700719 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
720 [](const Reference& a, const Reference& b) -> bool {
721 return a.equals(&b);
722 });
723}
724
Adam Lesinski769de982015-04-10 19:43:55 -0700725Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800726 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800727}
728
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700729void Styleable::print(std::ostream* out) const {
730 *out << "(styleable) " << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700731 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800732 << "]";
733}
734
735} // namespace aapt