ResourceTable.cpp revision e4bb9eb5af5b0899dc0921d5580220b20e15bd5a
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
1926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/**
1936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * The default handler for collisions. A return value of -1 means keep the
1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * existing value, 0 means fail, and +1 means take the incoming value.
1956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiint ResourceTable::resolveValueCollision(Value* existing, Value* incoming) {
1971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Attribute* existingAttr = valueCast<Attribute>(existing);
1981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Attribute* incomingAttr = valueCast<Attribute>(incoming);
1996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!incomingAttr) {
2011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (incoming->isWeak()) {
2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // We're trying to add a weak resource but a resource
2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // already exists. Keep the existing.
2046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return -1;
2051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        } else if (existing->isWeak()) {
2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // Override the weak resource with the new strong resource.
2076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return 1;
2086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
2096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The existing and incoming values are strong, this is an error
2106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // if the values are not both attributes.
2116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 0;
2126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!existingAttr) {
2151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (existing->isWeak()) {
2166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // The existing value is not an attribute and it is weak,
2176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // so take the incoming attribute value.
2186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return 1;
2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The existing value is not an attribute and it is strong,
2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // so the incoming attribute value is an error.
2226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 0;
2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    assert(incomingAttr && existingAttr);
2261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    //
2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // Attribute specific handling. At this point we know both
2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // values are attributes. Since we can declare and define
2306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // attributes all-over, we do special handling to see
2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    // which definition sticks.
2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    //
2331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (existingAttr->typeMask == incomingAttr->typeMask) {
2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The two attributes are both DECLs, but they are plain attributes
2356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // with the same formats.
2366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Keep the strongest one.
2371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return existingAttr->isWeak() ? 1 : -1;
2386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (existingAttr->isWeak() && existingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
2416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Any incoming attribute is better than this.
2426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return 1;
2436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (incomingAttr->isWeak() && incomingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // The incoming attribute may be a USE instead of a DECL.
2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        // Keep the existing attribute.
2486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return -1;
2496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return 0;
2516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic constexpr const char16_t* kValidNameChars = u"._-";
254330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskistatic constexpr const char16_t* kValidNameMangledChars = u"._-$";
255330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
256e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addResource(const ResourceNameRef& name,
257e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
258e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
259e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
260e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                IDiagnostics* diag) {
261e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, {}, config, product, std::move(value), kValidNameChars,
262fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
263330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
2646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
265e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addResource(const ResourceNameRef& name,
266e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ResourceId resId,
267e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const ConfigDescription& config,
268e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                const StringPiece& product,
269e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                std::unique_ptr<Value> value,
270e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                IDiagnostics* diag) {
271e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, resId, config, product, std::move(value), kValidNameChars,
272fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
2731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
275e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addFileReference(const ResourceNameRef& name,
276e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const ConfigDescription& config,
277e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const Source& source,
278e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const StringPiece16& path,
2791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                     IDiagnostics* diag) {
280fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski    return addFileReference(name, config, source, path, resolveValueCollision, diag);
281fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski}
282fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski
283e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ResourceTable::addFileReference(const ResourceNameRef& name,
284e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const ConfigDescription& config,
285e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const Source& source,
286e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                     const StringPiece16& path,
287fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                     std::function<int(Value*,Value*)> conflictResolver,
288fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                     IDiagnostics* diag) {
289e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
290e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            stringPool.makeRef(path));
291e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    fileRef->setSource(source);
292e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
293e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           kValidNameChars, conflictResolver, diag);
294330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
295330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
296330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskibool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
297330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                                            const ConfigDescription& config,
298e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
2991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            std::unique_ptr<Value> value,
3001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                            IDiagnostics* diag) {
301e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, ResourceId{}, config, product, std::move(value),
302e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           kValidNameMangledChars, resolveValueCollision, diag);
303330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
304330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
3059e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
3069e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            const ResourceId id,
3079e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            const ConfigDescription& config,
308e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                            const StringPiece& product,
3099e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            std::unique_ptr<Value> value,
3109e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski                                            IDiagnostics* diag) {
311e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return addResourceImpl(name, id, config, product, std::move(value), kValidNameMangledChars,
312fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                           resolveValueCollision, diag);
3139e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski}
3149e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski
315fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinskibool ResourceTable::addResourceImpl(const ResourceNameRef& name,
316fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const ResourceId resId,
317fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const ConfigDescription& config,
318e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                    const StringPiece& product,
319fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    std::unique_ptr<Value> value,
320fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    const char16_t* validChars,
321fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    std::function<int(Value*,Value*)> conflictResolver,
322fb48d292d9eb78a73f9473d90911ecb81da5fffdAdam Lesinski                                    IDiagnostics* diag) {
323e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(value && "value can't be nullptr");
324e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(diag && "diagnostics can't be nullptr");
325e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
3261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
3271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (badCharIter != name.entry.end()) {
328e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "resource '"
3301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' has invalid entry name '"
3321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name.entry
3331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'. Invalid character '"
3341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << StringPiece16(badCharIter, 1)
3351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'");
3366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findOrCreatePackage(name.package);
3401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
341e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but package '"
3471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << package->name
3481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
3491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) package->id.value() << std::dec);
3506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findOrCreateType(name.type);
3541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
355e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but type '"
3611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << type->type
3621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
3631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) type->id.value() << std::dec);
3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findOrCreateEntry(name.entry);
3681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
369e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(value->getSource())
3701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
3711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
3721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
3731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
3741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but resource already has ID "
3751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
3766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
379e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    ResourceConfigValue* configValue = entry->findOrCreateValue(config, product);
380e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (!configValue->value) {
381e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        // Resource does not exist, add it now.
382e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        configValue->value = std::move(value);
383e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
3846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    } else {
385e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        int collisionResult = conflictResolver(configValue->value.get(), value.get());
3866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (collisionResult > 0) {
3876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // Take the incoming value.
388e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            configValue->value = std::move(value);
3896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (collisionResult == 0) {
390e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski            diag->error(DiagMessage(value->getSource())
3911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        << "duplicate value for resource '" << name << "' "
392e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                        << "with config '" << config << "'");
393e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            diag->error(DiagMessage(configValue->value->getSource())
3941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        << "resource previously defined here");
3956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return false;
3966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
3976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (resId.isValid()) {
4001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        package->id = resId.packageId();
4011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        type->id = resId.typeId();
4021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        entry->id = resId.entryId();
4036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return true;
4056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4079e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::setSymbolState(const ResourceNameRef& name, const ResourceId resId,
408e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                   const Symbol& symbol, IDiagnostics* diag) {
409e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    return setSymbolStateImpl(name, resId, symbol, kValidNameChars, diag);
410330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
411330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
412e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinskibool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name,
413e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                               const ResourceId resId,
414e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                               const Symbol& symbol, IDiagnostics* diag) {
415e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    return setSymbolStateImpl(name, resId, symbol, kValidNameMangledChars, diag);
416330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
417330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
4189e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinskibool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
419e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                       const Symbol& symbol, const char16_t* validChars,
420e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                       IDiagnostics* diag) {
421e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    assert(diag && "diagnostics can't be nullptr");
422e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
4231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
4241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (badCharIter != name.entry.end()) {
425e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "resource '"
4271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' has invalid entry name '"
4291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name.entry
4301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'. Invalid character '"
4311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << StringPiece16(badCharIter, 1)
4321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "'");
4336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findOrCreatePackage(name.package);
4371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
438e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but package '"
4441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << package->name
4451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
4461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) package->id.value() << std::dec);
4476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findOrCreateType(name.type);
4511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
452e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but type '"
4581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << type->type
4591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' already has ID "
4601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << std::hex << (int) type->id.value() << std::dec);
4616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findOrCreateEntry(name.entry);
4651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
466e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski        diag->error(DiagMessage(symbol.source)
4671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "trying to add resource '"
4681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << name
4691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << "' with ID "
4701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << resId
4711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << " but resource already has ID "
4721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    << ResourceId(package->id.value(), type->id.value(), entry->id.value()));
4736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return false;
4746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
4756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
476a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (resId.isValid()) {
477a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        package->id = resId.packageId();
478a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        type->id = resId.typeId();
479a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        entry->id = resId.entryId();
480a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    }
481a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
4829e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    // Only mark the type state as public, it doesn't care about being private.
483e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski    if (symbol.state == SymbolState::kPublic) {
4849e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski        type->symbolStatus.state = SymbolState::kPublic;
4859e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    }
4869e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski
487a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (symbol.state == SymbolState::kUndefined &&
488a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski            entry->symbolStatus.state != SymbolState::kUndefined) {
489a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        // We can't undefine a symbol (remove its visibility). Ignore.
490a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        return true;
4919e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski    }
4926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
493a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    if (symbol.state == SymbolState::kPrivate &&
494a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski            entry->symbolStatus.state == SymbolState::kPublic) {
495a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        // We can't downgrade public to private. Ignore.
496a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski        return true;
497769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
498a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
499a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski    entry->symbolStatus = std::move(symbol);
500769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return true;
501769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
502769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
5031ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiMaybe<ResourceTable::SearchResult>
5041ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceTable::findResource(const ResourceNameRef& name) {
5051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTablePackage* package = findPackage(name.package);
5061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!package) {
507ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceTableType* type = package->findType(name.type);
5111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!type) {
512ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ResourceEntry* entry = type->findEntry(name.entry);
5161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!entry) {
517ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski        return {};
5186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
5191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return SearchResult{ package, type, entry };
5206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt
523