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 "proto/ProtoSerialize.h" 18 19#include "android-base/logging.h" 20#include "androidfw/ResourceTypes.h" 21 22#include "ResourceTable.h" 23#include "ResourceUtils.h" 24#include "ValueVisitor.h" 25#include "proto/ProtoHelpers.h" 26 27namespace aapt { 28 29namespace { 30 31class ReferenceIdToNameVisitor : public ValueVisitor { 32 public: 33 using ValueVisitor::Visit; 34 35 explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) 36 : mapping_(mapping) { 37 CHECK(mapping_ != nullptr); 38 } 39 40 void Visit(Reference* reference) override { 41 if (!reference->id || !reference->id.value().is_valid()) { 42 return; 43 } 44 45 ResourceId id = reference->id.value(); 46 auto cache_iter = mapping_->find(id); 47 if (cache_iter != mapping_->end()) { 48 reference->name = cache_iter->second.ToResourceName(); 49 } 50 } 51 52 private: 53 const std::map<ResourceId, ResourceNameRef>* mapping_; 54}; 55 56class PackagePbDeserializer { 57 public: 58 PackagePbDeserializer(const android::ResStringPool* valuePool, 59 const android::ResStringPool* sourcePool, 60 const android::ResStringPool* symbolPool, 61 const Source& source, IDiagnostics* diag) 62 : value_pool_(valuePool), 63 source_pool_(sourcePool), 64 symbol_pool_(symbolPool), 65 source_(source), 66 diag_(diag) {} 67 68 public: 69 bool DeserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) { 70 Maybe<uint8_t> id; 71 if (pbPackage.has_package_id()) { 72 id = static_cast<uint8_t>(pbPackage.package_id()); 73 } 74 75 std::map<ResourceId, ResourceNameRef> idIndex; 76 77 ResourceTablePackage* pkg = table->CreatePackage(pbPackage.package_name(), id); 78 for (const pb::Type& pbType : pbPackage.types()) { 79 const ResourceType* resType = ParseResourceType(pbType.name()); 80 if (!resType) { 81 diag_->Error(DiagMessage(source_) << "unknown type '" << pbType.name() << "'"); 82 return {}; 83 } 84 85 ResourceTableType* type = pkg->FindOrCreateType(*resType); 86 87 for (const pb::Entry& pbEntry : pbType.entries()) { 88 ResourceEntry* entry = type->FindOrCreateEntry(pbEntry.name()); 89 90 // Deserialize the symbol status (public/private with source and 91 // comments). 92 if (pbEntry.has_symbol_status()) { 93 const pb::SymbolStatus& pbStatus = pbEntry.symbol_status(); 94 if (pbStatus.has_source()) { 95 DeserializeSourceFromPb(pbStatus.source(), *source_pool_, &entry->symbol_status.source); 96 } 97 98 if (pbStatus.has_comment()) { 99 entry->symbol_status.comment = pbStatus.comment(); 100 } 101 102 entry->symbol_status.allow_new = pbStatus.allow_new(); 103 104 SymbolState visibility = DeserializeVisibilityFromPb(pbStatus.visibility()); 105 entry->symbol_status.state = visibility; 106 107 if (visibility == SymbolState::kPublic) { 108 // This is a public symbol, we must encode the ID now if there is one. 109 if (pbEntry.has_id()) { 110 entry->id = static_cast<uint16_t>(pbEntry.id()); 111 } 112 113 if (type->symbol_status.state != SymbolState::kPublic) { 114 // If the type has not been made public, do so now. 115 type->symbol_status.state = SymbolState::kPublic; 116 if (pbType.has_id()) { 117 type->id = static_cast<uint8_t>(pbType.id()); 118 } 119 } 120 } else if (visibility == SymbolState::kPrivate) { 121 if (type->symbol_status.state == SymbolState::kUndefined) { 122 type->symbol_status.state = SymbolState::kPrivate; 123 } 124 } 125 } 126 127 ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id()); 128 if (resId.is_valid()) { 129 idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name); 130 } 131 132 for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) { 133 const pb::ConfigDescription& pbConfig = pbConfigValue.config(); 134 135 ConfigDescription config; 136 if (!DeserializeConfigDescriptionFromPb(pbConfig, &config)) { 137 diag_->Error(DiagMessage(source_) << "invalid configuration"); 138 return {}; 139 } 140 141 ResourceConfigValue* configValue = entry->FindOrCreateValue(config, pbConfig.product()); 142 if (configValue->value) { 143 // Duplicate config. 144 diag_->Error(DiagMessage(source_) << "duplicate configuration"); 145 return {}; 146 } 147 148 configValue->value = 149 DeserializeValueFromPb(pbConfigValue.value(), config, &table->string_pool); 150 if (!configValue->value) { 151 return {}; 152 } 153 } 154 } 155 } 156 157 ReferenceIdToNameVisitor visitor(&idIndex); 158 VisitAllValuesInPackage(pkg, &visitor); 159 return true; 160 } 161 162 private: 163 std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, 164 const ConfigDescription& config, 165 StringPool* pool) { 166 if (pb_item.has_ref()) { 167 const pb::Reference& pb_ref = pb_item.ref(); 168 std::unique_ptr<Reference> ref = util::make_unique<Reference>(); 169 if (!DeserializeReferenceFromPb(pb_ref, ref.get())) { 170 return {}; 171 } 172 return std::move(ref); 173 174 } else if (pb_item.has_prim()) { 175 const pb::Primitive& pb_prim = pb_item.prim(); 176 android::Res_value prim = {}; 177 prim.dataType = static_cast<uint8_t>(pb_prim.type()); 178 prim.data = pb_prim.data(); 179 return util::make_unique<BinaryPrimitive>(prim); 180 181 } else if (pb_item.has_id()) { 182 return util::make_unique<Id>(); 183 184 } else if (pb_item.has_str()) { 185 const uint32_t idx = pb_item.str().idx(); 186 const std::string str = util::GetString(*value_pool_, idx); 187 188 const android::ResStringPool_span* spans = value_pool_->styleAt(idx); 189 if (spans && spans->name.index != android::ResStringPool_span::END) { 190 StyleString style_str = {str}; 191 while (spans->name.index != android::ResStringPool_span::END) { 192 style_str.spans.push_back( 193 Span{util::GetString(*value_pool_, spans->name.index), 194 spans->firstChar, spans->lastChar}); 195 spans++; 196 } 197 return util::make_unique<StyledString>(pool->MakeRef( 198 style_str, 199 StringPool::Context(StringPool::Context::kStylePriority, config))); 200 } 201 return util::make_unique<String>( 202 pool->MakeRef(str, StringPool::Context(config))); 203 204 } else if (pb_item.has_raw_str()) { 205 const uint32_t idx = pb_item.raw_str().idx(); 206 const std::string str = util::GetString(*value_pool_, idx); 207 return util::make_unique<RawString>( 208 pool->MakeRef(str, StringPool::Context(config))); 209 210 } else if (pb_item.has_file()) { 211 const uint32_t idx = pb_item.file().path_idx(); 212 const std::string str = util::GetString(*value_pool_, idx); 213 return util::make_unique<FileReference>(pool->MakeRef( 214 str, 215 StringPool::Context(StringPool::Context::kHighPriority, config))); 216 217 } else { 218 diag_->Error(DiagMessage(source_) << "unknown item"); 219 } 220 return {}; 221 } 222 223 std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, 224 const ConfigDescription& config, 225 StringPool* pool) { 226 const bool is_weak = pb_value.has_weak() ? pb_value.weak() : false; 227 228 std::unique_ptr<Value> value; 229 if (pb_value.has_item()) { 230 value = DeserializeItemFromPb(pb_value.item(), config, pool); 231 if (!value) { 232 return {}; 233 } 234 235 } else if (pb_value.has_compound_value()) { 236 const pb::CompoundValue& pb_compound_value = pb_value.compound_value(); 237 if (pb_compound_value.has_attr()) { 238 const pb::Attribute& pb_attr = pb_compound_value.attr(); 239 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak); 240 attr->type_mask = pb_attr.format_flags(); 241 attr->min_int = pb_attr.min_int(); 242 attr->max_int = pb_attr.max_int(); 243 for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbols()) { 244 Attribute::Symbol symbol; 245 DeserializeItemCommon(pb_symbol, &symbol.symbol); 246 if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) { 247 return {}; 248 } 249 symbol.value = pb_symbol.value(); 250 attr->symbols.push_back(std::move(symbol)); 251 } 252 value = std::move(attr); 253 254 } else if (pb_compound_value.has_style()) { 255 const pb::Style& pb_style = pb_compound_value.style(); 256 std::unique_ptr<Style> style = util::make_unique<Style>(); 257 if (pb_style.has_parent()) { 258 style->parent = Reference(); 259 if (!DeserializeReferenceFromPb(pb_style.parent(), 260 &style->parent.value())) { 261 return {}; 262 } 263 264 if (pb_style.has_parent_source()) { 265 Source parent_source; 266 DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_, 267 &parent_source); 268 style->parent.value().SetSource(std::move(parent_source)); 269 } 270 } 271 272 for (const pb::Style_Entry& pb_entry : pb_style.entries()) { 273 Style::Entry entry; 274 DeserializeItemCommon(pb_entry, &entry.key); 275 if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) { 276 return {}; 277 } 278 279 entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool); 280 if (!entry.value) { 281 return {}; 282 } 283 284 DeserializeItemCommon(pb_entry, entry.value.get()); 285 style->entries.push_back(std::move(entry)); 286 } 287 value = std::move(style); 288 289 } else if (pb_compound_value.has_styleable()) { 290 const pb::Styleable& pb_styleable = pb_compound_value.styleable(); 291 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); 292 for (const pb::Styleable_Entry& pb_entry : pb_styleable.entries()) { 293 Reference attr_ref; 294 DeserializeItemCommon(pb_entry, &attr_ref); 295 DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref); 296 styleable->entries.push_back(std::move(attr_ref)); 297 } 298 value = std::move(styleable); 299 300 } else if (pb_compound_value.has_array()) { 301 const pb::Array& pb_array = pb_compound_value.array(); 302 std::unique_ptr<Array> array = util::make_unique<Array>(); 303 for (const pb::Array_Entry& pb_entry : pb_array.entries()) { 304 std::unique_ptr<Item> item = 305 DeserializeItemFromPb(pb_entry.item(), config, pool); 306 if (!item) { 307 return {}; 308 } 309 310 DeserializeItemCommon(pb_entry, item.get()); 311 array->items.push_back(std::move(item)); 312 } 313 value = std::move(array); 314 315 } else if (pb_compound_value.has_plural()) { 316 const pb::Plural& pb_plural = pb_compound_value.plural(); 317 std::unique_ptr<Plural> plural = util::make_unique<Plural>(); 318 for (const pb::Plural_Entry& pb_entry : pb_plural.entries()) { 319 size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity()); 320 plural->values[pluralIdx] = 321 DeserializeItemFromPb(pb_entry.item(), config, pool); 322 if (!plural->values[pluralIdx]) { 323 return {}; 324 } 325 326 DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get()); 327 } 328 value = std::move(plural); 329 330 } else { 331 diag_->Error(DiagMessage(source_) << "unknown compound value"); 332 return {}; 333 } 334 } else { 335 diag_->Error(DiagMessage(source_) << "unknown value"); 336 return {}; 337 } 338 339 CHECK(value) << "forgot to set value"; 340 341 value->SetWeak(is_weak); 342 DeserializeItemCommon(pb_value, value.get()); 343 return value; 344 } 345 346 bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) { 347 out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); 348 out_ref->private_reference = pb_ref.private_(); 349 350 if (pb_ref.has_id()) { 351 out_ref->id = ResourceId(pb_ref.id()); 352 } 353 354 if (pb_ref.has_symbol_idx()) { 355 const std::string str_symbol = util::GetString(*symbol_pool_, pb_ref.symbol_idx()); 356 ResourceNameRef name_ref; 357 if (!ResourceUtils::ParseResourceName(str_symbol, &name_ref, nullptr)) { 358 diag_->Error(DiagMessage(source_) << "invalid reference name '" << str_symbol << "'"); 359 return false; 360 } 361 362 out_ref->name = name_ref.ToResourceName(); 363 } 364 return true; 365 } 366 367 template <typename T> 368 void DeserializeItemCommon(const T& pb_item, Value* out_value) { 369 if (pb_item.has_source()) { 370 Source source; 371 DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source); 372 out_value->SetSource(std::move(source)); 373 } 374 375 if (pb_item.has_comment()) { 376 out_value->SetComment(pb_item.comment()); 377 } 378 } 379 380 private: 381 const android::ResStringPool* value_pool_; 382 const android::ResStringPool* source_pool_; 383 const android::ResStringPool* symbol_pool_; 384 const Source source_; 385 IDiagnostics* diag_; 386}; 387 388} // namespace 389 390std::unique_ptr<ResourceTable> DeserializeTableFromPb( 391 const pb::ResourceTable& pb_table, const Source& source, 392 IDiagnostics* diag) { 393 // We import the android namespace because on Windows NO_ERROR is a macro, not 394 // an enum, which 395 // causes errors when qualifying it with android:: 396 using namespace android; 397 398 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); 399 400 if (!pb_table.has_string_pool()) { 401 diag->Error(DiagMessage(source) << "no string pool found"); 402 return {}; 403 } 404 405 ResStringPool value_pool; 406 status_t result = value_pool.setTo(pb_table.string_pool().data().data(), 407 pb_table.string_pool().data().size()); 408 if (result != NO_ERROR) { 409 diag->Error(DiagMessage(source) << "invalid string pool"); 410 return {}; 411 } 412 413 ResStringPool source_pool; 414 if (pb_table.has_source_pool()) { 415 result = source_pool.setTo(pb_table.source_pool().data().data(), 416 pb_table.source_pool().data().size()); 417 if (result != NO_ERROR) { 418 diag->Error(DiagMessage(source) << "invalid source pool"); 419 return {}; 420 } 421 } 422 423 ResStringPool symbol_pool; 424 if (pb_table.has_symbol_pool()) { 425 result = symbol_pool.setTo(pb_table.symbol_pool().data().data(), 426 pb_table.symbol_pool().data().size()); 427 if (result != NO_ERROR) { 428 diag->Error(DiagMessage(source) << "invalid symbol pool"); 429 return {}; 430 } 431 } 432 433 PackagePbDeserializer package_pb_deserializer(&value_pool, &source_pool, 434 &symbol_pool, source, diag); 435 for (const pb::Package& pb_package : pb_table.packages()) { 436 if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) { 437 return {}; 438 } 439 } 440 return table; 441} 442 443std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( 444 const pb::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) { 445 std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); 446 447 ResourceNameRef name_ref; 448 449 // Need to create an lvalue here so that nameRef can point to something real. 450 if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) { 451 diag->Error(DiagMessage(source) 452 << "invalid resource name in compiled file header: " 453 << pb_file.resource_name()); 454 return {}; 455 } 456 file->name = name_ref.ToResourceName(); 457 file->source.path = pb_file.source_path(); 458 DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config); 459 460 for (const pb::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbols()) { 461 // Need to create an lvalue here so that nameRef can point to something 462 // real. 463 if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), 464 &name_ref)) { 465 diag->Error(DiagMessage(source) 466 << "invalid resource name for exported symbol in " 467 "compiled file header: " 468 << pb_file.resource_name()); 469 return {}; 470 } 471 file->exported_symbols.push_back( 472 SourcedResourceName{name_ref.ToResourceName(), pb_symbol.line_no()}); 473 } 474 return file; 475} 476 477} // namespace aapt 478