summaryrefslogtreecommitdiff
path: root/tools/aapt2/compile/IdAssigner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt2/compile/IdAssigner.cpp')
-rw-r--r--tools/aapt2/compile/IdAssigner.cpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
new file mode 100644
index 000000000000..80c6bbc1abca
--- /dev/null
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceTable.h"
+
+#include "compile/IdAssigner.h"
+#include "process/IResourceTableConsumer.h"
+#include "util/Util.h"
+
+#include <bitset>
+#include <cassert>
+#include <set>
+
+namespace aapt {
+
+bool IdAssigner::consume(IAaptContext* context, ResourceTable* table) {
+ std::bitset<256> usedTypeIds;
+ std::set<uint16_t> usedEntryIds;
+
+ for (auto& package : table->packages) {
+ assert(package->id && "packages must have manually assigned IDs");
+
+ usedTypeIds.reset();
+
+ // Type ID 0 is invalid, reserve it.
+ usedTypeIds.set(0);
+
+ // Collect used type IDs.
+ for (auto& type : package->types) {
+ if (type->id) {
+ usedEntryIds.clear();
+
+ if (usedTypeIds[type->id.value()]) {
+ // This ID is already taken!
+ context->getDiagnostics()->error(DiagMessage()
+ << "type '" << type->type << "' in "
+ << "package '" << package->name << "' has "
+ << "duplicate ID "
+ << std::hex << (int) type->id.value()
+ << std::dec);
+ return false;
+ }
+
+ // Mark the type ID as taken.
+ usedTypeIds.set(type->id.value());
+ }
+
+ // Collect used entry IDs.
+ for (auto& entry : type->entries) {
+ if (entry->id) {
+ // Mark entry ID as taken.
+ if (!usedEntryIds.insert(entry->id.value()).second) {
+ // This ID existed before!
+ ResourceNameRef nameRef =
+ { package->name, type->type, entry->name };
+ ResourceId takenId(package->id.value(), type->id.value(),
+ entry->id.value());
+ context->getDiagnostics()->error(DiagMessage()
+ << "resource '" << nameRef << "' "
+ << "has duplicate ID '"
+ << takenId << "'");
+ return false;
+ }
+ }
+ }
+
+ // Assign unused entry IDs.
+ const auto endUsedEntryIter = usedEntryIds.end();
+ auto nextUsedEntryIter = usedEntryIds.begin();
+ uint16_t nextId = 0;
+ for (auto& entry : type->entries) {
+ if (!entry->id) {
+ // Assign the next available entryID.
+ while (nextUsedEntryIter != endUsedEntryIter &&
+ nextId == *nextUsedEntryIter) {
+ nextId++;
+ ++nextUsedEntryIter;
+ }
+ entry->id = nextId++;
+ }
+ }
+ }
+
+ // Assign unused type IDs.
+ size_t nextTypeId = 0;
+ for (auto& type : package->types) {
+ if (!type->id) {
+ while (nextTypeId < usedTypeIds.size() && usedTypeIds[nextTypeId]) {
+ nextTypeId++;
+ }
+ type->id = static_cast<uint8_t>(nextTypeId);
+ nextTypeId++;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace aapt