11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/* 21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License. 61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at 71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software 111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and 141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License. 151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 17cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include "link/TableMerger.h" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/logging.h" 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceTable.h" 22a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include "ResourceUtils.h" 231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceValues.h" 241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ValueVisitor.h" 251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 27d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinskiusing android::StringPiece; 28d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt { 301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 31ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiTableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table, 32cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const TableMergerOptions& options) 33ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski : context_(context), master_table_(out_table), options_(options) { 34cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Create the desired package that all tables will be merged into. 35ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski master_package_ = master_table_->CreatePackage( 36ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context_->GetCompilationPackage(), context_->GetPackageId()); 37ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CHECK(master_package_ != nullptr) << "package name or ID already taken"; 381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 40ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::Merge(const Source& src, ResourceTable* table, 4164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski io::IFileCollection* collection) { 42b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski return MergeImpl(src, table, collection, false /* overlay */, true /* allow new */); 4364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski} 4464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski 45ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::MergeOverlay(const Source& src, ResourceTable* table, 4664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski io::IFileCollection* collection) { 47b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski return MergeImpl(src, table, collection, true /* overlay */, options_.auto_add_overlay); 4864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski} 4964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski 5083f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski/** 5183f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski * This will merge packages with the same package name (or no package name). 5283f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski */ 53ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::MergeImpl(const Source& src, ResourceTable* table, 54cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski io::IFileCollection* collection, bool overlay, 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool allow_new) { 56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool error = false; 57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& package : table->packages) { 58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Only merge an empty package or the package we're building. 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Other packages may exist, which likely contain attribute definitions. 60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // This is because at compile time it is unknown if the attributes are 61b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski // simply uses of the attribute or definitions. 62b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski if (package->name.empty() || context_->GetCompilationPackage() == package->name) { 63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski FileMergeCallback callback; 64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (collection) { 65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski callback = [&](const ResourceNameRef& name, 66ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ConfigDescription& config, FileReference* new_file, 67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski FileReference* old_file) -> bool { 68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The old file's path points inside the APK, so we can use it as is. 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski io::IFile* f = collection->FindFile(*old_file->path); 70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!f) { 71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context_->GetDiagnostics()->Error(DiagMessage(src) 72b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski << "file '" << *old_file->path << "' not found"); 73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_file->file = f; 77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski }; 79cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Merge here. Once the entries are merged and mangled, any references to 82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // them are still valid. This is because un-mangled references are 83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // mangled, then looked up at resolution time. 84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Also, when linking, we convert references with no package name to use 85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // the compilation package name. 86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski error |= !DoMerge(src, table, package.get(), false /* mangle */, overlay, 87ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski allow_new, callback); 8883f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski } 89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return !error; 9183f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski} 9283f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski 9383f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski/** 9483f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski * This will merge and mangle resources from a static library. 9583f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski */ 96ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::MergeAndMangle(const Source& src, 97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const StringPiece& package_name, 98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable* table, 99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski io::IFileCollection* collection) { 100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool error = false; 101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& package : table->packages) { 102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Warn of packages with an unrelated ID. 103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (package_name != package->name) { 104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " 105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski << package->name); 106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool mangle = package_name != context_->GetCompilationPackage(); 110ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski merged_packages_.insert(package->name); 111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 112ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski auto callback = [&]( 113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceNameRef& name, const ConfigDescription& config, 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski FileReference* new_file, FileReference* old_file) -> bool { 115cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The old file's path points inside the APK, so we can use it as is. 116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski io::IFile* f = collection->FindFile(*old_file->path); 117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!f) { 118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context_->GetDiagnostics()->Error( 119ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski DiagMessage(src) << "file '" << *old_file->path << "' not found"); 120cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 122a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 123ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_file->file = f; 124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski }; 126a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski error |= !DoMerge(src, table, package.get(), mangle, false /* overlay */, 128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski true /* allow new */, callback); 129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return !error; 1311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 133ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool MergeType(IAaptContext* context, const Source& src, 134ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTableType* dst_type, 135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTableType* src_type) { 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (dst_type->symbol_status.state < src_type->symbol_status.state) { 137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The incoming type's visibility is stronger, so we should override 138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // the visibility. 139ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (src_type->symbol_status.state == SymbolState::kPublic) { 140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Only copy the ID if the source is public, or else the ID is 141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // meaningless. 142ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_type->id = src_type->id; 1435c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski } 144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_type->symbol_status = std::move(src_type->symbol_status); 145ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (dst_type->symbol_status.state == SymbolState::kPublic && 146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski src_type->symbol_status.state == SymbolState::kPublic && 147ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_type->id && src_type->id && 148ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_type->id.value() != src_type->id.value()) { 149cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Both types are public and have different IDs. 150ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(src) 151ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "cannot merge type '" << src_type->type 152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski << "': conflicting public IDs"); 153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 155cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 1565c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski} 1575c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 158ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool MergeEntry(IAaptContext* context, const Source& src, 159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* dst_entry, ResourceEntry* src_entry) { 160ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (dst_entry->symbol_status.state < src_entry->symbol_status.state) { 161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The incoming type's visibility is stronger, so we should override 162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // the visibility. 163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (src_entry->symbol_status.state == SymbolState::kPublic) { 164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Only copy the ID if the source is public, or else the ID is 165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // meaningless. 166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry->id = src_entry->id; 1675c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski } 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry->symbol_status = std::move(src_entry->symbol_status); 169ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (src_entry->symbol_status.state == SymbolState::kPublic && 170ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry->symbol_status.state == SymbolState::kPublic && 171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry->id && src_entry->id && 172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry->id.value() != src_entry->id.value()) { 173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Both entries are public and have different IDs. 174ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error( 175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski DiagMessage(src) << "cannot merge entry '" << src_entry->name 176ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "': conflicting public IDs"); 177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 179cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 1805c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski} 1815c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 1825924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// Modified CollisionResolver which will merge Styleables and Styles. Used with overlays. 1835924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// 1845924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// Styleables are not actual resources, but they are treated as such during the 1855924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// compilation phase. 1865924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// 1875924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// Styleables and Styles don't simply overlay each other, their definitions merge 1885924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// and accumulate. If both values are Styleables/Styles, we just merge them into the 1895924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski// existing value. 1905924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinskistatic ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, Value* incoming, 1915924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski StringPool* pool) { 192ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) { 193ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (Styleable* incoming_styleable = ValueCast<Styleable>(incoming)) { 194cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Styleables get merged. 195ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski existing_styleable->MergeWith(incoming_styleable); 196cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return ResourceTable::CollisionResult::kKeepOriginal; 1975c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski } 1985924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski } else if (Style* existing_style = ValueCast<Style>(existing)) { 1995924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski if (Style* incoming_style = ValueCast<Style>(incoming)) { 2005924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski // Styles get merged. 2015924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski existing_style->MergeWith(incoming_style, pool); 2025924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski return ResourceTable::CollisionResult::kKeepOriginal; 2035924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski } 204cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Delegate to the default handler. 206ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return ResourceTable::ResolveValueCollision(existing, incoming); 2075c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski} 2085c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 2095924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinskistatic ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context, 2105924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski const ResourceNameRef& res_name, 2115924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski const bool overlay, 2125924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski ResourceConfigValue* dst_config_value, 2135924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski ResourceConfigValue* src_config_value, 2145924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski StringPool* pool) { 215cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski using CollisionResult = ResourceTable::CollisionResult; 2165c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 217ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Value* dst_value = dst_config_value->value.get(); 218ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Value* src_value = src_config_value->value.get(); 2195c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 220ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CollisionResult collision_result; 221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (overlay) { 2225924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski collision_result = ResolveMergeCollision(dst_value, src_value, pool); 223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 2245924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value); 225cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (collision_result == CollisionResult::kConflict) { 2285c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski if (overlay) { 229cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return CollisionResult::kTakeNew; 2305c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski } 2315c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Error! 2335924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(src_value->GetSource()) 2345924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski << "resource '" << res_name << "' has a conflicting value for " 2355924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski << "configuration (" << src_config_value->config << ")"); 236ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(dst_value->GetSource()) 237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski << "originally defined here"); 238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return CollisionResult::kConflict; 239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 240ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return collision_result; 2415c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski} 2425c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 243ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::DoMerge(const Source& src, ResourceTable* src_table, 244ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTablePackage* src_package, 245ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const bool mangle_package, const bool overlay, 246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const bool allow_new_resources, 2479b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh const FileMergeCallback& callback) { 248cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool error = false; 249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 250ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (auto& src_type : src_package->types) { 2514488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski ResourceTableType* dst_type = master_package_->FindOrCreateType(src_type->type); 252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!MergeType(context_, src, dst_type, src_type.get())) { 253cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 254cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 255cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 2561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (auto& src_entry : src_type->entries) { 258ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string entry_name = src_entry->name; 259ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (mangle_package) { 2604488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski entry_name = NameMangler::MangleEntry(src_package->name, src_entry->name); 261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 263ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceEntry* dst_entry; 2644488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski if (allow_new_resources || src_entry->symbol_status.allow_new) { 265ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry = dst_type->FindOrCreateEntry(entry_name); 266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_entry = dst_type->FindEntry(entry_name); 268cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 269cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 2704488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski const ResourceNameRef res_name(src_package->name, src_type->type, src_entry->name); 271cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 272ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!dst_entry) { 2734488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski context_->GetDiagnostics()->Error(DiagMessage(src) 2744488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski << "resource " << res_name 2754488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski << " does not override an existing resource"); 2764488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski context_->GetDiagnostics()->Note(DiagMessage(src) << "define an <add-resource> tag or use " 2774488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski << "--auto-add-overlay"); 278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 281cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 282ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!MergeEntry(context_, src, dst_entry, src_entry.get())) { 283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 286cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 287ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (auto& src_config_value : src_entry->values) { 288cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski using CollisionResult = ResourceTable::CollisionResult; 289cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceConfigValue* dst_config_value = dst_entry->FindValue( 291ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski src_config_value->config, src_config_value->product); 292ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (dst_config_value) { 293ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CollisionResult collision_result = 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski MergeConfigValue(context_, res_name, overlay, dst_config_value, 2955924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski src_config_value.get(), &master_table_->string_pool); 296ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (collision_result == CollisionResult::kConflict) { 2975c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski error = true; 2985c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski continue; 299ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (collision_result == CollisionResult::kKeepOriginal) { 300cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 3035924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski dst_config_value = 3045924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski dst_entry->FindOrCreateValue(src_config_value->config, src_config_value->product); 3051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 307cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Continue if we're taking the new resource. 308cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 3095924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski if (FileReference* f = ValueCast<FileReference>(src_config_value->value.get())) { 310ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<FileReference> new_file_ref; 311ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (mangle_package) { 312ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_file_ref = CloneAndMangleFile(src_package->name, *f); 313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 3145924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski new_file_ref = std::unique_ptr<FileReference>(f->Clone(&master_table_->string_pool)); 315cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 317cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (callback) { 3185924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski if (!callback(res_name, src_config_value->config, new_file_ref.get(), f)) { 319cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 320cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 3215c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski } 322cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 323ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_config_value->value = std::move(new_file_ref); 3245c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski 325cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dst_config_value->value = std::unique_ptr<Value>( 327ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski src_config_value->value->Clone(&master_table_->string_pool)); 3281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 329cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 3301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 331cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 332cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return !error; 3331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<FileReference> TableMerger::CloneAndMangleFile( 336ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string& package, const FileReference& file_ref) { 337cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece prefix, entry, suffix; 338ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) { 339d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string()); 340d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string(); 341ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<FileReference> new_file_ref = 3425924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski util::make_unique<FileReference>(master_table_->string_pool.MakeRef(newPath)); 343ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_file_ref->SetComment(file_ref.GetComment()); 344ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_file_ref->SetSource(file_ref.GetSource()); 345ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return new_file_ref; 346cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 3475924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski return std::unique_ptr<FileReference>(file_ref.Clone(&master_table_->string_pool)); 348a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 349a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 3505924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinskibool TableMerger::MergeFileImpl(const ResourceFile& file_desc, io::IFile* file, bool overlay) { 351cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable table; 352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string path = ResourceUtils::BuildResourceFileName(file_desc); 353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<FileReference> file_ref = 354ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::make_unique<FileReference>(table.string_pool.MakeRef(path)); 355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski file_ref->SetSource(file_desc.source); 356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski file_ref->file = file; 357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 358ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTablePackage* pkg = table.CreatePackage(file_desc.name.package, 0x0); 359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski pkg->FindOrCreateType(file_desc.name.type) 360ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ->FindOrCreateEntry(file_desc.name.entry) 361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ->FindOrCreateValue(file_desc.config, {}) 362ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ->value = std::move(file_ref); 363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 364ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return DoMerge(file->GetSource(), &table, pkg, false /* mangle */, 365ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski overlay /* overlay */, true /* allow_new */, {}); 366a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 367a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 368ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::MergeFile(const ResourceFile& file_desc, io::IFile* file) { 369ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return MergeFileImpl(file_desc, file, false /* overlay */); 3701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 372ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableMerger::MergeFileOverlay(const ResourceFile& file_desc, 373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski io::IFile* file) { 374ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return MergeFileImpl(file_desc, file, true /* overlay */); 3751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 377cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 378