blob: 321f77667b759ea1e349736c196691fdcf703ac7 [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>
Adam Lesinski8197cc462016-08-19 12:16:49 -070027#include <set>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080028
29namespace aapt {
30
Adam Lesinski1ab598f2015-08-14 14:26:04 -070031template <typename Derived>
32void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
33 visitor->visit(static_cast<Derived*>(this));
34}
35
36template <typename Derived>
37void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
38 visitor->visit(static_cast<Derived*>(this));
39}
40
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041RawString::RawString(const StringPool::Ref& ref) : value(ref) {
42}
43
Adam Lesinski458b8772016-04-25 14:20:21 -070044bool RawString::equals(const Value* value) const {
45 const RawString* other = valueCast<RawString>(value);
46 if (!other) {
47 return false;
48 }
49 return *this->value == *other->value;
50}
51
Adam Lesinski769de982015-04-10 19:43:55 -070052RawString* RawString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -080053 RawString* rs = new RawString(newPool->makeRef(*value));
54 rs->mComment = mComment;
55 rs->mSource = mSource;
56 return rs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080057}
58
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059bool RawString::flatten(android::Res_value* outValue) const {
Adam Lesinski59e04c62016-02-04 15:59:23 -080060 outValue->dataType = android::Res_value::TYPE_STRING;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070061 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080062 return true;
63}
64
Adam Lesinski1ab598f2015-08-14 14:26:04 -070065void RawString::print(std::ostream* out) const {
66 *out << "(raw string) " << *value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080067}
68
69Reference::Reference() : referenceType(Reference::Type::kResource) {
70}
71
72Reference::Reference(const ResourceNameRef& n, Type t) :
73 name(n.toResourceName()), referenceType(t) {
74}
75
76Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
77}
78
Adam Lesinski458b8772016-04-25 14:20:21 -070079bool Reference::equals(const Value* value) const {
80 const Reference* other = valueCast<Reference>(value);
81 if (!other) {
82 return false;
83 }
84 return referenceType == other->referenceType && privateReference == other->privateReference &&
85 id == other->id && name == other->name;
86}
87
Adam Lesinski1ab598f2015-08-14 14:26:04 -070088bool Reference::flatten(android::Res_value* outValue) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080089 outValue->dataType = (referenceType == Reference::Type::kResource) ?
90 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070091 outValue->data = util::hostToDevice32(id ? id.value().id : 0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080092 return true;
93}
94
Adam Lesinski769de982015-04-10 19:43:55 -070095Reference* Reference::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080096 return new Reference(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080097}
98
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099void Reference::print(std::ostream* out) const {
100 *out << "(reference) ";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800101 if (referenceType == Reference::Type::kResource) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700102 *out << "@";
Adam Lesinski467f1712015-11-16 17:35:44 -0800103 if (privateReference) {
104 *out << "*";
105 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800106 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700107 *out << "?";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800108 }
109
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700110 if (name) {
111 *out << name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800112 }
113
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700114 if (id && !Res_INTERNALID(id.value().id)) {
115 *out << " " << id.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800116 }
117}
118
Adam Lesinski458b8772016-04-25 14:20:21 -0700119bool Id::equals(const Value* value) const {
120 return valueCast<Id>(value) != nullptr;
121}
122
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700123bool Id::flatten(android::Res_value* out) const {
124 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
125 out->data = util::hostToDevice32(0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800126 return true;
127}
128
Adam Lesinski769de982015-04-10 19:43:55 -0700129Id* Id::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800130 return new Id(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800131}
132
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700133void Id::print(std::ostream* out) const {
134 *out << "(id)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800135}
136
Adam Lesinski458b8772016-04-25 14:20:21 -0700137String::String(const StringPool::Ref& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800138}
139
Adam Lesinski458b8772016-04-25 14:20:21 -0700140bool String::equals(const Value* value) const {
141 const String* other = valueCast<String>(value);
142 if (!other) {
143 return false;
144 }
145 return *this->value == *other->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800146}
147
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700148bool String::flatten(android::Res_value* outValue) const {
149 // Verify that our StringPool index is within encode-able limits.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800150 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
151 return false;
152 }
153
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700154 outValue->dataType = android::Res_value::TYPE_STRING;
155 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800156 return true;
157}
158
Adam Lesinski769de982015-04-10 19:43:55 -0700159String* String::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800160 String* str = new String(newPool->makeRef(*value));
161 str->mComment = mComment;
162 str->mSource = mSource;
163 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800164}
165
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700166void String::print(std::ostream* out) const {
167 *out << "(string) \"" << *value << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800168}
169
Adam Lesinski458b8772016-04-25 14:20:21 -0700170StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800171}
172
Adam Lesinski458b8772016-04-25 14:20:21 -0700173bool StyledString::equals(const Value* value) const {
174 const StyledString* other = valueCast<StyledString>(value);
175 if (!other) {
176 return false;
177 }
Adam Lesinski393b5f02015-12-17 13:03:11 -0800178
Adam Lesinski458b8772016-04-25 14:20:21 -0700179 if (*this->value->str == *other->value->str) {
180 const std::vector<StringPool::Span>& spansA = this->value->spans;
181 const std::vector<StringPool::Span>& spansB = other->value->spans;
182 return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
183 [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
184 return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
185 });
186 }
187 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800188}
189
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700190bool StyledString::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800191 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
192 return false;
193 }
194
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700195 outValue->dataType = android::Res_value::TYPE_STRING;
196 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800197 return true;
198}
199
Adam Lesinski769de982015-04-10 19:43:55 -0700200StyledString* StyledString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800201 StyledString* str = new StyledString(newPool->makeRef(value));
202 str->mComment = mComment;
203 str->mSource = mSource;
204 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800205}
206
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700207void StyledString::print(std::ostream* out) const {
208 *out << "(styled string) \"" << *value->str << "\"";
Adam Lesinski458b8772016-04-25 14:20:21 -0700209 for (const StringPool::Span& span : value->spans) {
210 *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
211 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800212}
213
214FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
215}
216
Adam Lesinski458b8772016-04-25 14:20:21 -0700217bool FileReference::equals(const Value* value) const {
218 const FileReference* other = valueCast<FileReference>(value);
219 if (!other) {
220 return false;
221 }
222 return *path == *other->path;
223}
224
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700225bool FileReference::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800226 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
227 return false;
228 }
229
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700230 outValue->dataType = android::Res_value::TYPE_STRING;
231 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232 return true;
233}
234
Adam Lesinski769de982015-04-10 19:43:55 -0700235FileReference* FileReference::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800236 FileReference* fr = new FileReference(newPool->makeRef(*path));
Adam Lesinski355f2852016-02-13 20:26:45 -0800237 fr->file = file;
Adam Lesinskib274e352015-11-06 15:14:35 -0800238 fr->mComment = mComment;
239 fr->mSource = mSource;
240 return fr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800241}
242
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700243void FileReference::print(std::ostream* out) const {
244 *out << "(file) " << *path;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800245}
246
247BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
248}
249
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700250BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
251 value.dataType = dataType;
252 value.data = data;
253}
254
Adam Lesinski458b8772016-04-25 14:20:21 -0700255bool BinaryPrimitive::equals(const Value* value) const {
256 const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
257 if (!other) {
258 return false;
259 }
260 return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
261}
262
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700263bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
264 outValue->dataType = value.dataType;
265 outValue->data = util::hostToDevice32(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800266 return true;
267}
268
Adam Lesinski769de982015-04-10 19:43:55 -0700269BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800270 return new BinaryPrimitive(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800271}
272
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700273void BinaryPrimitive::print(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800274 switch (value.dataType) {
275 case android::Res_value::TYPE_NULL:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700276 *out << "(null)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277 break;
278 case android::Res_value::TYPE_INT_DEC:
Adam Lesinskia5870652015-11-20 15:32:30 -0800279 *out << "(integer) " << static_cast<int32_t>(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800280 break;
281 case android::Res_value::TYPE_INT_HEX:
Adam Lesinski458b8772016-04-25 14:20:21 -0700282 *out << "(integer) 0x" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800283 break;
284 case android::Res_value::TYPE_INT_BOOLEAN:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700285 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800286 break;
287 case android::Res_value::TYPE_INT_COLOR_ARGB8:
288 case android::Res_value::TYPE_INT_COLOR_RGB8:
289 case android::Res_value::TYPE_INT_COLOR_ARGB4:
290 case android::Res_value::TYPE_INT_COLOR_RGB4:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700291 *out << "(color) #" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800292 break;
293 default:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700294 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
295 << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800296 break;
297 }
298}
299
Adam Lesinskia5870652015-11-20 15:32:30 -0800300Attribute::Attribute(bool w, uint32_t t) :
Adam Lesinski393b5f02015-12-17 13:03:11 -0800301 typeMask(t),
Adam Lesinskia5870652015-11-20 15:32:30 -0800302 minInt(std::numeric_limits<int32_t>::min()),
303 maxInt(std::numeric_limits<int32_t>::max()) {
Adam Lesinski393b5f02015-12-17 13:03:11 -0800304 mWeak = w;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800305}
306
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700307template <typename T>
308T* addPointer(T& val) {
309 return &val;
310}
311
Adam Lesinski458b8772016-04-25 14:20:21 -0700312bool Attribute::equals(const Value* value) const {
313 const Attribute* other = valueCast<Attribute>(value);
314 if (!other) {
315 return false;
316 }
317
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700318 if (symbols.size() != other->symbols.size()) {
319 return false;
320 }
321
322 if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) {
323 return false;
324 }
325
326 std::vector<const Symbol*> sortedA;
327 std::transform(symbols.begin(), symbols.end(),
328 std::back_inserter(sortedA), addPointer<const Symbol>);
329 std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool {
330 return a->symbol.name < b->symbol.name;
331 });
332
333 std::vector<const Symbol*> sortedB;
334 std::transform(other->symbols.begin(), other->symbols.end(),
335 std::back_inserter(sortedB), addPointer<const Symbol>);
336 std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool {
337 return a->symbol.name < b->symbol.name;
338 });
339
340 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
341 [](const Symbol* a, const Symbol* b) -> bool {
342 return a->symbol.equals(&b->symbol) && a->value == b->value;
Adam Lesinski458b8772016-04-25 14:20:21 -0700343 });
344}
345
Adam Lesinski769de982015-04-10 19:43:55 -0700346Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800347 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800348}
349
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700350void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800351 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700352 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800353 return;
354 }
355
356 bool set = false;
357 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
358 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800359 set = true;
360 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700361 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800362 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700363 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800364 }
365
366 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
367 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800368 set = true;
369 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700370 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800371 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700372 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800373 }
374
375 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
376 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800377 set = true;
378 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700379 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800380 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700381 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800382 }
383
384 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
385 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800386 set = true;
387 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700388 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800389 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700390 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800391 }
392
393 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
394 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800395 set = true;
396 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700397 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800398 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700399 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800400 }
401
402 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
403 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800404 set = true;
405 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700406 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800407 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700408 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800409 }
410
411 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
412 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800413 set = true;
414 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700415 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800416 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700417 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800418 }
419
420 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
421 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800422 set = true;
423 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700424 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800425 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700426 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800427 }
428
429 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
430 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800431 set = true;
432 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700433 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800434 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700435 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800436 }
437
438 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
439 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800440 set = true;
441 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700442 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800443 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700444 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800445 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700446}
447
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700448void Attribute::print(std::ostream* out) const {
449 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700450 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800451
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700452 if (!symbols.empty()) {
Adam Lesinski36c73a52016-08-11 13:39:24 -0700453 *out << " [" << util::joiner(symbols, ", ") << "]";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700454 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800455
Adam Lesinski458b8772016-04-25 14:20:21 -0700456 if (minInt != std::numeric_limits<int32_t>::min()) {
457 *out << " min=" << minInt;
458 }
459
460 if (maxInt != std::numeric_limits<int32_t>::max()) {
461 *out << " max=" << maxInt;
462 }
463
Adam Lesinski393b5f02015-12-17 13:03:11 -0800464 if (isWeak()) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700465 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800466 }
467}
468
Adam Lesinskia5870652015-11-20 15:32:30 -0800469static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
470 const Item* value) {
471 *msg << "expected";
472 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
473 *msg << " boolean";
474 }
475
476 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
477 *msg << " color";
478 }
479
480 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
481 *msg << " dimension";
482 }
483
484 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
485 *msg << " enum";
486 }
487
488 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
489 *msg << " flags";
490 }
491
492 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
493 *msg << " float";
494 }
495
496 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
497 *msg << " fraction";
498 }
499
500 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
501 *msg << " integer";
502 }
503
504 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
505 *msg << " reference";
506 }
507
508 if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
509 *msg << " string";
510 }
511
512 *msg << " but got " << *value;
513}
514
515bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
516 android::Res_value val = {};
517 item->flatten(&val);
518
519 // Always allow references.
520 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
521 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
522 if (outMsg) {
523 buildAttributeMismatchMessage(outMsg, this, item);
524 }
525 return false;
526
527 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
528 android::ResTable_map::TYPE_INTEGER) {
529 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
530 if (outMsg) {
531 *outMsg << *item << " is less than minimum integer " << minInt;
532 }
533 return false;
534 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
535 if (outMsg) {
536 *outMsg << *item << " is greater than maximum integer " << maxInt;
537 }
538 return false;
539 }
540 }
541 return true;
542}
543
Adam Lesinski458b8772016-04-25 14:20:21 -0700544bool Style::equals(const Value* value) const {
545 const Style* other = valueCast<Style>(value);
546 if (!other) {
547 return false;
548 }
549 if (bool(parent) != bool(other->parent) ||
550 (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
551 return false;
552 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700553
554 if (entries.size() != other->entries.size()) {
555 return false;
556 }
557
558 std::vector<const Entry*> sortedA;
559 std::transform(entries.begin(), entries.end(),
560 std::back_inserter(sortedA), addPointer<const Entry>);
561 std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool {
562 return a->key.name < b->key.name;
563 });
564
565 std::vector<const Entry*> sortedB;
566 std::transform(other->entries.begin(), other->entries.end(),
567 std::back_inserter(sortedB), addPointer<const Entry>);
568 std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool {
569 return a->key.name < b->key.name;
570 });
571
572 return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
573 [](const Entry* a, const Entry* b) -> bool {
574 return a->key.equals(&b->key) && a->value->equals(b->value.get());
Adam Lesinski458b8772016-04-25 14:20:21 -0700575 });
576}
577
Adam Lesinski769de982015-04-10 19:43:55 -0700578Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700579 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800580 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700581 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800582 style->mComment = mComment;
583 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800584 for (auto& entry : entries) {
585 style->entries.push_back(Entry{
586 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700587 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800588 });
589 }
590 return style;
591}
592
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700593void Style::print(std::ostream* out) const {
594 *out << "(style) ";
595 if (parent && parent.value().name) {
Adam Lesinski24b8ff0f2015-12-16 14:01:57 -0800596 if (parent.value().privateReference) {
597 *out << "*";
598 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700599 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800600 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700601 *out << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700602 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800603 << "]";
604}
605
606static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700607 if (value.key.name) {
608 out << value.key.name.value();
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700609 } else if (value.key.id) {
610 out << value.key.id.value();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700611 } else {
612 out << "???";
613 }
614 out << " = ";
615 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800616 return out;
617}
618
Adam Lesinski458b8772016-04-25 14:20:21 -0700619bool Array::equals(const Value* value) const {
620 const Array* other = valueCast<Array>(value);
621 if (!other) {
622 return false;
623 }
624
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700625 if (items.size() != other->items.size()) {
626 return false;
627 }
628
Adam Lesinski458b8772016-04-25 14:20:21 -0700629 return std::equal(items.begin(), items.end(), other->items.begin(),
630 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
631 return a->equals(b.get());
632 });
633}
634
Adam Lesinski769de982015-04-10 19:43:55 -0700635Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800636 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800637 array->mComment = mComment;
638 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800639 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700640 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800641 }
642 return array;
643}
644
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700645void Array::print(std::ostream* out) const {
646 *out << "(array) ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700647 << util::joiner(items, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800648 << "]";
649}
650
Adam Lesinski458b8772016-04-25 14:20:21 -0700651bool Plural::equals(const Value* value) const {
652 const Plural* other = valueCast<Plural>(value);
653 if (!other) {
654 return false;
655 }
656
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700657 if (values.size() != other->values.size()) {
658 return false;
659 }
660
Adam Lesinski458b8772016-04-25 14:20:21 -0700661 return std::equal(values.begin(), values.end(), other->values.begin(),
662 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
663 if (bool(a) != bool(b)) {
664 return false;
665 }
666 return bool(a) == bool(b) || a->equals(b.get());
667 });
668}
669
Adam Lesinski769de982015-04-10 19:43:55 -0700670Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800671 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800672 p->mComment = mComment;
673 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800674 const size_t count = values.size();
675 for (size_t i = 0; i < count; i++) {
676 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700677 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800678 }
679 }
680 return p;
681}
682
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700683void Plural::print(std::ostream* out) const {
684 *out << "(plural)";
Adam Lesinski458b8772016-04-25 14:20:21 -0700685 if (values[Zero]) {
686 *out << " zero=" << *values[Zero];
687 }
688
689 if (values[One]) {
690 *out << " one=" << *values[One];
691 }
692
693 if (values[Two]) {
694 *out << " two=" << *values[Two];
695 }
696
697 if (values[Few]) {
698 *out << " few=" << *values[Few];
699 }
700
701 if (values[Many]) {
702 *out << " many=" << *values[Many];
703 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800704}
705
706static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
707 return out << *item;
708}
709
Adam Lesinski458b8772016-04-25 14:20:21 -0700710bool Styleable::equals(const Value* value) const {
711 const Styleable* other = valueCast<Styleable>(value);
712 if (!other) {
713 return false;
714 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700715
716 if (entries.size() != other->entries.size()) {
717 return false;
718 }
719
Adam Lesinski458b8772016-04-25 14:20:21 -0700720 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
721 [](const Reference& a, const Reference& b) -> bool {
722 return a.equals(&b);
723 });
724}
725
Adam Lesinski769de982015-04-10 19:43:55 -0700726Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800727 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800728}
729
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700730void Styleable::print(std::ostream* out) const {
731 *out << "(styleable) " << " ["
Adam Lesinski36c73a52016-08-11 13:39:24 -0700732 << util::joiner(entries, ", ")
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800733 << "]";
734}
735
Adam Lesinski8197cc462016-08-19 12:16:49 -0700736bool operator<(const Reference& a, const Reference& b) {
737 int cmp = a.name.valueOrDefault({}).compare(b.name.valueOrDefault({}));
738 if (cmp != 0) return cmp < 0;
739 return a.id < b.id;
740}
741
742bool operator==(const Reference& a, const Reference& b) {
743 return a.name == b.name && a.id == b.id;
744}
745
746bool operator!=(const Reference& a, const Reference& b) {
747 return a.name != b.name || a.id != b.id;
748}
749
750void Styleable::mergeWith(Styleable* other) {
751 std::set<Reference> references;
752 references.insert(entries.begin(), entries.end());
753 references.insert(other->entries.begin(), other->entries.end());
754 entries.clear();
755 entries.reserve(references.size());
756 entries.insert(entries.end(), references.begin(), references.end());
757}
758
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800759} // namespace aapt