Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 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 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 17 | #include "link/TableMerger.h" |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 18 | |
| 19 | #include "android-base/logging.h" |
| 20 | |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 21 | #include "ResourceTable.h" |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 22 | #include "ResourceUtils.h" |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 23 | #include "ResourceValues.h" |
| 24 | #include "ValueVisitor.h" |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 25 | #include "util/Util.h" |
| 26 | |
Adam Lesinski | d5083f6 | 2017-01-16 15:07:21 -0800 | [diff] [blame] | 27 | using android::StringPiece; |
| 28 | |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 29 | namespace aapt { |
| 30 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 31 | TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 32 | const TableMergerOptions& options) |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 33 | : context_(context), master_table_(out_table), options_(options) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 34 | // Create the desired package that all tables will be merged into. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 35 | master_package_ = master_table_->CreatePackage( |
| 36 | context_->GetCompilationPackage(), context_->GetPackageId()); |
| 37 | CHECK(master_package_ != nullptr) << "package name or ID already taken"; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 38 | } |
| 39 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 40 | bool TableMerger::Merge(const Source& src, ResourceTable* table, |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 41 | io::IFileCollection* collection) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 42 | return MergeImpl(src, table, collection, false /* overlay */, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 43 | true /* allow new */); |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 44 | } |
| 45 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 46 | bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table, |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 47 | io::IFileCollection* collection) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 48 | return MergeImpl(src, table, collection, true /* overlay */, |
| 49 | options_.auto_add_overlay); |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 50 | } |
| 51 | |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 52 | /** |
| 53 | * This will merge packages with the same package name (or no package name). |
| 54 | */ |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 55 | bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 56 | io::IFileCollection* collection, bool overlay, |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 57 | bool allow_new) { |
| 58 | const uint8_t desired_package_id = context_->GetPackageId(); |
Adam Lesinski | 085f495 | 2016-08-30 14:25:51 -0700 | [diff] [blame] | 59 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 60 | bool error = false; |
| 61 | for (auto& package : table->packages) { |
| 62 | // Warn of packages with an unrelated ID. |
| 63 | const Maybe<ResourceId>& id = package->id; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 64 | if (id && id.value() != 0x0 && id.value() != desired_package_id) { |
| 65 | context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 66 | << package->name); |
| 67 | continue; |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 68 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 69 | |
| 70 | // Only merge an empty package or the package we're building. |
| 71 | // Other packages may exist, which likely contain attribute definitions. |
| 72 | // This is because at compile time it is unknown if the attributes are |
| 73 | // simply |
| 74 | // uses of the attribute or definitions. |
| 75 | if (package->name.empty() || |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 76 | context_->GetCompilationPackage() == package->name) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 77 | FileMergeCallback callback; |
| 78 | if (collection) { |
| 79 | callback = [&](const ResourceNameRef& name, |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 80 | const ConfigDescription& config, FileReference* new_file, |
| 81 | FileReference* old_file) -> bool { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 82 | // The old file's path points inside the APK, so we can use it as is. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 83 | io::IFile* f = collection->FindFile(*old_file->path); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 84 | if (!f) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 85 | context_->GetDiagnostics()->Error(DiagMessage(src) |
| 86 | << "file '" << *old_file->path |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 87 | << "' not found"); |
| 88 | return false; |
| 89 | } |
| 90 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 91 | new_file->file = f; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 92 | return true; |
| 93 | }; |
| 94 | } |
| 95 | |
| 96 | // Merge here. Once the entries are merged and mangled, any references to |
| 97 | // them are still valid. This is because un-mangled references are |
| 98 | // mangled, then looked up at resolution time. |
| 99 | // Also, when linking, we convert references with no package name to use |
| 100 | // the compilation package name. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 101 | error |= !DoMerge(src, table, package.get(), false /* mangle */, overlay, |
| 102 | allow_new, callback); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 103 | } |
| 104 | } |
| 105 | return !error; |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | /** |
| 109 | * This will merge and mangle resources from a static library. |
| 110 | */ |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 111 | bool TableMerger::MergeAndMangle(const Source& src, |
| 112 | const StringPiece& package_name, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 113 | ResourceTable* table, |
| 114 | io::IFileCollection* collection) { |
| 115 | bool error = false; |
| 116 | for (auto& package : table->packages) { |
| 117 | // Warn of packages with an unrelated ID. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 118 | if (package_name != package->name) { |
| 119 | context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 120 | << package->name); |
| 121 | continue; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 122 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 123 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 124 | bool mangle = package_name != context_->GetCompilationPackage(); |
| 125 | merged_packages_.insert(package->name); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 126 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 127 | auto callback = [&]( |
| 128 | const ResourceNameRef& name, const ConfigDescription& config, |
| 129 | FileReference* new_file, FileReference* old_file) -> bool { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 130 | // The old file's path points inside the APK, so we can use it as is. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 131 | io::IFile* f = collection->FindFile(*old_file->path); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 132 | if (!f) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 133 | context_->GetDiagnostics()->Error( |
| 134 | DiagMessage(src) << "file '" << *old_file->path << "' not found"); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 135 | return false; |
| 136 | } |
| 137 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 138 | new_file->file = f; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 139 | return true; |
| 140 | }; |
| 141 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 142 | error |= !DoMerge(src, table, package.get(), mangle, false /* overlay */, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 143 | true /* allow new */, callback); |
| 144 | } |
| 145 | return !error; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 146 | } |
| 147 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 148 | static bool MergeType(IAaptContext* context, const Source& src, |
| 149 | ResourceTableType* dst_type, |
| 150 | ResourceTableType* src_type) { |
| 151 | if (dst_type->symbol_status.state < src_type->symbol_status.state) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 152 | // The incoming type's visibility is stronger, so we should override |
| 153 | // the visibility. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 154 | if (src_type->symbol_status.state == SymbolState::kPublic) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 155 | // Only copy the ID if the source is public, or else the ID is |
| 156 | // meaningless. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 157 | dst_type->id = src_type->id; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 158 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 159 | dst_type->symbol_status = std::move(src_type->symbol_status); |
| 160 | } else if (dst_type->symbol_status.state == SymbolState::kPublic && |
| 161 | src_type->symbol_status.state == SymbolState::kPublic && |
| 162 | dst_type->id && src_type->id && |
| 163 | dst_type->id.value() != src_type->id.value()) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 164 | // Both types are public and have different IDs. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 165 | context->GetDiagnostics()->Error(DiagMessage(src) |
| 166 | << "cannot merge type '" << src_type->type |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 167 | << "': conflicting public IDs"); |
| 168 | return false; |
| 169 | } |
| 170 | return true; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 171 | } |
| 172 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 173 | static bool MergeEntry(IAaptContext* context, const Source& src, |
| 174 | ResourceEntry* dst_entry, ResourceEntry* src_entry) { |
| 175 | if (dst_entry->symbol_status.state < src_entry->symbol_status.state) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 176 | // The incoming type's visibility is stronger, so we should override |
| 177 | // the visibility. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 178 | if (src_entry->symbol_status.state == SymbolState::kPublic) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 179 | // Only copy the ID if the source is public, or else the ID is |
| 180 | // meaningless. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 181 | dst_entry->id = src_entry->id; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 182 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 183 | dst_entry->symbol_status = std::move(src_entry->symbol_status); |
| 184 | } else if (src_entry->symbol_status.state == SymbolState::kPublic && |
| 185 | dst_entry->symbol_status.state == SymbolState::kPublic && |
| 186 | dst_entry->id && src_entry->id && |
| 187 | dst_entry->id.value() != src_entry->id.value()) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 188 | // Both entries are public and have different IDs. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 189 | context->GetDiagnostics()->Error( |
| 190 | DiagMessage(src) << "cannot merge entry '" << src_entry->name |
| 191 | << "': conflicting public IDs"); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 192 | return false; |
| 193 | } |
| 194 | return true; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Modified CollisionResolver which will merge Styleables. Used with overlays. |
| 199 | * |
| 200 | * Styleables are not actual resources, but they are treated as such during the |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 201 | * compilation phase. Styleables don't simply overlay each other, their |
| 202 | * definitions merge |
| 203 | * and accumulate. If both values are Styleables, we just merge them into the |
| 204 | * existing value. |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 205 | */ |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 206 | static ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 207 | Value* incoming) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 208 | if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) { |
| 209 | if (Styleable* incoming_styleable = ValueCast<Styleable>(incoming)) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 210 | // Styleables get merged. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 211 | existing_styleable->MergeWith(incoming_styleable); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 212 | return ResourceTable::CollisionResult::kKeepOriginal; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 213 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 214 | } |
| 215 | // Delegate to the default handler. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 216 | return ResourceTable::ResolveValueCollision(existing, incoming); |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 217 | } |
| 218 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 219 | static ResourceTable::CollisionResult MergeConfigValue( |
| 220 | IAaptContext* context, const ResourceNameRef& res_name, const bool overlay, |
| 221 | ResourceConfigValue* dst_config_value, |
| 222 | ResourceConfigValue* src_config_value) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 223 | using CollisionResult = ResourceTable::CollisionResult; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 224 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 225 | Value* dst_value = dst_config_value->value.get(); |
| 226 | Value* src_value = src_config_value->value.get(); |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 227 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 228 | CollisionResult collision_result; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 229 | if (overlay) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 230 | collision_result = ResolveMergeCollision(dst_value, src_value); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 231 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 232 | collision_result = |
| 233 | ResourceTable::ResolveValueCollision(dst_value, src_value); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 234 | } |
| 235 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 236 | if (collision_result == CollisionResult::kConflict) { |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 237 | if (overlay) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 238 | return CollisionResult::kTakeNew; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 239 | } |
| 240 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 241 | // Error! |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 242 | context->GetDiagnostics()->Error( |
| 243 | DiagMessage(src_value->GetSource()) |
| 244 | << "resource '" << res_name << "' has a conflicting value for " |
| 245 | << "configuration (" << src_config_value->config << ")"); |
| 246 | context->GetDiagnostics()->Note(DiagMessage(dst_value->GetSource()) |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 247 | << "originally defined here"); |
| 248 | return CollisionResult::kConflict; |
| 249 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 250 | return collision_result; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 251 | } |
| 252 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 253 | bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table, |
| 254 | ResourceTablePackage* src_package, |
| 255 | const bool mangle_package, const bool overlay, |
| 256 | const bool allow_new_resources, |
Chih-Hung Hsieh | 9b8528f | 2016-08-10 14:15:30 -0700 | [diff] [blame] | 257 | const FileMergeCallback& callback) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 258 | bool error = false; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 259 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 260 | for (auto& src_type : src_package->types) { |
| 261 | ResourceTableType* dst_type = |
| 262 | master_package_->FindOrCreateType(src_type->type); |
| 263 | if (!MergeType(context_, src, dst_type, src_type.get())) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 264 | error = true; |
| 265 | continue; |
| 266 | } |
| 267 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 268 | for (auto& src_entry : src_type->entries) { |
| 269 | std::string entry_name = src_entry->name; |
| 270 | if (mangle_package) { |
| 271 | entry_name = |
| 272 | NameMangler::MangleEntry(src_package->name, src_entry->name); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 273 | } |
| 274 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 275 | ResourceEntry* dst_entry; |
| 276 | if (allow_new_resources) { |
| 277 | dst_entry = dst_type->FindOrCreateEntry(entry_name); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 278 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 279 | dst_entry = dst_type->FindEntry(entry_name); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 280 | } |
| 281 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 282 | const ResourceNameRef res_name(src_package->name, src_type->type, |
| 283 | src_entry->name); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 284 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 285 | if (!dst_entry) { |
| 286 | context_->GetDiagnostics()->Error( |
| 287 | DiagMessage(src) << "resource " << res_name |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 288 | << " does not override an existing resource"); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 289 | context_->GetDiagnostics()->Note( |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 290 | DiagMessage(src) << "define an <add-resource> tag or use " |
| 291 | << "--auto-add-overlay"); |
| 292 | error = true; |
| 293 | continue; |
| 294 | } |
| 295 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 296 | if (!MergeEntry(context_, src, dst_entry, src_entry.get())) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 297 | error = true; |
| 298 | continue; |
| 299 | } |
| 300 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 301 | for (auto& src_config_value : src_entry->values) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 302 | using CollisionResult = ResourceTable::CollisionResult; |
| 303 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 304 | ResourceConfigValue* dst_config_value = dst_entry->FindValue( |
| 305 | src_config_value->config, src_config_value->product); |
| 306 | if (dst_config_value) { |
| 307 | CollisionResult collision_result = |
| 308 | MergeConfigValue(context_, res_name, overlay, dst_config_value, |
| 309 | src_config_value.get()); |
| 310 | if (collision_result == CollisionResult::kConflict) { |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 311 | error = true; |
| 312 | continue; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 313 | } else if (collision_result == CollisionResult::kKeepOriginal) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 314 | continue; |
| 315 | } |
| 316 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 317 | dst_config_value = dst_entry->FindOrCreateValue( |
| 318 | src_config_value->config, src_config_value->product); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 319 | } |
| 320 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 321 | // Continue if we're taking the new resource. |
| 322 | |
| 323 | if (FileReference* f = |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 324 | ValueCast<FileReference>(src_config_value->value.get())) { |
| 325 | std::unique_ptr<FileReference> new_file_ref; |
| 326 | if (mangle_package) { |
| 327 | new_file_ref = CloneAndMangleFile(src_package->name, *f); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 328 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 329 | new_file_ref = std::unique_ptr<FileReference>( |
| 330 | f->Clone(&master_table_->string_pool)); |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 331 | } |
| 332 | |
| 333 | if (callback) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 334 | if (!callback(res_name, src_config_value->config, |
| 335 | new_file_ref.get(), f)) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 336 | error = true; |
| 337 | continue; |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 338 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 339 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 340 | dst_config_value->value = std::move(new_file_ref); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 341 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 342 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 343 | dst_config_value->value = std::unique_ptr<Value>( |
| 344 | src_config_value->value->Clone(&master_table_->string_pool)); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 345 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 346 | } |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 347 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 348 | } |
| 349 | return !error; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 350 | } |
| 351 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 352 | std::unique_ptr<FileReference> TableMerger::CloneAndMangleFile( |
| 353 | const std::string& package, const FileReference& file_ref) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 354 | StringPiece prefix, entry, suffix; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 355 | if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) { |
Adam Lesinski | d5083f6 | 2017-01-16 15:07:21 -0800 | [diff] [blame] | 356 | std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string()); |
| 357 | std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 358 | std::unique_ptr<FileReference> new_file_ref = |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 359 | util::make_unique<FileReference>( |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 360 | master_table_->string_pool.MakeRef(newPath)); |
| 361 | new_file_ref->SetComment(file_ref.GetComment()); |
| 362 | new_file_ref->SetSource(file_ref.GetSource()); |
| 363 | return new_file_ref; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 364 | } |
| 365 | return std::unique_ptr<FileReference>( |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 366 | file_ref.Clone(&master_table_->string_pool)); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 367 | } |
| 368 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 369 | bool TableMerger::MergeFileImpl(const ResourceFile& file_desc, io::IFile* file, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 370 | bool overlay) { |
| 371 | ResourceTable table; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 372 | std::string path = ResourceUtils::BuildResourceFileName(file_desc); |
| 373 | std::unique_ptr<FileReference> file_ref = |
| 374 | util::make_unique<FileReference>(table.string_pool.MakeRef(path)); |
| 375 | file_ref->SetSource(file_desc.source); |
| 376 | file_ref->file = file; |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 377 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 378 | ResourceTablePackage* pkg = table.CreatePackage(file_desc.name.package, 0x0); |
| 379 | pkg->FindOrCreateType(file_desc.name.type) |
| 380 | ->FindOrCreateEntry(file_desc.name.entry) |
| 381 | ->FindOrCreateValue(file_desc.config, {}) |
| 382 | ->value = std::move(file_ref); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 383 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 384 | return DoMerge(file->GetSource(), &table, pkg, false /* mangle */, |
| 385 | overlay /* overlay */, true /* allow_new */, {}); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 386 | } |
| 387 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 388 | bool TableMerger::MergeFile(const ResourceFile& file_desc, io::IFile* file) { |
| 389 | return MergeFileImpl(file_desc, file, false /* overlay */); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 390 | } |
| 391 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 392 | bool TableMerger::MergeFileOverlay(const ResourceFile& file_desc, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 393 | io::IFile* file) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 394 | return MergeFileImpl(file_desc, file, true /* overlay */); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 395 | } |
| 396 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 397 | } // namespace aapt |