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 25namespace aapt { 26 27namespace { 28 29class ReferenceIdToNameVisitor : public ValueVisitor { 30public: 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 50private: 51 const std::map<ResourceId, ResourceNameRef>* mMapping; 52}; 53 54class PackagePbDeserializer { 55public: 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 64public: 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 158private: 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 attr->minInt = pbAttr.min_int(); 238 attr->maxInt = pbAttr.max_int(); 239 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) { 240 Attribute::Symbol symbol; 241 deserializeItemCommon(pbSymbol, &symbol.symbol); 242 if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) { 243 return {}; 244 } 245 symbol.value = pbSymbol.value(); 246 attr->symbols.push_back(std::move(symbol)); 247 } 248 value = std::move(attr); 249 250 } else if (pbCompoundValue.has_style()) { 251 const pb::Style& pbStyle = pbCompoundValue.style(); 252 std::unique_ptr<Style> style = util::make_unique<Style>(); 253 if (pbStyle.has_parent()) { 254 style->parent = Reference(); 255 if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) { 256 return {}; 257 } 258 259 if (pbStyle.has_parent_source()) { 260 Source parentSource; 261 deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool, 262 &parentSource); 263 style->parent.value().setSource(std::move(parentSource)); 264 } 265 } 266 267 for (const pb::Style_Entry& pbEntry : pbStyle.entries()) { 268 Style::Entry entry; 269 deserializeItemCommon(pbEntry, &entry.key); 270 if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) { 271 return {}; 272 } 273 274 entry.value = deserializeItemFromPb(pbEntry.item(), config, pool); 275 if (!entry.value) { 276 return {}; 277 } 278 279 deserializeItemCommon(pbEntry, entry.value.get()); 280 style->entries.push_back(std::move(entry)); 281 } 282 value = std::move(style); 283 284 } else if (pbCompoundValue.has_styleable()) { 285 const pb::Styleable& pbStyleable = pbCompoundValue.styleable(); 286 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); 287 for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) { 288 Reference attrRef; 289 deserializeItemCommon(pbEntry, &attrRef); 290 deserializeReferenceFromPb(pbEntry.attr(), &attrRef); 291 styleable->entries.push_back(std::move(attrRef)); 292 } 293 value = std::move(styleable); 294 295 } else if (pbCompoundValue.has_array()) { 296 const pb::Array& pbArray = pbCompoundValue.array(); 297 std::unique_ptr<Array> array = util::make_unique<Array>(); 298 for (const pb::Array_Entry& pbEntry : pbArray.entries()) { 299 std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config, 300 pool); 301 if (!item) { 302 return {}; 303 } 304 305 deserializeItemCommon(pbEntry, item.get()); 306 array->items.push_back(std::move(item)); 307 } 308 value = std::move(array); 309 310 } else if (pbCompoundValue.has_plural()) { 311 const pb::Plural& pbPlural = pbCompoundValue.plural(); 312 std::unique_ptr<Plural> plural = util::make_unique<Plural>(); 313 for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) { 314 size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity()); 315 plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config, 316 pool); 317 if (!plural->values[pluralIdx]) { 318 return {}; 319 } 320 321 deserializeItemCommon(pbEntry, plural->values[pluralIdx].get()); 322 } 323 value = std::move(plural); 324 325 } else { 326 mDiag->error(DiagMessage(mSource) << "unknown compound value"); 327 return {}; 328 } 329 } else { 330 mDiag->error(DiagMessage(mSource) << "unknown value"); 331 return {}; 332 } 333 334 assert(value && "forgot to set value"); 335 336 value->setWeak(isWeak); 337 deserializeItemCommon(pbValue, value.get()); 338 return value; 339 } 340 341 bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) { 342 outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type()); 343 outRef->privateReference = pbRef.private_(); 344 345 if (!pbRef.has_id() && !pbRef.has_symbol_idx()) { 346 return false; 347 } 348 349 if (pbRef.has_id()) { 350 outRef->id = ResourceId(pbRef.id()); 351 } 352 353 if (pbRef.has_symbol_idx()) { 354 StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx()); 355 ResourceNameRef nameRef; 356 if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) { 357 mDiag->error(DiagMessage(mSource) << "invalid reference name '" 358 << strSymbol << "'"); 359 return false; 360 } 361 362 outRef->name = nameRef.toResourceName(); 363 } 364 return true; 365 } 366 367 template <typename T> 368 void deserializeItemCommon(const T& pbItem, Value* outValue) { 369 if (pbItem.has_source()) { 370 Source source; 371 deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source); 372 outValue->setSource(std::move(source)); 373 } 374 375 if (pbItem.has_comment()) { 376 outValue->setComment(util::utf8ToUtf16(pbItem.comment())); 377 } 378 } 379 380private: 381 const android::ResStringPool* mValuePool; 382 const android::ResStringPool* mSourcePool; 383 const android::ResStringPool* mSymbolPool; 384 const Source mSource; 385 IDiagnostics* mDiag; 386}; 387 388} // namespace 389 390std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable, 391 const Source& source, 392 IDiagnostics* diag) { 393 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which 394 // causes errors when qualifying it with android:: 395 using namespace android; 396 397 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); 398 399 if (!pbTable.has_string_pool()) { 400 diag->error(DiagMessage(source) << "no string pool found"); 401 return {}; 402 } 403 404 ResStringPool valuePool; 405 status_t result = valuePool.setTo(pbTable.string_pool().data().data(), 406 pbTable.string_pool().data().size()); 407 if (result != NO_ERROR) { 408 diag->error(DiagMessage(source) << "invalid string pool"); 409 return {}; 410 } 411 412 ResStringPool sourcePool; 413 if (pbTable.has_source_pool()) { 414 result = sourcePool.setTo(pbTable.source_pool().data().data(), 415 pbTable.source_pool().data().size()); 416 if (result != NO_ERROR) { 417 diag->error(DiagMessage(source) << "invalid source pool"); 418 return {}; 419 } 420 } 421 422 ResStringPool symbolPool; 423 if (pbTable.has_symbol_pool()) { 424 result = symbolPool.setTo(pbTable.symbol_pool().data().data(), 425 pbTable.symbol_pool().data().size()); 426 if (result != NO_ERROR) { 427 diag->error(DiagMessage(source) << "invalid symbol pool"); 428 return {}; 429 } 430 } 431 432 PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag); 433 for (const pb::Package& pbPackage : pbTable.packages()) { 434 if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) { 435 return {}; 436 } 437 } 438 return table; 439} 440 441std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile, 442 const Source& source, 443 IDiagnostics* diag) { 444 std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); 445 446 ResourceNameRef nameRef; 447 448 // Need to create an lvalue here so that nameRef can point to something real. 449 std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name()); 450 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) { 451 diag->error(DiagMessage(source) << "invalid resource name in compiled file header: " 452 << pbFile.resource_name()); 453 return {}; 454 } 455 file->name = nameRef.toResourceName(); 456 file->source.path = pbFile.source_path(); 457 deserializeConfigDescriptionFromPb(pbFile.config(), &file->config); 458 459 for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) { 460 // Need to create an lvalue here so that nameRef can point to something real. 461 utf16Name = util::utf8ToUtf16(pbSymbol.resource_name()); 462 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) { 463 diag->error(DiagMessage(source) << "invalid resource name for exported symbol in " 464 "compiled file header: " 465 << pbFile.resource_name()); 466 return {}; 467 } 468 file->exportedSymbols.push_back( 469 SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() }); 470 } 471 return file; 472} 473 474CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) : 475 mIn(static_cast<const uint8_t*>(data), size), mPbFile(), 476 mData(static_cast<const uint8_t*>(data)), mSize(size) { 477} 478 479const pb::CompiledFile* CompiledFileInputStream::CompiledFile() { 480 if (!mPbFile) { 481 std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>(); 482 uint64_t pbSize = 0u; 483 if (!mIn.ReadLittleEndian64(&pbSize)) { 484 return nullptr; 485 } 486 mIn.PushLimit(static_cast<int>(pbSize)); 487 if (!pbFile->ParsePartialFromCodedStream(&mIn)) { 488 return nullptr; 489 } 490 491 const size_t padding = 4 - (pbSize & 0x03); 492 const size_t offset = sizeof(uint64_t) + pbSize + padding; 493 if (offset > mSize) { 494 return nullptr; 495 } 496 497 mData += offset; 498 mSize -= offset; 499 mPbFile = std::move(pbFile); 500 } 501 return mPbFile.get(); 502} 503 504const void* CompiledFileInputStream::data() { 505 if (!mPbFile) { 506 if (!CompiledFile()) { 507 return nullptr; 508 } 509 } 510 return mData; 511} 512 513size_t CompiledFileInputStream::size() { 514 if (!mPbFile) { 515 if (!CompiledFile()) { 516 return 0; 517 } 518 } 519 return mSize; 520} 521 522} // namespace aapt 523