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 42RawString* RawString::clone(StringPool* newPool) const { 43 RawString* rs = new RawString(newPool->makeRef(*value)); 44 rs->mComment = mComment; 45 rs->mSource = mSource; 46 return rs; 47} 48 49bool RawString::flatten(android::Res_value* outValue) const { 50 outValue->dataType = android::Res_value::TYPE_STRING; 51 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 52 return true; 53} 54 55void RawString::print(std::ostream* out) const { 56 *out << "(raw string) " << *value; 57} 58 59Reference::Reference() : referenceType(Reference::Type::kResource) { 60} 61 62Reference::Reference(const ResourceNameRef& n, Type t) : 63 name(n.toResourceName()), referenceType(t) { 64} 65 66Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) { 67} 68 69bool Reference::flatten(android::Res_value* outValue) const { 70 outValue->dataType = (referenceType == Reference::Type::kResource) ? 71 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE; 72 outValue->data = util::hostToDevice32(id ? id.value().id : 0); 73 return true; 74} 75 76Reference* Reference::clone(StringPool* /*newPool*/) const { 77 return new Reference(*this); 78} 79 80void Reference::print(std::ostream* out) const { 81 *out << "(reference) "; 82 if (referenceType == Reference::Type::kResource) { 83 *out << "@"; 84 if (privateReference) { 85 *out << "*"; 86 } 87 } else { 88 *out << "?"; 89 } 90 91 if (name) { 92 *out << name.value(); 93 } 94 95 if (id && !Res_INTERNALID(id.value().id)) { 96 *out << " " << id.value(); 97 } 98} 99 100bool Id::flatten(android::Res_value* out) const { 101 out->dataType = android::Res_value::TYPE_INT_BOOLEAN; 102 out->data = util::hostToDevice32(0); 103 return true; 104} 105 106Id* Id::clone(StringPool* /*newPool*/) const { 107 return new Id(*this); 108} 109 110void Id::print(std::ostream* out) const { 111 *out << "(id)"; 112} 113 114String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) { 115} 116 117void String::setTranslateable(bool val) { 118 mTranslateable = val; 119} 120 121bool String::isTranslateable() const { 122 return mTranslateable; 123} 124 125bool String::flatten(android::Res_value* outValue) const { 126 // Verify that our StringPool index is within encode-able limits. 127 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 128 return false; 129 } 130 131 outValue->dataType = android::Res_value::TYPE_STRING; 132 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 133 return true; 134} 135 136String* String::clone(StringPool* newPool) const { 137 String* str = new String(newPool->makeRef(*value)); 138 str->mComment = mComment; 139 str->mSource = mSource; 140 return str; 141} 142 143void String::print(std::ostream* out) const { 144 *out << "(string) \"" << *value << "\""; 145} 146 147StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) { 148} 149 150void StyledString::setTranslateable(bool val) { 151 mTranslateable = val; 152} 153 154bool StyledString::isTranslateable() const { 155 return mTranslateable; 156} 157 158bool StyledString::flatten(android::Res_value* outValue) const { 159 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 160 return false; 161 } 162 163 outValue->dataType = android::Res_value::TYPE_STRING; 164 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex())); 165 return true; 166} 167 168StyledString* StyledString::clone(StringPool* newPool) const { 169 StyledString* str = new StyledString(newPool->makeRef(value)); 170 str->mComment = mComment; 171 str->mSource = mSource; 172 return str; 173} 174 175void StyledString::print(std::ostream* out) const { 176 *out << "(styled string) \"" << *value->str << "\""; 177} 178 179FileReference::FileReference(const StringPool::Ref& _path) : path(_path) { 180} 181 182bool FileReference::flatten(android::Res_value* outValue) const { 183 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) { 184 return false; 185 } 186 187 outValue->dataType = android::Res_value::TYPE_STRING; 188 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex())); 189 return true; 190} 191 192FileReference* FileReference::clone(StringPool* newPool) const { 193 FileReference* fr = new FileReference(newPool->makeRef(*path)); 194 fr->file = file; 195 fr->mComment = mComment; 196 fr->mSource = mSource; 197 return fr; 198} 199 200void FileReference::print(std::ostream* out) const { 201 *out << "(file) " << *path; 202} 203 204BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) { 205} 206 207BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) { 208 value.dataType = dataType; 209 value.data = data; 210} 211 212bool BinaryPrimitive::flatten(android::Res_value* outValue) const { 213 outValue->dataType = value.dataType; 214 outValue->data = util::hostToDevice32(value.data); 215 return true; 216} 217 218BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const { 219 return new BinaryPrimitive(*this); 220} 221 222void BinaryPrimitive::print(std::ostream* out) const { 223 switch (value.dataType) { 224 case android::Res_value::TYPE_NULL: 225 *out << "(null)"; 226 break; 227 case android::Res_value::TYPE_INT_DEC: 228 *out << "(integer) " << static_cast<int32_t>(value.data); 229 break; 230 case android::Res_value::TYPE_INT_HEX: 231 *out << "(integer) " << std::hex << value.data << std::dec; 232 break; 233 case android::Res_value::TYPE_INT_BOOLEAN: 234 *out << "(boolean) " << (value.data != 0 ? "true" : "false"); 235 break; 236 case android::Res_value::TYPE_INT_COLOR_ARGB8: 237 case android::Res_value::TYPE_INT_COLOR_RGB8: 238 case android::Res_value::TYPE_INT_COLOR_ARGB4: 239 case android::Res_value::TYPE_INT_COLOR_RGB4: 240 *out << "(color) #" << std::hex << value.data << std::dec; 241 break; 242 default: 243 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x" 244 << std::hex << value.data << std::dec; 245 break; 246 } 247} 248 249Attribute::Attribute(bool w, uint32_t t) : 250 typeMask(t), 251 minInt(std::numeric_limits<int32_t>::min()), 252 maxInt(std::numeric_limits<int32_t>::max()) { 253 mWeak = w; 254} 255 256Attribute* Attribute::clone(StringPool* /*newPool*/) const { 257 return new Attribute(*this); 258} 259 260void Attribute::printMask(std::ostream* out) const { 261 if (typeMask == android::ResTable_map::TYPE_ANY) { 262 *out << "any"; 263 return; 264 } 265 266 bool set = false; 267 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) { 268 if (!set) { 269 set = true; 270 } else { 271 *out << "|"; 272 } 273 *out << "reference"; 274 } 275 276 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) { 277 if (!set) { 278 set = true; 279 } else { 280 *out << "|"; 281 } 282 *out << "string"; 283 } 284 285 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) { 286 if (!set) { 287 set = true; 288 } else { 289 *out << "|"; 290 } 291 *out << "integer"; 292 } 293 294 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) { 295 if (!set) { 296 set = true; 297 } else { 298 *out << "|"; 299 } 300 *out << "boolean"; 301 } 302 303 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) { 304 if (!set) { 305 set = true; 306 } else { 307 *out << "|"; 308 } 309 *out << "color"; 310 } 311 312 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) { 313 if (!set) { 314 set = true; 315 } else { 316 *out << "|"; 317 } 318 *out << "float"; 319 } 320 321 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) { 322 if (!set) { 323 set = true; 324 } else { 325 *out << "|"; 326 } 327 *out << "dimension"; 328 } 329 330 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) { 331 if (!set) { 332 set = true; 333 } else { 334 *out << "|"; 335 } 336 *out << "fraction"; 337 } 338 339 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) { 340 if (!set) { 341 set = true; 342 } else { 343 *out << "|"; 344 } 345 *out << "enum"; 346 } 347 348 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) { 349 if (!set) { 350 set = true; 351 } else { 352 *out << "|"; 353 } 354 *out << "flags"; 355 } 356} 357 358void Attribute::print(std::ostream* out) const { 359 *out << "(attr) "; 360 printMask(out); 361 362 if (!symbols.empty()) { 363 *out << " [" 364 << util::joiner(symbols.begin(), symbols.end(), ", ") 365 << "]"; 366 } 367 368 if (isWeak()) { 369 *out << " [weak]"; 370 } 371} 372 373static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr, 374 const Item* value) { 375 *msg << "expected"; 376 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) { 377 *msg << " boolean"; 378 } 379 380 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) { 381 *msg << " color"; 382 } 383 384 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) { 385 *msg << " dimension"; 386 } 387 388 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) { 389 *msg << " enum"; 390 } 391 392 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) { 393 *msg << " flags"; 394 } 395 396 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) { 397 *msg << " float"; 398 } 399 400 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) { 401 *msg << " fraction"; 402 } 403 404 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) { 405 *msg << " integer"; 406 } 407 408 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) { 409 *msg << " reference"; 410 } 411 412 if (attr->typeMask & android::ResTable_map::TYPE_STRING) { 413 *msg << " string"; 414 } 415 416 *msg << " but got " << *value; 417} 418 419bool Attribute::matches(const Item* item, DiagMessage* outMsg) const { 420 android::Res_value val = {}; 421 item->flatten(&val); 422 423 // Always allow references. 424 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE; 425 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) { 426 if (outMsg) { 427 buildAttributeMismatchMessage(outMsg, this, item); 428 } 429 return false; 430 431 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) & 432 android::ResTable_map::TYPE_INTEGER) { 433 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) { 434 if (outMsg) { 435 *outMsg << *item << " is less than minimum integer " << minInt; 436 } 437 return false; 438 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) { 439 if (outMsg) { 440 *outMsg << *item << " is greater than maximum integer " << maxInt; 441 } 442 return false; 443 } 444 } 445 return true; 446} 447 448Style* Style::clone(StringPool* newPool) const { 449 Style* style = new Style(); 450 style->parent = parent; 451 style->parentInferred = parentInferred; 452 style->mComment = mComment; 453 style->mSource = mSource; 454 for (auto& entry : entries) { 455 style->entries.push_back(Entry{ 456 entry.key, 457 std::unique_ptr<Item>(entry.value->clone(newPool)) 458 }); 459 } 460 return style; 461} 462 463void Style::print(std::ostream* out) const { 464 *out << "(style) "; 465 if (parent && parent.value().name) { 466 if (parent.value().privateReference) { 467 *out << "*"; 468 } 469 *out << parent.value().name.value(); 470 } 471 *out << " [" 472 << util::joiner(entries.begin(), entries.end(), ", ") 473 << "]"; 474} 475 476static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { 477 if (value.key.name) { 478 out << value.key.name.value(); 479 } else { 480 out << "???"; 481 } 482 out << " = "; 483 value.value->print(&out); 484 return out; 485} 486 487Array* Array::clone(StringPool* newPool) const { 488 Array* array = new Array(); 489 array->mComment = mComment; 490 array->mSource = mSource; 491 for (auto& item : items) { 492 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool))); 493 } 494 return array; 495} 496 497void Array::print(std::ostream* out) const { 498 *out << "(array) [" 499 << util::joiner(items.begin(), items.end(), ", ") 500 << "]"; 501} 502 503Plural* Plural::clone(StringPool* newPool) const { 504 Plural* p = new Plural(); 505 p->mComment = mComment; 506 p->mSource = mSource; 507 const size_t count = values.size(); 508 for (size_t i = 0; i < count; i++) { 509 if (values[i]) { 510 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool)); 511 } 512 } 513 return p; 514} 515 516void Plural::print(std::ostream* out) const { 517 *out << "(plural)"; 518} 519 520static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) { 521 return out << *item; 522} 523 524Styleable* Styleable::clone(StringPool* /*newPool*/) const { 525 return new Styleable(*this); 526} 527 528void Styleable::print(std::ostream* out) const { 529 *out << "(styleable) " << " [" 530 << util::joiner(entries.begin(), entries.end(), ", ") 531 << "]"; 532} 533 534} // namespace aapt 535