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