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