xref: /aosp_15_r20/frameworks/base/tools/aapt2/link/TableMerger.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "link/TableMerger.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include "android-base/logging.h"
20*d57664e9SAndroid Build Coastguard Worker 
21*d57664e9SAndroid Build Coastguard Worker #include "ResourceTable.h"
22*d57664e9SAndroid Build Coastguard Worker #include "ResourceUtils.h"
23*d57664e9SAndroid Build Coastguard Worker #include "ResourceValues.h"
24*d57664e9SAndroid Build Coastguard Worker #include "trace/TraceBuffer.h"
25*d57664e9SAndroid Build Coastguard Worker #include "ValueVisitor.h"
26*d57664e9SAndroid Build Coastguard Worker #include "util/Util.h"
27*d57664e9SAndroid Build Coastguard Worker 
28*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece;
29*d57664e9SAndroid Build Coastguard Worker 
30*d57664e9SAndroid Build Coastguard Worker namespace aapt {
31*d57664e9SAndroid Build Coastguard Worker 
TableMerger(IAaptContext * context,ResourceTable * out_table,const TableMergerOptions & options)32*d57664e9SAndroid Build Coastguard Worker TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
33*d57664e9SAndroid Build Coastguard Worker                          const TableMergerOptions& options)
34*d57664e9SAndroid Build Coastguard Worker     : context_(context), main_table_(out_table), options_(options) {
35*d57664e9SAndroid Build Coastguard Worker   // Create the desired package that all tables will be merged into.
36*d57664e9SAndroid Build Coastguard Worker   main_package_ = main_table_->FindOrCreatePackage(context_->GetCompilationPackage());
37*d57664e9SAndroid Build Coastguard Worker   CHECK(main_package_ != nullptr) << "package name or ID already taken";
38*d57664e9SAndroid Build Coastguard Worker }
39*d57664e9SAndroid Build Coastguard Worker 
Merge(const android::Source & src,ResourceTable * table,bool overlay)40*d57664e9SAndroid Build Coastguard Worker bool TableMerger::Merge(const android::Source& src, ResourceTable* table, bool overlay) {
41*d57664e9SAndroid Build Coastguard Worker   TRACE_CALL();
42*d57664e9SAndroid Build Coastguard Worker   // We allow adding new resources if this is not an overlay, or if the options allow overlays
43*d57664e9SAndroid Build Coastguard Worker   // to add new resources.
44*d57664e9SAndroid Build Coastguard Worker   return MergeImpl(src, table, overlay, options_.auto_add_overlay || !overlay /*allow_new*/);
45*d57664e9SAndroid Build Coastguard Worker }
46*d57664e9SAndroid Build Coastguard Worker 
47*d57664e9SAndroid Build Coastguard Worker // This will merge packages with the same package name (or no package name).
MergeImpl(const android::Source & src,ResourceTable * table,bool overlay,bool allow_new)48*d57664e9SAndroid Build Coastguard Worker bool TableMerger::MergeImpl(const android::Source& src, ResourceTable* table, bool overlay,
49*d57664e9SAndroid Build Coastguard Worker                             bool allow_new) {
50*d57664e9SAndroid Build Coastguard Worker   bool error = false;
51*d57664e9SAndroid Build Coastguard Worker   for (auto& package : table->packages) {
52*d57664e9SAndroid Build Coastguard Worker     // Only merge an empty package or the package we're building.
53*d57664e9SAndroid Build Coastguard Worker     // Other packages may exist, which likely contain attribute definitions.
54*d57664e9SAndroid Build Coastguard Worker     // This is because at compile time it is unknown if the attributes are
55*d57664e9SAndroid Build Coastguard Worker     // simply uses of the attribute or definitions.
56*d57664e9SAndroid Build Coastguard Worker     if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
57*d57664e9SAndroid Build Coastguard Worker       // Merge here. Once the entries are merged and mangled, any references to them are still
58*d57664e9SAndroid Build Coastguard Worker       // valid. This is because un-mangled references are mangled, then looked up at resolution
59*d57664e9SAndroid Build Coastguard Worker       // time. Also, when linking, we convert references with no package name to use the compilation
60*d57664e9SAndroid Build Coastguard Worker       // package name.
61*d57664e9SAndroid Build Coastguard Worker       error |= !DoMerge(src, package.get(), false /*mangle*/, overlay, allow_new);
62*d57664e9SAndroid Build Coastguard Worker     }
63*d57664e9SAndroid Build Coastguard Worker   }
64*d57664e9SAndroid Build Coastguard Worker   return !error;
65*d57664e9SAndroid Build Coastguard Worker }
66*d57664e9SAndroid Build Coastguard Worker 
67*d57664e9SAndroid Build Coastguard Worker // This will merge and mangle resources from a static library. It is assumed that all FileReferences
68*d57664e9SAndroid Build Coastguard Worker // have correctly set their io::IFile*.
MergeAndMangle(const android::Source & src,StringPiece package_name,ResourceTable * table)69*d57664e9SAndroid Build Coastguard Worker bool TableMerger::MergeAndMangle(const android::Source& src, StringPiece package_name,
70*d57664e9SAndroid Build Coastguard Worker                                  ResourceTable* table) {
71*d57664e9SAndroid Build Coastguard Worker   bool error = false;
72*d57664e9SAndroid Build Coastguard Worker   for (auto& package : table->packages) {
73*d57664e9SAndroid Build Coastguard Worker     // Warn of packages with an unrelated ID.
74*d57664e9SAndroid Build Coastguard Worker     if (package_name != package->name) {
75*d57664e9SAndroid Build Coastguard Worker       context_->GetDiagnostics()->Warn(android::DiagMessage(src)
76*d57664e9SAndroid Build Coastguard Worker                                        << "ignoring package " << package->name);
77*d57664e9SAndroid Build Coastguard Worker       continue;
78*d57664e9SAndroid Build Coastguard Worker     }
79*d57664e9SAndroid Build Coastguard Worker 
80*d57664e9SAndroid Build Coastguard Worker     bool mangle = package_name != context_->GetCompilationPackage();
81*d57664e9SAndroid Build Coastguard Worker     merged_packages_.insert(package->name);
82*d57664e9SAndroid Build Coastguard Worker     error |= !DoMerge(src, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
83*d57664e9SAndroid Build Coastguard Worker   }
84*d57664e9SAndroid Build Coastguard Worker   return !error;
85*d57664e9SAndroid Build Coastguard Worker }
86*d57664e9SAndroid Build Coastguard Worker 
MergeType(IAaptContext * context,const android::Source & src,ResourceTableType * dst_type,ResourceTableType * src_type)87*d57664e9SAndroid Build Coastguard Worker static bool MergeType(IAaptContext* context, const android::Source& src,
88*d57664e9SAndroid Build Coastguard Worker                       ResourceTableType* dst_type, ResourceTableType* src_type) {
89*d57664e9SAndroid Build Coastguard Worker   if (src_type->visibility_level >= dst_type->visibility_level) {
90*d57664e9SAndroid Build Coastguard Worker     // The incoming type's visibility is stronger, so we should override the visibility.
91*d57664e9SAndroid Build Coastguard Worker     dst_type->visibility_level = src_type->visibility_level;
92*d57664e9SAndroid Build Coastguard Worker   }
93*d57664e9SAndroid Build Coastguard Worker   return true;
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker 
MergeEntry(IAaptContext * context,const android::Source & src,ResourceEntry * dst_entry,ResourceEntry * src_entry,bool strict_visibility)96*d57664e9SAndroid Build Coastguard Worker static bool MergeEntry(IAaptContext* context, const android::Source& src, ResourceEntry* dst_entry,
97*d57664e9SAndroid Build Coastguard Worker                        ResourceEntry* src_entry, bool strict_visibility) {
98*d57664e9SAndroid Build Coastguard Worker   if (strict_visibility
99*d57664e9SAndroid Build Coastguard Worker       && dst_entry->visibility.level != Visibility::Level::kUndefined
100*d57664e9SAndroid Build Coastguard Worker       && src_entry->visibility.level != dst_entry->visibility.level) {
101*d57664e9SAndroid Build Coastguard Worker     context->GetDiagnostics()->Error(android::DiagMessage(src)
102*d57664e9SAndroid Build Coastguard Worker                                      << "cannot merge resource '" << dst_entry->name
103*d57664e9SAndroid Build Coastguard Worker                                      << "' with conflicting visibilities: "
104*d57664e9SAndroid Build Coastguard Worker                                      << "public and private");
105*d57664e9SAndroid Build Coastguard Worker     return false;
106*d57664e9SAndroid Build Coastguard Worker   }
107*d57664e9SAndroid Build Coastguard Worker 
108*d57664e9SAndroid Build Coastguard Worker   // Copy over the strongest visibility.
109*d57664e9SAndroid Build Coastguard Worker   if (src_entry->visibility.level > dst_entry->visibility.level) {
110*d57664e9SAndroid Build Coastguard Worker     // Only copy the ID if the source is public, or else the ID is meaningless.
111*d57664e9SAndroid Build Coastguard Worker     if (src_entry->visibility.level == Visibility::Level::kPublic) {
112*d57664e9SAndroid Build Coastguard Worker       dst_entry->id = src_entry->id;
113*d57664e9SAndroid Build Coastguard Worker     }
114*d57664e9SAndroid Build Coastguard Worker     dst_entry->visibility = std::move(src_entry->visibility);
115*d57664e9SAndroid Build Coastguard Worker   } else if (src_entry->visibility.level == Visibility::Level::kPublic &&
116*d57664e9SAndroid Build Coastguard Worker              dst_entry->visibility.level == Visibility::Level::kPublic && dst_entry->id &&
117*d57664e9SAndroid Build Coastguard Worker              src_entry->id && src_entry->id != dst_entry->id) {
118*d57664e9SAndroid Build Coastguard Worker     // Both entries are public and have different IDs.
119*d57664e9SAndroid Build Coastguard Worker     context->GetDiagnostics()->Error(android::DiagMessage(src)
120*d57664e9SAndroid Build Coastguard Worker                                      << "cannot merge entry '" << src_entry->name
121*d57664e9SAndroid Build Coastguard Worker                                      << "': conflicting public IDs");
122*d57664e9SAndroid Build Coastguard Worker     return false;
123*d57664e9SAndroid Build Coastguard Worker   }
124*d57664e9SAndroid Build Coastguard Worker 
125*d57664e9SAndroid Build Coastguard Worker   // Copy over the rest of the properties, if needed.
126*d57664e9SAndroid Build Coastguard Worker   if (src_entry->allow_new) {
127*d57664e9SAndroid Build Coastguard Worker     dst_entry->allow_new = std::move(src_entry->allow_new);
128*d57664e9SAndroid Build Coastguard Worker   }
129*d57664e9SAndroid Build Coastguard Worker 
130*d57664e9SAndroid Build Coastguard Worker   if (src_entry->overlayable_item) {
131*d57664e9SAndroid Build Coastguard Worker     if (dst_entry->overlayable_item) {
132*d57664e9SAndroid Build Coastguard Worker       CHECK(src_entry->overlayable_item.value().overlayable != nullptr);
133*d57664e9SAndroid Build Coastguard Worker       Overlayable* src_overlayable = src_entry->overlayable_item.value().overlayable.get();
134*d57664e9SAndroid Build Coastguard Worker 
135*d57664e9SAndroid Build Coastguard Worker       CHECK(dst_entry->overlayable_item.value().overlayable != nullptr);
136*d57664e9SAndroid Build Coastguard Worker       Overlayable* dst_overlayable = dst_entry->overlayable_item.value().overlayable.get();
137*d57664e9SAndroid Build Coastguard Worker 
138*d57664e9SAndroid Build Coastguard Worker       if (src_overlayable->name != dst_overlayable->name
139*d57664e9SAndroid Build Coastguard Worker           || src_overlayable->actor != dst_overlayable->actor
140*d57664e9SAndroid Build Coastguard Worker           || src_entry->overlayable_item.value().policies !=
141*d57664e9SAndroid Build Coastguard Worker              dst_entry->overlayable_item.value().policies) {
142*d57664e9SAndroid Build Coastguard Worker 
143*d57664e9SAndroid Build Coastguard Worker         // Do not allow a resource with an overlayable declaration to have that overlayable
144*d57664e9SAndroid Build Coastguard Worker         // declaration redefined.
145*d57664e9SAndroid Build Coastguard Worker         context->GetDiagnostics()->Error(
146*d57664e9SAndroid Build Coastguard Worker             android::DiagMessage(src_entry->overlayable_item.value().source)
147*d57664e9SAndroid Build Coastguard Worker             << "duplicate overlayable declaration for resource '" << src_entry->name << "'");
148*d57664e9SAndroid Build Coastguard Worker         context->GetDiagnostics()->Error(
149*d57664e9SAndroid Build Coastguard Worker             android::DiagMessage(dst_entry->overlayable_item.value().source)
150*d57664e9SAndroid Build Coastguard Worker             << "previous declaration here");
151*d57664e9SAndroid Build Coastguard Worker         return false;
152*d57664e9SAndroid Build Coastguard Worker       }
153*d57664e9SAndroid Build Coastguard Worker     }
154*d57664e9SAndroid Build Coastguard Worker 
155*d57664e9SAndroid Build Coastguard Worker     dst_entry->overlayable_item = std::move(src_entry->overlayable_item);
156*d57664e9SAndroid Build Coastguard Worker   }
157*d57664e9SAndroid Build Coastguard Worker 
158*d57664e9SAndroid Build Coastguard Worker   if (src_entry->staged_id) {
159*d57664e9SAndroid Build Coastguard Worker     if (dst_entry->staged_id &&
160*d57664e9SAndroid Build Coastguard Worker         dst_entry->staged_id.value().id != src_entry->staged_id.value().id) {
161*d57664e9SAndroid Build Coastguard Worker       context->GetDiagnostics()->Error(android::DiagMessage(src_entry->staged_id.value().source)
162*d57664e9SAndroid Build Coastguard Worker                                        << "conflicting staged id declaration for resource '"
163*d57664e9SAndroid Build Coastguard Worker                                        << src_entry->name << "'");
164*d57664e9SAndroid Build Coastguard Worker       context->GetDiagnostics()->Error(android::DiagMessage(dst_entry->staged_id.value().source)
165*d57664e9SAndroid Build Coastguard Worker                                        << "previous declaration here");
166*d57664e9SAndroid Build Coastguard Worker     }
167*d57664e9SAndroid Build Coastguard Worker     dst_entry->staged_id = std::move(src_entry->staged_id);
168*d57664e9SAndroid Build Coastguard Worker   }
169*d57664e9SAndroid Build Coastguard Worker 
170*d57664e9SAndroid Build Coastguard Worker   return true;
171*d57664e9SAndroid Build Coastguard Worker }
172*d57664e9SAndroid Build Coastguard Worker 
173*d57664e9SAndroid Build Coastguard Worker // Modified CollisionResolver which will merge Styleables and Styles. Used with overlays.
174*d57664e9SAndroid Build Coastguard Worker //
175*d57664e9SAndroid Build Coastguard Worker // Styleables are not actual resources, but they are treated as such during the compilation phase.
176*d57664e9SAndroid Build Coastguard Worker //
177*d57664e9SAndroid Build Coastguard Worker // Styleables and Styles don't simply overlay each other, their definitions merge and accumulate.
178*d57664e9SAndroid Build Coastguard Worker // If both values are Styleables/Styles, we just merge them into the existing value.
ResolveMergeCollision(bool override_styles_instead_of_overlaying,Value * existing,Value * incoming,android::StringPool * pool)179*d57664e9SAndroid Build Coastguard Worker static ResourceTable::CollisionResult ResolveMergeCollision(
180*d57664e9SAndroid Build Coastguard Worker     bool override_styles_instead_of_overlaying, Value* existing, Value* incoming,
181*d57664e9SAndroid Build Coastguard Worker     android::StringPool* pool) {
182*d57664e9SAndroid Build Coastguard Worker   if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) {
183*d57664e9SAndroid Build Coastguard Worker     if (Styleable* incoming_styleable = ValueCast<Styleable>(incoming)) {
184*d57664e9SAndroid Build Coastguard Worker       // Styleables get merged.
185*d57664e9SAndroid Build Coastguard Worker       existing_styleable->MergeWith(incoming_styleable);
186*d57664e9SAndroid Build Coastguard Worker       return ResourceTable::CollisionResult::kKeepOriginal;
187*d57664e9SAndroid Build Coastguard Worker     }
188*d57664e9SAndroid Build Coastguard Worker   } else if (!override_styles_instead_of_overlaying) {
189*d57664e9SAndroid Build Coastguard Worker     if (Style* existing_style = ValueCast<Style>(existing)) {
190*d57664e9SAndroid Build Coastguard Worker       if (Style* incoming_style = ValueCast<Style>(incoming)) {
191*d57664e9SAndroid Build Coastguard Worker         // Styles get merged.
192*d57664e9SAndroid Build Coastguard Worker         existing_style->MergeWith(incoming_style, pool);
193*d57664e9SAndroid Build Coastguard Worker         return ResourceTable::CollisionResult::kKeepOriginal;
194*d57664e9SAndroid Build Coastguard Worker       }
195*d57664e9SAndroid Build Coastguard Worker     }
196*d57664e9SAndroid Build Coastguard Worker   }
197*d57664e9SAndroid Build Coastguard Worker   // Delegate to the default handler.
198*d57664e9SAndroid Build Coastguard Worker   return ResourceTable::ResolveValueCollision(existing, incoming);
199*d57664e9SAndroid Build Coastguard Worker }
200*d57664e9SAndroid Build Coastguard Worker 
MergeConfigValue(IAaptContext * context,const ResourceNameRef & res_name,bool overlay,bool override_styles_instead_of_overlaying,ResourceConfigValue * dst_config_value,ResourceConfigValue * src_config_value,android::StringPool * pool)201*d57664e9SAndroid Build Coastguard Worker static ResourceTable::CollisionResult MergeConfigValue(
202*d57664e9SAndroid Build Coastguard Worker     IAaptContext* context, const ResourceNameRef& res_name, bool overlay,
203*d57664e9SAndroid Build Coastguard Worker     bool override_styles_instead_of_overlaying, ResourceConfigValue* dst_config_value,
204*d57664e9SAndroid Build Coastguard Worker     ResourceConfigValue* src_config_value, android::StringPool* pool) {
205*d57664e9SAndroid Build Coastguard Worker   using CollisionResult = ResourceTable::CollisionResult;
206*d57664e9SAndroid Build Coastguard Worker 
207*d57664e9SAndroid Build Coastguard Worker   Value* dst_value = dst_config_value->value.get();
208*d57664e9SAndroid Build Coastguard Worker   Value* src_value = src_config_value->value.get();
209*d57664e9SAndroid Build Coastguard Worker 
210*d57664e9SAndroid Build Coastguard Worker   CollisionResult collision_result =
211*d57664e9SAndroid Build Coastguard Worker       ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus());
212*d57664e9SAndroid Build Coastguard Worker   if (collision_result == CollisionResult::kConflict) {
213*d57664e9SAndroid Build Coastguard Worker     if (overlay) {
214*d57664e9SAndroid Build Coastguard Worker       collision_result =
215*d57664e9SAndroid Build Coastguard Worker           ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool);
216*d57664e9SAndroid Build Coastguard Worker     } else {
217*d57664e9SAndroid Build Coastguard Worker       collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value);
218*d57664e9SAndroid Build Coastguard Worker     }
219*d57664e9SAndroid Build Coastguard Worker   }
220*d57664e9SAndroid Build Coastguard Worker 
221*d57664e9SAndroid Build Coastguard Worker   if (collision_result == CollisionResult::kConflict) {
222*d57664e9SAndroid Build Coastguard Worker     if (overlay) {
223*d57664e9SAndroid Build Coastguard Worker       return CollisionResult::kTakeNew;
224*d57664e9SAndroid Build Coastguard Worker     }
225*d57664e9SAndroid Build Coastguard Worker 
226*d57664e9SAndroid Build Coastguard Worker     // Error!
227*d57664e9SAndroid Build Coastguard Worker     context->GetDiagnostics()->Error(android::DiagMessage(src_value->GetSource())
228*d57664e9SAndroid Build Coastguard Worker                                      << "resource '" << res_name << "' has a conflicting value for "
229*d57664e9SAndroid Build Coastguard Worker                                      << "configuration (" << src_config_value->config << ")");
230*d57664e9SAndroid Build Coastguard Worker     context->GetDiagnostics()->Note(android::DiagMessage(dst_value->GetSource())
231*d57664e9SAndroid Build Coastguard Worker                                     << "originally defined here");
232*d57664e9SAndroid Build Coastguard Worker     return CollisionResult::kConflict;
233*d57664e9SAndroid Build Coastguard Worker   }
234*d57664e9SAndroid Build Coastguard Worker   return collision_result;
235*d57664e9SAndroid Build Coastguard Worker }
236*d57664e9SAndroid Build Coastguard Worker 
DoMerge(const android::Source & src,ResourceTablePackage * src_package,bool mangle_package,bool overlay,bool allow_new_resources)237*d57664e9SAndroid Build Coastguard Worker bool TableMerger::DoMerge(const android::Source& src, ResourceTablePackage* src_package,
238*d57664e9SAndroid Build Coastguard Worker                           bool mangle_package, bool overlay, bool allow_new_resources) {
239*d57664e9SAndroid Build Coastguard Worker   bool error = false;
240*d57664e9SAndroid Build Coastguard Worker 
241*d57664e9SAndroid Build Coastguard Worker   for (auto& src_type : src_package->types) {
242*d57664e9SAndroid Build Coastguard Worker     ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->named_type);
243*d57664e9SAndroid Build Coastguard Worker     if (!MergeType(context_, src, dst_type, src_type.get())) {
244*d57664e9SAndroid Build Coastguard Worker       error = true;
245*d57664e9SAndroid Build Coastguard Worker       continue;
246*d57664e9SAndroid Build Coastguard Worker     }
247*d57664e9SAndroid Build Coastguard Worker 
248*d57664e9SAndroid Build Coastguard Worker     for (auto& src_entry : src_type->entries) {
249*d57664e9SAndroid Build Coastguard Worker       std::string entry_name = src_entry->name;
250*d57664e9SAndroid Build Coastguard Worker       if (mangle_package) {
251*d57664e9SAndroid Build Coastguard Worker         entry_name = NameMangler::MangleEntry(src_package->name, src_entry->name);
252*d57664e9SAndroid Build Coastguard Worker       }
253*d57664e9SAndroid Build Coastguard Worker 
254*d57664e9SAndroid Build Coastguard Worker       ResourceEntry* dst_entry;
255*d57664e9SAndroid Build Coastguard Worker       if (allow_new_resources || src_entry->allow_new) {
256*d57664e9SAndroid Build Coastguard Worker         dst_entry = dst_type->FindOrCreateEntry(entry_name);
257*d57664e9SAndroid Build Coastguard Worker       } else {
258*d57664e9SAndroid Build Coastguard Worker         dst_entry = dst_type->FindEntry(entry_name);
259*d57664e9SAndroid Build Coastguard Worker       }
260*d57664e9SAndroid Build Coastguard Worker 
261*d57664e9SAndroid Build Coastguard Worker       const ResourceNameRef res_name(src_package->name, src_type->named_type, src_entry->name);
262*d57664e9SAndroid Build Coastguard Worker 
263*d57664e9SAndroid Build Coastguard Worker       if (!dst_entry) {
264*d57664e9SAndroid Build Coastguard Worker         context_->GetDiagnostics()->Error(android::DiagMessage(src)
265*d57664e9SAndroid Build Coastguard Worker                                           << "resource " << res_name
266*d57664e9SAndroid Build Coastguard Worker                                           << " does not override an existing resource");
267*d57664e9SAndroid Build Coastguard Worker         context_->GetDiagnostics()->Note(android::DiagMessage(src)
268*d57664e9SAndroid Build Coastguard Worker                                          << "define an <add-resource> tag or use "
269*d57664e9SAndroid Build Coastguard Worker                                          << "--auto-add-overlay");
270*d57664e9SAndroid Build Coastguard Worker         error = true;
271*d57664e9SAndroid Build Coastguard Worker         continue;
272*d57664e9SAndroid Build Coastguard Worker       }
273*d57664e9SAndroid Build Coastguard Worker 
274*d57664e9SAndroid Build Coastguard Worker       if (!MergeEntry(context_, src, dst_entry, src_entry.get(), options_.strict_visibility)) {
275*d57664e9SAndroid Build Coastguard Worker         error = true;
276*d57664e9SAndroid Build Coastguard Worker         continue;
277*d57664e9SAndroid Build Coastguard Worker       }
278*d57664e9SAndroid Build Coastguard Worker 
279*d57664e9SAndroid Build Coastguard Worker       for (auto& src_config_value : src_entry->values) {
280*d57664e9SAndroid Build Coastguard Worker         using CollisionResult = ResourceTable::CollisionResult;
281*d57664e9SAndroid Build Coastguard Worker 
282*d57664e9SAndroid Build Coastguard Worker         ResourceConfigValue* dst_config_value = dst_entry->FindValue(
283*d57664e9SAndroid Build Coastguard Worker             src_config_value->config, src_config_value->product);
284*d57664e9SAndroid Build Coastguard Worker         if (dst_config_value) {
285*d57664e9SAndroid Build Coastguard Worker           CollisionResult collision_result = MergeConfigValue(
286*d57664e9SAndroid Build Coastguard Worker               context_, res_name, overlay, options_.override_styles_instead_of_overlaying,
287*d57664e9SAndroid Build Coastguard Worker               dst_config_value, src_config_value.get(), &main_table_->string_pool);
288*d57664e9SAndroid Build Coastguard Worker           if (collision_result == CollisionResult::kConflict) {
289*d57664e9SAndroid Build Coastguard Worker             error = true;
290*d57664e9SAndroid Build Coastguard Worker             continue;
291*d57664e9SAndroid Build Coastguard Worker           } else if (collision_result == CollisionResult::kKeepOriginal) {
292*d57664e9SAndroid Build Coastguard Worker             continue;
293*d57664e9SAndroid Build Coastguard Worker           }
294*d57664e9SAndroid Build Coastguard Worker         } else {
295*d57664e9SAndroid Build Coastguard Worker           dst_config_value =
296*d57664e9SAndroid Build Coastguard Worker               dst_entry->FindOrCreateValue(src_config_value->config, src_config_value->product);
297*d57664e9SAndroid Build Coastguard Worker         }
298*d57664e9SAndroid Build Coastguard Worker 
299*d57664e9SAndroid Build Coastguard Worker         // Continue if we're taking the new resource.
300*d57664e9SAndroid Build Coastguard Worker         CloningValueTransformer cloner(&main_table_->string_pool);
301*d57664e9SAndroid Build Coastguard Worker         if (FileReference* f = ValueCast<FileReference>(src_config_value->value.get())) {
302*d57664e9SAndroid Build Coastguard Worker           std::unique_ptr<FileReference> new_file_ref;
303*d57664e9SAndroid Build Coastguard Worker           if (mangle_package) {
304*d57664e9SAndroid Build Coastguard Worker             new_file_ref = CloneAndMangleFile(src_package->name, *f);
305*d57664e9SAndroid Build Coastguard Worker           } else {
306*d57664e9SAndroid Build Coastguard Worker             new_file_ref = std::unique_ptr<FileReference>(f->Transform(cloner));
307*d57664e9SAndroid Build Coastguard Worker           }
308*d57664e9SAndroid Build Coastguard Worker           dst_config_value->value = std::move(new_file_ref);
309*d57664e9SAndroid Build Coastguard Worker 
310*d57664e9SAndroid Build Coastguard Worker         } else {
311*d57664e9SAndroid Build Coastguard Worker           auto original_comment = (dst_config_value->value)
312*d57664e9SAndroid Build Coastguard Worker               ? dst_config_value->value->GetComment() : std::optional<std::string>();
313*d57664e9SAndroid Build Coastguard Worker 
314*d57664e9SAndroid Build Coastguard Worker           dst_config_value->value = src_config_value->value->Transform(cloner);
315*d57664e9SAndroid Build Coastguard Worker 
316*d57664e9SAndroid Build Coastguard Worker           // Keep the comment from the original resource and ignore all comments from overlaying
317*d57664e9SAndroid Build Coastguard Worker           // resources
318*d57664e9SAndroid Build Coastguard Worker           if (overlay && original_comment) {
319*d57664e9SAndroid Build Coastguard Worker             dst_config_value->value->SetComment(original_comment.value());
320*d57664e9SAndroid Build Coastguard Worker           }
321*d57664e9SAndroid Build Coastguard Worker         }
322*d57664e9SAndroid Build Coastguard Worker       }
323*d57664e9SAndroid Build Coastguard Worker 
324*d57664e9SAndroid Build Coastguard Worker       // disabled values
325*d57664e9SAndroid Build Coastguard Worker       for (auto& src_config_value : src_entry->flag_disabled_values) {
326*d57664e9SAndroid Build Coastguard Worker         auto dst_config_value = dst_entry->FindOrCreateFlagDisabledValue(
327*d57664e9SAndroid Build Coastguard Worker             src_config_value->value->GetFlag().value(), src_config_value->config,
328*d57664e9SAndroid Build Coastguard Worker             src_config_value->product);
329*d57664e9SAndroid Build Coastguard Worker         if (!dst_config_value->value) {
330*d57664e9SAndroid Build Coastguard Worker           // Resource does not exist, add it now.
331*d57664e9SAndroid Build Coastguard Worker           // Must clone the value since it might be in the values vector as well
332*d57664e9SAndroid Build Coastguard Worker           CloningValueTransformer cloner(&main_table_->string_pool);
333*d57664e9SAndroid Build Coastguard Worker           dst_config_value->value = src_config_value->value->Transform(cloner);
334*d57664e9SAndroid Build Coastguard Worker         } else {
335*d57664e9SAndroid Build Coastguard Worker           error = true;
336*d57664e9SAndroid Build Coastguard Worker           context_->GetDiagnostics()->Error(
337*d57664e9SAndroid Build Coastguard Worker               android::DiagMessage(src_config_value->value->GetSource())
338*d57664e9SAndroid Build Coastguard Worker               << "duplicate value for resource '" << src_entry->name << "' " << "with config '"
339*d57664e9SAndroid Build Coastguard Worker               << src_config_value->config << "' and flag '"
340*d57664e9SAndroid Build Coastguard Worker               << (src_config_value->value->GetFlag()->negated ? "!" : "")
341*d57664e9SAndroid Build Coastguard Worker               << src_config_value->value->GetFlag()->name << "'");
342*d57664e9SAndroid Build Coastguard Worker           context_->GetDiagnostics()->Note(
343*d57664e9SAndroid Build Coastguard Worker               android::DiagMessage(dst_config_value->value->GetSource())
344*d57664e9SAndroid Build Coastguard Worker               << "resource previously defined here");
345*d57664e9SAndroid Build Coastguard Worker         }
346*d57664e9SAndroid Build Coastguard Worker       }
347*d57664e9SAndroid Build Coastguard Worker     }
348*d57664e9SAndroid Build Coastguard Worker   }
349*d57664e9SAndroid Build Coastguard Worker   return !error;
350*d57664e9SAndroid Build Coastguard Worker }
351*d57664e9SAndroid Build Coastguard Worker 
CloneAndMangleFile(const std::string & package,const FileReference & file_ref)352*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<FileReference> TableMerger::CloneAndMangleFile(
353*d57664e9SAndroid Build Coastguard Worker     const std::string& package, const FileReference& file_ref) {
354*d57664e9SAndroid Build Coastguard Worker   StringPiece prefix, entry, suffix;
355*d57664e9SAndroid Build Coastguard Worker   if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) {
356*d57664e9SAndroid Build Coastguard Worker     std::string mangled_entry = NameMangler::MangleEntry(package, entry);
357*d57664e9SAndroid Build Coastguard Worker     std::string newPath = (std::string(prefix) += mangled_entry) += suffix;
358*d57664e9SAndroid Build Coastguard Worker     std::unique_ptr<FileReference> new_file_ref =
359*d57664e9SAndroid Build Coastguard Worker         util::make_unique<FileReference>(main_table_->string_pool.MakeRef(newPath));
360*d57664e9SAndroid Build Coastguard Worker     new_file_ref->SetComment(file_ref.GetComment());
361*d57664e9SAndroid Build Coastguard Worker     new_file_ref->SetSource(file_ref.GetSource());
362*d57664e9SAndroid Build Coastguard Worker     new_file_ref->type = file_ref.type;
363*d57664e9SAndroid Build Coastguard Worker     new_file_ref->file = file_ref.file;
364*d57664e9SAndroid Build Coastguard Worker     return new_file_ref;
365*d57664e9SAndroid Build Coastguard Worker   }
366*d57664e9SAndroid Build Coastguard Worker 
367*d57664e9SAndroid Build Coastguard Worker   CloningValueTransformer cloner(&main_table_->string_pool);
368*d57664e9SAndroid Build Coastguard Worker   return std::unique_ptr<FileReference>(file_ref.Transform(cloner));
369*d57664e9SAndroid Build Coastguard Worker }
370*d57664e9SAndroid Build Coastguard Worker 
MergeFile(const ResourceFile & file_desc,bool overlay,io::IFile * file)371*d57664e9SAndroid Build Coastguard Worker bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFile* file) {
372*d57664e9SAndroid Build Coastguard Worker   ResourceTable table;
373*d57664e9SAndroid Build Coastguard Worker   std::string path = ResourceUtils::BuildResourceFileName(file_desc);
374*d57664e9SAndroid Build Coastguard Worker   std::unique_ptr<FileReference> file_ref =
375*d57664e9SAndroid Build Coastguard Worker       util::make_unique<FileReference>(table.string_pool.MakeRef(path));
376*d57664e9SAndroid Build Coastguard Worker   file_ref->SetSource(file_desc.source);
377*d57664e9SAndroid Build Coastguard Worker   file_ref->type = file_desc.type;
378*d57664e9SAndroid Build Coastguard Worker   file_ref->file = file;
379*d57664e9SAndroid Build Coastguard Worker   file_ref->SetFlagStatus(file_desc.flag_status);
380*d57664e9SAndroid Build Coastguard Worker   file_ref->SetFlag(file_desc.flag);
381*d57664e9SAndroid Build Coastguard Worker 
382*d57664e9SAndroid Build Coastguard Worker   ResourceTablePackage* pkg = table.FindOrCreatePackage(file_desc.name.package);
383*d57664e9SAndroid Build Coastguard Worker   pkg->FindOrCreateType(file_desc.name.type)
384*d57664e9SAndroid Build Coastguard Worker       ->FindOrCreateEntry(file_desc.name.entry)
385*d57664e9SAndroid Build Coastguard Worker       ->FindOrCreateValue(file_desc.config, {})
386*d57664e9SAndroid Build Coastguard Worker       ->value = std::move(file_ref);
387*d57664e9SAndroid Build Coastguard Worker 
388*d57664e9SAndroid Build Coastguard Worker   return DoMerge(file->GetSource(), pkg, false /*mangle*/, overlay /*overlay*/, true /*allow_new*/);
389*d57664e9SAndroid Build Coastguard Worker }
390*d57664e9SAndroid Build Coastguard Worker 
391*d57664e9SAndroid Build Coastguard Worker }  // namespace aapt
392