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)29bool 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