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 "Resource.h" 18#include "ResourceUtils.h" 19#include "ResourceValues.h" 20#include "ValueVisitor.h" 21#include "io/File.h" 22#include "util/Util.h" 23 24#include <androidfw/ResourceTypes.h> 25#include <limits> 26 27namespace aapt { 28 29template <typename Derived> 30void BaseValue<Derived>::accept(RawValueVisitor* visitor) { 31 visitor->visit(static_cast<Derived*>(this)); 32} 33 34template <typename Derived> 35void BaseItem<Derived>::accept(RawValueVisitor* visitor) { 36 visitor->visit(static_cast<Derived*>(this)); 37} 38 39RawString::RawString(const StringPool::Ref& ref) : value(ref) { 40} 41 42bool RawString::equals(const Value* value) const { 43 const RawString* other = valueCast<RawString>(value); 44 if (!other) { 45 return false; 46 } 47 return *this->value == *other->value; 48} 49 50RawString* RawString::clone(StringPool* newPool) const { 51 RawString* rs = new RawString(newPool->makeRef(*value)); 52 rs->mComment = mComment; 53 rs->mSource = mSource; 54 return rs; 55} 56 57bool RawString::flatten(android::Res_value* outValue) const { 58 outValue->dataType = android::Res_value::TYPE_STRING; 59 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 60 return true; 61} 62 63void RawString::print(std::ostream* out) const { 64 *out << "(raw string) " << *value; 65} 66 67Reference::Reference() : referenceType(Reference::Type::kResource) { 68} 69 70Reference::Reference(const ResourceNameRef& n, Type t) : 71 name(n.toResourceName()), referenceType(t) { 72} 73 74Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) { 75} 76 77bool Reference::equals(const Value* value) const { 78 const Reference* other = valueCast<Reference>(value); 79 if (!other) { 80 return false; 81 } 82 return referenceType == other->referenceType && privateReference == other->privateReference && 83 id == other->id && name == other->name; 84} 85 86bool Reference::flatten(android::Res_value* outValue) const { 87 outValue->dataType = (referenceType == Reference::Type::kResource) ? 88 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE; 89 outValue->data = util::hostToDevice32(id ? id.value().id : 0); 90 return true; 91} 92 93Reference* Reference::clone(StringPool* /*newPool*/) const { 94 return new Reference(*this); 95} 96 97void Reference::print(std::ostream* out) const { 98 *out << "(reference) "; 99 if (referenceType == Reference::Type::kResource) { 100 *out << "@"; 101 if (privateReference) { 102 *out << "*"; 103 } 104 } else { 105 *out << "?"; 106 } 107 108 if (name) { 109 *out << name.value(); 110 } 111 112 if (id && !Res_INTERNALID(id.value().id)) { 113 *out << " " << id.value(); 114 } 115} 116 117bool Id::equals(const Value* value) const { 118 return valueCast<Id>(value) != nullptr; 119} 120 121bool Id::flatten(android::Res_value* out) const { 122 out->dataType = android::Res_value::TYPE_INT_BOOLEAN; 123 out->data = util::hostToDevice32(0); 124 return true; 125} 126 127Id* Id::clone(StringPool* /*newPool*/) const { 128 return new Id(*this); 129} 130 131void Id::print(std::ostream* out) const { 132 *out << "(id)"; 133} 134 135String::String(const StringPool::Ref& ref) : value(ref) { 136} 137 138bool String::equals(const Value* value) const { 139 const String* other = valueCast<String>(value); 140 if (!other) { 141 return false; 142 } 143 return *this->value == *other->value; 144} 145 146bool String::flatten(android::Res_value* outValue) const { 147 // Verify that our StringPool index is within encode-able limits. 148 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 149 return false; 150 } 151 152 outValue->dataType = android::Res_value::TYPE_STRING; 153 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 154 return true; 155} 156 157String* String::clone(StringPool* newPool) const { 158 String* str = new String(newPool->makeRef(*value)); 159 str->mComment = mComment; 160 str->mSource = mSource; 161 return str; 162} 163 164void String::print(std::ostream* out) const { 165 *out << "(string) \"" << *value << "\""; 166} 167 168StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) { 169} 170 171bool StyledString::equals(const Value* value) const { 172 const StyledString* other = valueCast<StyledString>(value); 173 if (!other) { 174 return false; 175 } 176 177 if (*this->value->str == *other->value->str) { 178 const std::vector<StringPool::Span>& spansA = this->value->spans; 179 const std::vector<StringPool::Span>& spansB = other->value->spans; 180 return std::equal(spansA.begin(), spansA.end(), spansB.begin(), 181 [](const StringPool::Span& a, const StringPool::Span& b) -> bool { 182 return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar; 183 }); 184 } 185 return false; 186} 187 188bool StyledString::flatten(android::Res_value* outValue) const { 189 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 190 return false; 191 } 192 193 outValue->dataType = android::Res_value::TYPE_STRING; 194 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 195 return true; 196} 197 198StyledString* StyledString::clone(StringPool* newPool) const { 199 StyledString* str = new StyledString(newPool->makeRef(value)); 200 str->mComment = mComment; 201 str->mSource = mSource; 202 return str; 203} 204 205void StyledString::print(std::ostream* out) const { 206 *out << "(styled string) \"" << *value->str << "\""; 207 for (const StringPool::Span& span : value->spans) { 208 *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar; 209 } 210} 211 212FileReference::FileReference(const StringPool::Ref& _path) : path(_path) { 213} 214 215bool FileReference::equals(const Value* value) const { 216 const FileReference* other = valueCast<FileReference>(value); 217 if (!other) { 218 return false; 219 } 220 return *path == *other->path; 221} 222 223bool FileReference::flatten(android::Res_value* outValue) const { 224 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) { 225 return false; 226 } 227 228 outValue->dataType = android::Res_value::TYPE_STRING; 229 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex())); 230 return true; 231} 232 233FileReference* FileReference::clone(StringPool* newPool) const { 234 FileReference* fr = new FileReference(newPool->makeRef(*path)); 235 fr->file = file; 236 fr->mComment = mComment; 237 fr->mSource = mSource; 238 return fr; 239} 240 241void FileReference::print(std::ostream* out) const { 242 *out << "(file) " << *path; 243} 244 245BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) { 246} 247 248BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) { 249 value.dataType = dataType; 250 value.data = data; 251} 252 253bool BinaryPrimitive::equals(const Value* value) const { 254 const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value); 255 if (!other) { 256 return false; 257 } 258 return this->value.dataType == other->value.dataType && this->value.data == other->value.data; 259} 260 261bool BinaryPrimitive::flatten(android::Res_value* outValue) const { 262 outValue->dataType = value.dataType; 263 outValue->data = util::hostToDevice32(value.data); 264 return true; 265} 266 267BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const { 268 return new BinaryPrimitive(*this); 269} 270 271void BinaryPrimitive::print(std::ostream* out) const { 272 switch (value.dataType) { 273 case android::Res_value::TYPE_NULL: 274 *out << "(null)"; 275 break; 276 case android::Res_value::TYPE_INT_DEC: 277 *out << "(integer) " << static_cast<int32_t>(value.data); 278 break; 279 case android::Res_value::TYPE_INT_HEX: 280 *out << "(integer) 0x" << std::hex << value.data << std::dec; 281 break; 282 case android::Res_value::TYPE_INT_BOOLEAN: 283 *out << "(boolean) " << (value.data != 0 ? "true" : "false"); 284 break; 285 case android::Res_value::TYPE_INT_COLOR_ARGB8: 286 case android::Res_value::TYPE_INT_COLOR_RGB8: 287 case android::Res_value::TYPE_INT_COLOR_ARGB4: 288 case android::Res_value::TYPE_INT_COLOR_RGB4: 289 *out << "(color) #" << std::hex << value.data << std::dec; 290 break; 291 default: 292 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x" 293 << std::hex << value.data << std::dec; 294 break; 295 } 296} 297 298Attribute::Attribute(bool w, uint32_t t) : 299 typeMask(t), 300 minInt(std::numeric_limits<int32_t>::min()), 301 maxInt(std::numeric_limits<int32_t>::max()) { 302 mWeak = w; 303} 304 305bool Attribute::equals(const Value* value) const { 306 const Attribute* other = valueCast<Attribute>(value); 307 if (!other) { 308 return false; 309 } 310 311 return this->typeMask == other->typeMask && this->minInt == other->minInt && 312 this->maxInt == other->maxInt && 313 std::equal(this->symbols.begin(), this->symbols.end(), 314 other->symbols.begin(), 315 [](const Symbol& a, const Symbol& b) -> bool { 316 return a.symbol.equals(&b.symbol) && a.value == b.value; 317 }); 318} 319 320Attribute* Attribute::clone(StringPool* /*newPool*/) const { 321 return new Attribute(*this); 322} 323 324void Attribute::printMask(std::ostream* out) const { 325 if (typeMask == android::ResTable_map::TYPE_ANY) { 326 *out << "any"; 327 return; 328 } 329 330 bool set = false; 331 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) { 332 if (!set) { 333 set = true; 334 } else { 335 *out << "|"; 336 } 337 *out << "reference"; 338 } 339 340 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) { 341 if (!set) { 342 set = true; 343 } else { 344 *out << "|"; 345 } 346 *out << "string"; 347 } 348 349 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) { 350 if (!set) { 351 set = true; 352 } else { 353 *out << "|"; 354 } 355 *out << "integer"; 356 } 357 358 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) { 359 if (!set) { 360 set = true; 361 } else { 362 *out << "|"; 363 } 364 *out << "boolean"; 365 } 366 367 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) { 368 if (!set) { 369 set = true; 370 } else { 371 *out << "|"; 372 } 373 *out << "color"; 374 } 375 376 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) { 377 if (!set) { 378 set = true; 379 } else { 380 *out << "|"; 381 } 382 *out << "float"; 383 } 384 385 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) { 386 if (!set) { 387 set = true; 388 } else { 389 *out << "|"; 390 } 391 *out << "dimension"; 392 } 393 394 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) { 395 if (!set) { 396 set = true; 397 } else { 398 *out << "|"; 399 } 400 *out << "fraction"; 401 } 402 403 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) { 404 if (!set) { 405 set = true; 406 } else { 407 *out << "|"; 408 } 409 *out << "enum"; 410 } 411 412 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) { 413 if (!set) { 414 set = true; 415 } else { 416 *out << "|"; 417 } 418 *out << "flags"; 419 } 420} 421 422void Attribute::print(std::ostream* out) const { 423 *out << "(attr) "; 424 printMask(out); 425 426 if (!symbols.empty()) { 427 *out << " [" 428 << util::joiner(symbols.begin(), symbols.end(), ", ") 429 << "]"; 430 } 431 432 if (minInt != std::numeric_limits<int32_t>::min()) { 433 *out << " min=" << minInt; 434 } 435 436 if (maxInt != std::numeric_limits<int32_t>::max()) { 437 *out << " max=" << maxInt; 438 } 439 440 if (isWeak()) { 441 *out << " [weak]"; 442 } 443} 444 445static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr, 446 const Item* value) { 447 *msg << "expected"; 448 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) { 449 *msg << " boolean"; 450 } 451 452 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) { 453 *msg << " color"; 454 } 455 456 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) { 457 *msg << " dimension"; 458 } 459 460 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) { 461 *msg << " enum"; 462 } 463 464 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) { 465 *msg << " flags"; 466 } 467 468 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) { 469 *msg << " float"; 470 } 471 472 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) { 473 *msg << " fraction"; 474 } 475 476 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) { 477 *msg << " integer"; 478 } 479 480 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) { 481 *msg << " reference"; 482 } 483 484 if (attr->typeMask & android::ResTable_map::TYPE_STRING) { 485 *msg << " string"; 486 } 487 488 *msg << " but got " << *value; 489} 490 491bool Attribute::matches(const Item* item, DiagMessage* outMsg) const { 492 android::Res_value val = {}; 493 item->flatten(&val); 494 495 // Always allow references. 496 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE; 497 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) { 498 if (outMsg) { 499 buildAttributeMismatchMessage(outMsg, this, item); 500 } 501 return false; 502 503 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) & 504 android::ResTable_map::TYPE_INTEGER) { 505 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) { 506 if (outMsg) { 507 *outMsg << *item << " is less than minimum integer " << minInt; 508 } 509 return false; 510 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) { 511 if (outMsg) { 512 *outMsg << *item << " is greater than maximum integer " << maxInt; 513 } 514 return false; 515 } 516 } 517 return true; 518} 519 520bool Style::equals(const Value* value) const { 521 const Style* other = valueCast<Style>(value); 522 if (!other) { 523 return false; 524 } 525 if (bool(parent) != bool(other->parent) || 526 (parent && other->parent && !parent.value().equals(&other->parent.value()))) { 527 return false; 528 } 529 return std::equal(entries.begin(), entries.end(), other->entries.begin(), 530 [](const Entry& a, const Entry& b) -> bool { 531 return a.key.equals(&b.key) && a.value->equals(b.value.get()); 532 }); 533} 534 535Style* Style::clone(StringPool* newPool) const { 536 Style* style = new Style(); 537 style->parent = parent; 538 style->parentInferred = parentInferred; 539 style->mComment = mComment; 540 style->mSource = mSource; 541 for (auto& entry : entries) { 542 style->entries.push_back(Entry{ 543 entry.key, 544 std::unique_ptr<Item>(entry.value->clone(newPool)) 545 }); 546 } 547 return style; 548} 549 550void Style::print(std::ostream* out) const { 551 *out << "(style) "; 552 if (parent && parent.value().name) { 553 if (parent.value().privateReference) { 554 *out << "*"; 555 } 556 *out << parent.value().name.value(); 557 } 558 *out << " [" 559 << util::joiner(entries.begin(), entries.end(), ", ") 560 << "]"; 561} 562 563static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { 564 if (value.key.name) { 565 out << value.key.name.value(); 566 } else { 567 out << "???"; 568 } 569 out << " = "; 570 value.value->print(&out); 571 return out; 572} 573 574bool Array::equals(const Value* value) const { 575 const Array* other = valueCast<Array>(value); 576 if (!other) { 577 return false; 578 } 579 580 return std::equal(items.begin(), items.end(), other->items.begin(), 581 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { 582 return a->equals(b.get()); 583 }); 584} 585 586Array* Array::clone(StringPool* newPool) const { 587 Array* array = new Array(); 588 array->mComment = mComment; 589 array->mSource = mSource; 590 for (auto& item : items) { 591 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool))); 592 } 593 return array; 594} 595 596void Array::print(std::ostream* out) const { 597 *out << "(array) [" 598 << util::joiner(items.begin(), items.end(), ", ") 599 << "]"; 600} 601 602bool Plural::equals(const Value* value) const { 603 const Plural* other = valueCast<Plural>(value); 604 if (!other) { 605 return false; 606 } 607 608 return std::equal(values.begin(), values.end(), other->values.begin(), 609 [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool { 610 if (bool(a) != bool(b)) { 611 return false; 612 } 613 return bool(a) == bool(b) || a->equals(b.get()); 614 }); 615} 616 617Plural* Plural::clone(StringPool* newPool) const { 618 Plural* p = new Plural(); 619 p->mComment = mComment; 620 p->mSource = mSource; 621 const size_t count = values.size(); 622 for (size_t i = 0; i < count; i++) { 623 if (values[i]) { 624 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool)); 625 } 626 } 627 return p; 628} 629 630void Plural::print(std::ostream* out) const { 631 *out << "(plural)"; 632 if (values[Zero]) { 633 *out << " zero=" << *values[Zero]; 634 } 635 636 if (values[One]) { 637 *out << " one=" << *values[One]; 638 } 639 640 if (values[Two]) { 641 *out << " two=" << *values[Two]; 642 } 643 644 if (values[Few]) { 645 *out << " few=" << *values[Few]; 646 } 647 648 if (values[Many]) { 649 *out << " many=" << *values[Many]; 650 } 651} 652 653static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) { 654 return out << *item; 655} 656 657bool Styleable::equals(const Value* value) const { 658 const Styleable* other = valueCast<Styleable>(value); 659 if (!other) { 660 return false; 661 } 662 return std::equal(entries.begin(), entries.end(), other->entries.begin(), 663 [](const Reference& a, const Reference& b) -> bool { 664 return a.equals(&b); 665 }); 666} 667 668Styleable* Styleable::clone(StringPool* /*newPool*/) const { 669 return new Styleable(*this); 670} 671 672void Styleable::print(std::ostream* out) const { 673 *out << "(styleable) " << " [" 674 << util::joiner(entries.begin(), entries.end(), ", ") 675 << "]"; 676} 677 678} // namespace aapt 679