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
176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ConfigDescription.h"
18769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "NameMangler.h"
196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h"
206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h"
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ValueVisitor.h"
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h"
236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <algorithm>
256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/ResourceTypes.h>
266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory>
276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string>
286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <tuple>
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic bool lessThanType(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return lhs->type < rhs;
346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskitemplate <typename T>
371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic bool lessThanStructWithName(const std::unique_ptr<T>& lhs,
381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                   const StringPiece16& rhs) {
396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
421ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTablePackage* ResourceTable::findPackage(const StringPiece16& name) {
431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto last = packages.end();
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(packages.begin(), last, name,
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                 lessThanStructWithName<ResourceTablePackage>);
461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && name == (*iter)->name) {
471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return nullptr;
506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
521ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTablePackage* ResourceTable::findPackageById(uint8_t id) {
531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (auto& package : packages) {
541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (package->id && package->id.value() == id) {
551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            return package.get();
566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return nullptr;
596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
619ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiResourceTablePackage* ResourceTable::createPackage(const StringPiece16& name, Maybe<uint8_t> id) {
621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findOrCreatePackage(name);
639ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    if (id && !package->id) {
641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        package->id = id;
651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return package;
666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
689ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    if (id && package->id && package->id.value() != id.value()) {
699ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski        return nullptr;
701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
719ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    return package;
726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
741ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTablePackage* ResourceTable::findOrCreatePackage(const StringPiece16& name) {
751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto last = packages.end();
761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(packages.begin(), last, name,
771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                 lessThanStructWithName<ResourceTablePackage>);
781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && name == (*iter)->name) {
791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    std::unique_ptr<ResourceTablePackage> newPackage = util::make_unique<ResourceTablePackage>();
831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    newPackage->name = name.toString();
841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return packages.emplace(iter, std::move(newPackage))->get();
851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
871ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTableType* ResourceTablePackage::findType(ResourceType type) {
881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto last = types.end();
891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(types.begin(), last, type, lessThanType);
901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && (*iter)->type == type) {
911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return nullptr;
941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
961ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTableType* ResourceTablePackage::findOrCreateType(ResourceType type) {
971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto last = types.end();
981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(types.begin(), last, type, lessThanType);
991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && (*iter)->type == type) {
1001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
102a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    return types.emplace(iter, new ResourceTableType(type))->get();
1031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1051ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceEntry* ResourceTableType::findEntry(const StringPiece16& name) {
1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto last = entries.end();
1071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(entries.begin(), last, name,
1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                 lessThanStructWithName<ResourceEntry>);
1091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && name == (*iter)->name) {
1101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return nullptr;
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1151ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceEntry* ResourceTableType::findOrCreateEntry(const StringPiece16& name) {
1161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto last = entries.end();
1171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto iter = std::lower_bound(entries.begin(), last, name,
1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                 lessThanStructWithName<ResourceEntry>);
1191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (iter != last && name == (*iter)->name) {
1201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return iter->get();
1211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
122a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    return entries.emplace(iter, new ResourceEntry(name))->get();
1231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
125e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiResourceConfigValue* ResourceEntry::findValue(const ConfigDescription& config) {
126e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return findValue(config, StringPiece());
127e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
128e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
129e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskistruct ConfigKey {
130e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    const ConfigDescription* config;
131e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    const StringPiece& product;
132e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski};
133e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
134e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
135e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    int cmp = lhs->config.compare(*rhs.config);
136e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (cmp == 0) {
137e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        cmp = StringPiece(lhs->product).compare(rhs.product);
138e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
139e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return cmp < 0;
140e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
141e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
142e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiResourceConfigValue* ResourceEntry::findValue(const ConfigDescription& config,
143e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                              const StringPiece& product) {
144e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    auto iter = std::lower_bound(values.begin(), values.end(),
145e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                 ConfigKey{ &config, product }, ltConfigKeyRef);
146e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (iter != values.end()) {
147e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* value = iter->get();
148e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (value->config == config && StringPiece(value->product) == product) {
149e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            return value;
150e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
151e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
152e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return nullptr;
153e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
154e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
155e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiResourceConfigValue* ResourceEntry::findOrCreateValue(const ConfigDescription& config,
156e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                                      const StringPiece& product) {
157e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    auto iter = std::lower_bound(values.begin(), values.end(),
158e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                 ConfigKey{ &config, product }, ltConfigKeyRef);
159e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (iter != values.end()) {
160e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* value = iter->get();
161e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (value->config == config && StringPiece(value->product) == product) {
162e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            return value;
163e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
164e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
165e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    ResourceConfigValue* newValue = values.insert(
166e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            iter, util::make_unique<ResourceConfigValue>(config, product))->get();
167e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return newValue;
168e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
169e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
170e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskistd::vector<ResourceConfigValue*> ResourceEntry::findAllValues(const ConfigDescription& config) {
171e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    std::vector<ResourceConfigValue*> results;
172e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
173e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    auto iter = values.begin();
174e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    for (; iter != values.end(); ++iter) {
175e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* value = iter->get();
176e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (value->config == config) {
177e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            results.push_back(value);
178e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            ++iter;
179e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            break;
180e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
181e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
182e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
183e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    for (; iter != values.end(); ++iter) {
184e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* value = iter->get();
185e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (value->config == config) {
186e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            results.push_back(value);
187e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
188e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
189e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return results;
190e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
191e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
192458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinskistd::vector<ResourceConfigValue*> ResourceEntry::findValuesIf(
193458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski        const std::function<bool(ResourceConfigValue*)>& f) {
194458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski    std::vector<ResourceConfigValue*> results;
195458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski    for (auto& configValue : values) {
196458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski        if (f(configValue.get())) {
197458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski            results.push_back(configValue.get());
198458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski        }
199458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski    }
200458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski    return results;
201458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski}
202458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski
2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/**
2046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * The default handler for collisions. A return value of -1 means keep the
2056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * existing value, 0 means fail, and +1 means take the incoming value.
2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
2071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiint ResourceTable::resolveValueCollision(Value* existing, Value* incoming) {
2081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Attribute* existingAttr = valueCast<Attribute>(existing);
2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Attribute* incomingAttr = valueCast<Attribute>(incoming);
2106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!incomingAttr) {
2121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (incoming->isWeak()) {
2136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // We're trying to add a weak resource but a resource
2146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // already exists. Keep the existing.
2156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return -1;
2161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        } else if (existing->isWeak()) {
2176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // Override the weak resource with the new strong resource.
2186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return 1;
2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The existing and incoming values are strong, this is an error
2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // if the values are not both attributes.
2226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 0;
2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!existingAttr) {
2261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (existing->isWeak()) {
2276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // The existing value is not an attribute and it is weak,
2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // so take the incoming attribute value.
2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return 1;
2306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The existing value is not an attribute and it is strong,
2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // so the incoming attribute value is an error.
2336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 0;
2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    assert(incomingAttr && existingAttr);
2371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    //
2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // Attribute specific handling. At this point we know both
2406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // values are attributes. Since we can declare and define
2416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // attributes all-over, we do special handling to see
2426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // which definition sticks.
2436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    //
2441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (existingAttr->typeMask == incomingAttr->typeMask) {
2456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The two attributes are both DECLs, but they are plain attributes
2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // with the same formats.
2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Keep the strongest one.
2481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return existingAttr->isWeak() ? 1 : -1;
2496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (existingAttr->isWeak() && existingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
2526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Any incoming attribute is better than this.
2536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 1;
2546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (incomingAttr->isWeak() && incomingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
2576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The incoming attribute may be a USE instead of a DECL.
2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Keep the existing attribute.
2596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return -1;
2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return 0;
2626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic constexpr const char16_t* kValidNameChars = u"._-";
265330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskistatic constexpr const char16_t* kValidNameMangledChars = u"._-$";
266330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
267e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addResource(const ResourceNameRef& name,
268e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
269e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
270e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
271e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                IDiagnostics* diag) {
272e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, {}, config, product, std::move(value), kValidNameChars,
273fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
274330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
2756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
276e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addResource(const ResourceNameRef& name,
277e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ResourceId resId,
278e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
279e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
280e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
281e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                IDiagnostics* diag) {
282e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, resId, config, product, std::move(value), kValidNameChars,
283fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
2841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
286e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addFileReference(const ResourceNameRef& name,
287e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const ConfigDescription& config,
288e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const Source& source,
289e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const StringPiece16& path,
2901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                     IDiagnostics* diag) {
291355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski    return addFileReferenceImpl(name, config, source, path, nullptr, kValidNameChars, diag);
292fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski}
293fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski
294355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinskibool ResourceTable::addFileReferenceAllowMangled(const ResourceNameRef& name,
295355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                                 const ConfigDescription& config,
296355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                                 const Source& source,
297355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                                 const StringPiece16& path,
298355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                                 io::IFile* file,
299355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                                 IDiagnostics* diag) {
300355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski    return addFileReferenceImpl(name, config, source, path, file, kValidNameMangledChars, diag);
301355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski}
302355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski
303355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinskibool ResourceTable::addFileReferenceImpl(const ResourceNameRef& name,
304355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         const ConfigDescription& config,
305355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         const Source& source,
306355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         const StringPiece16& path,
307355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         io::IFile* file,
308355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         const char16_t* validChars,
309355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                                         IDiagnostics* diag) {
310e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
311e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            stringPool.makeRef(path));
312e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    fileRef->setSource(source);
313355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski    fileRef->file = file;
314e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
315355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski                           kValidNameChars, resolveValueCollision, diag);
316330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
317330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
318330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskibool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
319330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                            const ConfigDescription& config,
320e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
3211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            std::unique_ptr<Value> value,
3221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            IDiagnostics* diag) {
323e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, ResourceId{}, config, product, std::move(value),
324e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           kValidNameMangledChars, resolveValueCollision, diag);
325330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
326330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
3279e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
3289e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            const ResourceId id,
3299e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            const ConfigDescription& config,
330e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
3319e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            std::unique_ptr<Value> value,
3329e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            IDiagnostics* diag) {
333e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, id, config, product, std::move(value), kValidNameMangledChars,
334fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
3359e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski}
3369e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski
337fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinskibool ResourceTable::addResourceImpl(const ResourceNameRef& name,
338fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const ResourceId resId,
339fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const ConfigDescription& config,
340e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                    const StringPiece& product,
341fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    std::unique_ptr<Value> value,
342fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const char16_t* validChars,
343fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    std::function<int(Value*,Value*)> conflictResolver,
344fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    IDiagnostics* diag) {
345e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(value && "value can't be nullptr");
346e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(diag && "diagnostics can't be nullptr");
347e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
3481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
3491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (badCharIter != name.entry.end()) {
350e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "resource '"
3521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' has invalid entry name '"
3541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name.entry
3551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'. Invalid character '"
3561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << StringPiece16(badCharIter, 1)
3571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'");
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findOrCreatePackage(name.package);
3621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
363e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but package '"
3691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << package->name
3701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
3711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) package->id.value() << std::dec);
3726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findOrCreateType(name.type);
3761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
377e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but type '"
3831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << type->type
3841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
3851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) type->id.value() << std::dec);
3866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findOrCreateEntry(name.entry);
3901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
391e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but resource already has ID "
3971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
3986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
401e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    ResourceConfigValue* configValue = entry->findOrCreateValue(config, product);
402e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (!configValue->value) {
403e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        // Resource does not exist, add it now.
404e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        configValue->value = std::move(value);
405e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
4066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    } else {
407e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        int collisionResult = conflictResolver(configValue->value.get(), value.get());
4086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (collisionResult > 0) {
4096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // Take the incoming value.
410e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            configValue->value = std::move(value);
4116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (collisionResult == 0) {
412e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            diag->error(DiagMessage(value->getSource())
4131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        << "duplicate value for resource '" << name << "' "
414e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                        << "with config '" << config << "'");
415e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            diag->error(DiagMessage(configValue->value->getSource())
4161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        << "resource previously defined here");
4176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return false;
4186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
4196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (resId.isValid()) {
4221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        package->id = resId.packageId();
4231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        type->id = resId.typeId();
4241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        entry->id = resId.entryId();
4256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return true;
4276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4299e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::setSymbolState(const ResourceNameRef& name, const ResourceId resId,
430e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                   const Symbol& symbol, IDiagnostics* diag) {
431e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    return setSymbolStateImpl(name, resId, symbol, kValidNameChars, diag);
432330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
433330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
434e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinskibool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name,
435e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                               const ResourceId resId,
436e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                               const Symbol& symbol, IDiagnostics* diag) {
437e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    return setSymbolStateImpl(name, resId, symbol, kValidNameMangledChars, diag);
438330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
439330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
4409e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
441e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                       const Symbol& symbol, const char16_t* validChars,
442e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                       IDiagnostics* diag) {
443e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(diag && "diagnostics can't be nullptr");
444e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
4451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
4461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (badCharIter != name.entry.end()) {
447e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "resource '"
4491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' has invalid entry name '"
4511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name.entry
4521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'. Invalid character '"
4531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << StringPiece16(badCharIter, 1)
4541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'");
4556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findOrCreatePackage(name.package);
4591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
460e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but package '"
4661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << package->name
4671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
4681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) package->id.value() << std::dec);
4696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findOrCreateType(name.type);
4731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
474e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but type '"
4801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << type->type
4811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
4821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) type->id.value() << std::dec);
4836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findOrCreateEntry(name.entry);
4871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
488e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but resource already has ID "
4941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
4956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
498a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (resId.isValid()) {
499a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        package->id = resId.packageId();
500a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        type->id = resId.typeId();
501a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        entry->id = resId.entryId();
502a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    }
503a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
5049e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    // Only mark the type state as public, it doesn't care about being private.
505e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    if (symbol.state == SymbolState::kPublic) {
5069e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski        type->symbolStatus.state = SymbolState::kPublic;
5079e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    }
5089e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski
509a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (symbol.state == SymbolState::kUndefined &&
510a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski            entry->symbolStatus.state != SymbolState::kUndefined) {
511a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        // We can't undefine a symbol (remove its visibility). Ignore.
512a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        return true;
5139e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    }
5146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
515a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (symbol.state == SymbolState::kPrivate &&
516a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski            entry->symbolStatus.state == SymbolState::kPublic) {
517a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        // We can't downgrade public to private. Ignore.
518a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        return true;
519769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
520a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
521a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    entry->symbolStatus = std::move(symbol);
522769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return true;
523769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
524769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
5251ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiMaybe<ResourceTable::SearchResult>
5261ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTable::findResource(const ResourceNameRef& name) {
5271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findPackage(name.package);
5281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!package) {
529ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findType(name.type);
5331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!type) {
534ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findEntry(name.entry);
5381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!entry) {
539ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return SearchResult{ package, type, entry };
5426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt
545