16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License.
66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at
76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software
116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and
146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License.
156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
17cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include "ResourceTable.h"
186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ConfigDescription.h"
19769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "NameMangler.h"
206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h"
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ValueVisitor.h"
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h"
236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <android-base/logging.h>
256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/ResourceTypes.h>
26cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include <algorithm>
276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory>
286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string>
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <tuple>
306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
31d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinskiusing android::StringPiece;
32d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
35b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskistatic bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
36cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return lhs->type < rhs;
376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskitemplate <typename T>
40b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskistatic bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
41cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) {
45cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const auto last = packages.end();
46b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter = std::lower_bound(packages.begin(), last, name,
47b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                               less_than_struct_with_name<ResourceTablePackage>);
48cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && name == (*iter)->name) {
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
50cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return nullptr;
526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) {
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (auto& package : packages) {
56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (package->id && package->id.value() == id) {
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return package.get();
586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return nullptr;
616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
63b1afa07745280c7a36077beda6293b69c6ba4ea2Adam LesinskiResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe<uint8_t> id) {
64ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTablePackage* package = FindOrCreatePackage(name);
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (id && !package->id) {
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    package->id = id;
679ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    return package;
68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (id && package->id && package->id.value() != id.value()) {
71cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return nullptr;
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return package;
74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
76b1afa07745280c7a36077beda6293b69c6ba4ea2Adam LesinskiResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const auto last = packages.end();
78b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter = std::lower_bound(packages.begin(), last, name,
79b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                               less_than_struct_with_name<ResourceTablePackage>);
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && name == (*iter)->name) {
81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
84b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
85d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  new_package->name = name.to_string();
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return packages.emplace(iter, std::move(new_package))->get();
871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceTableType* ResourceTablePackage::FindType(ResourceType type) {
90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const auto last = types.end();
91ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && (*iter)->type == type) {
93cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return nullptr;
961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
98ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const auto last = types.end();
100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  auto iter = std::lower_bound(types.begin(), last, type, less_than_type);
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && (*iter)->type == type) {
102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
103cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
104cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return types.emplace(iter, new ResourceTableType(type))->get();
1051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) {
108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const auto last = entries.end();
109b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter =
110b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski      std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && name == (*iter)->name) {
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
114cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return nullptr;
1151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) {
118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto last = entries.end();
119b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter =
120b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski      std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>);
121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != last && name == (*iter)->name) {
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return iter->get();
123cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return entries.emplace(iter, new ResourceEntry(name))->get();
1251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) {
128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return FindValue(config, StringPiece());
129e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
130e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
131e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskistruct ConfigKey {
132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ConfigDescription* config;
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const StringPiece& product;
134e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski};
135e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
136b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskibool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  int cmp = lhs->config.compare(*rhs.config);
138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (cmp == 0) {
139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    cmp = StringPiece(lhs->product).compare(rhs.product);
140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return cmp < 0;
142e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
143e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
145e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                              const StringPiece& product) {
146b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter =
147b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski      std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != values.end()) {
149cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceConfigValue* value = iter->get();
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (value->config == config && StringPiece(value->product) == product) {
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return value;
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return nullptr;
155e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
156e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
157b1afa07745280c7a36077beda6293b69c6ba4ea2Adam LesinskiResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
158b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                                      const StringPiece& product) {
159b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter =
160b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski      std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (iter != values.end()) {
162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceConfigValue* value = iter->get();
163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (value->config == config && StringPiece(value->product) == product) {
164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return value;
165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
167cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceConfigValue* newValue =
168b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski      values.insert(iter, util::make_unique<ResourceConfigValue>(config, product))->get();
169cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return newValue;
170e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
171e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
172b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskistd::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) {
173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::vector<ResourceConfigValue*> results;
174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
175cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto iter = values.begin();
176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (; iter != values.end(); ++iter) {
177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceConfigValue* value = iter->get();
178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (value->config == config) {
179cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      results.push_back(value);
180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      ++iter;
181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      break;
182e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
184e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
185cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (; iter != values.end(); ++iter) {
186cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceConfigValue* value = iter->get();
187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (value->config == config) {
188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      results.push_back(value);
189e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return results;
192e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
193e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::vector<ResourceConfigValue*> ResourceEntry::FindValuesIf(
195cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const std::function<bool(ResourceConfigValue*)>& f) {
196cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::vector<ResourceConfigValue*> results;
197cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (auto& configValue : values) {
198cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (f(configValue.get())) {
199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      results.push_back(configValue.get());
200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return results;
203458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski}
204458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski
2056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/**
2065c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski * The default handler for collisions.
2078197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
208cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * Typically, a weak value will be overridden by a strong value. An existing
209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * weak
2108197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski * value will not be overridden by an incoming weak value.
2118197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
2128197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski * There are some exceptions:
2138197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
2148197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski * Attributes: There are two types of Attribute values: USE and DECL.
2158197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
216cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * USE is anywhere an Attribute is declared without a format, and in a place
217cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * that would
2188197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski * be legal to declare if the Attribute already existed. This is typically in a
219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * <declare-styleable> tag. Attributes defined in a <declare-styleable> are also
220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * weak.
2218197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * DECL is an absolute declaration of an Attribute and specifies an explicit
223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * format.
2248197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski *
225cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * A DECL will override a USE without error. Two DECLs must match in their
226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * format for there to be
2278197cc460e02c6445434eace435e3d38ebe475c6Adam Lesinski * no error.
2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
229b1afa07745280c7a36077beda6293b69c6ba4ea2Adam LesinskiResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing,
230b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                                                    Value* incoming) {
231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* existing_attr = ValueCast<Attribute>(existing);
232ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* incoming_attr = ValueCast<Attribute>(incoming);
233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!incoming_attr) {
234ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (incoming->IsWeak()) {
235cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // We're trying to add a weak resource but a resource
236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // already exists. Keep the existing.
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return CollisionResult::kKeepOriginal;
238ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    } else if (existing->IsWeak()) {
239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // Override the weak resource with the new strong resource.
240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return CollisionResult::kTakeNew;
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // The existing and incoming values are strong, this is an error
243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // if the values are not both attributes.
244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return CollisionResult::kConflict;
245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!existing_attr) {
248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (existing->IsWeak()) {
249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // The existing value is not an attribute and it is weak,
250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // so take the incoming attribute value.
251cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return CollisionResult::kTakeNew;
2526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
253cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // The existing value is not an attribute and it is strong,
254cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // so the incoming attribute value is an error.
2555c3464c75fc517c0306a4ffd39c59671ccfde544Adam Lesinski    return CollisionResult::kConflict;
256cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
257cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
258ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  CHECK(incoming_attr != nullptr && existing_attr != nullptr);
259cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
260cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  //
261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Attribute specific handling. At this point we know both
262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // values are attributes. Since we can declare and define
263cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // attributes all-over, we do special handling to see
264cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // which definition sticks.
265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  //
266ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (existing_attr->type_mask == incoming_attr->type_mask) {
267cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // The two attributes are both DECLs, but they are plain attributes
268cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // with the same formats.
269cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Keep the strongest one.
270b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski    return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
271cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
272cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
273b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  if (existing_attr->IsWeak() && existing_attr->type_mask == android::ResTable_map::TYPE_ANY) {
274cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Any incoming attribute is better than this.
275cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return CollisionResult::kTakeNew;
276cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
278b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  if (incoming_attr->IsWeak() && incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) {
279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // The incoming attribute may be a USE instead of a DECL.
280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Keep the existing attribute.
281cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return CollisionResult::kKeepOriginal;
282cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return CollisionResult::kConflict;
2846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
286d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinskistatic constexpr const char* kValidNameChars = "._-";
287b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski
288b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskistatic StringPiece ValidateName(const StringPiece& name) {
289b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  auto iter = util::FindNonAlphaNumericAndNotInSet(name, kValidNameChars);
290b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  if (iter != name.end()) {
291b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski    return StringPiece(iter, 1);
292b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  }
293b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return {};
294b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski}
295b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski
296b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskistatic StringPiece SkipValidateName(const StringPiece& /*name*/) {
297b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return {};
298b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski}
299330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
300ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddResource(const ResourceNameRef& name,
301e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
302e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
303e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
304e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                IDiagnostics* diag) {
305b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddResourceImpl(name, {}, config, product, std::move(value), ValidateName,
306b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                         ResolveValueCollision, diag);
307330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
309ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddResource(const ResourceNameRef& name,
310ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                const ResourceId& res_id,
311e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
312e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
313e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
314e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                IDiagnostics* diag) {
315b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddResourceImpl(name, res_id, config, product, std::move(value), ValidateName,
316b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                         ResolveValueCollision, diag);
3171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
3181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
319ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddFileReference(const ResourceNameRef& name,
320e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const ConfigDescription& config,
321e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const Source& source,
322d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski                                     const StringPiece& path,
3231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                     IDiagnostics* diag) {
324b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddFileReferenceImpl(name, config, source, path, nullptr, ValidateName, diag);
325fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski}
326fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski
327ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddFileReferenceAllowMangled(
328cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const ResourceNameRef& name, const ConfigDescription& config,
329cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const Source& source, const StringPiece& path, io::IFile* file,
330cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    IDiagnostics* diag) {
331b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddFileReferenceImpl(name, config, source, path, file, SkipValidateName, diag);
332355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski}
333355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski
334b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskibool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name,
335b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                         const ConfigDescription& config, const Source& source,
336b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                         const StringPiece& path, io::IFile* file,
337b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                         NameValidator name_validator, IDiagnostics* diag) {
338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::unique_ptr<FileReference> fileRef =
339ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      util::make_unique<FileReference>(string_pool.MakeRef(path));
340ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  fileRef->SetSource(source);
341cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  fileRef->file = file;
342b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
343b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                         name_validator, ResolveValueCollision, diag);
344330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
345330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
346ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
347330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                            const ConfigDescription& config,
348e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
3491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            std::unique_ptr<Value> value,
3501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            IDiagnostics* diag) {
351b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipValidateName,
352b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                         ResolveValueCollision, diag);
353330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
354330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name,
3569b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh                                            const ResourceId& id,
3579e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            const ConfigDescription& config,
358e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
3599e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            std::unique_ptr<Value> value,
3609e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            IDiagnostics* diag) {
361b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return AddResourceImpl(name, id, config, product, std::move(value), SkipValidateName,
362b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                         ResolveValueCollision, diag);
3639e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski}
3649e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski
365b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskibool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
366b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                    const ConfigDescription& config, const StringPiece& product,
367b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                    std::unique_ptr<Value> value, NameValidator name_validator,
368b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                    const CollisionResolverFunc& conflictResolver,
369b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                    IDiagnostics* diag) {
370ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  CHECK(value != nullptr);
371ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  CHECK(diag != nullptr);
372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
373b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  const StringPiece bad_char = name_validator(name.entry);
374b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  if (!bad_char.empty()) {
375b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski    diag->Error(DiagMessage(value->GetSource()) << "resource '" << name
376b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                                << "' has invalid entry name '" << name.entry
377b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                                << "'. Invalid character '" << bad_char << "'");
378b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski
379cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
380cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
381cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
382ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTablePackage* package = FindOrCreatePackage(name.package);
383ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
384ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(value->GetSource())
385ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
386cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but package '" << package->name << "' already has ID "
387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << std::hex << (int)package->id.value() << std::dec);
388cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
391ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTableType* type = package->FindOrCreateType(name.type);
392ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
393ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(value->GetSource())
394ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but type '" << type->type << "' already has ID "
396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << std::hex << (int)type->id.value() << std::dec);
397cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
399cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
400ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
401ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
402ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(value->GetSource())
403ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but resource already has ID "
405cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << ResourceId(package->id.value(), type->id.value(),
406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                              entry->id.value()));
407cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
408cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
409cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
410ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product);
411ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (!config_value->value) {
412cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Resource does not exist, add it now.
413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    config_value->value = std::move(value);
414cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
415cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else {
416ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    switch (conflictResolver(config_value->value.get(), value.get())) {
417cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      case CollisionResult::kTakeNew:
418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // Take the incoming value.
419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        config_value->value = std::move(value);
420cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        break;
4216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
422cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      case CollisionResult::kConflict:
423ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        diag->Error(DiagMessage(value->GetSource())
424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                    << "duplicate value for resource '" << name << "' "
425cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                    << "with config '" << config << "'");
426ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        diag->Error(DiagMessage(config_value->value->GetSource())
427cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                    << "resource previously defined here");
4286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
429e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      case CollisionResult::kKeepOriginal:
431cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        break;
4326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
433cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
4346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
435ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic()) {
436ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    package->id = res_id.package_id();
437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type->id = res_id.type_id();
438ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    entry->id = res_id.entry_id();
439cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
4416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4434488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinskibool ResourceTable::SetSymbolState(const ResourceNameRef& name, const ResourceId& res_id,
444e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                   const Symbol& symbol, IDiagnostics* diag) {
445b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return SetSymbolStateImpl(name, res_id, symbol, ValidateName, diag);
446330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
447330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
448ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ResourceTable::SetSymbolStateAllowMangled(const ResourceNameRef& name,
449ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                               const ResourceId& res_id,
450cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                                               const Symbol& symbol,
451cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                                               IDiagnostics* diag) {
452b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  return SetSymbolStateImpl(name, res_id, symbol, SkipValidateName, diag);
453330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
454330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
455b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinskibool ResourceTable::SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
456b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                       const Symbol& symbol, NameValidator name_validator,
457e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                       IDiagnostics* diag) {
458ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  CHECK(diag != nullptr);
459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
460b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  const StringPiece bad_char = name_validator(name.entry);
461b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski  if (!bad_char.empty()) {
462b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski    diag->Error(DiagMessage(symbol.source) << "resource '" << name << "' has invalid entry name '"
463b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                           << name.entry << "'. Invalid character '" << bad_char
464b1afa07745280c7a36077beda6293b69c6ba4ea2Adam Lesinski                                           << "'");
465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
466cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
467cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTablePackage* package = FindOrCreatePackage(name.package);
469ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
470ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(symbol.source)
471ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
472cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but package '" << package->name << "' already has ID "
473cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << std::hex << (int)package->id.value() << std::dec);
474cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
477ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTableType* type = package->FindOrCreateType(name.type);
478ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) {
479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(symbol.source)
480ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but type '" << type->type << "' already has ID "
482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << std::hex << (int)type->id.value() << std::dec);
483cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
484cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
485cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
486ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
487ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) {
488ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    diag->Error(DiagMessage(symbol.source)
489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                << "trying to add resource '" << name << "' with ID " << res_id
490cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                << " but resource already has ID "
4914488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski                << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
492cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return false;
493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
495ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  if (res_id.is_valid_dynamic()) {
496ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    package->id = res_id.package_id();
497ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type->id = res_id.type_id();
498ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    entry->id = res_id.entry_id();
499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
500cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Only mark the type state as public, it doesn't care about being private.
502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (symbol.state == SymbolState::kPublic) {
503ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type->symbol_status.state = SymbolState::kPublic;
504cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
505cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
5064488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  if (symbol.allow_new) {
5074488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski    // This symbol can be added as a new resource when merging (if it belongs to an overlay).
5084488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski    entry->symbol_status.allow_new = true;
5094488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  }
5104488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski
511cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (symbol.state == SymbolState::kUndefined &&
512ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      entry->symbol_status.state != SymbolState::kUndefined) {
513cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // We can't undefine a symbol (remove its visibility). Ignore.
514769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return true;
515cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
516769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
517cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (symbol.state == SymbolState::kPrivate &&
518ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      entry->symbol_status.state == SymbolState::kPublic) {
519cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // We can't downgrade public to private. Ignore.
520cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
5226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5234488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  // This symbol definition takes precedence, replace.
5244488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  entry->symbol_status.state = symbol.state;
5254488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  entry->symbol_status.source = symbol.source;
5264488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  entry->symbol_status.comment = symbol.comment;
527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
528cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
5296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
530b1afa07745280c7a36077beda6293b69c6ba4ea2Adam LesinskiMaybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) {
531ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTablePackage* package = FindPackage(name.package);
532cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (!package) {
533cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return {};
534cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
536ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTableType* type = package->FindType(name.type);
537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (!type) {
538cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return {};
539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
541ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceEntry* entry = type->FindEntry(name.entry);
542cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (!entry) {
543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return {};
544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
545cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return SearchResult{package, type, entry};
5466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
549