1e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski/*
2e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * Copyright (C) 2016 The Android Open Source Project
3e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski *
4e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * you may not use this file except in compliance with the License.
6e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * You may obtain a copy of the License at
7e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski *
8e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski *
10e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * See the License for the specific language governing permissions and
14e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski * limitations under the License.
15e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski */
16e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
17e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski#include "link/ProductFilter.h"
18e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
19e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskinamespace aapt {
20e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
21e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiProductFilter::ResourceConfigValueIter
22e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiProductFilter::selectProductToKeep(const ResourceNameRef& name,
23e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                   const ResourceConfigValueIter begin,
24e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                   const ResourceConfigValueIter end,
25e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                   IDiagnostics* diag) {
26e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    ResourceConfigValueIter defaultProductIter = end;
27e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    ResourceConfigValueIter selectedProductIter = end;
28e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
29e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    for (ResourceConfigValueIter iter = begin; iter != end; ++iter) {
30e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        ResourceConfigValue* configValue = iter->get();
31e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (mProducts.find(configValue->product) != mProducts.end()) {
32e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            if (selectedProductIter != end) {
33e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                // We have two possible values for this product!
34e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                diag->error(DiagMessage(configValue->value->getSource())
35e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            << "selection of product '" << configValue->product
36e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            << "' for resource " << name << " is ambiguous");
37e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
38e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                ResourceConfigValue* previouslySelectedConfigValue = selectedProductIter->get();
39e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                diag->note(DiagMessage(previouslySelectedConfigValue->value->getSource())
40e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           << "product '" << previouslySelectedConfigValue->product
41e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           << "' is also a candidate");
42e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                return end;
43e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            }
44e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
45e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            // Select this product.
46e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            selectedProductIter = iter;
47e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
48e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
49e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (configValue->product.empty() || configValue->product == "default") {
50e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            if (defaultProductIter != end) {
51e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                // We have two possible default values.
52e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                diag->error(DiagMessage(configValue->value->getSource())
53e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            << "multiple default products defined for resource " << name);
54e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
55e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                ResourceConfigValue* previouslyDefaultConfigValue = defaultProductIter->get();
56e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                diag->note(DiagMessage(previouslyDefaultConfigValue->value->getSource())
57e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                           << "default product also defined here");
58e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                return end;
59e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            }
60e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
61e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            // Mark the default.
62e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            defaultProductIter = iter;
63e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
64e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
65e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
66e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (defaultProductIter == end) {
67e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        diag->error(DiagMessage() << "no default product defined for resource " << name);
68e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        return end;
69e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
70e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
71e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    if (selectedProductIter == end) {
72e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        selectedProductIter = defaultProductIter;
73e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
74e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return selectedProductIter;
75e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
76e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
77e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinskibool ProductFilter::consume(IAaptContext* context, ResourceTable* table) {
78e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    bool error = false;
79e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    for (auto& pkg : table->packages) {
80e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        for (auto& type : pkg->types) {
81e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            for (auto& entry : type->entries) {
82e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                std::vector<std::unique_ptr<ResourceConfigValue>> newValues;
83e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
84e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                ResourceConfigValueIter iter = entry->values.begin();
85e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                ResourceConfigValueIter startRangeIter = iter;
86e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                while (iter != entry->values.end()) {
87e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    ++iter;
88e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    if (iter == entry->values.end() ||
89e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            (*iter)->config != (*startRangeIter)->config) {
90e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
91e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        // End of the array, or we saw a different config,
92e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        // so this must be the end of a range of products.
93e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        // Select the product to keep from the set of products defined.
94e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        ResourceNameRef name(pkg->name, type->type, entry->name);
95e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        auto valueToKeep = selectProductToKeep(name, startRangeIter, iter,
96e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                                               context->getDiagnostics());
97e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        if (valueToKeep == iter) {
98e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            // An error occurred, we could not pick a product.
99e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            error = true;
100e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        } else {
101e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            // We selected a product to keep. Move it to the new array.
102e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            newValues.push_back(std::move(*valueToKeep));
103e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        }
104e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
105e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        // Start the next range of products.
106e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                        startRangeIter = iter;
107e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    }
108e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                }
109e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
110e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                // Now move the new values in to place.
111e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                entry->values = std::move(newValues);
112e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            }
113e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
114e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
115e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    return !error;
116e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski}
117e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski
118e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski} // namespace aapt
119