AAPT2

First checking of AAPT2. The individual phases of AAPT2 work, but there
are some missing pieces.

For early testing we are missing:
- Need to properly mark file references and include them in package
- Need to package into zip

Final AAPT for apps we are missing:
- Need to crush PNGs
- Need to parse 9-patches
- Need to validate all of AndroidManifest.xml
- Need to write align method to align resource tables for splits.

Final AAPT for apps + system we are missing:
- Need to handle overlays
- Need to store comments for R file
- Need to handle --shared-lib (dynamic references too).

New AAPT features coming:
- Need to import compiled libraries
    - Name mangling
    - R file generation for library code

Change-Id: I95f8a63581b81a1f424ae6fb2c373c883b72c18d
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
new file mode 100644
index 0000000..0b3dd78
--- /dev/null
+++ b/tools/aapt2/ResourceTable.cpp
@@ -0,0 +1,334 @@
+/*
+ * 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 "ConfigDescription.h"
+#include "Logger.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <androidfw/ResourceTypes.h>
+#include <memory>
+#include <string>
+#include <tuple>
+
+namespace aapt {
+
+static bool compareConfigs(const ResourceConfigValue& lhs, const ConfigDescription& rhs) {
+    return lhs.config < rhs;
+}
+
+static bool lessThanType(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
+    return lhs->type < rhs;
+}
+
+static bool lessThanEntry(const std::unique_ptr<ResourceEntry>& lhs, const StringPiece16& rhs) {
+    return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
+}
+
+ResourceTable::ResourceTable() : mPackageId(kUnsetPackageId) {
+}
+
+std::unique_ptr<ResourceTableType>& ResourceTable::findOrCreateType(ResourceType type) {
+    auto last = mTypes.end();
+    auto iter = std::lower_bound(mTypes.begin(), last, type, lessThanType);
+    if (iter != last) {
+        if ((*iter)->type == type) {
+            return *iter;
+        }
+    }
+    return *mTypes.emplace(iter, new ResourceTableType{ type });
+}
+
+std::unique_ptr<ResourceEntry>& ResourceTable::findOrCreateEntry(
+        std::unique_ptr<ResourceTableType>& type, const StringPiece16& name) {
+    auto last = type->entries.end();
+    auto iter = std::lower_bound(type->entries.begin(), last, name, lessThanEntry);
+    if (iter != last) {
+        if (name == (*iter)->name) {
+            return *iter;
+        }
+    }
+    return *type->entries.emplace(iter, new ResourceEntry{ name });
+}
+
+struct IsAttributeVisitor : ConstValueVisitor {
+    bool isAttribute = false;
+
+    void visit(const Attribute&, ValueVisitorArgs&) override {
+        isAttribute = true;
+    }
+
+    operator bool() {
+        return isAttribute;
+    }
+};
+
+/**
+ * The default handler for collisions. A return value of -1 means keep the
+ * existing value, 0 means fail, and +1 means take the incoming value.
+ */
+static int defaultCollisionHandler(const Value& existing, const Value& incoming) {
+    IsAttributeVisitor existingIsAttr, incomingIsAttr;
+    existing.accept(existingIsAttr, {});
+    incoming.accept(incomingIsAttr, {});
+
+    if (!incomingIsAttr) {
+        if (incoming.isWeak()) {
+            // We're trying to add a weak resource but a resource
+            // already exists. Keep the existing.
+            return -1;
+        } else if (existing.isWeak()) {
+            // Override the weak resource with the new strong resource.
+            return 1;
+        }
+        // The existing and incoming values are strong, this is an error
+        // if the values are not both attributes.
+        return 0;
+    }
+
+    if (!existingIsAttr) {
+        if (existing.isWeak()) {
+            // The existing value is not an attribute and it is weak,
+            // so take the incoming attribute value.
+            return 1;
+        }
+        // The existing value is not an attribute and it is strong,
+        // so the incoming attribute value is an error.
+        return 0;
+    }
+
+    //
+    // Attribute specific handling. At this point we know both
+    // values are attributes. Since we can declare and define
+    // attributes all-over, we do special handling to see
+    // which definition sticks.
+    //
+    const Attribute& existingAttr = static_cast<const Attribute&>(existing);
+    const Attribute& incomingAttr = static_cast<const Attribute&>(incoming);
+    if (existingAttr.typeMask == incomingAttr.typeMask) {
+        // The two attributes are both DECLs, but they are plain attributes
+        // with the same formats.
+        // Keep the strongest one.
+        return existingAttr.isWeak() ? 1 : -1;
+    }
+
+    if (existingAttr.isWeak() && existingAttr.typeMask == android::ResTable_map::TYPE_ANY) {
+        // Any incoming attribute is better than this.
+        return 1;
+    }
+
+    if (incomingAttr.isWeak() && incomingAttr.typeMask == android::ResTable_map::TYPE_ANY) {
+        // The incoming attribute may be a USE instead of a DECL.
+        // Keep the existing attribute.
+        return -1;
+    }
+    return 0;
+}
+
+static constexpr const char16_t* kValidNameChars = u"._-";
+
+bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
+        const ConfigDescription& config, const SourceLine& source,
+        std::unique_ptr<Value> value) {
+    if (!name.package.empty() && name.package != mPackage) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has incompatible package. Must be '"
+                << mPackage
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, kValidNameChars);
+    if (badCharIter != name.entry.end()) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has invalid entry name '"
+                << name.entry
+                << "'. Invalid character '"
+                << *badCharIter
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
+    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
+            type->typeId != resId.typeId()) {
+        Logger::error(source)
+                << "trying to add resource '"
+                << name
+                << "' with ID "
+                << resId
+                << " but type '"
+                << type->type
+                << "' already has ID "
+                << std::hex << type->typeId << std::dec
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
+    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
+            entry->entryId != resId.entryId()) {
+        Logger::error(source)
+                << "trying to add resource '"
+                << name
+                << "' with ID "
+                << resId
+                << " but resource already has ID "
+                << ResourceId(mPackageId, type->typeId, entry->entryId)
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    const auto endIter = std::end(entry->values);
+    auto iter = std::lower_bound(std::begin(entry->values), endIter, config, compareConfigs);
+    if (iter == endIter || iter->config != config) {
+        // This resource did not exist before, add it.
+        entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) });
+    } else {
+        int collisionResult = defaultCollisionHandler(*iter->value, *value);
+        if (collisionResult > 0) {
+            // Take the incoming value.
+            *iter = ResourceConfigValue{ config, source, {}, std::move(value) };
+        } else if (collisionResult == 0) {
+            Logger::error(source)
+                    << "duplicate value for resource '" << name << "' "
+                    << "with config '" << iter->config << "'."
+                    << std::endl;
+
+            Logger::error(iter->source)
+                    << "resource previously defined here."
+                    << std::endl;
+            return false;
+        }
+    }
+
+    if (resId.isValid()) {
+        type->typeId = resId.typeId();
+        entry->entryId = resId.entryId();
+    }
+    return true;
+}
+
+bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
+                                const SourceLine& source, std::unique_ptr<Value> value) {
+    return addResource(name, ResourceId{}, config, source, std::move(value));
+}
+
+bool ResourceTable::markPublic(const ResourceNameRef& name, const ResourceId resId,
+                               const SourceLine& source) {
+    if (!name.package.empty() && name.package != mPackage) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has incompatible package. Must be '"
+                << mPackage
+                << "'."
+            << std::endl;
+        return false;
+    }
+
+    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, kValidNameChars);
+    if (badCharIter != name.entry.end()) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has invalid entry name '"
+                << name.entry
+                << "'. Invalid character '"
+                << *badCharIter
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
+    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
+            type->typeId != resId.typeId()) {
+        Logger::error(source)
+                << "trying to make resource '"
+                << name
+                << "' public with ID "
+                << resId
+                << " but type '"
+                << type->type
+                << "' already has ID "
+                << std::hex << type->typeId << std::dec
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
+    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
+            entry->entryId != resId.entryId()) {
+        Logger::error(source)
+                << "trying to make resource '"
+                << name
+                << "' public with ID "
+                << resId
+                << " but resource already has ID "
+                << ResourceId(mPackageId, type->typeId, entry->entryId)
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    type->publicStatus.isPublic = true;
+    entry->publicStatus.isPublic = true;
+
+    if (resId.isValid()) {
+        type->typeId = resId.typeId();
+        entry->entryId = resId.entryId();
+    }
+
+    if (entry->values.empty()) {
+        entry->values.push_back(ResourceConfigValue{ {}, source, {},
+                                    util::make_unique<Sentinel>() });
+    }
+    return true;
+}
+
+std::tuple<const ResourceTableType*, const ResourceEntry*>
+ResourceTable::findResource(const ResourceNameRef& name) const {
+    if (name.package != mPackage) {
+        return {nullptr, nullptr};
+    }
+
+    auto iter = std::lower_bound(mTypes.begin(), mTypes.end(), name.type, lessThanType);
+    if (iter == mTypes.end() || (*iter)->type != name.type) {
+        return {nullptr, nullptr};
+    }
+
+    const std::unique_ptr<ResourceTableType>& type = *iter;
+    auto iter2 = std::lower_bound(type->entries.begin(), type->entries.end(), name.entry,
+                                  lessThanEntry);
+    if (iter2 == type->entries.end() || name.entry != (*iter2)->name) {
+        return {nullptr, nullptr};
+    }
+    return {iter->get(), iter2->get()};
+}
+
+} // namespace aapt