AAPT2: Add support to specify stable IDs

The --stable-ids flag allows the user to specify a file containing
a list of resource name and resource ID pairs in the form of:

package:type/name = 0xPPTTEEEE

This assigns the given resource the specified ID. It helps ensure
that when adding or removing resources, IDs are assigned in a stable
fashion.

If a package, type, or name is not found, no error or warning is
raised.

Change-Id: Ibc2f4e05cc924be255fedd862d835cb5b18d7584
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 45d3db9..a144c6a 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -589,17 +589,14 @@
 
     outResource->name.type = *parsedType;
 
-    if (Maybe<StringPiece> maybeId = xml::findNonEmptyAttribute(parser, "id")) {
-        android::Res_value val;
-        std::u16string idStr16 = util::utf8ToUtf16(maybeId.value());
-        bool result = android::ResTable::stringToInt(idStr16.data(), idStr16.size(), &val);
-        ResourceId resourceId(val.data);
-        if (!result || !resourceId.isValid()) {
+    if (Maybe<StringPiece> maybeIdStr = xml::findNonEmptyAttribute(parser, "id")) {
+        Maybe<ResourceId> maybeId = ResourceUtils::tryParseResourceId(maybeIdStr.value());
+        if (!maybeId) {
             mDiag->error(DiagMessage(outResource->source)
                          << "invalid resource ID '" << maybeId.value() << "' in <public>");
             return false;
         }
-        outResource->id = resourceId;
+        outResource->id = maybeId.value();
     }
 
     if (*parsedType == ResourceType::kId) {
@@ -626,23 +623,22 @@
         return false;
     }
 
-    Maybe<StringPiece> maybeId = xml::findNonEmptyAttribute(parser, "first-id");
-    if (!maybeId) {
+    Maybe<StringPiece> maybeIdStr = xml::findNonEmptyAttribute(parser, "first-id");
+    if (!maybeIdStr) {
         mDiag->error(DiagMessage(outResource->source)
                      << "<public-group> must have a 'first-id' attribute");
         return false;
     }
 
-    android::Res_value val;
-    std::u16string idStr16 = util::utf8ToUtf16(maybeId.value());
-    bool result = android::ResTable::stringToInt(idStr16.data(), idStr16.size(), &val);
-    ResourceId nextId(val.data);
-    if (!result || !nextId.isValid()) {
+    Maybe<ResourceId> maybeId = ResourceUtils::tryParseResourceId(maybeIdStr.value());
+    if (!maybeId) {
         mDiag->error(DiagMessage(outResource->source)
-                     << "invalid resource ID '" << maybeId.value() << "' in <public-group>");
+                     << "invalid resource ID '" << maybeIdStr.value() << "' in <public-group>");
         return false;
     }
 
+    ResourceId nextId = maybeId.value();
+
     std::string comment;
     bool error = false;
     const size_t depth = parser->getDepth();