AAPT2: Record public status in a more robust way

This allows us to store the source and comments of a resource's
public declaration and avoids issues where there is no default
configuration for a publicly declared resource (like with drawables
of various densities) and AAPT2 mistakenly took this as an error.

Change-Id: I07a2fe9f551daefcce842f205fb219d2fa453ebc
diff --git a/tools/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp
index bad5aa5..d16f63b 100644
--- a/tools/aapt2/BinaryResourceParser.cpp
+++ b/tools/aapt2/BinaryResourceParser.cpp
@@ -396,6 +396,12 @@
             }
             break;
 
+        case RES_TABLE_PUBLIC_TYPE:
+            if (!parsePublic(parser.getChunk())) {
+                return false;
+            }
+            break;
+
         default:
             Logger::warn(mSource)
                     << "unexpected chunk of type "
@@ -429,6 +435,55 @@
     return true;
 }
 
+bool BinaryResourceParser::parsePublic(const ResChunk_header* chunk) {
+    const Public_header* header = convertTo<Public_header>(chunk);
+
+    if (header->typeId == 0) {
+        Logger::error(mSource)
+                << "invalid type ID " << header->typeId << std::endl;
+        return false;
+    }
+
+    const ResourceType* parsedType = parseResourceType(util::getString(mTypePool,
+                                                                       header->typeId - 1));
+    if (!parsedType) {
+        Logger::error(mSource)
+                << "invalid type " << util::getString(mTypePool, header->typeId - 1) << std::endl;
+        return false;
+    }
+
+    const uintptr_t chunkEnd = reinterpret_cast<uintptr_t>(chunk) + chunk->size;
+    const Public_entry* entry = reinterpret_cast<const Public_entry*>(
+            getChunkData(header->header));
+    for (uint32_t i = 0; i < header->count; i++) {
+        if (reinterpret_cast<uintptr_t>(entry) + sizeof(*entry) > chunkEnd) {
+            Logger::error(mSource)
+                    << "Public_entry extends beyond chunk."
+                    << std::endl;
+            return false;
+        }
+
+        const ResourceId resId = { mTable->getPackageId(), header->typeId, entry->entryId };
+        const ResourceName name = {
+                mTable->getPackage(),
+                *parsedType,
+                util::getString(mKeyPool, entry->key.index).toString() };
+
+        SourceLine source;
+        if (mSourcePool.getError() == NO_ERROR) {
+            source.path = util::utf16ToUtf8(util::getString(mSourcePool, entry->source.index));
+            source.line = entry->sourceLine;
+        }
+
+        if (!mTable->markPublic(name, resId, source)) {
+            return false;
+        }
+
+        entry++;
+    }
+    return true;
+}
+
 bool BinaryResourceParser::parseTypeSpec(const ResChunk_header* chunk) {
     if (mTypePool.getError() != NO_ERROR) {
         Logger::error(mSource)
@@ -636,10 +691,6 @@
         return util::make_unique<BinaryPrimitive>(nullType);
     }
 
-    if (value->dataType == ExtendedTypes::TYPE_SENTINEL) {
-        return util::make_unique<Sentinel>();
-    }
-
     if (value->dataType == ExtendedTypes::TYPE_RAW_STRING) {
         return util::make_unique<RawString>(
                 mTable->getValueStringPool().makeRef(util::getString(mValuePool, value->data),