1 /* 2 * Copyright (C) 2016 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 "ResourceTable.h" 18 #include "ResourceUtils.h" 19 #include "ValueVisitor.h" 20 #include "proto/ProtoHelpers.h" 21 #include "proto/ProtoSerialize.h" 22 23 #include <androidfw/ResourceTypes.h> 24 25 namespace aapt { 26 27 namespace { 28 29 class ReferenceIdToNameVisitor : public ValueVisitor { 30 public: 31 using ValueVisitor::visit; 32 33 ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) : 34 mMapping(mapping) { 35 assert(mMapping); 36 } 37 38 void visit(Reference* reference) override { 39 if (!reference->id || !reference->id.value().isValid()) { 40 return; 41 } 42 43 ResourceId id = reference->id.value(); 44 auto cacheIter = mMapping->find(id); 45 if (cacheIter != mMapping->end()) { 46 reference->name = cacheIter->second.toResourceName(); 47 } 48 } 49 50 private: 51 const std::map<ResourceId, ResourceNameRef>* mMapping; 52 }; 53 54 class PackagePbDeserializer { 55 public: 56 PackagePbDeserializer(const android::ResStringPool* valuePool, 57 const android::ResStringPool* sourcePool, 58 const android::ResStringPool* symbolPool, 59 const Source& source, IDiagnostics* diag) : 60 mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool), 61 mSource(source), mDiag(diag) { 62 } 63 64 public: 65 bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) { 66 Maybe<uint8_t> id; 67 if (pbPackage.has_package_id()) { 68 id = static_cast<uint8_t>(pbPackage.package_id()); 69 } 70 71 std::map<ResourceId, ResourceNameRef> idIndex; 72 73 ResourceTablePackage* pkg = table->createPackage( 74 util::utf8ToUtf16(pbPackage.package_name()), id); 75 for (const pb::Type& pbType : pbPackage.types()) { 76 const ResourceType* resType = parseResourceType(util::utf8ToUtf16(pbType.name())); 77 if (!resType) { 78 mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'"); 79 return {}; 80 } 81 82 ResourceTableType* type = pkg->findOrCreateType(*resType); 83 84 for (const pb::Entry& pbEntry : pbType.entries()) { 85 ResourceEntry* entry = type->findOrCreateEntry(util::utf8ToUtf16(pbEntry.name())); 86 87 // Deserialize the symbol status (public/private with source and comments). 88 if (pbEntry.has_symbol_status()) { 89 const pb::SymbolStatus& pbStatus = pbEntry.symbol_status(); 90 if (pbStatus.has_source()) { 91 deserializeSourceFromPb(pbStatus.source(), *mSourcePool, 92 &entry->symbolStatus.source); 93 } 94 95 if (pbStatus.has_comment()) { 96 entry->symbolStatus.comment = util::utf8ToUtf16(pbStatus.comment()); 97 } 98 99 SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility()); 100 entry->symbolStatus.state = visibility; 101 102 if (visibility == SymbolState::kPublic) { 103 // This is a public symbol, we must encode the ID now if there is one. 104 if (pbEntry.has_id()) { 105 entry->id = static_cast<uint16_t>(pbEntry.id()); 106 } 107 108 if (type->symbolStatus.state != SymbolState::kPublic) { 109 // If the type has not been made public, do so now. 110 type->symbolStatus.state = SymbolState::kPublic; 111 if (pbType.has_id()) { 112 type->id = static_cast<uint8_t>(pbType.id()); 113 } 114 } 115 } else if (visibility == SymbolState::kPrivate) { 116 if (type->symbolStatus.state == SymbolState::kUndefined) { 117 type->symbolStatus.state = SymbolState::kPrivate; 118 } 119 } 120 } 121 122 ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id()); 123 if (resId.isValid()) { 124 idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name); 125 } 126 127 for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) { 128 const pb::ConfigDescription& pbConfig = pbConfigValue.config(); 129 130 ConfigDescription config; 131 if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) { 132 mDiag->error(DiagMessage(mSource) << "invalid configuration"); 133 return {}; 134 } 135 136 ResourceConfigValue* configValue = entry->findOrCreateValue(config, 137 pbConfig.product()); 138 if (configValue->value) { 139 // Duplicate config. 140 mDiag->error(DiagMessage(mSource) << "duplicate configuration"); 141 return {}; 142 } 143 144 configValue->value = deserializeValueFromPb(pbConfigValue.value(), 145 config, &table->stringPool); 146 if (!configValue->value) { 147 return {}; 148 } 149 } 150 } 151 } 152 153 ReferenceIdToNameVisitor visitor(&idIndex); 154 visitAllValuesInPackage(pkg, &visitor); 155 return true; 156 } 157 158 private: 159 std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem, 160 const ConfigDescription& config, 161 StringPool* pool) { 162 if (pbItem.has_ref()) { 163 const pb::Reference& pbRef = pbItem.ref(); 164 std::unique_ptr<Reference> ref = util::make_unique<Reference>(); 165 if (!deserializeReferenceFromPb(pbRef, ref.get())) { 166 return {}; 167 } 168 return std::move(ref); 169 170 } else if (pbItem.has_prim()) { 171 const pb::Primitive& pbPrim = pbItem.prim(); 172 android::Res_value prim = {}; 173 prim.dataType = static_cast<uint8_t>(pbPrim.type()); 174 prim.data = pbPrim.data(); 175 return util::make_unique<BinaryPrimitive>(prim); 176 177 } else if (pbItem.has_id()) { 178 return util::make_unique<Id>(); 179 180 } else if (pbItem.has_str()) { 181 const uint32_t idx = pbItem.str().idx(); 182 StringPiece16 str = util::getString(*mValuePool, idx); 183 184 const android::ResStringPool_span* spans = mValuePool->styleAt(idx); 185 if (spans && spans->name.index != android::ResStringPool_span::END) { 186 StyleString styleStr = { str.toString() }; 187 while (spans->name.index != android::ResStringPool_span::END) { 188 styleStr.spans.push_back(Span{ 189 util::getString(*mValuePool, spans->name.index).toString(), 190 spans->firstChar, 191 spans->lastChar 192 }); 193 spans++; 194 } 195 return util::make_unique<StyledString>( 196 pool->makeRef(styleStr, StringPool::Context{ 1, config })); 197 } 198 return util::make_unique<String>( 199 pool->makeRef(str, StringPool::Context{ 1, config })); 200 201 } else if (pbItem.has_raw_str()) { 202 const uint32_t idx = pbItem.raw_str().idx(); 203 StringPiece16 str = util::getString(*mValuePool, idx); 204 return util::make_unique<RawString>( 205 pool->makeRef(str, StringPool::Context{ 1, config })); 206 207 } else if (pbItem.has_file()) { 208 const uint32_t idx = pbItem.file().path_idx(); 209 StringPiece16 str = util::getString(*mValuePool, idx); 210 return util::make_unique<FileReference>( 211 pool->makeRef(str, StringPool::Context{ 0, config })); 212 213 } else { 214 mDiag->error(DiagMessage(mSource) << "unknown item"); 215 } 216 return {}; 217 } 218 219 std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue, 220 const ConfigDescription& config, 221 StringPool* pool) { 222 const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false; 223 224 std::unique_ptr<Value> value; 225 if (pbValue.has_item()) { 226 value = deserializeItemFromPb(pbValue.item(), config, pool); 227 if (!value) { 228 return {}; 229 } 230 231 } else if (pbValue.has_compound_value()) { 232 const pb::CompoundValue pbCompoundValue = pbValue.compound_value(); 233 if (pbCompoundValue.has_attr()) { 234 const pb::Attribute& pbAttr = pbCompoundValue.attr(); 235 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak); 236 attr->typeMask = pbAttr.format_flags(); 237 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) { 238 Attribute::Symbol symbol; 239 deserializeItemCommon(pbSymbol, &symbol.symbol); 240 if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) { 241 return {}; 242 } 243 symbol.value = pbSymbol.value(); 244 attr->symbols.push_back(std::move(symbol)); 245 } 246 value = std::move(attr); 247 248 } else if (pbCompoundValue.has_style()) { 249 const pb::Style& pbStyle = pbCompoundValue.style(); 250 std::unique_ptr<Style> style = util::make_unique<Style>(); 251 if (pbStyle.has_parent()) { 252 style->parent = Reference(); 253 if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) { 254 return {}; 255 } 256 257 if (pbStyle.has_parent_source()) { 258 Source parentSource; 259 deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool, 260 &parentSource); 261 style->parent.value().setSource(std::move(parentSource)); 262 } 263 } 264 265 for (const pb::Style_Entry& pbEntry : pbStyle.entries()) { 266 Style::Entry entry; 267 deserializeItemCommon(pbEntry, &entry.key); 268 if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) { 269 return {}; 270 } 271 272 entry.value = deserializeItemFromPb(pbEntry.item(), config, pool); 273 if (!entry.value) { 274 return {}; 275 } 276 277 deserializeItemCommon(pbEntry, entry.value.get()); 278 style->entries.push_back(std::move(entry)); 279 } 280 value = std::move(style); 281 282 } else if (pbCompoundValue.has_styleable()) { 283 const pb::Styleable& pbStyleable = pbCompoundValue.styleable(); 284 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); 285 for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) { 286 Reference attrRef; 287 deserializeItemCommon(pbEntry, &attrRef); 288 deserializeReferenceFromPb(pbEntry.attr(), &attrRef); 289 styleable->entries.push_back(std::move(attrRef)); 290 } 291 value = std::move(styleable); 292 293 } else if (pbCompoundValue.has_array()) { 294 const pb::Array& pbArray = pbCompoundValue.array(); 295 std::unique_ptr<Array> array = util::make_unique<Array>(); 296 for (const pb::Array_Entry& pbEntry : pbArray.entries()) { 297 std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config, 298 pool); 299 if (!item) { 300 return {}; 301 } 302 303 deserializeItemCommon(pbEntry, item.get()); 304 array->items.push_back(std::move(item)); 305 } 306 value = std::move(array); 307 308 } else if (pbCompoundValue.has_plural()) { 309 const pb::Plural& pbPlural = pbCompoundValue.plural(); 310 std::unique_ptr<Plural> plural = util::make_unique<Plural>(); 311 for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) { 312 size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity()); 313 plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config, 314 pool); 315 if (!plural->values[pluralIdx]) { 316 return {}; 317 } 318 319 deserializeItemCommon(pbEntry, plural->values[pluralIdx].get()); 320 } 321 value = std::move(plural); 322 323 } else { 324 mDiag->error(DiagMessage(mSource) << "unknown compound value"); 325 return {}; 326 } 327 } else { 328 mDiag->error(DiagMessage(mSource) << "unknown value"); 329 return {}; 330 } 331 332 assert(value && "forgot to set value"); 333 334 value->setWeak(isWeak); 335 deserializeItemCommon(pbValue, value.get()); 336 return value; 337 } 338 339 bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) { 340 outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type()); 341 outRef->privateReference = pbRef.private_(); 342 343 if (!pbRef.has_id() && !pbRef.has_symbol_idx()) { 344 return false; 345 } 346 347 if (pbRef.has_id()) { 348 outRef->id = ResourceId(pbRef.id()); 349 } 350 351 if (pbRef.has_symbol_idx()) { 352 StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx()); 353 ResourceNameRef nameRef; 354 if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) { 355 mDiag->error(DiagMessage(mSource) << "invalid reference name '" 356 << strSymbol << "'"); 357 return false; 358 } 359 360 outRef->name = nameRef.toResourceName(); 361 } 362 return true; 363 } 364 365 template <typename T> 366 void deserializeItemCommon(const T& pbItem, Value* outValue) { 367 if (pbItem.has_source()) { 368 Source source; 369 deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source); 370 outValue->setSource(std::move(source)); 371 } 372 373 if (pbItem.has_comment()) { 374 outValue->setComment(util::utf8ToUtf16(pbItem.comment())); 375 } 376 } 377 378 private: 379 const android::ResStringPool* mValuePool; 380 const android::ResStringPool* mSourcePool; 381 const android::ResStringPool* mSymbolPool; 382 const Source mSource; 383 IDiagnostics* mDiag; 384 }; 385 386 } // namespace 387 388 std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable, 389 const Source& source, 390 IDiagnostics* diag) { 391 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which 392 // causes errors when qualifying it with android:: 393 using namespace android; 394 395 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); 396 397 if (!pbTable.has_string_pool()) { 398 diag->error(DiagMessage(source) << "no string pool found"); 399 return {}; 400 } 401 402 ResStringPool valuePool; 403 status_t result = valuePool.setTo(pbTable.string_pool().data().data(), 404 pbTable.string_pool().data().size()); 405 if (result != NO_ERROR) { 406 diag->error(DiagMessage(source) << "invalid string pool"); 407 return {}; 408 } 409 410 ResStringPool sourcePool; 411 if (pbTable.has_source_pool()) { 412 result = sourcePool.setTo(pbTable.source_pool().data().data(), 413 pbTable.source_pool().data().size()); 414 if (result != NO_ERROR) { 415 diag->error(DiagMessage(source) << "invalid source pool"); 416 return {}; 417 } 418 } 419 420 ResStringPool symbolPool; 421 if (pbTable.has_symbol_pool()) { 422 result = symbolPool.setTo(pbTable.symbol_pool().data().data(), 423 pbTable.symbol_pool().data().size()); 424 if (result != NO_ERROR) { 425 diag->error(DiagMessage(source) << "invalid symbol pool"); 426 return {}; 427 } 428 } 429 430 PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag); 431 for (const pb::Package& pbPackage : pbTable.packages()) { 432 if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) { 433 return {}; 434 } 435 } 436 return table; 437 } 438 439 std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile, 440 const Source& source, 441 IDiagnostics* diag) { 442 std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); 443 444 ResourceNameRef nameRef; 445 446 // Need to create an lvalue here so that nameRef can point to something real. 447 std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name()); 448 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) { 449 diag->error(DiagMessage(source) << "invalid resource name in compiled file header: " 450 << pbFile.resource_name()); 451 return {}; 452 } 453 file->name = nameRef.toResourceName(); 454 file->source.path = pbFile.source_path(); 455 deserializeConfigDescriptionFromPb(pbFile.config(), &file->config); 456 457 for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) { 458 // Need to create an lvalue here so that nameRef can point to something real. 459 utf16Name = util::utf8ToUtf16(pbSymbol.resource_name()); 460 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) { 461 diag->error(DiagMessage(source) << "invalid resource name for exported symbol in " 462 "compiled file header: " 463 << pbFile.resource_name()); 464 return {}; 465 } 466 file->exportedSymbols.push_back( 467 SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() }); 468 } 469 return file; 470 } 471 472 CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) : 473 mIn(static_cast<const uint8_t*>(data), size), mPbFile(), 474 mData(static_cast<const uint8_t*>(data)), mSize(size) { 475 } 476 477 const pb::CompiledFile* CompiledFileInputStream::CompiledFile() { 478 if (!mPbFile) { 479 std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>(); 480 uint64_t pbSize = 0u; 481 if (!mIn.ReadLittleEndian64(&pbSize)) { 482 return nullptr; 483 } 484 mIn.PushLimit(static_cast<int>(pbSize)); 485 if (!pbFile->ParsePartialFromCodedStream(&mIn)) { 486 return nullptr; 487 } 488 489 const size_t padding = 4 - (pbSize & 0x03); 490 const size_t offset = sizeof(uint64_t) + pbSize + padding; 491 if (offset > mSize) { 492 return nullptr; 493 } 494 495 mData += offset; 496 mSize -= offset; 497 mPbFile = std::move(pbFile); 498 } 499 return mPbFile.get(); 500 } 501 502 const void* CompiledFileInputStream::data() { 503 if (!mPbFile) { 504 if (!CompiledFile()) { 505 return nullptr; 506 } 507 } 508 return mData; 509 } 510 511 size_t CompiledFileInputStream::size() { 512 if (!mPbFile) { 513 if (!CompiledFile()) { 514 return 0; 515 } 516 } 517 return mSize; 518 } 519 520 } // namespace aapt 521