1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ResourceTable.h"
18 
19 #include "compile/IdAssigner.h"
20 #include "process/IResourceTableConsumer.h"
21 #include "util/Util.h"
22 
23 #include <bitset>
24 #include <cassert>
25 #include <set>
26 
27 namespace aapt {
28 
consume(IAaptContext * context,ResourceTable * table)29 bool IdAssigner::consume(IAaptContext* context, ResourceTable* table) {
30     std::bitset<256> usedTypeIds;
31     std::set<uint16_t> usedEntryIds;
32 
33     for (auto& package : table->packages) {
34         assert(package->id && "packages must have manually assigned IDs");
35 
36         usedTypeIds.reset();
37 
38         // Type ID 0 is invalid, reserve it.
39         usedTypeIds.set(0);
40 
41         // Collect used type IDs.
42         for (auto& type : package->types) {
43             if (type->id) {
44                 usedEntryIds.clear();
45 
46                 if (usedTypeIds[type->id.value()]) {
47                     // This ID is already taken!
48                     context->getDiagnostics()->error(DiagMessage()
49                                                      << "type '" << type->type << "' in "
50                                                      << "package '" << package->name << "' has "
51                                                      << "duplicate ID "
52                                                      << std::hex << (int) type->id.value()
53                                                      << std::dec);
54                     return false;
55                 }
56 
57                 // Mark the type ID as taken.
58                 usedTypeIds.set(type->id.value());
59             }
60 
61             // Collect used entry IDs.
62             for (auto& entry : type->entries) {
63                 if (entry->id) {
64                     // Mark entry ID as taken.
65                     if (!usedEntryIds.insert(entry->id.value()).second) {
66                         // This ID existed before!
67                         ResourceNameRef nameRef(package->name, type->type, entry->name);
68                         context->getDiagnostics()->error(DiagMessage()
69                                                          << "resource '" << nameRef << "' "
70                                                          << "has duplicate entry ID "
71                                                          << std::hex << (int) entry->id.value()
72                                                          << std::dec);
73                         return false;
74                     }
75                 }
76             }
77 
78             // Assign unused entry IDs.
79             const auto endUsedEntryIter = usedEntryIds.end();
80             auto nextUsedEntryIter = usedEntryIds.begin();
81             uint16_t nextId = 0;
82             for (auto& entry : type->entries) {
83                 if (!entry->id) {
84                     // Assign the next available entryID.
85                     while (nextUsedEntryIter != endUsedEntryIter &&
86                             nextId == *nextUsedEntryIter) {
87                         nextId++;
88                         ++nextUsedEntryIter;
89                     }
90                     entry->id = nextId++;
91                 }
92             }
93         }
94 
95         // Assign unused type IDs.
96         size_t nextTypeId = 0;
97         for (auto& type : package->types) {
98             if (!type->id) {
99                 while (nextTypeId < usedTypeIds.size() && usedTypeIds[nextTypeId]) {
100                     nextTypeId++;
101                 }
102                 type->id = static_cast<uint8_t>(nextTypeId);
103                 nextTypeId++;
104             }
105         }
106     }
107     return true;
108 }
109 
110 } // namespace aapt
111