1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ResourceValues.h"
18
19 #include <algorithm>
20 #include <limits>
21 #include <set>
22
23 #include "androidfw/ResourceTypes.h"
24
25 #include "Resource.h"
26 #include "ResourceUtils.h"
27 #include "ValueVisitor.h"
28 #include "util/Util.h"
29
30 namespace aapt {
31
operator <<(std::ostream & out,const Value & value)32 std::ostream& operator<<(std::ostream& out, const Value& value) {
33 value.Print(&out);
34 return out;
35 }
36
37 template <typename Derived>
Accept(RawValueVisitor * visitor)38 void BaseValue<Derived>::Accept(RawValueVisitor* visitor) {
39 visitor->Visit(static_cast<Derived*>(this));
40 }
41
42 template <typename Derived>
Accept(RawValueVisitor * visitor)43 void BaseItem<Derived>::Accept(RawValueVisitor* visitor) {
44 visitor->Visit(static_cast<Derived*>(this));
45 }
46
RawString(const StringPool::Ref & ref)47 RawString::RawString(const StringPool::Ref& ref) : value(ref) {}
48
Equals(const Value * value) const49 bool RawString::Equals(const Value* value) const {
50 const RawString* other = ValueCast<RawString>(value);
51 if (!other) {
52 return false;
53 }
54 return *this->value == *other->value;
55 }
56
Clone(StringPool * new_pool) const57 RawString* RawString::Clone(StringPool* new_pool) const {
58 RawString* rs = new RawString(new_pool->MakeRef(*value));
59 rs->comment_ = comment_;
60 rs->source_ = source_;
61 return rs;
62 }
63
Flatten(android::Res_value * out_value) const64 bool RawString::Flatten(android::Res_value* out_value) const {
65 out_value->dataType = android::Res_value::TYPE_STRING;
66 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
67 return true;
68 }
69
Print(std::ostream * out) const70 void RawString::Print(std::ostream* out) const {
71 *out << "(raw string) " << *value;
72 }
73
Reference()74 Reference::Reference() : reference_type(Type::kResource) {}
75
Reference(const ResourceNameRef & n,Type t)76 Reference::Reference(const ResourceNameRef& n, Type t)
77 : name(n.ToResourceName()), reference_type(t) {}
78
Reference(const ResourceId & i,Type type)79 Reference::Reference(const ResourceId& i, Type type)
80 : id(i), reference_type(type) {}
81
Reference(const ResourceNameRef & n,const ResourceId & i)82 Reference::Reference(const ResourceNameRef& n, const ResourceId& i)
83 : name(n.ToResourceName()), id(i), reference_type(Type::kResource) {}
84
Equals(const Value * value) const85 bool Reference::Equals(const Value* value) const {
86 const Reference* other = ValueCast<Reference>(value);
87 if (!other) {
88 return false;
89 }
90 return reference_type == other->reference_type &&
91 private_reference == other->private_reference && id == other->id &&
92 name == other->name;
93 }
94
Flatten(android::Res_value * out_value) const95 bool Reference::Flatten(android::Res_value* out_value) const {
96 const ResourceId resid = id.value_or_default(ResourceId(0));
97 const bool dynamic = resid.is_valid_dynamic() && resid.package_id() != kFrameworkPackageId &&
98 resid.package_id() != kAppPackageId;
99
100 if (reference_type == Reference::Type::kResource) {
101 if (dynamic) {
102 out_value->dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
103 } else {
104 out_value->dataType = android::Res_value::TYPE_REFERENCE;
105 }
106 } else {
107 if (dynamic) {
108 out_value->dataType = android::Res_value::TYPE_DYNAMIC_ATTRIBUTE;
109 } else {
110 out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
111 }
112 }
113 out_value->data = util::HostToDevice32(resid.id);
114 return true;
115 }
116
Clone(StringPool *) const117 Reference* Reference::Clone(StringPool* /*new_pool*/) const {
118 return new Reference(*this);
119 }
120
Print(std::ostream * out) const121 void Reference::Print(std::ostream* out) const {
122 if (reference_type == Type::kResource) {
123 *out << "(reference) @";
124 if (!name && !id) {
125 *out << "null";
126 return;
127 }
128 } else {
129 *out << "(attr-reference) ?";
130 }
131
132 if (private_reference) {
133 *out << "*";
134 }
135
136 if (name) {
137 *out << name.value();
138 }
139
140 if (id && id.value().is_valid_dynamic()) {
141 if (name) {
142 *out << " ";
143 }
144 *out << id.value();
145 }
146 }
147
Equals(const Value * value) const148 bool Id::Equals(const Value* value) const {
149 return ValueCast<Id>(value) != nullptr;
150 }
151
Flatten(android::Res_value * out) const152 bool Id::Flatten(android::Res_value* out) const {
153 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
154 out->data = util::HostToDevice32(0);
155 return true;
156 }
157
Clone(StringPool *) const158 Id* Id::Clone(StringPool* /*new_pool*/) const { return new Id(*this); }
159
Print(std::ostream * out) const160 void Id::Print(std::ostream* out) const { *out << "(id)"; }
161
String(const StringPool::Ref & ref)162 String::String(const StringPool::Ref& ref) : value(ref) {}
163
Equals(const Value * value) const164 bool String::Equals(const Value* value) const {
165 const String* other = ValueCast<String>(value);
166 if (!other) {
167 return false;
168 }
169
170 if (this->value != other->value) {
171 return false;
172 }
173
174 if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
175 return false;
176 }
177
178 auto other_iter = other->untranslatable_sections.begin();
179 for (const UntranslatableSection& this_section : untranslatable_sections) {
180 if (this_section != *other_iter) {
181 return false;
182 }
183 ++other_iter;
184 }
185 return true;
186 }
187
Flatten(android::Res_value * out_value) const188 bool String::Flatten(android::Res_value* out_value) const {
189 // Verify that our StringPool index is within encode-able limits.
190 if (value.index() > std::numeric_limits<uint32_t>::max()) {
191 return false;
192 }
193
194 out_value->dataType = android::Res_value::TYPE_STRING;
195 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
196 return true;
197 }
198
Clone(StringPool * new_pool) const199 String* String::Clone(StringPool* new_pool) const {
200 String* str = new String(new_pool->MakeRef(*value));
201 str->comment_ = comment_;
202 str->source_ = source_;
203 str->untranslatable_sections = untranslatable_sections;
204 return str;
205 }
206
Print(std::ostream * out) const207 void String::Print(std::ostream* out) const {
208 *out << "(string) \"" << *value << "\"";
209 }
210
StyledString(const StringPool::StyleRef & ref)211 StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {}
212
Equals(const Value * value) const213 bool StyledString::Equals(const Value* value) const {
214 const StyledString* other = ValueCast<StyledString>(value);
215 if (!other) {
216 return false;
217 }
218
219 if (this->value != other->value) {
220 return false;
221 }
222
223 if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
224 return false;
225 }
226
227 auto other_iter = other->untranslatable_sections.begin();
228 for (const UntranslatableSection& this_section : untranslatable_sections) {
229 if (this_section != *other_iter) {
230 return false;
231 }
232 ++other_iter;
233 }
234 return true;
235 }
236
Flatten(android::Res_value * out_value) const237 bool StyledString::Flatten(android::Res_value* out_value) const {
238 if (value.index() > std::numeric_limits<uint32_t>::max()) {
239 return false;
240 }
241
242 out_value->dataType = android::Res_value::TYPE_STRING;
243 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
244 return true;
245 }
246
Clone(StringPool * new_pool) const247 StyledString* StyledString::Clone(StringPool* new_pool) const {
248 StyledString* str = new StyledString(new_pool->MakeRef(value));
249 str->comment_ = comment_;
250 str->source_ = source_;
251 str->untranslatable_sections = untranslatable_sections;
252 return str;
253 }
254
Print(std::ostream * out) const255 void StyledString::Print(std::ostream* out) const {
256 *out << "(styled string) \"" << *value->str << "\"";
257 for (const StringPool::Span& span : value->spans) {
258 *out << " " << *span.name << ":" << span.first_char << ","
259 << span.last_char;
260 }
261 }
262
FileReference(const StringPool::Ref & _path)263 FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {}
264
Equals(const Value * value) const265 bool FileReference::Equals(const Value* value) const {
266 const FileReference* other = ValueCast<FileReference>(value);
267 if (!other) {
268 return false;
269 }
270 return path == other->path;
271 }
272
Flatten(android::Res_value * out_value) const273 bool FileReference::Flatten(android::Res_value* out_value) const {
274 if (path.index() > std::numeric_limits<uint32_t>::max()) {
275 return false;
276 }
277
278 out_value->dataType = android::Res_value::TYPE_STRING;
279 out_value->data = util::HostToDevice32(static_cast<uint32_t>(path.index()));
280 return true;
281 }
282
Clone(StringPool * new_pool) const283 FileReference* FileReference::Clone(StringPool* new_pool) const {
284 FileReference* fr = new FileReference(new_pool->MakeRef(*path));
285 fr->file = file;
286 fr->comment_ = comment_;
287 fr->source_ = source_;
288 return fr;
289 }
290
Print(std::ostream * out) const291 void FileReference::Print(std::ostream* out) const {
292 *out << "(file) " << *path;
293 }
294
BinaryPrimitive(const android::Res_value & val)295 BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {}
296
BinaryPrimitive(uint8_t dataType,uint32_t data)297 BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
298 value.dataType = dataType;
299 value.data = data;
300 }
301
Equals(const Value * value) const302 bool BinaryPrimitive::Equals(const Value* value) const {
303 const BinaryPrimitive* other = ValueCast<BinaryPrimitive>(value);
304 if (!other) {
305 return false;
306 }
307 return this->value.dataType == other->value.dataType &&
308 this->value.data == other->value.data;
309 }
310
Flatten(android::Res_value * out_value) const311 bool BinaryPrimitive::Flatten(android::Res_value* out_value) const {
312 out_value->dataType = value.dataType;
313 out_value->data = util::HostToDevice32(value.data);
314 return true;
315 }
316
Clone(StringPool *) const317 BinaryPrimitive* BinaryPrimitive::Clone(StringPool* /*new_pool*/) const {
318 return new BinaryPrimitive(*this);
319 }
320
Print(std::ostream * out) const321 void BinaryPrimitive::Print(std::ostream* out) const {
322 switch (value.dataType) {
323 case android::Res_value::TYPE_NULL:
324 if (value.data == android::Res_value::DATA_NULL_EMPTY) {
325 *out << "(empty)";
326 } else {
327 *out << "(null)";
328 }
329 break;
330 case android::Res_value::TYPE_INT_DEC:
331 *out << "(integer) " << static_cast<int32_t>(value.data);
332 break;
333 case android::Res_value::TYPE_INT_HEX:
334 *out << "(integer) 0x" << std::hex << value.data << std::dec;
335 break;
336 case android::Res_value::TYPE_INT_BOOLEAN:
337 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
338 break;
339 case android::Res_value::TYPE_INT_COLOR_ARGB8:
340 case android::Res_value::TYPE_INT_COLOR_RGB8:
341 case android::Res_value::TYPE_INT_COLOR_ARGB4:
342 case android::Res_value::TYPE_INT_COLOR_RGB4:
343 *out << "(color) #" << std::hex << value.data << std::dec;
344 break;
345 default:
346 *out << "(unknown 0x" << std::hex << (int)value.dataType << ") 0x"
347 << std::hex << value.data << std::dec;
348 break;
349 }
350 }
351
Attribute()352 Attribute::Attribute()
353 : type_mask(0u),
354 min_int(std::numeric_limits<int32_t>::min()),
355 max_int(std::numeric_limits<int32_t>::max()) {
356 }
357
Attribute(bool w,uint32_t t)358 Attribute::Attribute(bool w, uint32_t t)
359 : type_mask(t),
360 min_int(std::numeric_limits<int32_t>::min()),
361 max_int(std::numeric_limits<int32_t>::max()) {
362 weak_ = w;
363 }
364
operator <<(std::ostream & out,const Attribute::Symbol & s)365 std::ostream& operator<<(std::ostream& out, const Attribute::Symbol& s) {
366 if (s.symbol.name) {
367 out << s.symbol.name.value().entry;
368 } else {
369 out << "???";
370 }
371 return out << "=" << s.value;
372 }
373
374 template <typename T>
add_pointer(T & val)375 constexpr T* add_pointer(T& val) {
376 return &val;
377 }
378
Equals(const Value * value) const379 bool Attribute::Equals(const Value* value) const {
380 const Attribute* other = ValueCast<Attribute>(value);
381 if (!other) {
382 return false;
383 }
384
385 if (symbols.size() != other->symbols.size()) {
386 return false;
387 }
388
389 if (type_mask != other->type_mask || min_int != other->min_int || max_int != other->max_int) {
390 return false;
391 }
392
393 std::vector<const Symbol*> sorted_a;
394 std::transform(symbols.begin(), symbols.end(), std::back_inserter(sorted_a),
395 add_pointer<const Symbol>);
396 std::sort(sorted_a.begin(), sorted_a.end(), [](const Symbol* a, const Symbol* b) -> bool {
397 return a->symbol.name < b->symbol.name;
398 });
399
400 std::vector<const Symbol*> sorted_b;
401 std::transform(other->symbols.begin(), other->symbols.end(), std::back_inserter(sorted_b),
402 add_pointer<const Symbol>);
403 std::sort(sorted_b.begin(), sorted_b.end(), [](const Symbol* a, const Symbol* b) -> bool {
404 return a->symbol.name < b->symbol.name;
405 });
406
407 return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(),
408 [](const Symbol* a, const Symbol* b) -> bool {
409 return a->symbol.Equals(&b->symbol) && a->value == b->value;
410 });
411 }
412
Clone(StringPool *) const413 Attribute* Attribute::Clone(StringPool* /*new_pool*/) const {
414 return new Attribute(*this);
415 }
416
PrintMask(std::ostream * out) const417 void Attribute::PrintMask(std::ostream* out) const {
418 if (type_mask == android::ResTable_map::TYPE_ANY) {
419 *out << "any";
420 return;
421 }
422
423 bool set = false;
424 if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) {
425 if (!set) {
426 set = true;
427 } else {
428 *out << "|";
429 }
430 *out << "reference";
431 }
432
433 if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) {
434 if (!set) {
435 set = true;
436 } else {
437 *out << "|";
438 }
439 *out << "string";
440 }
441
442 if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) {
443 if (!set) {
444 set = true;
445 } else {
446 *out << "|";
447 }
448 *out << "integer";
449 }
450
451 if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
452 if (!set) {
453 set = true;
454 } else {
455 *out << "|";
456 }
457 *out << "boolean";
458 }
459
460 if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) {
461 if (!set) {
462 set = true;
463 } else {
464 *out << "|";
465 }
466 *out << "color";
467 }
468
469 if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) {
470 if (!set) {
471 set = true;
472 } else {
473 *out << "|";
474 }
475 *out << "float";
476 }
477
478 if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) {
479 if (!set) {
480 set = true;
481 } else {
482 *out << "|";
483 }
484 *out << "dimension";
485 }
486
487 if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) {
488 if (!set) {
489 set = true;
490 } else {
491 *out << "|";
492 }
493 *out << "fraction";
494 }
495
496 if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) {
497 if (!set) {
498 set = true;
499 } else {
500 *out << "|";
501 }
502 *out << "enum";
503 }
504
505 if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) {
506 if (!set) {
507 set = true;
508 } else {
509 *out << "|";
510 }
511 *out << "flags";
512 }
513 }
514
Print(std::ostream * out) const515 void Attribute::Print(std::ostream* out) const {
516 *out << "(attr) ";
517 PrintMask(out);
518
519 if (!symbols.empty()) {
520 *out << " [" << util::Joiner(symbols, ", ") << "]";
521 }
522
523 if (min_int != std::numeric_limits<int32_t>::min()) {
524 *out << " min=" << min_int;
525 }
526
527 if (max_int != std::numeric_limits<int32_t>::max()) {
528 *out << " max=" << max_int;
529 }
530
531 if (IsWeak()) {
532 *out << " [weak]";
533 }
534 }
535
BuildAttributeMismatchMessage(DiagMessage * msg,const Attribute * attr,const Item * value)536 static void BuildAttributeMismatchMessage(DiagMessage* msg,
537 const Attribute* attr,
538 const Item* value) {
539 *msg << "expected";
540 if (attr->type_mask & android::ResTable_map::TYPE_BOOLEAN) {
541 *msg << " boolean";
542 }
543
544 if (attr->type_mask & android::ResTable_map::TYPE_COLOR) {
545 *msg << " color";
546 }
547
548 if (attr->type_mask & android::ResTable_map::TYPE_DIMENSION) {
549 *msg << " dimension";
550 }
551
552 if (attr->type_mask & android::ResTable_map::TYPE_ENUM) {
553 *msg << " enum";
554 }
555
556 if (attr->type_mask & android::ResTable_map::TYPE_FLAGS) {
557 *msg << " flags";
558 }
559
560 if (attr->type_mask & android::ResTable_map::TYPE_FLOAT) {
561 *msg << " float";
562 }
563
564 if (attr->type_mask & android::ResTable_map::TYPE_FRACTION) {
565 *msg << " fraction";
566 }
567
568 if (attr->type_mask & android::ResTable_map::TYPE_INTEGER) {
569 *msg << " integer";
570 }
571
572 if (attr->type_mask & android::ResTable_map::TYPE_REFERENCE) {
573 *msg << " reference";
574 }
575
576 if (attr->type_mask & android::ResTable_map::TYPE_STRING) {
577 *msg << " string";
578 }
579
580 *msg << " but got " << *value;
581 }
582
Matches(const Item * item,DiagMessage * out_msg) const583 bool Attribute::Matches(const Item* item, DiagMessage* out_msg) const {
584 android::Res_value val = {};
585 item->Flatten(&val);
586
587 // Always allow references.
588 const uint32_t mask = type_mask | android::ResTable_map::TYPE_REFERENCE;
589 if (!(mask & ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType))) {
590 if (out_msg) {
591 BuildAttributeMismatchMessage(out_msg, this, item);
592 }
593 return false;
594
595 } else if (ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType) &
596 android::ResTable_map::TYPE_INTEGER) {
597 if (static_cast<int32_t>(util::DeviceToHost32(val.data)) < min_int) {
598 if (out_msg) {
599 *out_msg << *item << " is less than minimum integer " << min_int;
600 }
601 return false;
602 } else if (static_cast<int32_t>(util::DeviceToHost32(val.data)) > max_int) {
603 if (out_msg) {
604 *out_msg << *item << " is greater than maximum integer " << max_int;
605 }
606 return false;
607 }
608 }
609 return true;
610 }
611
operator <<(std::ostream & out,const Style::Entry & entry)612 std::ostream& operator<<(std::ostream& out, const Style::Entry& entry) {
613 if (entry.key.name) {
614 out << entry.key.name.value();
615 } else if (entry.key.id) {
616 out << entry.key.id.value();
617 } else {
618 out << "???";
619 }
620 out << " = " << entry.value;
621 return out;
622 }
623
624 template <typename T>
ToPointerVec(std::vector<T> & src)625 std::vector<T*> ToPointerVec(std::vector<T>& src) {
626 std::vector<T*> dst;
627 dst.reserve(src.size());
628 for (T& in : src) {
629 dst.push_back(&in);
630 }
631 return dst;
632 }
633
634 template <typename T>
ToPointerVec(const std::vector<T> & src)635 std::vector<const T*> ToPointerVec(const std::vector<T>& src) {
636 std::vector<const T*> dst;
637 dst.reserve(src.size());
638 for (const T& in : src) {
639 dst.push_back(&in);
640 }
641 return dst;
642 }
643
KeyNameComparator(const Style::Entry * a,const Style::Entry * b)644 static bool KeyNameComparator(const Style::Entry* a, const Style::Entry* b) {
645 return a->key.name < b->key.name;
646 }
647
Equals(const Value * value) const648 bool Style::Equals(const Value* value) const {
649 const Style* other = ValueCast<Style>(value);
650 if (!other) {
651 return false;
652 }
653
654 if (bool(parent) != bool(other->parent) ||
655 (parent && other->parent && !parent.value().Equals(&other->parent.value()))) {
656 return false;
657 }
658
659 if (entries.size() != other->entries.size()) {
660 return false;
661 }
662
663 std::vector<const Entry*> sorted_a = ToPointerVec(entries);
664 std::sort(sorted_a.begin(), sorted_a.end(), KeyNameComparator);
665
666 std::vector<const Entry*> sorted_b = ToPointerVec(other->entries);
667 std::sort(sorted_b.begin(), sorted_b.end(), KeyNameComparator);
668
669 return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(),
670 [](const Entry* a, const Entry* b) -> bool {
671 return a->key.Equals(&b->key) && a->value->Equals(b->value.get());
672 });
673 }
674
Clone(StringPool * new_pool) const675 Style* Style::Clone(StringPool* new_pool) const {
676 Style* style = new Style();
677 style->parent = parent;
678 style->parent_inferred = parent_inferred;
679 style->comment_ = comment_;
680 style->source_ = source_;
681 for (auto& entry : entries) {
682 style->entries.push_back(Entry{entry.key, std::unique_ptr<Item>(entry.value->Clone(new_pool))});
683 }
684 return style;
685 }
686
Print(std::ostream * out) const687 void Style::Print(std::ostream* out) const {
688 *out << "(style) ";
689 if (parent && parent.value().name) {
690 const Reference& parent_ref = parent.value();
691 if (parent_ref.private_reference) {
692 *out << "*";
693 }
694 *out << parent_ref.name.value();
695 }
696 *out << " [" << util::Joiner(entries, ", ") << "]";
697 }
698
CloneEntry(const Style::Entry & entry,StringPool * pool)699 Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
700 Style::Entry cloned_entry{entry.key};
701 if (entry.value != nullptr) {
702 cloned_entry.value.reset(entry.value->Clone(pool));
703 }
704 return cloned_entry;
705 }
706
MergeWith(Style * other,StringPool * pool)707 void Style::MergeWith(Style* other, StringPool* pool) {
708 if (other->parent) {
709 parent = other->parent;
710 }
711
712 // We can't assume that the entries are sorted alphabetically since they're supposed to be
713 // sorted by Resource Id. Not all Resource Ids may be set though, so we can't sort and merge
714 // them keying off that.
715 //
716 // Instead, sort the entries of each Style by their name in a separate structure. Then merge
717 // those.
718
719 std::vector<Entry*> this_sorted = ToPointerVec(entries);
720 std::sort(this_sorted.begin(), this_sorted.end(), KeyNameComparator);
721
722 std::vector<Entry*> other_sorted = ToPointerVec(other->entries);
723 std::sort(other_sorted.begin(), other_sorted.end(), KeyNameComparator);
724
725 auto this_iter = this_sorted.begin();
726 const auto this_end = this_sorted.end();
727
728 auto other_iter = other_sorted.begin();
729 const auto other_end = other_sorted.end();
730
731 std::vector<Entry> merged_entries;
732 while (this_iter != this_end) {
733 if (other_iter != other_end) {
734 if ((*this_iter)->key.name < (*other_iter)->key.name) {
735 merged_entries.push_back(std::move(**this_iter));
736 ++this_iter;
737 } else {
738 // The other overrides.
739 merged_entries.push_back(CloneEntry(**other_iter, pool));
740 if ((*this_iter)->key.name == (*other_iter)->key.name) {
741 ++this_iter;
742 }
743 ++other_iter;
744 }
745 } else {
746 merged_entries.push_back(std::move(**this_iter));
747 ++this_iter;
748 }
749 }
750
751 while (other_iter != other_end) {
752 merged_entries.push_back(CloneEntry(**other_iter, pool));
753 ++other_iter;
754 }
755
756 entries = std::move(merged_entries);
757 }
758
Equals(const Value * value) const759 bool Array::Equals(const Value* value) const {
760 const Array* other = ValueCast<Array>(value);
761 if (!other) {
762 return false;
763 }
764
765 if (items.size() != other->items.size()) {
766 return false;
767 }
768
769 return std::equal(items.begin(), items.end(), other->items.begin(),
770 [](const std::unique_ptr<Item>& a,
771 const std::unique_ptr<Item>& b) -> bool {
772 return a->Equals(b.get());
773 });
774 }
775
Clone(StringPool * new_pool) const776 Array* Array::Clone(StringPool* new_pool) const {
777 Array* array = new Array();
778 array->comment_ = comment_;
779 array->source_ = source_;
780 for (auto& item : items) {
781 array->items.emplace_back(std::unique_ptr<Item>(item->Clone(new_pool)));
782 }
783 return array;
784 }
785
Print(std::ostream * out) const786 void Array::Print(std::ostream* out) const {
787 *out << "(array) [" << util::Joiner(items, ", ") << "]";
788 }
789
Equals(const Value * value) const790 bool Plural::Equals(const Value* value) const {
791 const Plural* other = ValueCast<Plural>(value);
792 if (!other) {
793 return false;
794 }
795
796 auto one_iter = values.begin();
797 auto one_end_iter = values.end();
798 auto two_iter = other->values.begin();
799 for (; one_iter != one_end_iter; ++one_iter, ++two_iter) {
800 const std::unique_ptr<Item>& a = *one_iter;
801 const std::unique_ptr<Item>& b = *two_iter;
802 if (a != nullptr && b != nullptr) {
803 if (!a->Equals(b.get())) {
804 return false;
805 }
806 } else if (a != b) {
807 return false;
808 }
809 }
810 return true;
811 }
812
Clone(StringPool * new_pool) const813 Plural* Plural::Clone(StringPool* new_pool) const {
814 Plural* p = new Plural();
815 p->comment_ = comment_;
816 p->source_ = source_;
817 const size_t count = values.size();
818 for (size_t i = 0; i < count; i++) {
819 if (values[i]) {
820 p->values[i] = std::unique_ptr<Item>(values[i]->Clone(new_pool));
821 }
822 }
823 return p;
824 }
825
Print(std::ostream * out) const826 void Plural::Print(std::ostream* out) const {
827 *out << "(plural)";
828 if (values[Zero]) {
829 *out << " zero=" << *values[Zero];
830 }
831
832 if (values[One]) {
833 *out << " one=" << *values[One];
834 }
835
836 if (values[Two]) {
837 *out << " two=" << *values[Two];
838 }
839
840 if (values[Few]) {
841 *out << " few=" << *values[Few];
842 }
843
844 if (values[Many]) {
845 *out << " many=" << *values[Many];
846 }
847
848 if (values[Other]) {
849 *out << " other=" << *values[Other];
850 }
851 }
852
Equals(const Value * value) const853 bool Styleable::Equals(const Value* value) const {
854 const Styleable* other = ValueCast<Styleable>(value);
855 if (!other) {
856 return false;
857 }
858
859 if (entries.size() != other->entries.size()) {
860 return false;
861 }
862
863 return std::equal(entries.begin(), entries.end(), other->entries.begin(),
864 [](const Reference& a, const Reference& b) -> bool {
865 return a.Equals(&b);
866 });
867 }
868
Clone(StringPool *) const869 Styleable* Styleable::Clone(StringPool* /*new_pool*/) const {
870 return new Styleable(*this);
871 }
872
Print(std::ostream * out) const873 void Styleable::Print(std::ostream* out) const {
874 *out << "(styleable) "
875 << " [" << util::Joiner(entries, ", ") << "]";
876 }
877
operator <(const Reference & a,const Reference & b)878 bool operator<(const Reference& a, const Reference& b) {
879 int cmp = a.name.value_or_default({}).compare(b.name.value_or_default({}));
880 if (cmp != 0) return cmp < 0;
881 return a.id < b.id;
882 }
883
operator ==(const Reference & a,const Reference & b)884 bool operator==(const Reference& a, const Reference& b) {
885 return a.name == b.name && a.id == b.id;
886 }
887
operator !=(const Reference & a,const Reference & b)888 bool operator!=(const Reference& a, const Reference& b) {
889 return a.name != b.name || a.id != b.id;
890 }
891
892 struct NameOnlyComparator {
operator ()aapt::NameOnlyComparator893 bool operator()(const Reference& a, const Reference& b) const {
894 return a.name < b.name;
895 }
896 };
897
MergeWith(Styleable * other)898 void Styleable::MergeWith(Styleable* other) {
899 // Compare only names, because some References may already have their IDs
900 // assigned (framework IDs that don't change).
901 std::set<Reference, NameOnlyComparator> references;
902 references.insert(entries.begin(), entries.end());
903 references.insert(other->entries.begin(), other->entries.end());
904 entries.clear();
905 entries.reserve(references.size());
906 entries.insert(entries.end(), references.begin(), references.end());
907 }
908
909 } // namespace aapt
910