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 <cinttypes> 21#include <limits> 22#include <set> 23#include <sstream> 24 25#include "android-base/stringprintf.h" 26#include "androidfw/ResourceTypes.h" 27 28#include "Resource.h" 29#include "ResourceUtils.h" 30#include "ValueVisitor.h" 31#include "util/Util.h" 32 33using ::aapt::text::Printer; 34using ::android::StringPiece; 35using ::android::base::StringPrintf; 36 37namespace aapt { 38 39void Value::PrettyPrint(Printer* printer) const { 40 std::ostringstream str_stream; 41 Print(&str_stream); 42 printer->Print(str_stream.str()); 43} 44 45std::ostream& operator<<(std::ostream& out, const Value& value) { 46 value.Print(&out); 47 return out; 48} 49 50template <typename Derived> 51void BaseValue<Derived>::Accept(ValueVisitor* visitor) { 52 visitor->Visit(static_cast<Derived*>(this)); 53} 54 55template <typename Derived> 56void BaseValue<Derived>::Accept(ConstValueVisitor* visitor) const { 57 visitor->Visit(static_cast<const Derived*>(this)); 58} 59 60template <typename Derived> 61void BaseItem<Derived>::Accept(ValueVisitor* visitor) { 62 visitor->Visit(static_cast<Derived*>(this)); 63} 64 65template <typename Derived> 66void BaseItem<Derived>::Accept(ConstValueVisitor* visitor) const { 67 visitor->Visit(static_cast<const Derived*>(this)); 68} 69 70RawString::RawString(const StringPool::Ref& ref) : value(ref) {} 71 72bool RawString::Equals(const Value* value) const { 73 const RawString* other = ValueCast<RawString>(value); 74 if (!other) { 75 return false; 76 } 77 return *this->value == *other->value; 78} 79 80RawString* RawString::Clone(StringPool* new_pool) const { 81 RawString* rs = new RawString(new_pool->MakeRef(value)); 82 rs->comment_ = comment_; 83 rs->source_ = source_; 84 return rs; 85} 86 87bool RawString::Flatten(android::Res_value* out_value) const { 88 out_value->dataType = android::Res_value::TYPE_STRING; 89 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index())); 90 return true; 91} 92 93void RawString::Print(std::ostream* out) const { 94 *out << "(raw string) " << *value; 95} 96 97Reference::Reference() : reference_type(Type::kResource) {} 98 99Reference::Reference(const ResourceNameRef& n, Type t) 100 : name(n.ToResourceName()), reference_type(t) {} 101 102Reference::Reference(const ResourceId& i, Type type) 103 : id(i), reference_type(type) {} 104 105Reference::Reference(const ResourceNameRef& n, const ResourceId& i) 106 : name(n.ToResourceName()), id(i), reference_type(Type::kResource) {} 107 108bool Reference::Equals(const Value* value) const { 109 const Reference* other = ValueCast<Reference>(value); 110 if (!other) { 111 return false; 112 } 113 return reference_type == other->reference_type && 114 private_reference == other->private_reference && id == other->id && 115 name == other->name; 116} 117 118bool Reference::Flatten(android::Res_value* out_value) const { 119 const ResourceId resid = id.value_or_default(ResourceId(0)); 120 const bool dynamic = resid.is_valid_dynamic() && is_dynamic; 121 122 if (reference_type == Reference::Type::kResource) { 123 if (dynamic) { 124 out_value->dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE; 125 } else { 126 out_value->dataType = android::Res_value::TYPE_REFERENCE; 127 } 128 } else { 129 if (dynamic) { 130 out_value->dataType = android::Res_value::TYPE_DYNAMIC_ATTRIBUTE; 131 } else { 132 out_value->dataType = android::Res_value::TYPE_ATTRIBUTE; 133 } 134 } 135 out_value->data = util::HostToDevice32(resid.id); 136 return true; 137} 138 139Reference* Reference::Clone(StringPool* /*new_pool*/) const { 140 return new Reference(*this); 141} 142 143void Reference::Print(std::ostream* out) const { 144 if (reference_type == Type::kResource) { 145 *out << "(reference) @"; 146 if (!name && !id) { 147 *out << "null"; 148 return; 149 } 150 } else { 151 *out << "(attr-reference) ?"; 152 } 153 154 if (private_reference) { 155 *out << "*"; 156 } 157 158 if (name) { 159 *out << name.value(); 160 } 161 162 if (id && id.value().is_valid_dynamic()) { 163 if (name) { 164 *out << " "; 165 } 166 *out << id.value(); 167 } 168} 169 170static void PrettyPrintReferenceImpl(const Reference& ref, bool print_package, Printer* printer) { 171 switch (ref.reference_type) { 172 case Reference::Type::kResource: 173 printer->Print("@"); 174 break; 175 176 case Reference::Type::kAttribute: 177 printer->Print("?"); 178 break; 179 } 180 181 if (!ref.name && !ref.id) { 182 printer->Print("null"); 183 return; 184 } 185 186 if (ref.private_reference) { 187 printer->Print("*"); 188 } 189 190 if (ref.name) { 191 const ResourceName& name = ref.name.value(); 192 if (print_package) { 193 printer->Print(name.to_string()); 194 } else { 195 printer->Print(to_string(name.type)); 196 printer->Print("/"); 197 printer->Print(name.entry); 198 } 199 } else if (ref.id && ref.id.value().is_valid_dynamic()) { 200 printer->Print(ref.id.value().to_string()); 201 } 202} 203 204void Reference::PrettyPrint(Printer* printer) const { 205 PrettyPrintReferenceImpl(*this, true /*print_package*/, printer); 206} 207 208void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const { 209 const bool print_package = name ? package != name.value().package : true; 210 PrettyPrintReferenceImpl(*this, print_package, printer); 211} 212 213bool Id::Equals(const Value* value) const { 214 return ValueCast<Id>(value) != nullptr; 215} 216 217bool Id::Flatten(android::Res_value* out) const { 218 out->dataType = android::Res_value::TYPE_INT_BOOLEAN; 219 out->data = util::HostToDevice32(0); 220 return true; 221} 222 223Id* Id::Clone(StringPool* /*new_pool*/) const { 224 return new Id(*this); 225} 226 227void Id::Print(std::ostream* out) const { 228 *out << "(id)"; 229} 230 231String::String(const StringPool::Ref& ref) : value(ref) { 232} 233 234bool String::Equals(const Value* value) const { 235 const String* other = ValueCast<String>(value); 236 if (!other) { 237 return false; 238 } 239 240 if (this->value != other->value) { 241 return false; 242 } 243 244 if (untranslatable_sections.size() != other->untranslatable_sections.size()) { 245 return false; 246 } 247 248 auto other_iter = other->untranslatable_sections.begin(); 249 for (const UntranslatableSection& this_section : untranslatable_sections) { 250 if (this_section != *other_iter) { 251 return false; 252 } 253 ++other_iter; 254 } 255 return true; 256} 257 258bool String::Flatten(android::Res_value* out_value) const { 259 // Verify that our StringPool index is within encode-able limits. 260 if (value.index() > std::numeric_limits<uint32_t>::max()) { 261 return false; 262 } 263 264 out_value->dataType = android::Res_value::TYPE_STRING; 265 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index())); 266 return true; 267} 268 269String* String::Clone(StringPool* new_pool) const { 270 String* str = new String(new_pool->MakeRef(value)); 271 str->comment_ = comment_; 272 str->source_ = source_; 273 str->untranslatable_sections = untranslatable_sections; 274 return str; 275} 276 277void String::Print(std::ostream* out) const { 278 *out << "(string) \"" << *value << "\""; 279} 280 281void String::PrettyPrint(Printer* printer) const { 282 printer->Print("\""); 283 printer->Print(*value); 284 printer->Print("\""); 285} 286 287StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) { 288} 289 290bool StyledString::Equals(const Value* value) const { 291 const StyledString* other = ValueCast<StyledString>(value); 292 if (!other) { 293 return false; 294 } 295 296 if (this->value != other->value) { 297 return false; 298 } 299 300 if (untranslatable_sections.size() != other->untranslatable_sections.size()) { 301 return false; 302 } 303 304 auto other_iter = other->untranslatable_sections.begin(); 305 for (const UntranslatableSection& this_section : untranslatable_sections) { 306 if (this_section != *other_iter) { 307 return false; 308 } 309 ++other_iter; 310 } 311 return true; 312} 313 314bool StyledString::Flatten(android::Res_value* out_value) const { 315 if (value.index() > std::numeric_limits<uint32_t>::max()) { 316 return false; 317 } 318 319 out_value->dataType = android::Res_value::TYPE_STRING; 320 out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index())); 321 return true; 322} 323 324StyledString* StyledString::Clone(StringPool* new_pool) const { 325 StyledString* str = new StyledString(new_pool->MakeRef(value)); 326 str->comment_ = comment_; 327 str->source_ = source_; 328 str->untranslatable_sections = untranslatable_sections; 329 return str; 330} 331 332void StyledString::Print(std::ostream* out) const { 333 *out << "(styled string) \"" << value->value << "\""; 334 for (const StringPool::Span& span : value->spans) { 335 *out << " " << *span.name << ":" << span.first_char << "," << span.last_char; 336 } 337} 338 339FileReference::FileReference(const StringPool::Ref& _path) : path(_path) { 340} 341 342bool FileReference::Equals(const Value* value) const { 343 const FileReference* other = ValueCast<FileReference>(value); 344 if (!other) { 345 return false; 346 } 347 return path == other->path; 348} 349 350bool FileReference::Flatten(android::Res_value* out_value) const { 351 if (path.index() > std::numeric_limits<uint32_t>::max()) { 352 return false; 353 } 354 355 out_value->dataType = android::Res_value::TYPE_STRING; 356 out_value->data = util::HostToDevice32(static_cast<uint32_t>(path.index())); 357 return true; 358} 359 360FileReference* FileReference::Clone(StringPool* new_pool) const { 361 FileReference* fr = new FileReference(new_pool->MakeRef(path)); 362 fr->file = file; 363 fr->type = type; 364 fr->comment_ = comment_; 365 fr->source_ = source_; 366 return fr; 367} 368 369void FileReference::Print(std::ostream* out) const { 370 *out << "(file) " << *path; 371 switch (type) { 372 case ResourceFile::Type::kBinaryXml: 373 *out << " type=XML"; 374 break; 375 case ResourceFile::Type::kProtoXml: 376 *out << " type=protoXML"; 377 break; 378 case ResourceFile::Type::kPng: 379 *out << " type=PNG"; 380 break; 381 default: 382 break; 383 } 384} 385 386BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) { 387} 388 389BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) { 390 value.dataType = dataType; 391 value.data = data; 392} 393 394bool BinaryPrimitive::Equals(const Value* value) const { 395 const BinaryPrimitive* other = ValueCast<BinaryPrimitive>(value); 396 if (!other) { 397 return false; 398 } 399 return this->value.dataType == other->value.dataType && 400 this->value.data == other->value.data; 401} 402 403bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const { 404 out_value->dataType = value.dataType; 405 out_value->data = util::HostToDevice32(value.data); 406 return true; 407} 408 409BinaryPrimitive* BinaryPrimitive::Clone(StringPool* /*new_pool*/) const { 410 return new BinaryPrimitive(*this); 411} 412 413void BinaryPrimitive::Print(std::ostream* out) const { 414 *out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data); 415} 416 417static std::string ComplexToString(uint32_t complex_value, bool fraction) { 418 using ::android::Res_value; 419 420 constexpr std::array<int, 4> kRadixShifts = {{23, 16, 8, 0}}; 421 422 // Determine the radix that was used. 423 const uint32_t radix = 424 (complex_value >> Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK; 425 const uint64_t mantissa = uint64_t{(complex_value >> Res_value::COMPLEX_MANTISSA_SHIFT) & 426 Res_value::COMPLEX_MANTISSA_MASK} 427 << kRadixShifts[radix]; 428 const float value = mantissa * (1.0f / (1 << 23)); 429 430 std::string str = StringPrintf("%f", value); 431 432 const int unit_type = 433 (complex_value >> Res_value::COMPLEX_UNIT_SHIFT) & Res_value::COMPLEX_UNIT_MASK; 434 if (fraction) { 435 switch (unit_type) { 436 case Res_value::COMPLEX_UNIT_FRACTION: 437 str += "%"; 438 break; 439 case Res_value::COMPLEX_UNIT_FRACTION_PARENT: 440 str += "%p"; 441 break; 442 default: 443 str += "???"; 444 break; 445 } 446 } else { 447 switch (unit_type) { 448 case Res_value::COMPLEX_UNIT_PX: 449 str += "px"; 450 break; 451 case Res_value::COMPLEX_UNIT_DIP: 452 str += "dp"; 453 break; 454 case Res_value::COMPLEX_UNIT_SP: 455 str += "sp"; 456 break; 457 case Res_value::COMPLEX_UNIT_PT: 458 str += "pt"; 459 break; 460 case Res_value::COMPLEX_UNIT_IN: 461 str += "in"; 462 break; 463 case Res_value::COMPLEX_UNIT_MM: 464 str += "mm"; 465 break; 466 default: 467 str += "???"; 468 break; 469 } 470 } 471 return str; 472} 473 474void BinaryPrimitive::PrettyPrint(Printer* printer) const { 475 using ::android::Res_value; 476 switch (value.dataType) { 477 case Res_value::TYPE_NULL: 478 if (value.data == Res_value::DATA_NULL_EMPTY) { 479 printer->Print("@empty"); 480 } else { 481 printer->Print("@null"); 482 } 483 break; 484 485 case Res_value::TYPE_INT_DEC: 486 printer->Print(StringPrintf("%" PRIi32, static_cast<int32_t>(value.data))); 487 break; 488 489 case Res_value::TYPE_INT_HEX: 490 printer->Print(StringPrintf("0x%08x", value.data)); 491 break; 492 493 case Res_value::TYPE_INT_BOOLEAN: 494 printer->Print(value.data != 0 ? "true" : "false"); 495 break; 496 497 case Res_value::TYPE_INT_COLOR_ARGB8: 498 case Res_value::TYPE_INT_COLOR_RGB8: 499 case Res_value::TYPE_INT_COLOR_ARGB4: 500 case Res_value::TYPE_INT_COLOR_RGB4: 501 printer->Print(StringPrintf("#%08x", value.data)); 502 break; 503 504 case Res_value::TYPE_FLOAT: 505 printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data))); 506 break; 507 508 case Res_value::TYPE_DIMENSION: 509 printer->Print(ComplexToString(value.data, false /*fraction*/)); 510 break; 511 512 case Res_value::TYPE_FRACTION: 513 printer->Print(ComplexToString(value.data, true /*fraction*/)); 514 break; 515 516 default: 517 printer->Print(StringPrintf("(unknown 0x%02x) 0x%08x", value.dataType, value.data)); 518 break; 519 } 520} 521 522Attribute::Attribute(uint32_t t) 523 : type_mask(t), 524 min_int(std::numeric_limits<int32_t>::min()), 525 max_int(std::numeric_limits<int32_t>::max()) { 526} 527 528std::ostream& operator<<(std::ostream& out, const Attribute::Symbol& s) { 529 if (s.symbol.name) { 530 out << s.symbol.name.value().entry; 531 } else { 532 out << "???"; 533 } 534 return out << "=" << s.value; 535} 536 537template <typename T> 538constexpr T* add_pointer(T& val) { 539 return &val; 540} 541 542bool Attribute::Equals(const Value* value) const { 543 const Attribute* other = ValueCast<Attribute>(value); 544 if (!other) { 545 return false; 546 } 547 548 if (symbols.size() != other->symbols.size()) { 549 return false; 550 } 551 552 if (type_mask != other->type_mask || min_int != other->min_int || max_int != other->max_int) { 553 return false; 554 } 555 556 std::vector<const Symbol*> sorted_a; 557 std::transform(symbols.begin(), symbols.end(), std::back_inserter(sorted_a), 558 add_pointer<const Symbol>); 559 std::sort(sorted_a.begin(), sorted_a.end(), [](const Symbol* a, const Symbol* b) -> bool { 560 return a->symbol.name < b->symbol.name; 561 }); 562 563 std::vector<const Symbol*> sorted_b; 564 std::transform(other->symbols.begin(), other->symbols.end(), std::back_inserter(sorted_b), 565 add_pointer<const Symbol>); 566 std::sort(sorted_b.begin(), sorted_b.end(), [](const Symbol* a, const Symbol* b) -> bool { 567 return a->symbol.name < b->symbol.name; 568 }); 569 570 return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(), 571 [](const Symbol* a, const Symbol* b) -> bool { 572 return a->symbol.Equals(&b->symbol) && a->value == b->value; 573 }); 574} 575 576bool Attribute::IsCompatibleWith(const Attribute& attr) const { 577 // If the high bits are set on any of these attribute type masks, then they are incompatible. 578 // We don't check that flags and enums are identical. 579 if ((type_mask & ~android::ResTable_map::TYPE_ANY) != 0 || 580 (attr.type_mask & ~android::ResTable_map::TYPE_ANY) != 0) { 581 return false; 582 } 583 584 // Every attribute accepts a reference. 585 uint32_t this_type_mask = type_mask | android::ResTable_map::TYPE_REFERENCE; 586 uint32_t that_type_mask = attr.type_mask | android::ResTable_map::TYPE_REFERENCE; 587 return this_type_mask == that_type_mask; 588} 589 590Attribute* Attribute::Clone(StringPool* /*new_pool*/) const { 591 return new Attribute(*this); 592} 593 594std::string Attribute::MaskString() const { 595 if (type_mask == android::ResTable_map::TYPE_ANY) { 596 return "any"; 597 } 598 599 std::ostringstream out; 600 bool set = false; 601 if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) { 602 if (!set) { 603 set = true; 604 } else { 605 out << "|"; 606 } 607 out << "reference"; 608 } 609 610 if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) { 611 if (!set) { 612 set = true; 613 } else { 614 out << "|"; 615 } 616 out << "string"; 617 } 618 619 if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) { 620 if (!set) { 621 set = true; 622 } else { 623 out << "|"; 624 } 625 out << "integer"; 626 } 627 628 if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) { 629 if (!set) { 630 set = true; 631 } else { 632 out << "|"; 633 } 634 out << "boolean"; 635 } 636 637 if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) { 638 if (!set) { 639 set = true; 640 } else { 641 out << "|"; 642 } 643 out << "color"; 644 } 645 646 if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) { 647 if (!set) { 648 set = true; 649 } else { 650 out << "|"; 651 } 652 out << "float"; 653 } 654 655 if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) { 656 if (!set) { 657 set = true; 658 } else { 659 out << "|"; 660 } 661 out << "dimension"; 662 } 663 664 if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) { 665 if (!set) { 666 set = true; 667 } else { 668 out << "|"; 669 } 670 out << "fraction"; 671 } 672 673 if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) { 674 if (!set) { 675 set = true; 676 } else { 677 out << "|"; 678 } 679 out << "enum"; 680 } 681 682 if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) { 683 if (!set) { 684 set = true; 685 } else { 686 out << "|"; 687 } 688 out << "flags"; 689 } 690 return out.str(); 691} 692 693void Attribute::Print(std::ostream* out) const { 694 *out << "(attr) " << MaskString(); 695 696 if (!symbols.empty()) { 697 *out << " [" << util::Joiner(symbols, ", ") << "]"; 698 } 699 700 if (min_int != std::numeric_limits<int32_t>::min()) { 701 *out << " min=" << min_int; 702 } 703 704 if (max_int != std::numeric_limits<int32_t>::max()) { 705 *out << " max=" << max_int; 706 } 707 708 if (IsWeak()) { 709 *out << " [weak]"; 710 } 711} 712 713static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& value, 714 DiagMessage* out_msg) { 715 *out_msg << "expected"; 716 if (attr.type_mask & android::ResTable_map::TYPE_BOOLEAN) { 717 *out_msg << " boolean"; 718 } 719 720 if (attr.type_mask & android::ResTable_map::TYPE_COLOR) { 721 *out_msg << " color"; 722 } 723 724 if (attr.type_mask & android::ResTable_map::TYPE_DIMENSION) { 725 *out_msg << " dimension"; 726 } 727 728 if (attr.type_mask & android::ResTable_map::TYPE_ENUM) { 729 *out_msg << " enum"; 730 } 731 732 if (attr.type_mask & android::ResTable_map::TYPE_FLAGS) { 733 *out_msg << " flags"; 734 } 735 736 if (attr.type_mask & android::ResTable_map::TYPE_FLOAT) { 737 *out_msg << " float"; 738 } 739 740 if (attr.type_mask & android::ResTable_map::TYPE_FRACTION) { 741 *out_msg << " fraction"; 742 } 743 744 if (attr.type_mask & android::ResTable_map::TYPE_INTEGER) { 745 *out_msg << " integer"; 746 } 747 748 if (attr.type_mask & android::ResTable_map::TYPE_REFERENCE) { 749 *out_msg << " reference"; 750 } 751 752 if (attr.type_mask & android::ResTable_map::TYPE_STRING) { 753 *out_msg << " string"; 754 } 755 756 *out_msg << " but got " << value; 757} 758 759bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const { 760 constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM; 761 constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS; 762 constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER; 763 constexpr const uint32_t TYPE_REFERENCE = android::ResTable_map::TYPE_REFERENCE; 764 765 android::Res_value val = {}; 766 item.Flatten(&val); 767 768 const uint32_t flattened_data = util::DeviceToHost32(val.data); 769 770 // Always allow references. 771 const uint32_t actual_type = ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType); 772 773 // Only one type must match between the actual and expected. 774 if ((actual_type & (type_mask | TYPE_REFERENCE)) == 0) { 775 if (out_msg) { 776 BuildAttributeMismatchMessage(*this, item, out_msg); 777 } 778 return false; 779 } 780 781 // Enums and flags are encoded as integers, so check them first before doing any range checks. 782 if ((type_mask & TYPE_ENUM) != 0 && (actual_type & TYPE_ENUM) != 0) { 783 for (const Symbol& s : symbols) { 784 if (flattened_data == s.value) { 785 return true; 786 } 787 } 788 789 // If the attribute accepts integers, we can't fail here. 790 if ((type_mask & TYPE_INTEGER) == 0) { 791 if (out_msg) { 792 *out_msg << item << " is not a valid enum"; 793 } 794 return false; 795 } 796 } 797 798 if ((type_mask & TYPE_FLAGS) != 0 && (actual_type & TYPE_FLAGS) != 0) { 799 uint32_t mask = 0u; 800 for (const Symbol& s : symbols) { 801 mask |= s.value; 802 } 803 804 // Check if the flattened data is covered by the flag bit mask. 805 // If the attribute accepts integers, we can't fail here. 806 if ((mask & flattened_data) == flattened_data) { 807 return true; 808 } else if ((type_mask & TYPE_INTEGER) == 0) { 809 if (out_msg) { 810 *out_msg << item << " is not a valid flag"; 811 } 812 return false; 813 } 814 } 815 816 // Finally check the integer range of the value. 817 if ((type_mask & TYPE_INTEGER) != 0 && (actual_type & TYPE_INTEGER) != 0) { 818 if (static_cast<int32_t>(flattened_data) < min_int) { 819 if (out_msg) { 820 *out_msg << item << " is less than minimum integer " << min_int; 821 } 822 return false; 823 } else if (static_cast<int32_t>(flattened_data) > max_int) { 824 if (out_msg) { 825 *out_msg << item << " is greater than maximum integer " << max_int; 826 } 827 return false; 828 } 829 } 830 return true; 831} 832 833std::ostream& operator<<(std::ostream& out, const Style::Entry& entry) { 834 if (entry.key.name) { 835 out << entry.key.name.value(); 836 } else if (entry.key.id) { 837 out << entry.key.id.value(); 838 } else { 839 out << "???"; 840 } 841 out << " = " << entry.value; 842 return out; 843} 844 845template <typename T> 846std::vector<T*> ToPointerVec(std::vector<T>& src) { 847 std::vector<T*> dst; 848 dst.reserve(src.size()); 849 for (T& in : src) { 850 dst.push_back(&in); 851 } 852 return dst; 853} 854 855template <typename T> 856std::vector<const T*> ToPointerVec(const std::vector<T>& src) { 857 std::vector<const T*> dst; 858 dst.reserve(src.size()); 859 for (const T& in : src) { 860 dst.push_back(&in); 861 } 862 return dst; 863} 864 865static bool KeyNameComparator(const Style::Entry* a, const Style::Entry* b) { 866 return a->key.name < b->key.name; 867} 868 869bool Style::Equals(const Value* value) const { 870 const Style* other = ValueCast<Style>(value); 871 if (!other) { 872 return false; 873 } 874 875 if (bool(parent) != bool(other->parent) || 876 (parent && other->parent && !parent.value().Equals(&other->parent.value()))) { 877 return false; 878 } 879 880 if (entries.size() != other->entries.size()) { 881 return false; 882 } 883 884 std::vector<const Entry*> sorted_a = ToPointerVec(entries); 885 std::sort(sorted_a.begin(), sorted_a.end(), KeyNameComparator); 886 887 std::vector<const Entry*> sorted_b = ToPointerVec(other->entries); 888 std::sort(sorted_b.begin(), sorted_b.end(), KeyNameComparator); 889 890 return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(), 891 [](const Entry* a, const Entry* b) -> bool { 892 return a->key.Equals(&b->key) && a->value->Equals(b->value.get()); 893 }); 894} 895 896Style* Style::Clone(StringPool* new_pool) const { 897 Style* style = new Style(); 898 style->parent = parent; 899 style->parent_inferred = parent_inferred; 900 style->comment_ = comment_; 901 style->source_ = source_; 902 for (auto& entry : entries) { 903 style->entries.push_back(Entry{entry.key, std::unique_ptr<Item>(entry.value->Clone(new_pool))}); 904 } 905 return style; 906} 907 908void Style::Print(std::ostream* out) const { 909 *out << "(style) "; 910 if (parent && parent.value().name) { 911 const Reference& parent_ref = parent.value(); 912 if (parent_ref.private_reference) { 913 *out << "*"; 914 } 915 *out << parent_ref.name.value(); 916 } 917 *out << " [" << util::Joiner(entries, ", ") << "]"; 918} 919 920Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) { 921 Style::Entry cloned_entry{entry.key}; 922 if (entry.value != nullptr) { 923 cloned_entry.value.reset(entry.value->Clone(pool)); 924 } 925 return cloned_entry; 926} 927 928void Style::MergeWith(Style* other, StringPool* pool) { 929 if (other->parent) { 930 parent = other->parent; 931 } 932 933 // We can't assume that the entries are sorted alphabetically since they're supposed to be 934 // sorted by Resource Id. Not all Resource Ids may be set though, so we can't sort and merge 935 // them keying off that. 936 // 937 // Instead, sort the entries of each Style by their name in a separate structure. Then merge 938 // those. 939 940 std::vector<Entry*> this_sorted = ToPointerVec(entries); 941 std::sort(this_sorted.begin(), this_sorted.end(), KeyNameComparator); 942 943 std::vector<Entry*> other_sorted = ToPointerVec(other->entries); 944 std::sort(other_sorted.begin(), other_sorted.end(), KeyNameComparator); 945 946 auto this_iter = this_sorted.begin(); 947 const auto this_end = this_sorted.end(); 948 949 auto other_iter = other_sorted.begin(); 950 const auto other_end = other_sorted.end(); 951 952 std::vector<Entry> merged_entries; 953 while (this_iter != this_end) { 954 if (other_iter != other_end) { 955 if ((*this_iter)->key.name < (*other_iter)->key.name) { 956 merged_entries.push_back(std::move(**this_iter)); 957 ++this_iter; 958 } else { 959 // The other overrides. 960 merged_entries.push_back(CloneEntry(**other_iter, pool)); 961 if ((*this_iter)->key.name == (*other_iter)->key.name) { 962 ++this_iter; 963 } 964 ++other_iter; 965 } 966 } else { 967 merged_entries.push_back(std::move(**this_iter)); 968 ++this_iter; 969 } 970 } 971 972 while (other_iter != other_end) { 973 merged_entries.push_back(CloneEntry(**other_iter, pool)); 974 ++other_iter; 975 } 976 977 entries = std::move(merged_entries); 978} 979 980bool Array::Equals(const Value* value) const { 981 const Array* other = ValueCast<Array>(value); 982 if (!other) { 983 return false; 984 } 985 986 if (elements.size() != other->elements.size()) { 987 return false; 988 } 989 990 return std::equal(elements.begin(), elements.end(), other->elements.begin(), 991 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { 992 return a->Equals(b.get()); 993 }); 994} 995 996Array* Array::Clone(StringPool* new_pool) const { 997 Array* array = new Array(); 998 array->comment_ = comment_; 999 array->source_ = source_; 1000 for (auto& item : elements) { 1001 array->elements.emplace_back(std::unique_ptr<Item>(item->Clone(new_pool))); 1002 } 1003 return array; 1004} 1005 1006void Array::Print(std::ostream* out) const { 1007 *out << "(array) [" << util::Joiner(elements, ", ") << "]"; 1008} 1009 1010bool Plural::Equals(const Value* value) const { 1011 const Plural* other = ValueCast<Plural>(value); 1012 if (!other) { 1013 return false; 1014 } 1015 1016 auto one_iter = values.begin(); 1017 auto one_end_iter = values.end(); 1018 auto two_iter = other->values.begin(); 1019 for (; one_iter != one_end_iter; ++one_iter, ++two_iter) { 1020 const std::unique_ptr<Item>& a = *one_iter; 1021 const std::unique_ptr<Item>& b = *two_iter; 1022 if (a != nullptr && b != nullptr) { 1023 if (!a->Equals(b.get())) { 1024 return false; 1025 } 1026 } else if (a != b) { 1027 return false; 1028 } 1029 } 1030 return true; 1031} 1032 1033Plural* Plural::Clone(StringPool* new_pool) const { 1034 Plural* p = new Plural(); 1035 p->comment_ = comment_; 1036 p->source_ = source_; 1037 const size_t count = values.size(); 1038 for (size_t i = 0; i < count; i++) { 1039 if (values[i]) { 1040 p->values[i] = std::unique_ptr<Item>(values[i]->Clone(new_pool)); 1041 } 1042 } 1043 return p; 1044} 1045 1046void Plural::Print(std::ostream* out) const { 1047 *out << "(plural)"; 1048 if (values[Zero]) { 1049 *out << " zero=" << *values[Zero]; 1050 } 1051 1052 if (values[One]) { 1053 *out << " one=" << *values[One]; 1054 } 1055 1056 if (values[Two]) { 1057 *out << " two=" << *values[Two]; 1058 } 1059 1060 if (values[Few]) { 1061 *out << " few=" << *values[Few]; 1062 } 1063 1064 if (values[Many]) { 1065 *out << " many=" << *values[Many]; 1066 } 1067 1068 if (values[Other]) { 1069 *out << " other=" << *values[Other]; 1070 } 1071} 1072 1073bool Styleable::Equals(const Value* value) const { 1074 const Styleable* other = ValueCast<Styleable>(value); 1075 if (!other) { 1076 return false; 1077 } 1078 1079 if (entries.size() != other->entries.size()) { 1080 return false; 1081 } 1082 1083 return std::equal(entries.begin(), entries.end(), other->entries.begin(), 1084 [](const Reference& a, const Reference& b) -> bool { 1085 return a.Equals(&b); 1086 }); 1087} 1088 1089Styleable* Styleable::Clone(StringPool* /*new_pool*/) const { 1090 return new Styleable(*this); 1091} 1092 1093void Styleable::Print(std::ostream* out) const { 1094 *out << "(styleable) " 1095 << " [" << util::Joiner(entries, ", ") << "]"; 1096} 1097 1098bool operator<(const Reference& a, const Reference& b) { 1099 int cmp = a.name.value_or_default({}).compare(b.name.value_or_default({})); 1100 if (cmp != 0) return cmp < 0; 1101 return a.id < b.id; 1102} 1103 1104bool operator==(const Reference& a, const Reference& b) { 1105 return a.name == b.name && a.id == b.id; 1106} 1107 1108bool operator!=(const Reference& a, const Reference& b) { 1109 return a.name != b.name || a.id != b.id; 1110} 1111 1112struct NameOnlyComparator { 1113 bool operator()(const Reference& a, const Reference& b) const { 1114 return a.name < b.name; 1115 } 1116}; 1117 1118void Styleable::MergeWith(Styleable* other) { 1119 // Compare only names, because some References may already have their IDs 1120 // assigned (framework IDs that don't change). 1121 std::set<Reference, NameOnlyComparator> references; 1122 references.insert(entries.begin(), entries.end()); 1123 references.insert(other->entries.begin(), other->entries.end()); 1124 entries.clear(); 1125 entries.reserve(references.size()); 1126 entries.insert(entries.end(), references.begin(), references.end()); 1127} 1128 1129} // namespace aapt 1130