Support multiple resource tables with same package

In order to support APK split features, the resource
table needs to support loading multiple resource
tables with the same package but potentially new set
of type IDs.

This adds some complexity as the type ID space changes
from dense and ordered to potentially sparse.

A ByteBucketArray is used to store the type IDs in
a memory efficient way that allows for fast retrieval.

In addition, the IDMAP format has changed. We no longer
need random access to the type data, since we store the
types differently. However, random access to entries of
a given type is still required.

Change-Id: If6f5be680b405b368941d9c1f2b5d2ddca964160
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index d21197e..957809d 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -25,6 +25,7 @@
     ObbFile.cpp \
     ResourceTypes.cpp \
     StreamingZipInflater.cpp \
+    TypeWrappers.cpp \
     ZipFileRO.cpp \
     ZipUtils.cpp
 
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 1b3f1fd..0340928 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -256,7 +256,7 @@
     String8 targetPath;
     String8 overlayPath;
     if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
-                NULL, NULL, &targetPath, &overlayPath)) {
+                NULL, NULL, NULL, &targetPath, &overlayPath)) {
         ALOGW("failed to read idmap file %s\n", idmapPath.string());
         delete idmap;
         return false;
@@ -311,7 +311,7 @@
             ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
             return false;
         }
-        tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */);
+        tables[i].add(ass);
     }
 
     return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
@@ -617,7 +617,7 @@
                     // can quickly copy it out for others.
                     ALOGV("Creating shared resources for %s", ap.path.string());
                     sharedRes = new ResTable();
-                    sharedRes->add(ass, i + 1, false, idmap);
+                    sharedRes->add(ass, idmap, i + 1, false);
 #ifdef HAVE_ANDROID_OS
                     const char* data = getenv("ANDROID_DATA");
                     LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
@@ -646,7 +646,7 @@
                 mResources->add(sharedRes);
             } else {
                 ALOGV("Parsing resources for %s", ap.path.string());
-                mResources->add(ass, i + 1, !shared, idmap);
+                mResources->add(ass, idmap, i + 1, !shared);
             }
             onlyEmptyResources = false;
 
@@ -654,7 +654,7 @@
                 delete ass;
             }
         } else {
-            ALOGW("Installing empty resources in to table %p\n", mResources);
+            ALOGV("Installing empty resources in to table %p\n", mResources);
             mResources->addEmpty(i + 1);
         }
 
@@ -736,7 +736,7 @@
         if (oass != NULL) {
             Asset* oidmap = openIdmapLocked(oap);
             offset++;
-            sharedRes->add(oass, offset + 1, false, oidmap);
+            sharedRes->add(oass, oidmap, offset + 1, false);
             const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
             const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
         }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index a4b78a6..2e3abb5 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -17,7 +17,9 @@
 #define LOG_TAG "ResourceType"
 //#define LOG_NDEBUG 0
 
+#include <androidfw/ByteBucketArray.h>
 #include <androidfw/ResourceTypes.h>
+#include <androidfw/TypeWrappers.h>
 #include <utils/Atomic.h>
 #include <utils/ByteOrder.h>
 #include <utils/Debug.h>
@@ -30,6 +32,7 @@
 #include <memory.h>
 #include <ctype.h>
 #include <stdint.h>
+#include <stddef.h>
 
 #ifndef INT32_MAX
 #define INT32_MAX ((int32_t)(2147483647))
@@ -42,7 +45,7 @@
 #define TABLE_SUPER_NOISY(x) //x
 #define LOAD_TABLE_NOISY(x) //x
 #define TABLE_THEME(x) //x
-#define LIB_NOISY(x) x
+#define LIB_NOISY(x) //x
 
 namespace android {
 
@@ -63,9 +66,8 @@
 #endif
 #endif
 
-#define IDMAP_MAGIC         0x706d6469
-// size measured in sizeof(uint32_t)
-#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+#define IDMAP_MAGIC             0x504D4449
+#define IDMAP_CURRENT_VERSION   0x00000001
 
 #define APP_PACKAGE_ID      0x7f
 #define SYS_PACKAGE_ID      0x01
@@ -77,6 +79,11 @@
     return (c < 0x0080 && isspace(c));
 }
 
+template<typename T>
+inline static T max(T a, T b) {
+    return a > b ? a : b;
+}
+
 // range checked; guaranteed to NUL-terminate within the stated number of available slots
 // NOTE: if this truncates the dst string due to running out of space, no attempt is
 // made to avoid splitting surrogate pairs.
@@ -215,104 +222,179 @@
     fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
 }
 
-static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
-{
-    if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
-        ALOGW("idmap assertion failed: size=%d bytes\n", (int)sizeBytes);
+static bool assertIdmapHeader(const void* idmap, size_t size) {
+    if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
+        ALOGE("idmap: header is not word aligned");
         return false;
     }
-    if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
-        ALOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
-             *map, htodl(IDMAP_MAGIC));
+
+    if (size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+        ALOGW("idmap: header too small (%d bytes)", (uint32_t) size);
+        return false;
+    }
+
+    const uint32_t magic = htodl(*reinterpret_cast<const uint32_t*>(idmap));
+    if (magic != IDMAP_MAGIC) {
+        ALOGW("idmap: no magic found in header (is 0x%08x, expected 0x%08x)",
+             magic, IDMAP_MAGIC);
+        return false;
+    }
+
+    const uint32_t version = htodl(*(reinterpret_cast<const uint32_t*>(idmap) + 1));
+    if (version != IDMAP_CURRENT_VERSION) {
+        // We are strict about versions because files with this format are
+        // auto-generated and don't need backwards compatibility.
+        ALOGW("idmap: version mismatch in header (is 0x%08x, expected 0x%08x)",
+                version, IDMAP_CURRENT_VERSION);
         return false;
     }
     return true;
 }
 
-static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
-{
-    // see README for details on the format of map
-    if (!assertIdmapHeader(map, sizeBytes)) {
-        return UNKNOWN_ERROR;
-    }
-    map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
-    // size of data block, in uint32_t
-    const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
-    const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
-    const uint32_t entry = Res_GETENTRY(key);
-    const uint32_t typeCount = *map;
+class IdmapEntries {
+public:
+    IdmapEntries() : mData(NULL) {}
 
-    if (type > typeCount) {
-        ALOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
-        return UNKNOWN_ERROR;
-    }
-    if (typeCount > size) {
-        ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, (int)size);
-        return UNKNOWN_ERROR;
-    }
-    const uint32_t typeOffset = map[type];
-    if (typeOffset == 0) {
-        *outValue = 0;
-        return NO_ERROR;
-    }
-    if (typeOffset + 1 > size) {
-        ALOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
-             typeOffset, (int)size);
-        return UNKNOWN_ERROR;
-    }
-    const uint32_t entryCount = map[typeOffset];
-    const uint32_t entryOffset = map[typeOffset + 1];
-    if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
-        *outValue = 0;
-        return NO_ERROR;
-    }
-    const uint32_t index = typeOffset + 2 + entry - entryOffset;
-    if (index > size) {
-        ALOGW("Resource ID map: entry index=%u exceeds size of map=%d\n", index, (int)size);
-        *outValue = 0;
-        return NO_ERROR;
-    }
-    *outValue = map[index];
+    bool hasEntries() const {
+        if (mData == NULL) {
+            return false;
+        }
 
-    return NO_ERROR;
-}
+        return (dtohs(*mData) > 0);
+    }
 
-static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
-{
-    if (!assertIdmapHeader(map, mapSize)) {
-        return UNKNOWN_ERROR;
+    size_t byteSize() const {
+        if (mData == NULL) {
+            return 0;
+        }
+        uint16_t entryCount = dtohs(mData[2]);
+        return (sizeof(uint16_t) * 4) + (sizeof(uint32_t) * static_cast<size_t>(entryCount));
     }
-    if (mapSize <= IDMAP_HEADER_SIZE + 1) {
-        ALOGW("corrupt idmap: map size %d too short\n", (int)mapSize);
-        return UNKNOWN_ERROR;
+
+    uint8_t targetTypeId() const {
+        if (mData == NULL) {
+            return 0;
+        }
+        return dtohs(mData[0]);
     }
-    uint32_t typeCount = *(map + IDMAP_HEADER_SIZE);
-    if (typeCount == 0) {
-        ALOGW("corrupt idmap: no types\n");
-        return UNKNOWN_ERROR;
+
+    uint8_t overlayTypeId() const {
+        if (mData == NULL) {
+            return 0;
+        }
+        return dtohs(mData[1]);
     }
-    if (IDMAP_HEADER_SIZE + 1 + typeCount > mapSize) {
-        ALOGW("corrupt idmap: number of types %u extends past idmap size %d\n", typeCount, (int)mapSize);
-        return UNKNOWN_ERROR;
-    }
-    const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
-    // find first defined type
-    while (*p == 0) {
-        ++p;
-        if (--typeCount == 0) {
-            ALOGW("corrupt idmap: types declared, none found\n");
+
+    status_t setTo(const void* entryHeader, size_t size) {
+        if (reinterpret_cast<uintptr_t>(entryHeader) & 0x03) {
+            ALOGE("idmap: entry header is not word aligned");
             return UNKNOWN_ERROR;
         }
+
+        if (size < sizeof(uint16_t) * 4) {
+            ALOGE("idmap: entry header is too small (%u bytes)", (uint32_t) size);
+            return UNKNOWN_ERROR;
+        }
+
+        const uint16_t* header = reinterpret_cast<const uint16_t*>(entryHeader);
+        const uint16_t targetTypeId = dtohs(header[0]);
+        const uint16_t overlayTypeId = dtohs(header[1]);
+        if (targetTypeId == 0 || overlayTypeId == 0 || targetTypeId > 255 || overlayTypeId > 255) {
+            ALOGE("idmap: invalid type map (%u -> %u)", targetTypeId, overlayTypeId);
+            return UNKNOWN_ERROR;
+        }
+
+        uint16_t entryCount = dtohs(header[2]);
+        if (size < sizeof(uint32_t) * (entryCount + 2)) {
+            ALOGE("idmap: too small (%u bytes) for the number of entries (%u)",
+                    (uint32_t) size, (uint32_t) entryCount);
+            return UNKNOWN_ERROR;
+        }
+        mData = header;
+        return NO_ERROR;
     }
 
-    // determine package id from first entry of first type
-    const uint32_t offset = *p + IDMAP_HEADER_SIZE + 2;
-    if (offset > mapSize) {
-        ALOGW("corrupt idmap: entry offset %u points outside map size %d\n", offset, (int)mapSize);
+    status_t lookup(uint16_t entryId, uint16_t* outEntryId) const {
+        uint16_t entryCount = dtohs(mData[2]);
+        uint16_t offset = dtohs(mData[3]);
+
+        if (entryId < offset) {
+            // The entry is not present in this idmap
+            return BAD_INDEX;
+        }
+
+        entryId -= offset;
+
+        if (entryId >= entryCount) {
+            // The entry is not present in this idmap
+            return BAD_INDEX;
+        }
+
+        // It is safe to access the type here without checking the size because
+        // we have checked this when it was first loaded.
+        const uint32_t* entries = reinterpret_cast<const uint32_t*>(mData) + 2;
+        uint32_t mappedEntry = dtohl(entries[entryId]);
+        if (mappedEntry == 0xffffffff) {
+            // This entry is not present in this idmap
+            return BAD_INDEX;
+        }
+        *outEntryId = static_cast<uint16_t>(mappedEntry);
+        return NO_ERROR;
+    }
+
+private:
+    const uint16_t* mData;
+};
+
+status_t parseIdmap(const void* idmap, size_t size, uint8_t* outPackageId, KeyedVector<uint8_t, IdmapEntries>* outMap) {
+    if (!assertIdmapHeader(idmap, size)) {
         return UNKNOWN_ERROR;
     }
-    *outId = (map[offset] >> 24) & 0x000000ff;
 
+    size -= ResTable::IDMAP_HEADER_SIZE_BYTES;
+    if (size < sizeof(uint16_t) * 2) {
+        ALOGE("idmap: too small to contain any mapping");
+        return UNKNOWN_ERROR;
+    }
+
+    const uint16_t* data = reinterpret_cast<const uint16_t*>(
+            reinterpret_cast<const uint8_t*>(idmap) + ResTable::IDMAP_HEADER_SIZE_BYTES);
+
+    uint16_t targetPackageId = dtohs(*(data++));
+    if (targetPackageId == 0 || targetPackageId > 255) {
+        ALOGE("idmap: target package ID is invalid (%02x)", targetPackageId);
+        return UNKNOWN_ERROR;
+    }
+
+    uint16_t mapCount = dtohs(*(data++));
+    if (mapCount == 0) {
+        ALOGE("idmap: no mappings");
+        return UNKNOWN_ERROR;
+    }
+
+    if (mapCount > 255) {
+        ALOGW("idmap: too many mappings. Only 255 are possible but %u are present", (uint32_t) mapCount);
+    }
+
+    while (size > sizeof(uint16_t) * 4) {
+        IdmapEntries entries;
+        status_t err = entries.setTo(data, size);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        ssize_t index = outMap->add(entries.overlayTypeId(), entries);
+        if (index < 0) {
+            return NO_MEMORY;
+        }
+
+        data += entries.byteSize() / sizeof(uint16_t);
+        size -= entries.byteSize();
+    }
+
+    if (outPackageId != NULL) {
+        *outPackageId = static_cast<uint8_t>(targetPackageId);
+    }
     return NO_ERROR;
 }
 
@@ -2726,7 +2808,7 @@
         free(resourceIDMap);
     }
 
-    ResTable* const                 owner;
+    const ResTable* const           owner;
     void*                           ownedData;
     const ResTable_header*          header;
     size_t                          size;
@@ -2739,6 +2821,17 @@
     size_t                          resourceIDMapSize;
 };
 
+struct ResTable::Entry {
+    ResTable_config config;
+    const ResTable_entry* entry;
+    const ResTable_type* type;
+    uint32_t specFlags;
+    const Package* package;
+
+    StringPoolRef typeStr;
+    StringPoolRef keyStr;
+};
+
 struct ResTable::Type
 {
     Type(const Header* _header, const Package* _package, size_t count)
@@ -2749,33 +2842,29 @@
     const size_t                    entryCount;
     const ResTable_typeSpec*        typeSpec;
     const uint32_t*                 typeSpecFlags;
+    IdmapEntries                    idmapEntries;
     Vector<const ResTable_type*>    configs;
 };
 
 struct ResTable::Package
 {
     Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
-        : owner(_owner), header(_header), package(_package) { }
-    ~Package()
-    {
-        size_t i = types.size();
-        while (i > 0) {
-            i--;
-            delete types[i];
+        : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
+        if (dtohs(package->header.headerSize) == sizeof(package)) {
+            // The package structure is the same size as the definition.
+            // This means it contains the typeIdOffset field.
+            typeIdOffset = package->typeIdOffset;
         }
     }
 
-    ResTable* const                 owner;
+    const ResTable* const           owner;
     const Header* const             header;
     const ResTable_package* const   package;
-    Vector<Type*>                   types;
 
     ResStringPool                   typeStrings;
     ResStringPool                   keyStrings;
 
-    const Type* getType(size_t idx) const {
-        return idx < types.size() ? types[idx] : NULL;
-    }
+    size_t                          typeIdOffset;
 };
 
 // A group of objects describing a particular resource package.
@@ -2787,13 +2876,24 @@
         : owner(_owner)
         , name(_name)
         , id(_id)
-        , typeCount(0)
+        , largestTypeId(0)
         , bags(NULL)
         , dynamicRefTable(static_cast<uint8_t>(_id))
     { }
 
     ~PackageGroup() {
         clearBagCache();
+        const size_t numTypes = types.size();
+        for (size_t i = 0; i < numTypes; i++) {
+            const TypeList& typeList = types[i];
+            const size_t numInnerTypes = typeList.size();
+            for (size_t j = 0; j < numInnerTypes; j++) {
+                if (typeList[j]->package->owner == owner) {
+                    delete typeList[j];
+                }
+            }
+        }
+
         const size_t N = packages.size();
         for (size_t i=0; i<N; i++) {
             Package* pkg = packages[i];
@@ -2806,17 +2906,15 @@
     void clearBagCache() {
         if (bags) {
             TABLE_NOISY(printf("bags=%p\n", bags));
-            Package* pkg = packages[0];
-            TABLE_NOISY(printf("typeCount=%x\n", typeCount));
-            for (size_t i=0; i<typeCount; i++) {
+            for (size_t i = 0; i < bags->size(); i++) {
                 TABLE_NOISY(printf("type=%d\n", i));
-                const Type* type = pkg->getType(i);
-                if (type != NULL) {
-                    bag_set** typeBags = bags[i];
+                const TypeList& typeList = types[i];
+                if (typeList.isEmpty()) {
+                    bag_set** typeBags = bags->get(i);
                     TABLE_NOISY(printf("typeBags=%p\n", typeBags));
                     if (typeBags) {
-                        TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
-                        const size_t N = type->entryCount;
+                        const size_t N = typeList[0]->entryCount;
+                        TABLE_NOISY(printf("type->entryCount=%x\n", N));
                         for (size_t j=0; j<N; j++) {
                             if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
                                 free(typeBags[j]);
@@ -2825,25 +2923,38 @@
                     }
                 }
             }
-            free(bags);
+            delete bags;
             bags = NULL;
         }
     }
 
-    ResTable* const                 owner;
+    ssize_t findType16(const char16_t* type, size_t len) const {
+        const size_t N = packages.size();
+        for (size_t i = 0; i < N; i++) {
+            ssize_t index = packages[i]->typeStrings.indexOfString(type, len);
+            if (index >= 0) {
+                return index + packages[i]->typeIdOffset;
+            }
+        }
+        return -1;
+    }
+
+    const ResTable* const           owner;
     String16 const                  name;
     uint32_t const                  id;
+
+    // This is mainly used to keep track of the loaded packages
+    // and to clean them up properly. Accessing resources happens from
+    // the 'types' array.
     Vector<Package*>                packages;
 
-    // This is for finding typeStrings and other common package stuff.
-    Package*                        basePackage;
+    ByteBucketArray<TypeList>       types;
 
-    // For quick access.
-    size_t                          typeCount;
+    uint8_t                         largestTypeId;
 
     // Computed attribute bags, first indexed by the type and second
     // by the entry in that type.
-    bag_set***                      bags;
+    ByteBucketArray<bag_set**>*     bags;
 
     // The table mapping dynamic references to resolved references for
     // this package group.
@@ -2879,7 +2990,7 @@
 
 void ResTable::Theme::free_package(package_info* pi)
 {
-    for (size_t j=0; j<pi->numTypes; j++) {
+    for (size_t j = 0; j <= Res_MAXTYPE; j++) {
         theme_entry* te = pi->types[j].entries;
         if (te != NULL) {
             free(te);
@@ -2890,10 +3001,8 @@
 
 ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
 {
-    package_info* newpi = (package_info*)malloc(
-        sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
-    newpi->numTypes = pi->numTypes;
-    for (size_t j=0; j<newpi->numTypes; j++) {
+    package_info* newpi = (package_info*)malloc(sizeof(package_info));
+    for (size_t j = 0; j <= Res_MAXTYPE; j++) {
         size_t cnt = pi->types[j].numEntries;
         newpi->types[j].numEntries = cnt;
         theme_entry* te = pi->types[j].entries;
@@ -2946,17 +3055,14 @@
             curPI = mPackages[pidx];
             if (curPI == NULL) {
                 PackageGroup* const grp = mTable.mPackageGroups[pidx];
-                int cnt = grp->typeCount;
-                curPI = (package_info*)malloc(
-                    sizeof(package_info) + (cnt*sizeof(type_info)));
-                curPI->numTypes = cnt;
-                memset(curPI->types, 0, cnt*sizeof(type_info));
+                curPI = (package_info*)malloc(sizeof(package_info));
+                memset(curPI, 0, sizeof(*curPI));
                 mPackages[pidx] = curPI;
             }
             curType = 0xffffffff;
         }
         if (curType != t) {
-            if (t >= curPI->numTypes) {
+            if (t > Res_MAXTYPE) {
                 ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
                 bag++;
                 continue;
@@ -2965,8 +3071,8 @@
             curEntries = curPI->types[t].entries;
             if (curEntries == NULL) {
                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
-                const Type* type = grp->packages[0]->getType(t);
-                int cnt = type != NULL ? type->entryCount : 0;
+                const TypeList& typeList = grp->types[t];
+                int cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
                 curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
                 memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
                 curPI->types[t].numEntries = cnt;
@@ -2981,8 +3087,8 @@
         }
         theme_entry* curEntry = curEntries + e;
         TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
-                   attrRes, bag->map.value.dataType, bag->map.value.data,
-             curEntry->value.dataType));
+                attrRes, bag->map.value.dataType, bag->map.value.data,
+                curEntry->value.dataType));
         if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
             curEntry->stringBlock = bag->stringBlock;
             curEntry->typeSpecFlags |= bagTypeSpecFlags;
@@ -3057,8 +3163,8 @@
             const package_info* const pi = mPackages[p];
             TABLE_THEME(ALOGI("Found package: %p", pi));
             if (pi != NULL) {
-                TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, pi->numTypes));
-                if (t < pi->numTypes) {
+                TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, Res_MAXTYPE + 1));
+                if (t <= Res_MAXTYPE) {
                     const type_info& ti = pi->types[t];
                     TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries));
                     if (e < ti.numEntries) {
@@ -3120,14 +3226,13 @@
         package_info* pi = mPackages[i];
         if (pi == NULL) continue;
 
-        ALOGI("  Package #0x%02x:\n", (int)(i+1));
-        for (size_t j=0; j<pi->numTypes; j++) {
+        ALOGI("  Package #0x%02x:\n", (int)(i + 1));
+        for (size_t j = 0; j <= Res_MAXTYPE; j++) {
             type_info& ti = pi->types[j];
             if (ti.numEntries == 0) continue;
-
-            ALOGI("    Type #0x%02x:\n", (int)(j+1));
-            for (size_t k=0; k<ti.numEntries; k++) {
-                theme_entry& te = ti.entries[k];
+            ALOGI("    Type #0x%02x:\n", (int)(j + 1));
+            for (size_t k = 0; k < ti.numEntries; k++) {
+                const theme_entry& te = ti.entries[k];
                 if (te.value.dataType == Res_value::TYPE_NULL) continue;
                 ALOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
                      (int)Res_MAKEID(i, j, k),
@@ -3150,7 +3255,7 @@
 {
     memset(&mParams, 0, sizeof(mParams));
     memset(mPackageMap, 0, sizeof(mPackageMap));
-    addInternal(data, size, cookie, copyData, NULL /* idMap */);
+    addInternal(data, size, NULL, 0, cookie, copyData);
     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
     //ALOGI("Creating ResTable %p\n", this);
 }
@@ -3166,21 +3271,45 @@
     return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
 }
 
-status_t ResTable::add(const void* data, size_t size) {
-    return addInternal(data, size, 0 /* cookie */,
-            false /* copyData */, NULL /* idMap */);
+status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
+    return addInternal(data, size, NULL, 0, cookie, copyData);
 }
 
-status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData, const void* idmap)
-{
+status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
+        const int32_t cookie, bool copyData) {
+    return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
+}
+
+status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
         return UNKNOWN_ERROR;
     }
-    size_t size = (size_t)asset->getLength();
-    return addInternal(data, size, cookie, copyData,
-            reinterpret_cast<const Asset*>(idmap));
+
+    return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
+}
+
+status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
+    const void* data = asset->getBuffer(true);
+    if (data == NULL) {
+        ALOGW("Unable to get buffer of resource asset file");
+        return UNKNOWN_ERROR;
+    }
+
+    size_t idmapSize = 0;
+    const void* idmapData = NULL;
+    if (idmapAsset != NULL) {
+        idmapData = idmapAsset->getBuffer(true);
+        if (idmapData == NULL) {
+            ALOGW("Unable to get buffer of idmap asset file");
+            return UNKNOWN_ERROR;
+        }
+        idmapSize = static_cast<size_t>(idmapAsset->getLength());
+    }
+
+    return addInternal(data, static_cast<size_t>(asset->getLength()),
+            idmapData, idmapSize, cookie, copyData);
 }
 
 status_t ResTable::add(ResTable* src)
@@ -3197,8 +3326,16 @@
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
-        pg->basePackage = srcPg->basePackage;
-        pg->typeCount = srcPg->typeCount;
+
+        for (size_t j = 0; j < srcPg->types.size(); j++) {
+            if (srcPg->types[j].isEmpty()) {
+                continue;
+            }
+
+            TypeList& typeList = pg->types.editItemAt(j);
+            typeList.appendVector(srcPg->types[j]);
+        }
+        pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
         mPackageGroups.add(pg);
     }
 
@@ -3224,38 +3361,39 @@
     return (mError=NO_ERROR);
 }
 
-status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie,
-                       bool copyData, const Asset* idmap)
+status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
+        const int32_t cookie, bool copyData)
 {
-    if (!data) return NO_ERROR;
+    if (!data) {
+        return NO_ERROR;
+    }
+
     Header* header = new Header(this);
     header->index = mHeaders.size();
     header->cookie = cookie;
-    if (idmap != NULL) {
-        const size_t idmap_size = idmap->getLength();
-        const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
-        header->resourceIDMap = (uint32_t*)malloc(idmap_size);
+    if (idmapData != NULL) {
+        header->resourceIDMap = (uint32_t*) malloc(idmapDataSize);
         if (header->resourceIDMap == NULL) {
             delete header;
             return (mError = NO_MEMORY);
         }
-        memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
-        header->resourceIDMapSize = idmap_size;
+        memcpy(header->resourceIDMap, idmapData, idmapDataSize);
+        header->resourceIDMapSize = idmapDataSize;
     }
     mHeaders.add(header);
 
     const bool notDeviceEndian = htods(0xf0) != 0xf0;
 
     LOAD_TABLE_NOISY(
-        ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, asset=%p, copy=%d "
-             "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
+        ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, copy=%d "
+             "idmap=%p\n", data, dataSize, cookie, copyData, idmap));
 
     if (copyData || notDeviceEndian) {
-        header->ownedData = malloc(size);
+        header->ownedData = malloc(dataSize);
         if (header->ownedData == NULL) {
             return (mError=NO_MEMORY);
         }
-        memcpy(header->ownedData, data, size);
+        memcpy(header->ownedData, data, dataSize);
         data = header->ownedData;
     }
 
@@ -3265,10 +3403,10 @@
     //     dtohl(header->header->header.size), header->header->header.size);
     LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header));
     if (dtohs(header->header->header.headerSize) > header->size
-            || header->size > size) {
+            || header->size > dataSize) {
         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
              (int)dtohs(header->header->header.headerSize),
-             (int)header->size, (int)size);
+             (int)header->size, (int)dataSize);
         return (mError=BAD_TYPE);
     }
     if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
@@ -3313,16 +3451,8 @@
                      dtohl(header->header->packageCount));
                 return (mError=BAD_TYPE);
             }
-            uint32_t idmap_id = 0;
-            if (idmap != NULL) {
-                uint32_t tmp;
-                if (getIdmapPackageId(header->resourceIDMap,
-                                      header->resourceIDMapSize,
-                                      &tmp) == NO_ERROR) {
-                    idmap_id = tmp;
-                }
-            }
-            if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
+
+            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -3405,46 +3535,38 @@
         ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
         return false;
     }
-    if (grp->packages.size() > 0) {
-        const Package* const package = grp->packages[0];
 
-        const ResTable_type* type;
-        const ResTable_entry* entry;
-        ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
-        if (offset <= 0) {
-            return false;
-        }
-
-        outName->package = grp->name.string();
-        outName->packageLen = grp->name.size();
-        if (allowUtf8) {
-            outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen);
-            outName->name8 = grp->basePackage->keyStrings.string8At(
-                dtohl(entry->key.index), &outName->nameLen);
-        } else {
-            outName->type8 = NULL;
-            outName->name8 = NULL;
-        }
-        if (outName->type8 == NULL) {
-            outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
-            // If we have a bad index for some reason, we should abort.
-            if (outName->type == NULL) {
-                return false;
-            }
-        }
-        if (outName->name8 == NULL) {
-            outName->name = grp->basePackage->keyStrings.stringAt(
-                dtohl(entry->key.index), &outName->nameLen);
-            // If we have a bad index for some reason, we should abort.
-            if (outName->name == NULL) {
-                return false;
-            }
-        }
-
-        return true;
+    Entry entry;
+    status_t err = getEntry(grp, t, e, NULL, &entry);
+    if (err != NO_ERROR) {
+        return false;
     }
 
-    return false;
+    outName->package = grp->name.string();
+    outName->packageLen = grp->name.size();
+    if (allowUtf8) {
+        outName->type8 = entry.typeStr.string8(&outName->typeLen);
+        outName->name8 = entry.keyStr.string8(&outName->nameLen);
+    } else {
+        outName->type8 = NULL;
+        outName->name8 = NULL;
+    }
+    if (outName->type8 == NULL) {
+        outName->type = entry.typeStr.string16(&outName->typeLen);
+        // If we have a bad index for some reason, we should abort.
+        if (outName->type == NULL) {
+            return false;
+        }
+    }
+    if (outName->name8 == NULL) {
+        outName->name = entry.keyStr.string16(&outName->nameLen);
+        // If we have a bad index for some reason, we should abort.
+        if (outName->name == NULL) {
+            return false;
+        }
+    }
+
+    return true;
 }
 
 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
@@ -3471,15 +3593,6 @@
         return BAD_INDEX;
     }
 
-    const Res_value* bestValue = NULL;
-    const Package* bestPackage = NULL;
-    ResTable_config bestItem;
-    memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
-
-    if (outSpecFlags != NULL) *outSpecFlags = 0;
-
-    // Look through all resource packages, starting with the most
-    // recently added.
     const PackageGroup* const grp = mPackageGroups[p];
     if (grp == NULL) {
         ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
@@ -3487,142 +3600,62 @@
     }
 
     // Allow overriding density
-    const ResTable_config* desiredConfig = &mParams;
-    ResTable_config* overrideConfig = NULL;
+    ResTable_config desiredConfig = mParams;
     if (density > 0) {
-        overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config));
-        if (overrideConfig == NULL) {
-            ALOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno));
-            return BAD_INDEX;
-        }
-        memcpy(overrideConfig, &mParams, sizeof(ResTable_config));
-        overrideConfig->density = density;
-        desiredConfig = overrideConfig;
+        desiredConfig.density = density;
     }
 
-    ssize_t rc = BAD_VALUE;
-    size_t ip = grp->packages.size();
-    while (ip > 0) {
-        ip--;
-        int T = t;
-        int E = e;
-
-        const Package* const package = grp->packages[ip];
-        if (package->header->resourceIDMap) {
-            uint32_t overlayResID = 0x0;
-            status_t retval = idmapLookup(package->header->resourceIDMap,
-                                          package->header->resourceIDMapSize,
-                                          resID, &overlayResID);
-            if (retval == NO_ERROR && overlayResID != 0x0) {
-                // for this loop iteration, this is the type and entry we really want
-                ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
-                T = Res_GETTYPE(overlayResID);
-                E = Res_GETENTRY(overlayResID);
-            } else {
-                // resource not present in overlay package, continue with the next package
-                continue;
-            }
-        }
-
-        const ResTable_type* type;
-        const ResTable_entry* entry;
-        const Type* typeClass;
-        ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);
-        if (offset <= 0) {
-            // No {entry, appropriate config} pair found in package. If this
-            // package is an overlay package (ip != 0), this simply means the
-            // overlay package did not specify a default.
-            // Non-overlay packages are still required to provide a default.
-            if (offset < 0 && ip == 0) {
-                ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
-                        resID, T, E, ip, (int)offset);
-                rc = offset;
-                goto out;
-            }
-            continue;
-        }
-
-        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
-            if (!mayBeBag) {
-                ALOGW("Requesting resource 0x%x failed because it is complex\n",
-                     resID);
-            }
-            continue;
-        }
-
-        if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
-            ALOGW("ResTable_item at %d is beyond type chunk data %d",
-                 (int)offset, dtohl(type->header.size));
-            rc = BAD_TYPE;
-            goto out;
-        }
-
-        const Res_value* item =
-            (const Res_value*)(((const uint8_t*)type) + offset);
-        ResTable_config thisConfig;
-        thisConfig.copyFromDtoH(type->config);
-
-        if (outSpecFlags != NULL) {
-            if (typeClass->typeSpecFlags != NULL) {
-                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
-            } else {
-                *outSpecFlags = -1;
-            }
-        }
-
-        if (bestPackage != NULL &&
-            (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
-            // Discard thisConfig not only if bestItem is more specific, but also if the two configs
-            // are identical (diff == 0), or overlay packages will not take effect.
-            continue;
-        }
-
-        bestItem = thisConfig;
-        bestValue = item;
-        bestPackage = package;
+    Entry entry;
+    status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
+    if (err != NO_ERROR) {
+        ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
+                resID, t, e, err);
+        return err;
     }
 
-    TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
-
-    if (bestValue) {
-        outValue->size = dtohs(bestValue->size);
-        outValue->res0 = bestValue->res0;
-        outValue->dataType = bestValue->dataType;
-        outValue->data = dtohl(bestValue->data);
-
-        // The reference may be pointing to a resource in a shared library. These
-        // references have build-time generated package IDs. These ids may not match
-        // the actual package IDs of the corresponding packages in this ResTable.
-        // We need to fix the package ID based on a mapping.
-        status_t err = grp->dynamicRefTable.lookupResourceValue(outValue);
-        if (err != NO_ERROR) {
-            ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
-            rc = BAD_VALUE;
-            goto out;
+    if ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) != 0) {
+        if (!mayBeBag) {
+            ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
         }
-
-        if (outConfig != NULL) {
-            *outConfig = bestItem;
-        }
-        TABLE_NOISY(size_t len;
-              printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
-                     bestPackage->header->index,
-                     outValue->dataType,
-                     outValue->dataType == bestValue->TYPE_STRING
-                     ? String8(bestPackage->header->values.stringAt(
-                         outValue->data, &len)).string()
-                     : "",
-                     outValue->data));
-        rc = bestPackage->header->index;
-        goto out;
+        return BAD_VALUE;
     }
 
-out:
-    if (overrideConfig != NULL) {
-        free(overrideConfig);
+    const Res_value* value = reinterpret_cast<const Res_value*>(
+            reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);
+
+    outValue->size = dtohs(value->size);
+    outValue->res0 = value->res0;
+    outValue->dataType = value->dataType;
+    outValue->data = dtohl(value->data);
+
+    // The reference may be pointing to a resource in a shared library. These
+    // references have build-time generated package IDs. These ids may not match
+    // the actual package IDs of the corresponding packages in this ResTable.
+    // We need to fix the package ID based on a mapping.
+    if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
+        ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
+        return BAD_VALUE;
     }
 
-    return rc;
+    TABLE_NOISY(size_t len;
+          printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
+                 entry.package->header->index,
+                 outValue->dataType,
+                 outValue->dataType == Res_value::TYPE_STRING
+                 ? String8(entry.package->header->values.stringAt(
+                     outValue->data, &len)).string()
+                 : "",
+                 outValue->data));
+
+    if (outSpecFlags != NULL) {
+        *outSpecFlags = entry.specFlags;
+    }
+
+    if (outConfig != NULL) {
+        *outConfig = entry.config;
+    }
+
+    return entry.package->header->index;
 }
 
 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
@@ -3721,29 +3754,25 @@
     PackageGroup* const grp = mPackageGroups[p];
     if (grp == NULL) {
         ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
-        return false;
-    }
-
-    if (t >= (int)grp->typeCount) {
-        ALOGW("Type identifier 0x%x is larger than type count 0x%x",
-             t+1, (int)grp->typeCount);
         return BAD_INDEX;
     }
 
-    const Package* const basePackage = grp->packages[0];
+    const TypeList& typeConfigs = grp->types[t];
+    if (typeConfigs.isEmpty()) {
+        ALOGW("Type identifier 0x%x does not exist.", t+1);
+        return BAD_INDEX;
+    }
 
-    const Type* const typeConfigs = basePackage->getType(t);
-
-    const size_t NENTRY = typeConfigs->entryCount;
+    const size_t NENTRY = typeConfigs[0]->entryCount;
     if (e >= (int)NENTRY) {
         ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
-             e, (int)typeConfigs->entryCount);
+             e, (int)typeConfigs[0]->entryCount);
         return BAD_INDEX;
     }
 
     // First see if we've already computed this bag...
     if (grp->bags) {
-        bag_set** typeSet = grp->bags[t];
+        bag_set** typeSet = grp->bags->get(t);
         if (typeSet) {
             bag_set* set = typeSet[e];
             if (set) {
@@ -3764,229 +3793,174 @@
 
     // Bag not found, we need to compute it!
     if (!grp->bags) {
-        grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*));
+        grp->bags = new ByteBucketArray<bag_set**>();
         if (!grp->bags) return NO_MEMORY;
     }
 
-    bag_set** typeSet = grp->bags[t];
+    bag_set** typeSet = grp->bags->get(t);
     if (!typeSet) {
         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
         if (!typeSet) return NO_MEMORY;
-        grp->bags[t] = typeSet;
+        grp->bags->set(t, typeSet);
     }
 
     // Mark that we are currently working on this one.
     typeSet[e] = (bag_set*)0xFFFFFFFF;
 
+    TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
+
+    // Now collect all bag attributes
+    Entry entry;
+    status_t err = getEntry(grp, t, e, &mParams, &entry);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    const uint16_t entrySize = dtohs(entry.entry->size);
+    const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
+        ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0;
+    const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
+        ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0;
+
+    size_t N = count;
+
+    TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
+                     entrySize, parent, count));
+
+    // If this map inherits from another, we need to start
+    // with its parent's values.  Otherwise start out empty.
+    TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+                       entrySize, parent));
+
     // This is what we are building.
     bag_set* set = NULL;
 
-    TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
+    if (parent) {
+        uint32_t resolvedParent = parent;
 
-    ResTable_config bestConfig;
-    memset(&bestConfig, 0, sizeof(bestConfig));
-
-    // Now collect all bag attributes from all packages.
-    size_t ip = grp->packages.size();
-    while (ip > 0) {
-        ip--;
-        int T = t;
-        int E = e;
-
-        const Package* const package = grp->packages[ip];
-        if (package->header->resourceIDMap) {
-            uint32_t overlayResID = 0x0;
-            status_t retval = idmapLookup(package->header->resourceIDMap,
-                                          package->header->resourceIDMapSize,
-                                          resID, &overlayResID);
-            if (retval == NO_ERROR && overlayResID != 0x0) {
-                // for this loop iteration, this is the type and entry we really want
-                ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
-                T = Res_GETTYPE(overlayResID);
-                E = Res_GETENTRY(overlayResID);
-            } else {
-                // resource not present in overlay package, continue with the next package
-                continue;
-            }
+        // Bags encode a parent reference without using the standard
+        // Res_value structure. That means we must always try to
+        // resolve a parent reference in case it is actually a
+        // TYPE_DYNAMIC_REFERENCE.
+        status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
+        if (err != NO_ERROR) {
+            ALOGE("Failed resolving bag parent id 0x%08x", parent);
+            return UNKNOWN_ERROR;
         }
 
-        const ResTable_type* type;
-        const ResTable_entry* entry;
-        const Type* typeClass;
-        ALOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
-        ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
-        ALOGV("Resulting offset=%d\n", (int)offset);
-        if (offset <= 0) {
-            // No {entry, appropriate config} pair found in package. If this
-            // package is an overlay package (ip != 0), this simply means the
-            // overlay package did not specify a default.
-            // Non-overlay packages are still required to provide a default.
-            if (offset < 0 && ip == 0) {
-                if (set) free(set);
-                return offset;
-            }
-            continue;
+        const bag_entry* parentBag;
+        uint32_t parentTypeSpecFlags = 0;
+        const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
+        const size_t NT = ((NP >= 0) ? NP : 0) + N;
+        set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+        if (set == NULL) {
+            return NO_MEMORY;
         }
-
-        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
-            ALOGW("Skipping entry 0x%x in package table %zu because it is not complex!\n",
-                 resID, ip);
-            continue;
-        }
-
-        if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
-            continue;
-        }
-        bestConfig = type->config;
-        if (set) {
-            free(set);
-            set = NULL;
-        }
-
-        const uint16_t entrySize = dtohs(entry->size);
-        const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
-            ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
-        const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
-            ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
-
-        size_t N = count;
-
-        TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
-                         entrySize, parent, count));
-
-        // If this map inherits from another, we need to start
-        // with its parent's values.  Otherwise start out empty.
-        TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
-                           entrySize, parent));
-        if (parent) {
-            uint32_t resolvedParent = parent;
-
-            // Bags encode a parent reference without using the standard
-            // Res_value structure. That means we must always try to
-            // resolve a parent reference in case it is actually a
-            // TYPE_DYNAMIC_REFERENCE.
-            status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
-            if (err != NO_ERROR) {
-                ALOGE("Failed resolving bag parent id 0x%08x", parent);
-                return UNKNOWN_ERROR;
-            }
-
-            const bag_entry* parentBag;
-            uint32_t parentTypeSpecFlags = 0;
-            const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
-            const size_t NT = ((NP >= 0) ? NP : 0) + N;
-            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
-            if (set == NULL) {
-                return NO_MEMORY;
-            }
-            if (NP > 0) {
-                memcpy(set+1, parentBag, NP*sizeof(bag_entry));
-                set->numAttrs = NP;
-                TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP));
-            } else {
-                TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n"));
-                set->numAttrs = 0;
-            }
-            set->availAttrs = NT;
-            set->typeSpecFlags = parentTypeSpecFlags;
+        if (NP > 0) {
+            memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+            set->numAttrs = NP;
+            TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP));
         } else {
-            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
-            if (set == NULL) {
-                return NO_MEMORY;
-            }
+            TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n"));
             set->numAttrs = 0;
-            set->availAttrs = N;
-            set->typeSpecFlags = 0;
         }
-
-        if (typeClass->typeSpecFlags != NULL) {
-            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
-        } else {
-            set->typeSpecFlags = -1;
+        set->availAttrs = NT;
+        set->typeSpecFlags = parentTypeSpecFlags;
+    } else {
+        set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+        if (set == NULL) {
+            return NO_MEMORY;
         }
+        set->numAttrs = 0;
+        set->availAttrs = N;
+        set->typeSpecFlags = 0;
+    }
 
-        // Now merge in the new attributes...
-        ssize_t curOff = offset;
-        const ResTable_map* map;
-        bag_entry* entries = (bag_entry*)(set+1);
-        size_t curEntry = 0;
-        uint32_t pos = 0;
-        TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n",
-                     set, entries, set->availAttrs));
-        while (pos < count) {
-            TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
+    set->typeSpecFlags |= entry.specFlags;
 
-            if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
-                ALOGW("ResTable_map at %d is beyond type chunk data %d",
-                     (int)curOff, dtohl(type->header.size));
-                return BAD_TYPE;
-            }
-            map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
-            N++;
+    // Now merge in the new attributes...
+    size_t curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
+        + dtohs(entry.entry->size);
+    const ResTable_map* map;
+    bag_entry* entries = (bag_entry*)(set+1);
+    size_t curEntry = 0;
+    uint32_t pos = 0;
+    TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n",
+                 set, entries, set->availAttrs));
+    while (pos < count) {
+        TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
 
-            const uint32_t newName = htodl(map->name.ident);
-            bool isInside;
-            uint32_t oldName = 0;
-            while ((isInside=(curEntry < set->numAttrs))
-                    && (oldName=entries[curEntry].map.name.ident) < newName) {
-                TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
-                             curEntry, entries[curEntry].map.name.ident));
-                curEntry++;
-            }
+        if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
+            ALOGW("ResTable_map at %d is beyond type chunk data %d",
+                 (int)curOff, dtohl(entry.type->header.size));
+            return BAD_TYPE;
+        }
+        map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
+        N++;
 
-            if ((!isInside) || oldName != newName) {
-                // This is a new attribute...  figure out what to do with it.
-                if (set->numAttrs >= set->availAttrs) {
-                    // Need to alloc more memory...
-                    const size_t newAvail = set->availAttrs+N;
-                    set = (bag_set*)realloc(set,
-                                            sizeof(bag_set)
-                                            + sizeof(bag_entry)*newAvail);
-                    if (set == NULL) {
-                        return NO_MEMORY;
-                    }
-                    set->availAttrs = newAvail;
-                    entries = (bag_entry*)(set+1);
-                    TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
-                                 set, entries, set->availAttrs));
-                }
-                if (isInside) {
-                    // Going in the middle, need to make space.
-                    memmove(entries+curEntry+1, entries+curEntry,
-                            sizeof(bag_entry)*(set->numAttrs-curEntry));
-                    set->numAttrs++;
-                }
-                TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
-                             curEntry, newName));
-            } else {
-                TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
-                             curEntry, oldName));
-            }
-
-            bag_entry* cur = entries+curEntry;
-
-            cur->stringBlock = package->header->index;
-            cur->map.name.ident = newName;
-            cur->map.value.copyFrom_dtoh(map->value);
-            status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
-            if (err != NO_ERROR) {
-                ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
-                return UNKNOWN_ERROR;
-            }
-
-            TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
-                         curEntry, cur, cur->stringBlock, cur->map.name.ident,
-                         cur->map.value.dataType, cur->map.value.data));
-
-            // On to the next!
+        const uint32_t newName = htodl(map->name.ident);
+        bool isInside;
+        uint32_t oldName = 0;
+        while ((isInside=(curEntry < set->numAttrs))
+                && (oldName=entries[curEntry].map.name.ident) < newName) {
+            TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
+                         curEntry, entries[curEntry].map.name.ident));
             curEntry++;
-            pos++;
-            const size_t size = dtohs(map->value.size);
-            curOff += size + sizeof(*map)-sizeof(map->value);
-        };
-        if (curEntry > set->numAttrs) {
-            set->numAttrs = curEntry;
         }
+
+        if ((!isInside) || oldName != newName) {
+            // This is a new attribute...  figure out what to do with it.
+            if (set->numAttrs >= set->availAttrs) {
+                // Need to alloc more memory...
+                const size_t newAvail = set->availAttrs+N;
+                set = (bag_set*)realloc(set,
+                                        sizeof(bag_set)
+                                        + sizeof(bag_entry)*newAvail);
+                if (set == NULL) {
+                    return NO_MEMORY;
+                }
+                set->availAttrs = newAvail;
+                entries = (bag_entry*)(set+1);
+                TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
+                             set, entries, set->availAttrs));
+            }
+            if (isInside) {
+                // Going in the middle, need to make space.
+                memmove(entries+curEntry+1, entries+curEntry,
+                        sizeof(bag_entry)*(set->numAttrs-curEntry));
+                set->numAttrs++;
+            }
+            TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
+                         curEntry, newName));
+        } else {
+            TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
+                         curEntry, oldName));
+        }
+
+        bag_entry* cur = entries+curEntry;
+
+        cur->stringBlock = entry.package->header->index;
+        cur->map.name.ident = newName;
+        cur->map.value.copyFrom_dtoh(map->value);
+        status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
+        if (err != NO_ERROR) {
+            ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
+            return UNKNOWN_ERROR;
+        }
+
+        TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
+                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
+                     cur->map.value.dataType, cur->map.value.data));
+
+        // On to the next!
+        curEntry++;
+        pos++;
+        const size_t size = dtohs(map->value.size);
+        curOff += size + sizeof(*map)-sizeof(map->value);
+    };
+
+    if (curEntry > set->numAttrs) {
+        set->numAttrs = curEntry;
     }
 
     // And this is it...
@@ -4154,80 +4128,63 @@
             continue;
         }
 
-        const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
+        const ssize_t ti = group->findType16(type, typeLen);
         if (ti < 0) {
             TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
             continue;
         }
 
-        const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
-        if (ei < 0) {
-            TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
+        const TypeList& typeList = group->types[ti];
+        if (typeList.isEmpty()) {
+            TABLE_NOISY(printf("Expected type structure not found in package %s for index %d\n",
+                               String8(group->name).string(), ti));
             continue;
         }
 
-        TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
+        const size_t typeCount = typeList.size();
+        for (size_t i = 0; i < typeCount; i++) {
+            const Type* t = typeList[i];
+            const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
+            if (ei < 0) {
+                continue;
+            }
 
-        const Type* const typeConfigs = group->packages[0]->getType(ti);
-        if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
-            TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
-                               String8(group->name).string(), ti));
-        }
-
-        size_t NTC = typeConfigs->configs.size();
-        for (size_t tci=0; tci<NTC; tci++) {
-            const ResTable_type* const ty = typeConfigs->configs[tci];
-            const uint32_t typeOffset = dtohl(ty->entriesStart);
-
-            const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
-            const uint32_t* const eindex = (const uint32_t*)
-                (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
-
-            const size_t NE = dtohl(ty->entryCount);
-            for (size_t i=0; i<NE; i++) {
-                uint32_t offset = dtohl(eindex[i]);
-                if (offset == ResTable_type::NO_ENTRY) {
-                    continue;
-                }
-
-                offset += typeOffset;
-
-                if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
-                    ALOGW("ResTable_entry at %d is beyond type chunk data %d",
-                         offset, dtohl(ty->header.size));
-                    return 0;
-                }
-                if ((offset&0x3) != 0) {
-                    ALOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
-                         (int)offset, (int)group->id, (int)ti+1, (int)i,
-                         String8(package, packageLen).string(),
-                         String8(type, typeLen).string(),
-                         String8(name, nameLen).string());
-                    return 0;
-                }
-
-                const ResTable_entry* const entry = (const ResTable_entry*)
-                    (((const uint8_t*)ty) + offset);
-                if (dtohs(entry->size) < sizeof(*entry)) {
-                    ALOGW("ResTable_entry size %d is too small", dtohs(entry->size));
-                    return BAD_TYPE;
-                }
-
-                TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
-                                         i, ei, dtohl(entry->key.index)));
-                if (dtohl(entry->key.index) == (size_t)ei) {
-                    if (outTypeSpecFlags) {
-                        *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
-                        if (fakePublic) {
-                            *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
-                        }
+            const size_t configCount = t->configs.size();
+            for (size_t j = 0; j < configCount; j++) {
+                const TypeVariant tv(t->configs[j]);
+                for (TypeVariant::iterator iter = tv.beginEntries();
+                     iter != tv.endEntries();
+                     iter++) {
+                    const ResTable_entry* entry = *iter;
+                    if (entry == NULL) {
+                        continue;
                     }
-                    return Res_MAKEID(group->id-1, ti, i);
+
+                    if (dtohl(entry->key.index) == (size_t) ei) {
+                        uint32_t resId = Res_MAKEID(group->id - 1, ti, iter.index());
+                        if (outTypeSpecFlags) {
+                            Entry result;
+                            if (getEntry(group, ti, iter.index(), NULL, &result) != NO_ERROR) {
+                                ALOGW("Failed to find spec flags for %s:%s/%s (0x%08x)",
+                                        String8(group->name).string(),
+                                        String8(String16(type, typeLen)).string(),
+                                        String8(String16(name, nameLen)).string(),
+                                        resId);
+                                return 0;
+                            }
+                            *outTypeSpecFlags = result.specFlags;
+
+                            if (fakePublic) {
+                                *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
+                            }
+                        }
+                        return resId;
+                    }
                 }
             }
         }
+        break;
     }
-
     return 0;
 }
 
@@ -5260,6 +5217,18 @@
     return mPackageGroups[idx]->id;
 }
 
+uint32_t ResTable::getLastTypeIdForPackage(size_t idx) const
+{
+    if (mError != NO_ERROR) {
+        return 0;
+    }
+    LOG_FATAL_IF(idx >= mPackageGroups.size(),
+            "Requested package index %d past package count %d",
+            (int)idx, (int)mPackageGroups.size());
+    const PackageGroup* const group = mPackageGroups[idx];
+    return group->largestTypeId;
+}
+
 size_t ResTable::getTableCount() const
 {
     return mHeaders.size();
@@ -5292,32 +5261,31 @@
 
 void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
 {
-    const size_t I = mPackageGroups.size();
-    for (size_t i=0; i<I; i++) {
+    const size_t packageCount = mPackageGroups.size();
+    for (size_t i = 0; i < packageCount; i++) {
         const PackageGroup* packageGroup = mPackageGroups[i];
-        const size_t J = packageGroup->packages.size();
-        for (size_t j=0; j<J; j++) {
-            const Package* package = packageGroup->packages[j];
-            const size_t K = package->types.size();
-            for (size_t k=0; k<K; k++) {
-                const Type* type = package->types[k];
-                if (type == NULL) continue;
-                const size_t L = type->configs.size();
-                for (size_t l=0; l<L; l++) {
-                    const ResTable_type* config = type->configs[l];
+        const size_t typeCount = packageGroup->types.size();
+        for (size_t j = 0; j < typeCount; j++) {
+            const TypeList& typeList = packageGroup->types[j];
+            const size_t numTypes = typeList.size();
+            for (size_t k = 0; k < numTypes; k++) {
+                const Type* type = typeList[k];
+                const size_t numConfigs = type->configs.size();
+                for (size_t m = 0; m < numConfigs; m++) {
+                    const ResTable_type* config = type->configs[m];
                     ResTable_config cfg;
                     memset(&cfg, 0, sizeof(ResTable_config));
                     cfg.copyFromDtoH(config->config);
                     // only insert unique
-                    const size_t M = configs->size();
-                    size_t m;
-                    for (m=0; m<M; m++) {
-                        if (0 == (*configs)[m].compare(cfg)) {
+                    const size_t N = configs->size();
+                    size_t n;
+                    for (n = 0; n < N; n++) {
+                        if (0 == (*configs)[n].compare(cfg)) {
                             break;
                         }
                     }
                     // if we didn't find it
-                    if (m == M) {
+                    if (n == N) {
                         configs->add(cfg);
                     }
                 }
@@ -5350,122 +5318,180 @@
     }
 }
 
-ssize_t ResTable::getEntry(
-    const Package* package, int typeIndex, int entryIndex,
-    const ResTable_config* config,
-    const ResTable_type** outType, const ResTable_entry** outEntry,
-    const Type** outTypeClass) const
-{
-    ALOGV("Getting entry from package %p\n", package);
-    const ResTable_package* const pkg = package->package;
+StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
+    : mPool(pool), mIndex(index) {}
 
-    const Type* allTypes = package->getType(typeIndex);
-    ALOGV("allTypes=%p\n", allTypes);
-    if (allTypes == NULL) {
-        ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
-        return 0;
+StringPoolRef::StringPoolRef()
+    : mPool(NULL), mIndex(0) {}
+
+const char* StringPoolRef::string8(size_t* outLen) const {
+    if (mPool != NULL) {
+        return mPool->string8At(mIndex, outLen);
     }
+    if (outLen != NULL) {
+        *outLen = 0;
+    }
+    return NULL;
+}
 
-    if ((size_t)entryIndex >= allTypes->entryCount) {
-        ALOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
-            entryIndex, (int)allTypes->entryCount);
+const char16_t* StringPoolRef::string16(size_t* outLen) const {
+    if (mPool != NULL) {
+        return mPool->stringAt(mIndex, outLen);
+    }
+    if (outLen != NULL) {
+        *outLen = 0;
+    }
+    return NULL;
+}
+
+status_t ResTable::getEntry(
+        const PackageGroup* packageGroup, int typeIndex, int entryIndex,
+        const ResTable_config* config,
+        Entry* outEntry) const
+{
+    const TypeList& typeList = packageGroup->types[typeIndex];
+    if (typeList.isEmpty()) {
+        ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
         return BAD_TYPE;
     }
 
-    const ResTable_type* type = NULL;
-    uint32_t offset = ResTable_type::NO_ENTRY;
+    const ResTable_type* bestType = NULL;
+    uint32_t bestOffset = ResTable_type::NO_ENTRY;
+    const Package* bestPackage = NULL;
+    uint32_t specFlags = 0;
+    uint8_t actualTypeIndex = typeIndex;
     ResTable_config bestConfig;
-    memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
+    memset(&bestConfig, 0, sizeof(bestConfig));
 
-    const size_t NT = allTypes->configs.size();
-    for (size_t i=0; i<NT; i++) {
-        const ResTable_type* const thisType = allTypes->configs[i];
-        if (thisType == NULL) continue;
+    // Iterate over the Types of each package.
+    const size_t typeCount = typeList.size();
+    for (size_t i = 0; i < typeCount; i++) {
+        const Type* const typeSpec = typeList[i];
 
-        ResTable_config thisConfig;
-        thisConfig.copyFromDtoH(thisType->config);
+        int realEntryIndex = entryIndex;
+        int realTypeIndex = typeIndex;
+        bool currentTypeIsOverlay = false;
 
-        TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
-                           entryIndex, typeIndex+1, dtohl(thisType->config.size),
-                           thisConfig.toString().string()));
-
-        // Check to make sure this one is valid for the current parameters.
-        if (config && !thisConfig.match(*config)) {
-            TABLE_GETENTRY(ALOGI("Does not match config!\n"));
-            continue;
-        }
-
-        // Check if there is the desired entry in this type.
-
-        const uint8_t* const end = ((const uint8_t*)thisType)
-            + dtohl(thisType->header.size);
-        const uint32_t* const eindex = (const uint32_t*)
-            (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
-
-        uint32_t thisOffset = dtohl(eindex[entryIndex]);
-        if (thisOffset == ResTable_type::NO_ENTRY) {
-            TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n"));
-            continue;
-        }
-
-        if (type != NULL) {
-            // Check if this one is less specific than the last found.  If so,
-            // we will skip it.  We check starting with things we most care
-            // about to those we least care about.
-            if (!thisConfig.isBetterThan(bestConfig, config)) {
-                TABLE_GETENTRY(ALOGI("This config is worse than last!\n"));
+        // Runtime overlay packages provide a mapping of app resource
+        // ID to package resource ID.
+        if (typeSpec->idmapEntries.hasEntries()) {
+            uint16_t overlayEntryIndex;
+            if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) {
+                // No such mapping exists
                 continue;
             }
+            realEntryIndex = overlayEntryIndex;
+            realTypeIndex = typeSpec->idmapEntries.overlayTypeId() - 1;
+            currentTypeIsOverlay = true;
         }
 
-        type = thisType;
-        offset = thisOffset;
-        bestConfig = thisConfig;
-        TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n"));
-        if (!config) break;
+        if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
+            ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
+                    Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
+                    entryIndex, static_cast<int>(typeSpec->entryCount));
+            // We should normally abort here, but some legacy apps declare
+            // resources in the 'android' package (old bug in AAPT).
+            continue;
+        }
+
+        // Aggregate all the flags for each package that defines this entry.
+        if (typeSpec->typeSpecFlags != NULL) {
+            specFlags |= dtohl(typeSpec->typeSpecFlags[realEntryIndex]);
+        } else {
+            specFlags = -1;
+        }
+
+        const size_t numConfigs = typeSpec->configs.size();
+        for (size_t c = 0; c < numConfigs; c++) {
+            const ResTable_type* const thisType = typeSpec->configs[c];
+            if (thisType == NULL) {
+                continue;
+            }
+
+            ResTable_config thisConfig;
+            thisConfig.copyFromDtoH(thisType->config);
+
+            // Check to make sure this one is valid for the current parameters.
+            if (config != NULL && !thisConfig.match(*config)) {
+                continue;
+            }
+
+            // Check if there is the desired entry in this type.
+            const uint8_t* const end = reinterpret_cast<const uint8_t*>(thisType)
+                    + dtohl(thisType->header.size);
+            const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
+                    reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
+
+            uint32_t thisOffset = dtohl(eindex[realEntryIndex]);
+            if (thisOffset == ResTable_type::NO_ENTRY) {
+                // There is no entry for this index and configuration.
+                continue;
+            }
+
+            if (bestType != NULL) {
+                // Check if this one is less specific than the last found.  If so,
+                // we will skip it.  We check starting with things we most care
+                // about to those we least care about.
+                if (!thisConfig.isBetterThan(bestConfig, config)) {
+                    if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
+                        continue;
+                    }
+                }
+            }
+
+            bestType = thisType;
+            bestOffset = thisOffset;
+            bestConfig = thisConfig;
+            bestPackage = typeSpec->package;
+            actualTypeIndex = realTypeIndex;
+
+            // If no config was specified, any type will do, so skip
+            if (config == NULL) {
+                break;
+            }
+        }
     }
 
-    if (type == NULL) {
-        TABLE_GETENTRY(ALOGI("No value found for requested entry!\n"));
+    if (bestType == NULL) {
         return BAD_INDEX;
     }
 
-    offset += dtohl(type->entriesStart);
-    TABLE_NOISY(ALOGD("Looking in resource table %p, typeOff=%p, offset=%p",
-            package->header->header, (void*)(((const char*)type)-((const char*)package->header->header)),
-            (void*)offset));
+    bestOffset += dtohl(bestType->entriesStart);
 
-    if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
+    if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
         ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
-             offset, dtohl(type->header.size));
+                bestOffset, dtohl(bestType->header.size));
         return BAD_TYPE;
     }
-    if ((offset&0x3) != 0) {
-        ALOGW("ResTable_entry at 0x%x is not on an integer boundary",
-             offset);
+    if ((bestOffset & 0x3) != 0) {
+        ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
         return BAD_TYPE;
     }
 
-    const ResTable_entry* const entry = (const ResTable_entry*)
-        (((const uint8_t*)type) + offset);
+    const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
+            reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
     if (dtohs(entry->size) < sizeof(*entry)) {
         ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
         return BAD_TYPE;
     }
 
-    *outType = type;
-    *outEntry = entry;
-    if (outTypeClass != NULL) {
-        *outTypeClass = allTypes;
+    if (outEntry != NULL) {
+        outEntry->entry = entry;
+        outEntry->config = bestConfig;
+        outEntry->type = bestType;
+        outEntry->specFlags = specFlags;
+        outEntry->package = bestPackage;
+        outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset);
+        outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, dtohl(entry->key.index));
     }
-    return offset + dtohs(entry->size);
+    return NO_ERROR;
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header, uint32_t idmap_id)
+                                const Header* const header)
 {
     const uint8_t* base = (const uint8_t*)pkg;
-    status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
+    status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
                                   header->dataEnd, "ResTable_package");
     if (err != NO_ERROR) {
         return (mError=err);
@@ -5494,89 +5520,88 @@
         return (mError=BAD_TYPE);
     }
 
-    Package* package = NULL;
-    PackageGroup* group = NULL;
-    uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
-    // If at this point id == 0, pkg is an overlay package without a
-    // corresponding idmap. During regular usage, overlay packages are
-    // always loaded alongside their idmaps, but during idmap creation
-    // the package is temporarily loaded by itself.
-    if (id < 256) {
+    uint32_t id = dtohl(pkg->id);
+    KeyedVector<uint8_t, IdmapEntries> idmapEntries;
 
-        package = new Package(this, header, pkg);
-        if (package == NULL) {
+    if (header->resourceIDMap != NULL) {
+        uint8_t targetPackageId = 0;
+        status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
+        if (err != NO_ERROR) {
+            ALOGW("Overlay is broken");
+            return (mError=err);
+        }
+        id = targetPackageId;
+    }
+
+    if (id >= 256) {
+        LOG_ALWAYS_FATAL("Package id out of range");
+        return NO_ERROR;
+    } else if (id == 0) {
+        // This is a library so assign an ID
+        id = mNextPackageId++;
+    }
+
+    PackageGroup* group = NULL;
+    Package* package = new Package(this, header, pkg);
+    if (package == NULL) {
+        return (mError=NO_MEMORY);
+    }
+
+    err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+                                   header->dataEnd-(base+dtohl(pkg->typeStrings)));
+    if (err != NO_ERROR) {
+        delete group;
+        delete package;
+        return (mError=err);
+    }
+
+    err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+                                  header->dataEnd-(base+dtohl(pkg->keyStrings)));
+    if (err != NO_ERROR) {
+        delete group;
+        delete package;
+        return (mError=err);
+    }
+
+    size_t idx = mPackageMap[id];
+    if (idx == 0) {
+        idx = mPackageGroups.size() + 1;
+
+        char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
+        strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
+        group = new PackageGroup(this, String16(tmpName), id);
+        if (group == NULL) {
+            delete package;
             return (mError=NO_MEMORY);
         }
 
-        if (idmap_id == 0) {
-            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
-                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
-            if (err != NO_ERROR) {
-                delete group;
-                delete package;
-                return (mError=err);
-            }
-
-            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
-                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
-            if (err != NO_ERROR) {
-                delete group;
-                delete package;
-                return (mError=err);
-            }
-        }
-
-        if (id == 0) {
-            // This is a library so assign an ID
-            id = mNextPackageId++;
-        }
-
-        size_t idx = mPackageMap[id];
-        if (idx == 0) {
-            idx = mPackageGroups.size()+1;
-
-            char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
-            strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
-            group = new PackageGroup(this, String16(tmpName), id);
-            if (group == NULL) {
-                delete package;
-                return (mError=NO_MEMORY);
-            }
-
-            //printf("Adding new package id %d at index %d\n", id, idx);
-            err = mPackageGroups.add(group);
-            if (err < NO_ERROR) {
-                return (mError=err);
-            }
-            group->basePackage = package;
-
-            mPackageMap[id] = (uint8_t)idx;
-
-            // Find all packages that reference this package
-            size_t N = mPackageGroups.size();
-            for (size_t i = 0; i < N; i++) {
-                mPackageGroups[i]->dynamicRefTable.addMapping(
-                        group->name, static_cast<uint8_t>(group->id));
-            }
-        } else {
-            group = mPackageGroups.itemAt(idx-1);
-            if (group == NULL) {
-                return (mError=UNKNOWN_ERROR);
-            }
-        }
-        err = group->packages.add(package);
+        //printf("Adding new package id %d at index %d\n", id, idx);
+        err = mPackageGroups.add(group);
         if (err < NO_ERROR) {
             return (mError=err);
         }
+
+        mPackageMap[id] = static_cast<uint8_t>(idx);
+
+        // Find all packages that reference this package
+        size_t N = mPackageGroups.size();
+        for (size_t i = 0; i < N; i++) {
+            mPackageGroups[i]->dynamicRefTable.addMapping(
+                    group->name, static_cast<uint8_t>(group->id));
+        }
     } else {
-        LOG_ALWAYS_FATAL("Package id out of range");
-        return NO_ERROR;
+        group = mPackageGroups.itemAt(idx - 1);
+        if (group == NULL) {
+            return (mError=UNKNOWN_ERROR);
+        }
     }
 
+    err = group->packages.add(package);
+    if (err < NO_ERROR) {
+        return (mError=err);
+    }
 
     // Iterate through all chunks.
-    size_t curPackage = 0;
-
     const ResChunk_header* chunk =
         (const ResChunk_header*)(((const uint8_t*)pkg)
                                  + dtohs(pkg->header.headerSize));
@@ -5597,6 +5622,7 @@
             }
 
             const size_t typeSpecSize = dtohl(typeSpec->header.size);
+            const size_t newEntryCount = dtohl(typeSpec->entryCount);
 
             LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
                                     (void*)(base-(const uint8_t*)chunk),
@@ -5605,12 +5631,11 @@
                                     (void*)typeSpecSize));
             // look for block overrun or int overflow when multiplying by 4
             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
-                    || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
+                    || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
                     > typeSpecSize)) {
                 ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
-                     (void*)(dtohs(typeSpec->header.headerSize)
-                             +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
-                     (void*)typeSpecSize);
+                        (void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
+                        (void*)typeSpecSize);
                 return (mError=BAD_TYPE);
             }
 
@@ -5619,21 +5644,36 @@
                 return (mError=BAD_TYPE);
             }
 
-            while (package->types.size() < typeSpec->id) {
-                package->types.add(NULL);
+            if (newEntryCount > 0) {
+                uint8_t typeIndex = typeSpec->id - 1;
+                ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
+                if (idmapIndex >= 0) {
+                    typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+                }
+
+                TypeList& typeList = group->types.editItemAt(typeIndex);
+                if (!typeList.isEmpty()) {
+                    const Type* existingType = typeList[0];
+                    if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
+                        ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
+                                (int) newEntryCount, (int) existingType->entryCount);
+                        // We should normally abort here, but some legacy apps declare
+                        // resources in the 'android' package (old bug in AAPT).
+                    }
+                }
+
+                Type* t = new Type(header, package, newEntryCount);
+                t->typeSpec = typeSpec;
+                t->typeSpecFlags = (const uint32_t*)(
+                        ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
+                if (idmapIndex >= 0) {
+                    t->idmapEntries = idmapEntries[idmapIndex];
+                }
+                typeList.add(t);
+                group->largestTypeId = max(group->largestTypeId, typeSpec->id);
+            } else {
+                ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
             }
-            Type* t = package->types[typeSpec->id-1];
-            if (t == NULL) {
-                t = new Type(header, package, dtohl(typeSpec->entryCount));
-                package->types.editItemAt(typeSpec->id-1) = t;
-            } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
-                ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
-                    (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
-                return (mError=BAD_TYPE);
-            }
-            t->typeSpecFlags = (const uint32_t*)(
-                    ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
-            t->typeSpec = typeSpec;
 
         } else if (ctype == RES_TABLE_TYPE_TYPE) {
             const ResTable_type* type = (const ResTable_type*)(chunk);
@@ -5644,50 +5684,69 @@
             }
 
             const uint32_t typeSize = dtohl(type->header.size);
+            const size_t newEntryCount = dtohl(type->entryCount);
 
             LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
                                     (void*)(base-(const uint8_t*)chunk),
                                     dtohs(type->header.type),
                                     dtohs(type->header.headerSize),
                                     (void*)typeSize));
-            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
-                > typeSize) {
+            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
+                    > typeSize) {
                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
-                     (void*)(dtohs(type->header.headerSize)
-                             +(sizeof(uint32_t)*dtohl(type->entryCount))),
-                     typeSize);
+                        (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
+                        typeSize);
                 return (mError=BAD_TYPE);
             }
-            if (dtohl(type->entryCount) != 0
+
+            if (newEntryCount != 0
                 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
                 ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
                      dtohl(type->entriesStart), typeSize);
                 return (mError=BAD_TYPE);
             }
+
             if (type->id == 0) {
                 ALOGW("ResTable_type has an id of 0.");
                 return (mError=BAD_TYPE);
             }
 
-            while (package->types.size() < type->id) {
-                package->types.add(NULL);
-            }
-            Type* t = package->types[type->id-1];
-            if (t == NULL) {
-                t = new Type(header, package, dtohl(type->entryCount));
-                package->types.editItemAt(type->id-1) = t;
-            } else if (dtohl(type->entryCount) != t->entryCount) {
-                ALOGW("ResTable_type entry count inconsistent: given %d, previously %d",
-                    (int)dtohl(type->entryCount), (int)t->entryCount);
-                return (mError=BAD_TYPE);
+            if (newEntryCount > 0) {
+                uint8_t typeIndex = type->id - 1;
+                ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
+                if (idmapIndex >= 0) {
+                    typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
+                }
+
+                TypeList& typeList = group->types.editItemAt(typeIndex);
+                if (typeList.isEmpty()) {
+                    ALOGE("No TypeSpec for type %d", type->id);
+                    return (mError=BAD_TYPE);
+                }
+
+                Type* t = typeList.editItemAt(typeList.size() - 1);
+                if (newEntryCount != t->entryCount) {
+                    ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
+                        (int)newEntryCount, (int)t->entryCount);
+                    return (mError=BAD_TYPE);
+                }
+
+                if (t->package != package) {
+                    ALOGE("No TypeSpec for type %d", type->id);
+                    return (mError=BAD_TYPE);
+                }
+
+                t->configs.add(type);
+
+                TABLE_GETENTRY(
+                    ResTable_config thisConfig;
+                    thisConfig.copyFromDtoH(type->config);
+                    ALOGI("Adding config to type %d: %s\n",
+                          type->id, thisConfig.toString().string()));
+            } else {
+                ALOGV("Skipping empty ResTable_type for type %d", type->id);
             }
 
-            TABLE_GETENTRY(
-                ResTable_config thisConfig;
-                thisConfig.copyFromDtoH(type->config);
-                ALOGI("Adding config to type %d: %s\n",
-                      type->id, thisConfig.toString().string()));
-            t->configs.add(type);
         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
             if (group->dynamicRefTable.entries().size() == 0) {
                 status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
@@ -5714,10 +5773,6 @@
             (((const uint8_t*)chunk) + csize);
     }
 
-    if (group->typeCount == 0) {
-        group->typeCount = package->types.size();
-    }
-
     return NO_ERROR;
 }
 
@@ -5818,6 +5873,12 @@
     return NO_ERROR;
 }
 
+struct IdmapTypeMap {
+    ssize_t overlayTypeId;
+    size_t entryOffset;
+    Vector<uint32_t> entryMap;
+};
+
 status_t ResTable::createIdmap(const ResTable& overlay,
         uint32_t targetCrc, uint32_t overlayCrc,
         const char* targetPath, const char* overlayPath,
@@ -5828,41 +5889,46 @@
         ALOGW("idmap: target package has no package groups, cannot create idmap\n");
         return UNKNOWN_ERROR;
     }
+
     if (mPackageGroups[0]->packages.size() == 0) {
         ALOGW("idmap: target package has no packages in its first package group, "
                 "cannot create idmap\n");
         return UNKNOWN_ERROR;
     }
 
-    Vector<Vector<uint32_t> > map;
+    KeyedVector<uint8_t, IdmapTypeMap> map;
+
     // overlaid packages are assumed to contain only one package group
     const PackageGroup* pg = mPackageGroups[0];
-    const Package* pkg = pg->packages[0];
-    size_t typeCount = pkg->types.size();
-    // starting size is header + first item (number of types in map)
-    *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+
+    // starting size is header
+    *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES;
+
+    // target package id and number of types in map
+    *outSize += 2 * sizeof(uint16_t);
+
     // overlay packages are assumed to contain only one package group
     const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
-    const uint32_t pkg_id = pkg->package->id << 24;
 
-    for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
-        ssize_t first = -1;
-        ssize_t last = -1;
-        const Type* typeConfigs = pkg->getType(typeIndex);
-        ssize_t mapIndex = map.add();
-        if (mapIndex < 0) {
-            return NO_MEMORY;
+    for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
+        const TypeList& typeList = pg->types[typeIndex];
+        if (typeList.isEmpty()) {
+            continue;
         }
-        Vector<uint32_t>& vector = map.editItemAt(mapIndex);
+
+        const Type* typeConfigs = typeList[0];
+
+        IdmapTypeMap typeMap;
+        typeMap.overlayTypeId = -1;
+        typeMap.entryOffset = 0;
+
         for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
-            uint32_t resID = pkg_id
-                | (0x00ff0000 & ((typeIndex+1)<<16))
-                | (0x0000ffff & (entryIndex));
+            uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex);
             resource_name resName;
             if (!this->getResourceName(resID, false, &resName)) {
-                ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
-                // add dummy value, or trimming leading/trailing zeroes later will fail
-                vector.push(0);
+                if (typeMap.entryMap.isEmpty()) {
+                    typeMap.entryOffset++;
+                }
                 continue;
             }
 
@@ -5874,49 +5940,55 @@
                                                               overlayType.size(),
                                                               overlayPackage.string(),
                                                               overlayPackage.size());
-            if (overlayResID != 0) {
-                overlayResID = pkg_id | (0x00ffffff & overlayResID);
-                last = Res_GETENTRY(resID);
-                if (first == -1) {
-                    first = Res_GETENTRY(resID);
+            if (overlayResID == 0) {
+                if (typeMap.entryMap.isEmpty()) {
+                    typeMap.entryOffset++;
                 }
+                continue;
             }
-            vector.push(overlayResID);
-#if 0
-            if (overlayResID != 0) {
-                ALOGD("%s/%s 0x%08x -> 0x%08x\n",
-                     String8(String16(resName.type)).string(),
-                     String8(String16(resName.name)).string(),
-                     resID, overlayResID);
+
+            if (typeMap.overlayTypeId == -1) {
+                typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1;
             }
-#endif
+
+            if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
+                ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
+                        " but entries should map to resources of type %02x",
+                        resID, overlayResID, typeMap.overlayTypeId);
+                return BAD_TYPE;
+            }
+
+            if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
+                // Resize to accomodate this entry and the 0's in between.
+                if (typeMap.entryMap.resize((entryIndex - typeMap.entryOffset) + 1) < 0) {
+                    return NO_MEMORY;
+                }
+                typeMap.entryMap.editTop() = Res_GETENTRY(overlayResID);
+            } else {
+                typeMap.entryMap.add(Res_GETENTRY(overlayResID));
+            }
         }
 
-        if (first != -1) {
-            // shave off trailing entries which lack overlay values
-            const size_t last_past_one = last + 1;
-            if (last_past_one < vector.size()) {
-                vector.removeItemsAt(last_past_one, vector.size() - last_past_one);
+        if (!typeMap.entryMap.isEmpty()) {
+            if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) {
+                return NO_MEMORY;
             }
-            // shave off leading entries which lack overlay values
-            vector.removeItemsAt(0, first);
-            // store offset to first overlaid resource ID of this type
-            vector.insertAt((uint32_t)first, 0, 1);
-            // reserve space for number and offset of entries, and the actual entries
-            *outSize += (2 + vector.size()) * sizeof(uint32_t);
-        } else {
-            // no entries of current type defined in overlay package
-            vector.clear();
-            // reserve space for type offset
-            *outSize += 1 * sizeof(uint32_t);
+            *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t));
         }
     }
 
+    if (map.isEmpty()) {
+        ALOGW("idmap: no resources in overlay package present in base package");
+        return UNKNOWN_ERROR;
+    }
+
     if ((*outData = malloc(*outSize)) == NULL) {
         return NO_MEMORY;
     }
+
     uint32_t* data = (uint32_t*)*outData;
     *data++ = htodl(IDMAP_MAGIC);
+    *data++ = htodl(IDMAP_CURRENT_VERSION);
     *data++ = htodl(targetCrc);
     *data++ = htodl(overlayCrc);
     const char* paths[] = { targetPath, overlayPath };
@@ -5934,44 +6006,30 @@
         data += 256 / sizeof(uint32_t);
     }
     const size_t mapSize = map.size();
-    *data++ = htodl(mapSize);
-    size_t offset = mapSize;
+    uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
+    *typeData++ = htods(pg->id);
+    *typeData++ = htods(mapSize);
     for (size_t i = 0; i < mapSize; ++i) {
-        const Vector<uint32_t>& vector = map.itemAt(i);
-        const size_t N = vector.size();
-        if (N == 0) {
-            *data++ = htodl(0);
-        } else {
-            offset++;
-            *data++ = htodl(offset);
-            offset += N;
+        uint8_t targetTypeId = map.keyAt(i);
+        const IdmapTypeMap& typeMap = map[i];
+        *typeData++ = htods(targetTypeId + 1);
+        *typeData++ = htods(typeMap.overlayTypeId);
+        *typeData++ = htods(typeMap.entryMap.size());
+        *typeData++ = htods(typeMap.entryOffset);
+
+        const size_t entryCount = typeMap.entryMap.size();
+        uint32_t* entries = reinterpret_cast<uint32_t*>(typeData);
+        for (size_t j = 0; j < entryCount; j++) {
+            entries[j] = htodl(typeMap.entryMap[j]);
         }
-    }
-    if (offset == mapSize) {
-        ALOGW("idmap: no resources in overlay package present in base package\n");
-        return UNKNOWN_ERROR;
-    }
-    for (size_t i = 0; i < mapSize; ++i) {
-        const Vector<uint32_t>& vector = map.itemAt(i);
-        const size_t N = vector.size();
-        if (N == 0) {
-            continue;
-        }
-        if (N == 1) { // vector expected to hold (offset) + (N > 0 entries)
-            ALOGW("idmap: type %u supposedly has entries, but no entries found\n", (uint32_t)i);
-            return UNKNOWN_ERROR;
-        }
-        *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
-        for (size_t j = 0; j < N; ++j) {
-            const uint32_t& overlayResID = vector.itemAt(j);
-            *data++ = htodl(overlayResID);
-        }
+        typeData += entryCount * 2;
     }
 
     return NO_ERROR;
 }
 
 bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
+                            uint32_t* pVersion,
                             uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
                             String8* pTargetPath, String8* pOverlayPath)
 {
@@ -5979,17 +6037,20 @@
     if (!assertIdmapHeader(map, sizeBytes)) {
         return false;
     }
+    if (pVersion) {
+        *pVersion = dtohl(map[1]);
+    }
     if (pTargetCrc) {
-        *pTargetCrc = map[1];
+        *pTargetCrc = dtohl(map[2]);
     }
     if (pOverlayCrc) {
-        *pOverlayCrc = map[2];
+        *pOverlayCrc = dtohl(map[3]);
     }
     if (pTargetPath) {
-        pTargetPath->setTo(reinterpret_cast<const char*>(map + 3));
+        pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
     }
     if (pOverlayPath) {
-        pOverlayPath->setTo(reinterpret_cast<const char*>(map + 3 + 256 / sizeof(uint32_t)));
+        pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
     }
     return true;
 }
@@ -6138,184 +6199,184 @@
         size_t pkgCount = pg->packages.size();
         for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
             const Package* pkg = pg->packages[pkgIndex];
-            size_t typeCount = pkg->types.size();
-            printf("  Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
-                    pkg->package->id, String8(String16(pkg->package->name)).string(),
-                    (int)typeCount);
-            for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
-                const Type* typeConfigs = pkg->getType(typeIndex);
-                if (typeConfigs == NULL) {
-                    printf("    type %d NULL\n", (int)typeIndex);
+            printf("  Package %d id=%d name=%s\n", (int)pkgIndex,
+                    pkg->package->id, String8(String16(pkg->package->name)).string());
+        }
+
+        for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
+            const TypeList& typeList = pg->types[typeIndex];
+            if (typeList.isEmpty()) {
+                //printf("    type %d NULL\n", (int)typeIndex);
+                continue;
+            }
+            const Type* typeConfigs = typeList[0];
+            const size_t NTC = typeConfigs->configs.size();
+            printf("    type %d configCount=%d entryCount=%d\n",
+                   (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
+            if (typeConfigs->typeSpecFlags != NULL) {
+                for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
+                    uint32_t resID = (0xff000000 & ((pg->id)<<24))
+                                | (0x00ff0000 & ((typeIndex+1)<<16))
+                                | (0x0000ffff & (entryIndex));
+                    // Since we are creating resID without actually
+                    // iterating over them, we have no idea which is a
+                    // dynamic reference. We must check.
+                    pg->dynamicRefTable.lookupResourceId(&resID);
+
+                    resource_name resName;
+                    if (this->getResourceName(resID, true, &resName)) {
+                        String8 type8;
+                        String8 name8;
+                        if (resName.type8 != NULL) {
+                            type8 = String8(resName.type8, resName.typeLen);
+                        } else {
+                            type8 = String8(resName.type, resName.typeLen);
+                        }
+                        if (resName.name8 != NULL) {
+                            name8 = String8(resName.name8, resName.nameLen);
+                        } else {
+                            name8 = String8(resName.name, resName.nameLen);
+                        }
+                        printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+                            resID,
+                            CHAR16_TO_CSTR(resName.package, resName.packageLen),
+                            type8.string(), name8.string(),
+                            dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+                    } else {
+                        printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
+                    }
+                }
+            }
+            for (size_t configIndex=0; configIndex<NTC; configIndex++) {
+                const ResTable_type* type = typeConfigs->configs[configIndex];
+                if ((((uint64_t)type)&0x3) != 0) {
+                    printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                     continue;
                 }
-                const size_t NTC = typeConfigs->configs.size();
-                printf("    type %d configCount=%d entryCount=%d\n",
-                       (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
-                if (typeConfigs->typeSpecFlags != NULL) {
-                    for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
-                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
-                                    | (0x00ff0000 & ((typeIndex+1)<<16))
-                                    | (0x0000ffff & (entryIndex));
-                        // Since we are creating resID without actually
-                        // iterating over them, we have no idea which is a
-                        // dynamic reference. We must check.
-                        pg->dynamicRefTable.lookupResourceId(&resID);
-
-                        resource_name resName;
-                        if (this->getResourceName(resID, true, &resName)) {
-                            String8 type8;
-                            String8 name8;
-                            if (resName.type8 != NULL) {
-                                type8 = String8(resName.type8, resName.typeLen);
-                            } else {
-                                type8 = String8(resName.type, resName.typeLen);
-                            }
-                            if (resName.name8 != NULL) {
-                                name8 = String8(resName.name8, resName.nameLen);
-                            } else {
-                                name8 = String8(resName.name, resName.nameLen);
-                            }
-                            printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
-                                resID,
-                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                type8.string(), name8.string(),
-                                dtohl(typeConfigs->typeSpecFlags[entryIndex]));
-                        } else {
-                            printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
-                        }
-                    }
+                String8 configStr = type->config.toString();
+                printf("      config %s:\n", configStr.size() > 0
+                        ? configStr.string() : "(default)");
+                size_t entryCount = dtohl(type->entryCount);
+                uint32_t entriesStart = dtohl(type->entriesStart);
+                if ((entriesStart&0x3) != 0) {
+                    printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart);
+                    continue;
                 }
-                for (size_t configIndex=0; configIndex<NTC; configIndex++) {
-                    const ResTable_type* type = typeConfigs->configs[configIndex];
-                    if ((((uint64_t)type)&0x3) != 0) {
-                        printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
+                uint32_t typeSize = dtohl(type->header.size);
+                if ((typeSize&0x3) != 0) {
+                    printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
+                    continue;
+                }
+                for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
+
+                    const uint8_t* const end = ((const uint8_t*)type)
+                        + dtohl(type->header.size);
+                    const uint32_t* const eindex = (const uint32_t*)
+                        (((const uint8_t*)type) + dtohs(type->header.headerSize));
+
+                    uint32_t thisOffset = dtohl(eindex[entryIndex]);
+                    if (thisOffset == ResTable_type::NO_ENTRY) {
                         continue;
                     }
-                    String8 configStr = type->config.toString();
-                    printf("      config %s:\n", configStr.size() > 0
-                            ? configStr.string() : "(default)");
-                    size_t entryCount = dtohl(type->entryCount);
-                    uint32_t entriesStart = dtohl(type->entriesStart);
-                    if ((entriesStart&0x3) != 0) {
-                        printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart);
-                        continue;
-                    }
-                    uint32_t typeSize = dtohl(type->header.size);
-                    if ((typeSize&0x3) != 0) {
-                        printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
-                        continue;
-                    }
-                    for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
 
-                        const uint8_t* const end = ((const uint8_t*)type)
-                            + dtohl(type->header.size);
-                        const uint32_t* const eindex = (const uint32_t*)
-                            (((const uint8_t*)type) + dtohs(type->header.headerSize));
-
-                        uint32_t thisOffset = dtohl(eindex[entryIndex]);
-                        if (thisOffset == ResTable_type::NO_ENTRY) {
-                            continue;
-                        }
-
-                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
-                                    | (0x00ff0000 & ((typeIndex+1)<<16))
-                                    | (0x0000ffff & (entryIndex));
-                        pg->dynamicRefTable.lookupResourceId(&resID);
-                        resource_name resName;
-                        if (this->getResourceName(resID, true, &resName)) {
-                            String8 type8;
-                            String8 name8;
-                            if (resName.type8 != NULL) {
-                                type8 = String8(resName.type8, resName.typeLen);
-                            } else {
-                                type8 = String8(resName.type, resName.typeLen);
-                            }
-                            if (resName.name8 != NULL) {
-                                name8 = String8(resName.name8, resName.nameLen);
-                            } else {
-                                name8 = String8(resName.name, resName.nameLen);
-                            }
-                            printf("        resource 0x%08x %s:%s/%s: ", resID,
-                                    CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                    type8.string(), name8.string());
+                    uint32_t resID = (0xff000000 & ((pg->id)<<24))
+                                | (0x00ff0000 & ((typeIndex+1)<<16))
+                                | (0x0000ffff & (entryIndex));
+                    pg->dynamicRefTable.lookupResourceId(&resID);
+                    resource_name resName;
+                    if (this->getResourceName(resID, true, &resName)) {
+                        String8 type8;
+                        String8 name8;
+                        if (resName.type8 != NULL) {
+                            type8 = String8(resName.type8, resName.typeLen);
                         } else {
-                            printf("        INVALID RESOURCE 0x%08x: ", resID);
+                            type8 = String8(resName.type, resName.typeLen);
                         }
-                        if ((thisOffset&0x3) != 0) {
-                            printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
-                            continue;
-                        }
-                        if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
-                            printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
-                                   entriesStart, thisOffset, typeSize);
-                            continue;
-                        }
-
-                        const ResTable_entry* ent = (const ResTable_entry*)
-                            (((const uint8_t*)type) + entriesStart + thisOffset);
-                        if (((entriesStart + thisOffset)&0x3) != 0) {
-                            printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
-                                 (entriesStart + thisOffset));
-                            continue;
-                        }
-
-                        uintptr_t esize = dtohs(ent->size);
-                        if ((esize&0x3) != 0) {
-                            printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
-                            continue;
-                        }
-                        if ((thisOffset+esize) > typeSize) {
-                            printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
-                                   entriesStart, thisOffset, (void *)esize, typeSize);
-                            continue;
-                        }
-
-                        const Res_value* valuePtr = NULL;
-                        const ResTable_map_entry* bagPtr = NULL;
-                        Res_value value;
-                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
-                            printf("<bag>");
-                            bagPtr = (const ResTable_map_entry*)ent;
+                        if (resName.name8 != NULL) {
+                            name8 = String8(resName.name8, resName.nameLen);
                         } else {
-                            valuePtr = (const Res_value*)
-                                (((const uint8_t*)ent) + esize);
-                            value.copyFrom_dtoh(*valuePtr);
-                            printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
-                                   (int)value.dataType, (int)value.data,
-                                   (int)value.size, (int)value.res0);
+                            name8 = String8(resName.name, resName.nameLen);
                         }
+                        printf("        resource 0x%08x %s:%s/%s: ", resID,
+                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
+                                type8.string(), name8.string());
+                    } else {
+                        printf("        INVALID RESOURCE 0x%08x: ", resID);
+                    }
+                    if ((thisOffset&0x3) != 0) {
+                        printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
+                        continue;
+                    }
+                    if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
+                        printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
+                               entriesStart, thisOffset, typeSize);
+                        continue;
+                    }
 
-                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
-                            printf(" (PUBLIC)");
-                        }
-                        printf("\n");
+                    const ResTable_entry* ent = (const ResTable_entry*)
+                        (((const uint8_t*)type) + entriesStart + thisOffset);
+                    if (((entriesStart + thisOffset)&0x3) != 0) {
+                        printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
+                             (entriesStart + thisOffset));
+                        continue;
+                    }
 
-                        if (inclValues) {
-                            if (valuePtr != NULL) {
-                                printf("          ");
-                                print_value(pkg, value);
-                            } else if (bagPtr != NULL) {
-                                const int N = dtohl(bagPtr->count);
-                                const uint8_t* baseMapPtr = (const uint8_t*)ent;
-                                size_t mapOffset = esize;
-                                const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
-                                const uint32_t parent = dtohl(bagPtr->parent.ident);
-                                uint32_t resolvedParent = parent;
-                                status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
-                                if (err != NO_ERROR) {
-                                    resolvedParent = 0;
-                                }
-                                printf("          Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
-                                        parent, resolvedParent, N);
-                                for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
-                                    printf("          #%i (Key=0x%08x): ",
-                                        i, dtohl(mapPtr->name.ident));
-                                    value.copyFrom_dtoh(mapPtr->value);
-                                    print_value(pkg, value);
-                                    const size_t size = dtohs(mapPtr->value.size);
-                                    mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
-                                    mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
-                                }
+                    uintptr_t esize = dtohs(ent->size);
+                    if ((esize&0x3) != 0) {
+                        printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
+                        continue;
+                    }
+                    if ((thisOffset+esize) > typeSize) {
+                        printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
+                               entriesStart, thisOffset, (void *)esize, typeSize);
+                        continue;
+                    }
+
+                    const Res_value* valuePtr = NULL;
+                    const ResTable_map_entry* bagPtr = NULL;
+                    Res_value value;
+                    if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
+                        printf("<bag>");
+                        bagPtr = (const ResTable_map_entry*)ent;
+                    } else {
+                        valuePtr = (const Res_value*)
+                            (((const uint8_t*)ent) + esize);
+                        value.copyFrom_dtoh(*valuePtr);
+                        printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
+                               (int)value.dataType, (int)value.data,
+                               (int)value.size, (int)value.res0);
+                    }
+
+                    if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
+                        printf(" (PUBLIC)");
+                    }
+                    printf("\n");
+
+                    if (inclValues) {
+                        if (valuePtr != NULL) {
+                            printf("          ");
+                            print_value(typeConfigs->package, value);
+                        } else if (bagPtr != NULL) {
+                            const int N = dtohl(bagPtr->count);
+                            const uint8_t* baseMapPtr = (const uint8_t*)ent;
+                            size_t mapOffset = esize;
+                            const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
+                            const uint32_t parent = dtohl(bagPtr->parent.ident);
+                            uint32_t resolvedParent = parent;
+                            status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
+                            if (err != NO_ERROR) {
+                                resolvedParent = 0;
+                            }
+                            printf("          Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
+                                    parent, resolvedParent, N);
+                            for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
+                                printf("          #%i (Key=0x%08x): ",
+                                    i, dtohl(mapPtr->name.ident));
+                                value.copyFrom_dtoh(mapPtr->value);
+                                print_value(typeConfigs->package, value);
+                                const size_t size = dtohs(mapPtr->value.size);
+                                mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
+                                mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
                             }
                         }
                     }
diff --git a/libs/androidfw/TypeWrappers.cpp b/libs/androidfw/TypeWrappers.cpp
new file mode 100644
index 0000000..8929b66
--- /dev/null
+++ b/libs/androidfw/TypeWrappers.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/TypeWrappers.h>
+
+namespace android {
+
+TypeVariant::iterator& TypeVariant::iterator::operator++() {
+    mIndex++;
+    if (mIndex > dtohl(mTypeVariant->data->entryCount)) {
+        mIndex = dtohl(mTypeVariant->data->entryCount);
+    }
+    return *this;
+}
+
+const ResTable_entry* TypeVariant::iterator::operator*() const {
+    const ResTable_type* type = mTypeVariant->data;
+    const uint32_t entryCount = dtohl(type->entryCount);
+    if (mIndex >= entryCount) {
+        return NULL;
+    }
+
+    const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
+            + dtohl(type->header.size);
+    const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
+            reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
+    if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount) > containerEnd) {
+        ALOGE("Type's entry indices extend beyond its boundaries");
+        return NULL;
+    }
+
+    const uint32_t entryOffset = dtohl(entryIndices[mIndex]);
+    if (entryOffset == ResTable_type::NO_ENTRY) {
+        return NULL;
+    }
+
+    if ((entryOffset & 0x3) != 0) {
+        ALOGE("Index %u points to entry with unaligned offset %p", mIndex, (void*) entryOffset);
+        return NULL;
+    }
+
+    const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
+            reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset);
+    if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) {
+        ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex);
+        return NULL;
+    } else if (reinterpret_cast<uintptr_t>(entry) + dtohs(entry->size) > containerEnd) {
+        ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex);
+        return NULL;
+    } else if (dtohs(entry->size) < sizeof(*entry)) {
+        ALOGE("Entry at index %u is too small (%u)", mIndex, dtohs(entry->size));
+        return NULL;
+    }
+    return entry;
+}
+
+} // namespace android
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 9e9649c..4ff6eec 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -1,33 +1,66 @@
-# Build the unit tests.
+#
+# Copyright (C) 2014 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.
+#
+
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
 LOCAL_PATH:= $(call my-dir)
+testFiles := \
+    ByteBucketArray_test.cpp \
+    Idmap_test.cpp \
+    ResourceTypes_test.cpp \
+    ResTable_test.cpp \
+    Split_test.cpp \
+    TypeWrappers_test.cpp \
+    ZipUtils_test.cpp
+
+# ==========================================================
+# Build the host tests: libandroidfw_tests
+# ==========================================================
 include $(CLEAR_VARS)
 
-# Build the unit tests.
-test_src_files := \
-    BackupData_test.cpp \
-    ObbFile_test.cpp \
-    ZipUtils_test.cpp \
-    ResourceTypes_test.cpp
+LOCAL_MODULE := libandroidfw_tests
 
-shared_libraries := \
+LOCAL_SRC_FILES := $(testFiles)
+LOCAL_STATIC_LIBRARIES := \
+    libandroidfw \
+    libutils \
+    libcutils \
+	liblog
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# ==========================================================
+# Build the device tests: libandroidfw_tests
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libandroidfw_tests
+
+LOCAL_SRC_FILES := $(testFiles) \
+    BackupData_test.cpp \
+    ObbFile_test.cpp
+
+LOCAL_SHARED_LIBRARIES := \
     libandroidfw \
     libcutils \
     libutils \
     libui \
     libstlport
 
-static_libraries := \
-    libgtest \
-    libgtest_main
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/androidfw/tests/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp
new file mode 100644
index 0000000..376e79c
--- /dev/null
+++ b/libs/androidfw/tests/ByteBucketArray_test.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/ByteBucketArray.h>
+
+#include <gtest/gtest.h>
+
+using android::ByteBucketArray;
+
+TEST(ByteBucketArrayTest, TestSparseInsertion) {
+    ByteBucketArray<int> bba;
+    ASSERT_TRUE(bba.set(0, 1));
+    ASSERT_TRUE(bba.set(10, 2));
+    ASSERT_TRUE(bba.set(26, 3));
+    ASSERT_TRUE(bba.set(129, 4));
+    ASSERT_TRUE(bba.set(234, 5));
+
+    for (size_t i = 0; i < bba.size(); i++) {
+        switch (i) {
+            case 0: EXPECT_EQ(1, bba[i]); break;
+            case 10: EXPECT_EQ(2, bba[i]); break;
+            case 26: EXPECT_EQ(3, bba[i]); break;
+            case 129: EXPECT_EQ(4, bba[i]); break;
+            case 234: EXPECT_EQ(5, bba[i]); break;
+            default: EXPECT_EQ(0, bba[i]); break;
+        }
+    }
+}
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
new file mode 100644
index 0000000..d829b76
--- /dev/null
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+/**
+ * Include a binary resource table.
+ *
+ * Package: com.android.test.basic
+ */
+#include "data/basic/basic_arsc.h"
+
+/**
+ * Include a binary resource table.
+ * This table is an overlay.
+ *
+ * Package: com.android.test.basic
+ */
+#include "data/overlay/overlay_arsc.h"
+
+enum { MAY_NOT_BE_BAG = false };
+
+static const uint32_t attr_attr1            = 0x7f010000;
+static const uint32_t attr_attr2            = 0x7f010001;
+static const uint32_t string_test1          = 0x7f020000;
+static const uint32_t string_test2          = 0x7f020001;
+static const uint32_t integer_number1       = 0x7f030000;
+static const uint32_t integer_number2       = 0x7f030001;
+static const uint32_t style_Theme1          = 0x7f040000;
+static const uint32_t style_Theme2          = 0x7f040001;
+static const uint32_t array_integerArray1   = 0x7f050000;
+
+class IdmapTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        ASSERT_EQ(NO_ERROR, mTargetTable.add(basic_arsc, basic_arsc_len));
+        ASSERT_EQ(NO_ERROR, mOverlayTable.add(overlay_arsc, overlay_arsc_len));
+        char targetName[256] = "com.android.test.basic";
+        ASSERT_EQ(NO_ERROR, mTargetTable.createIdmap(mOverlayTable, 0, 0,
+                    targetName, targetName, &mData, &mDataSize));
+    }
+
+    virtual void TearDown() {
+        free(mData);
+    }
+
+    ResTable mTargetTable;
+    ResTable mOverlayTable;
+    void* mData;
+    size_t mDataSize;
+};
+
+TEST_F(IdmapTest, canLoadIdmap) {
+    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+}
+
+TEST_F(IdmapTest, overlayOverridesResourceValue) {
+    Res_value val;
+    ssize_t block = mTargetTable.getResource(string_test2, &val, false);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+    const ResStringPool* pool = mTargetTable.getTableStringBlock(block);
+    ASSERT_TRUE(pool != NULL);
+    ASSERT_LT(val.data, pool->size());
+
+    size_t strLen;
+    const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
+    ASSERT_TRUE(targetStr16 != NULL);
+    ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
+
+    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+
+    ssize_t newBlock = mTargetTable.getResource(string_test2, &val, false);
+    ASSERT_GE(newBlock, 0);
+    ASSERT_NE(block, newBlock);
+    ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+    pool = mTargetTable.getTableStringBlock(newBlock);
+    ASSERT_TRUE(pool != NULL);
+    ASSERT_LT(val.data, pool->size());
+
+    targetStr16 = pool->stringAt(val.data, &strLen);
+    ASSERT_TRUE(targetStr16 != NULL);
+    ASSERT_EQ(String16("test2-overlay"), String16(targetStr16, strLen));
+}
+
+TEST_F(IdmapTest, overlaidResourceHasSameName) {
+    ASSERT_EQ(NO_ERROR, mTargetTable.add(overlay_arsc, overlay_arsc_len, mData, mDataSize));
+
+    ResTable::resource_name resName;
+    ASSERT_TRUE(mTargetTable.getResourceName(array_integerArray1, false, &resName));
+
+    ASSERT_TRUE(resName.package != NULL);
+    ASSERT_TRUE(resName.type != NULL);
+    ASSERT_TRUE(resName.name != NULL);
+
+    EXPECT_EQ(String16("com.android.test.basic"), String16(resName.package, resName.packageLen));
+    EXPECT_EQ(String16("array"), String16(resName.type, resName.typeLen));
+    EXPECT_EQ(String16("integerArray1"), String16(resName.name, resName.nameLen));
+}
+
+} // namespace
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
new file mode 100644
index 0000000..54d42c3
--- /dev/null
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+/**
+ * Include a binary resource table.
+ *
+ * Package: com.android.test.basic
+ */
+#include "data/basic/basic_arsc.h"
+
+enum { MAY_NOT_BE_BAG = false };
+
+static const uint32_t attr_attr1            = 0x7f010000;
+static const uint32_t attr_attr2            = 0x7f010001;
+static const uint32_t string_test1          = 0x7f020000;
+static const uint32_t string_test2          = 0x7f020001;
+static const uint32_t integer_number1       = 0x7f030000;
+static const uint32_t integer_number2       = 0x7f030001;
+static const uint32_t style_Theme1          = 0x7f040000;
+static const uint32_t style_Theme2          = 0x7f040001;
+static const uint32_t array_integerArray1   = 0x7f050000;
+
+TEST(ResTableTest, shouldLoadSuccessfully) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+}
+
+TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    Res_value val;
+    ssize_t block = table.getResource(string_test1, &val, MAY_NOT_BE_BAG);
+
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+
+    const ResStringPool* pool = table.getTableStringBlock(block);
+    ASSERT_TRUE(NULL != pool);
+    ASSERT_EQ(String8("test1"), pool->string8ObjectAt(val.data));
+}
+
+TEST(ResTableTest, resourceNameIsResolved) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    String16 defPackage("com.android.test.basic");
+    String16 testName("@string/test1");
+    uint32_t resID = table.identifierForName(testName.string(), testName.size(),
+                                             0, 0,
+                                             defPackage.string(), defPackage.size());
+    ASSERT_NE(uint32_t(0x00000000), resID);
+    ASSERT_EQ(string_test1, resID);
+}
+
+TEST(ResTableTest, noParentThemeIsAppliedCorrectly) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    ResTable::Theme theme(table);
+    ASSERT_EQ(NO_ERROR, theme.applyStyle(style_Theme1));
+
+    Res_value val;
+    uint32_t specFlags = 0;
+    ssize_t index = theme.getAttribute(attr_attr1, &val, &specFlags);
+    ASSERT_GE(index, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(100), val.data);
+
+    index = theme.getAttribute(attr_attr2, &val, &specFlags);
+    ASSERT_GE(index, 0);
+    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+    ASSERT_EQ(integer_number1, val.data);
+}
+
+TEST(ResTableTest, parentThemeIsAppliedCorrectly) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    ResTable::Theme theme(table);
+    ASSERT_EQ(NO_ERROR, theme.applyStyle(style_Theme2));
+
+    Res_value val;
+    uint32_t specFlags = 0;
+    ssize_t index = theme.getAttribute(attr_attr1, &val, &specFlags);
+    ASSERT_GE(index, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(300), val.data);
+
+    index = theme.getAttribute(attr_attr2, &val, &specFlags);
+    ASSERT_GE(index, 0);
+    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+    ASSERT_EQ(integer_number1, val.data);
+}
+
+TEST(ResTableTest, referenceToBagIsNotResolved) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    Res_value val;
+    ssize_t block = table.getResource(integer_number2, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+    ASSERT_EQ(array_integerArray1, val.data);
+
+    ssize_t newBlock = table.resolveReference(&val, block);
+    EXPECT_EQ(block, newBlock);
+    EXPECT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+    EXPECT_EQ(array_integerArray1, val.data);
+}
+
+TEST(ResTableTest, resourcesStillAccessibleAfterParameterChange) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    Res_value val;
+    ssize_t block = table.getResource(integer_number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+
+    const ResTable::bag_entry* entry;
+    ssize_t count = table.lockBag(array_integerArray1, &entry);
+    ASSERT_GE(count, 0);
+    table.unlockBag(entry);
+
+    ResTable_config param;
+    memset(&param, 0, sizeof(param));
+    param.density = 320;
+    table.setParameters(&param);
+
+    block = table.getResource(integer_number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+
+    count = table.lockBag(array_integerArray1, &entry);
+    ASSERT_GE(count, 0);
+    table.unlockBag(entry);
+}
+
+TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    Res_value val;
+    ssize_t block = table.getResource(integer_number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(200), val.data);
+
+    ResTable_config param;
+    memset(&param, 0, sizeof(param));
+    param.language[0] = 's';
+    param.language[1] = 'v';
+    param.country[0] = 'S';
+    param.country[1] = 'E';
+    table.setParameters(&param);
+
+    block = table.getResource(integer_number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(400), val.data);
+}
+
+}
diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp
index 4888b4a..6041e08 100644
--- a/libs/androidfw/tests/ResourceTypes_test.cpp
+++ b/libs/androidfw/tests/ResourceTypes_test.cpp
@@ -64,8 +64,8 @@
      config.packLanguage("eng");
 
      // 1-00110-01 101-00100
-     EXPECT_EQ(0x99, config.language[0]);
-     EXPECT_EQ(0xa4, config.language[1]);
+     EXPECT_EQ('\x99', config.language[0]);
+     EXPECT_EQ('\xA4', config.language[1]);
 
      char out[4] = { 1, 1, 1, 1};
      config.unpackLanguage(out);
diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp
new file mode 100644
index 0000000..dbfdeae
--- /dev/null
+++ b/libs/androidfw/tests/Split_test.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+
+#include <gtest/gtest.h>
+
+/**
+ * Include a binary resource table. This table
+ * is a base table for an APK split.
+ *
+ * Package: com.android.example.split
+ *
+ * layout/main          0x7f020000 {default, fr-sw600dp-v13}
+ *
+ * string/app_title     0x7f030000 {default}
+ * string/test          0x7f030001 {default}
+ * string/boom          0x7f030002 {default}
+ * string/blah          0x7f030003 {default}
+ *
+ * array/lotsofstrings  0x7f040000 {default}
+ * array/numList        0x7f040001 {default}
+ * array/ary            0x7f040002 {default}
+ *
+ */
+#include "data/split_base_arsc.h"
+
+/**
+ * Include a binary resource table. This table
+ * is a configuration split table for an APK split.
+ *
+ * Package: com.android.example.split
+ *
+ * string/app_title     0x7f030000 {fr}
+ * string/test          0x7f030001 {de,fr}
+ * string/blah          0x7f030003 {fr}
+ *
+ * array/lotsofstrings  0x7f040000 {fr}
+ *
+ */
+#include "data/split_de_fr_arsc.h"
+
+
+using namespace android;
+
+enum { MAY_NOT_BE_BAG = false };
+
+void makeConfigFrench(ResTable_config* config) {
+    memset(config, 0, sizeof(*config));
+    config->language[0] = 'f';
+    config->language[1] = 'r';
+}
+
+TEST(SplitTest, TestLoadBase) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(split_base_arsc, split_base_arsc_len));
+}
+
+TEST(SplitTest, TestGetResourceFromBase) {
+    ResTable_config frenchConfig;
+    makeConfigFrench(&frenchConfig);
+
+    ResTable table;
+    table.setParameters(&frenchConfig);
+
+    ASSERT_EQ(NO_ERROR, table.add(split_base_arsc, split_base_arsc_len));
+
+    ResTable_config expectedConfig;
+    memset(&expectedConfig, 0, sizeof(expectedConfig));
+
+    Res_value val;
+    ResTable_config config;
+    ssize_t block = table.getResource(0x7f030000, &val, MAY_NOT_BE_BAG, 0, NULL, &config);
+
+    // The returned block should tell us which string pool to get the value, if it is a string.
+    EXPECT_GE(block, 0);
+
+    // We expect the default resource to be selected since it is the only resource configuration.
+    EXPECT_EQ(0, expectedConfig.compare(config));
+
+    EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
+}
+
+TEST(SplitTest, TestGetResourceFromSplit) {
+    ResTable_config expectedConfig;
+    makeConfigFrench(&expectedConfig);
+
+    ResTable table;
+    table.setParameters(&expectedConfig);
+
+    ASSERT_EQ(NO_ERROR, table.add(split_base_arsc, split_base_arsc_len));
+    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+
+    Res_value val;
+    ResTable_config config;
+    ssize_t block = table.getResource(0x7f030000, &val, MAY_NOT_BE_BAG, 0, NULL, &config);
+
+    EXPECT_GE(block, 0);
+
+    EXPECT_EQ(0, expectedConfig.compare(config));
+
+    EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
+}
+
+TEST(SplitTest, ResourcesFromBaseAndSplitHaveSameNames) {
+    ResTable_config expectedConfig;
+    makeConfigFrench(&expectedConfig);
+
+    ResTable table;
+    table.setParameters(&expectedConfig);
+
+    ASSERT_EQ(NO_ERROR, table.add(split_base_arsc, split_base_arsc_len));
+
+    ResTable::resource_name baseName;
+    EXPECT_TRUE(table.getResourceName(0x7f030003, false, &baseName));
+
+    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+
+    ResTable::resource_name frName;
+    EXPECT_TRUE(table.getResourceName(0x7f030003, false, &frName));
+
+    EXPECT_EQ(
+            String16(baseName.package, baseName.packageLen),
+            String16(frName.package, frName.packageLen));
+
+    EXPECT_EQ(
+            String16(baseName.type, baseName.typeLen),
+            String16(frName.type, frName.typeLen));
+
+    EXPECT_EQ(
+            String16(baseName.name, baseName.nameLen),
+            String16(frName.name, frName.nameLen));
+}
+
+TEST(SplitTest, TypeEntrySpecFlagsAreUpdated) {
+    ResTable_config defaultConfig;
+    memset(&defaultConfig, 0, sizeof(defaultConfig));
+
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(split_base_arsc, split_base_arsc_len));
+
+    Res_value val;
+    uint32_t specFlags = 0;
+    ssize_t block = table.getResource(0x7f030000, &val, MAY_NOT_BE_BAG, 0, &specFlags, NULL);
+    EXPECT_GE(block, 0);
+
+    EXPECT_EQ(static_cast<uint32_t>(0), specFlags);
+
+    ASSERT_EQ(NO_ERROR, table.add(split_de_fr_arsc, split_de_fr_arsc_len));
+
+    uint32_t frSpecFlags = 0;
+    block = table.getResource(0x7f030000, &val, MAY_NOT_BE_BAG, 0, &frSpecFlags, NULL);
+    EXPECT_GE(block, 0);
+
+    EXPECT_EQ(ResTable_config::CONFIG_LOCALE, frSpecFlags);
+}
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
new file mode 100644
index 0000000..75a233a
--- /dev/null
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -0,0 +1,17 @@
+#ifndef __TEST_HELPERS_H
+#define __TEST_HELPERS_H
+
+#include <ostream>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) {
+    return out << str.string();
+}
+
+static inline ::std::ostream& operator<<(::std::ostream& out, const android::String16& str) {
+    return out << android::String8(str).string();
+}
+
+#endif // __TEST_HELPERS_H
diff --git a/libs/androidfw/tests/TypeWrappers_test.cpp b/libs/androidfw/tests/TypeWrappers_test.cpp
new file mode 100644
index 0000000..d69abe5
--- /dev/null
+++ b/libs/androidfw/tests/TypeWrappers_test.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
+#include <androidfw/TypeWrappers.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+void* createTypeData() {
+    ResTable_type t;
+    memset(&t, 0, sizeof(t));
+    t.header.type = RES_TABLE_TYPE_TYPE;
+    t.header.headerSize = sizeof(t);
+    t.id = 1;
+    t.entryCount = 3;
+
+    uint32_t offsets[3];
+    t.entriesStart = t.header.headerSize + sizeof(offsets);
+    t.header.size = t.entriesStart;
+
+    offsets[0] = 0;
+    ResTable_entry e1;
+    memset(&e1, 0, sizeof(e1));
+    e1.size = sizeof(e1);
+    e1.key.index = 0;
+    t.header.size += sizeof(e1);
+
+    Res_value v1;
+    memset(&v1, 0, sizeof(v1));
+    t.header.size += sizeof(v1);
+
+    offsets[1] = ResTable_type::NO_ENTRY;
+
+    offsets[2] = sizeof(e1) + sizeof(v1);
+    ResTable_entry e2;
+    memset(&e2, 0, sizeof(e2));
+    e2.size = sizeof(e2);
+    e2.key.index = 1;
+    t.header.size += sizeof(e2);
+
+    Res_value v2;
+    memset(&v2, 0, sizeof(v2));
+    t.header.size += sizeof(v2);
+
+    uint8_t* data = (uint8_t*)malloc(t.header.size);
+    uint8_t* p = data;
+    memcpy(p, &t, sizeof(t));
+    p += sizeof(t);
+    memcpy(p, offsets, sizeof(offsets));
+    p += sizeof(offsets);
+    memcpy(p, &e1, sizeof(e1));
+    p += sizeof(e1);
+    memcpy(p, &v1, sizeof(v1));
+    p += sizeof(v1);
+    memcpy(p, &e2, sizeof(e2));
+    p += sizeof(e2);
+    memcpy(p, &v2, sizeof(v2));
+    p += sizeof(v2);
+    return data;
+}
+
+TEST(TypeVariantIteratorTest, shouldIterateOverTypeWithoutErrors) {
+    ResTable_type* data = (ResTable_type*) createTypeData();
+
+    TypeVariant v(data);
+
+    TypeVariant::iterator iter = v.beginEntries();
+    ASSERT_EQ(uint32_t(0), iter.index());
+    ASSERT_TRUE(NULL != *iter);
+    ASSERT_EQ(uint32_t(0), iter->key.index);
+    ASSERT_NE(v.endEntries(), iter);
+
+    iter++;
+
+    ASSERT_EQ(uint32_t(1), iter.index());
+    ASSERT_TRUE(NULL == *iter);
+    ASSERT_NE(v.endEntries(), iter);
+
+    iter++;
+
+    ASSERT_EQ(uint32_t(2), iter.index());
+    ASSERT_TRUE(NULL != *iter);
+    ASSERT_EQ(uint32_t(1), iter->key.index);
+    ASSERT_NE(v.endEntries(), iter);
+
+    iter++;
+
+    ASSERT_EQ(v.endEntries(), iter);
+
+    free(data);
+}
+
+} // namespace android
diff --git a/libs/androidfw/tests/data/.gitignore b/libs/androidfw/tests/data/.gitignore
new file mode 100644
index 0000000..c05cfb0
--- /dev/null
+++ b/libs/androidfw/tests/data/.gitignore
@@ -0,0 +1,2 @@
+*.apk
+*.arsc
diff --git a/libs/androidfw/tests/data/basic/AndroidManifest.xml b/libs/androidfw/tests/data/basic/AndroidManifest.xml
new file mode 100644
index 0000000..a56ac18
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.basic">
+    <application>
+    </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h
new file mode 100644
index 0000000..6532076
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/basic_arsc.h
@@ -0,0 +1,131 @@
+unsigned char basic_arsc[] = {
+  0x02, 0x00, 0x0c, 0x00, 0xfc, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xb0, 0x05, 0x00, 0x00,
+  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
+  0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+  0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+  0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00,
+  0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00,
+  0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
+  0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+  0xdc, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+  0x2a, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
+  0x5c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+  0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00,
+  0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00,
+  0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x31, 0x00,
+  0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00,
+  0x65, 0x00, 0x72, 0x00, 0x32, 0x00, 0x00, 0x00, 0x06, 0x00, 0x54, 0x00,
+  0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x31, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
+  0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00, 0x72, 0x00,
+  0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x7f,
+  0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x90, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10,
+  0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x03, 0x7f, 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x04, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
+  0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x7c, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
+};
+unsigned int basic_arsc_len = 1532;
diff --git a/libs/androidfw/tests/data/basic/build b/libs/androidfw/tests/data/basic/build
new file mode 100755
index 0000000..237342c
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc basic.arsc && \
+xxd -i basic.arsc > basic_arsc.h
diff --git a/libs/androidfw/tests/data/basic/res/values-sv/values.xml b/libs/androidfw/tests/data/basic/res/values-sv/values.xml
new file mode 100644
index 0000000..9d52307
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/values-sv/values.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <integer name="number1">400</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
new file mode 100644
index 0000000..662eda6
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <attr name="attr1" format="reference|integer" />
+    <attr name="attr2" format="reference|integer" />
+
+    <string name="test1">test1</string>
+    <string name="test2">test2</string>
+
+    <integer name="number1">200</integer>
+    <integer name="number2">@array/integerArray1</integer>
+
+    <style name="Theme1">
+        <item name="com.android.test.basic:attr1">100</item>
+        <item name="com.android.test.basic:attr2">@integer/number1</item>
+    </style>
+
+    <style name="Theme2" parent="@com.android.test.basic:style/Theme1">
+        <item name="com.android.test.basic:attr1">300</item>
+    </style>
+
+    <integer-array name="integerArray1">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </integer-array>
+</resources>
diff --git a/libs/androidfw/tests/data/overlay/AndroidManifest.xml b/libs/androidfw/tests/data/overlay/AndroidManifest.xml
new file mode 100644
index 0000000..a56ac18
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.basic">
+    <application>
+    </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/overlay/build b/libs/androidfw/tests/data/overlay/build
new file mode 100755
index 0000000..87cf6de
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc overlay.arsc && \
+xxd -i overlay.arsc > overlay_arsc.h
diff --git a/libs/androidfw/tests/data/overlay/overlay_arsc.h b/libs/androidfw/tests/data/overlay/overlay_arsc.h
new file mode 100644
index 0000000..5bd98b2
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/overlay_arsc.h
@@ -0,0 +1,69 @@
+unsigned char overlay_arsc[] = {
+  0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x74, 0x00,
+  0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x6f, 0x00,
+  0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xc4, 0x02, 0x00, 0x00,
+  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+  0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+  0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00,
+  0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x50, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+  0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x69, 0x00, 0x6e, 0x00,
+  0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00,
+  0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
+  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10,
+  0x0b, 0x00, 0x00, 0x00
+};
+unsigned int overlay_arsc_len = 784;
diff --git a/libs/androidfw/tests/data/overlay/res/values/values.xml b/libs/androidfw/tests/data/overlay/res/values/values.xml
new file mode 100644
index 0000000..227e889
--- /dev/null
+++ b/libs/androidfw/tests/data/overlay/res/values/values.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="test2">test2-overlay</string>
+    <integer-array name="integerArray1">
+        <item>10</item>
+        <item>11</item>
+    </integer-array>
+</resources>
diff --git a/libs/androidfw/tests/data/split_base_arsc.h b/libs/androidfw/tests/data/split_base_arsc.h
new file mode 100644
index 0000000..e0321e9
--- /dev/null
+++ b/libs/androidfw/tests/data/split_base_arsc.h
@@ -0,0 +1,221 @@
+unsigned char split_base_arsc[] = {
+  0x02, 0x00, 0x0c, 0x00, 0x30, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0x94, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
+  0x72, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00,
+  0xb4, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
+  0xf4, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00,
+  0x44, 0x01, 0x00, 0x00, 0x13, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00,
+  0x2f, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
+  0x74, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
+  0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x22, 0x00,
+  0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x61, 0x00,
+  0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x66, 0x00,
+  0x72, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x77, 0x00, 0x36, 0x00, 0x30, 0x00,
+  0x30, 0x00, 0x64, 0x00, 0x70, 0x00, 0x2d, 0x00, 0x76, 0x00, 0x31, 0x00,
+  0x33, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
+  0x2e, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x53, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x74, 0x00, 0x20, 0x00,
+  0x41, 0x00, 0x50, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x48, 0x00,
+  0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x2c, 0x00, 0x20, 0x00,
+  0x57, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+  0x21, 0x00, 0x00, 0x00, 0x07, 0x00, 0x42, 0x00, 0x6c, 0x00, 0x61, 0x00,
+  0x68, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x0b, 0x00,
+  0x48, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00,
+  0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x20, 0x00,
+  0x62, 0x00, 0x79, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x49, 0x00,
+  0x20, 0x00, 0x68, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x20, 0x00, 0x41, 0x00,
+  0x4c, 0x00, 0x4c, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x49, 0x00,
+  0x20, 0x00, 0x68, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x20, 0x00, 0x31, 0x00,
+  0x21, 0x00, 0x31, 0x00, 0x21, 0x00, 0x20, 0x00, 0x3a, 0x00, 0x29, 0x00,
+  0x00, 0x00, 0x0b, 0x00, 0x49, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x6f, 0x00,
+  0x20, 0x00, 0x68, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x20, 0x00, 0x3a, 0x00,
+  0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x01,
+  0x90, 0x08, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+  0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
+  0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00,
+  0x61, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2e, 0x00,
+  0x73, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x74, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xd4, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x3a, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+  0x66, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00,
+  0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+  0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00,
+  0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x07, 0x00,
+  0x70, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6c, 0x00,
+  0x73, 0x00, 0x00, 0x00, 0x04, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00,
+  0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00,
+  0x6f, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x64, 0x00, 0x69, 0x00,
+  0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x69, 0x00,
+  0x64, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
+  0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0x30, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+  0x46, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,
+  0x80, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
+  0xa4, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00,
+  0x69, 0x00, 0x74, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x62, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x68, 0x00, 0x00, 0x00, 0x0d, 0x00,
+  0x6c, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
+  0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00,
+  0x73, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00,
+  0x4c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x61, 0x00, 0x72, 0x00, 0x79, 0x00, 0x00, 0x00, 0x04, 0x00, 0x70, 0x00,
+  0x6c, 0x00, 0x75, 0x00, 0x72, 0x00, 0x00, 0x00, 0x03, 0x00, 0x71, 0x00,
+  0x75, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x67, 0x00, 0x72, 0x00,
+  0x65, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x77, 0x00,
+  0x69, 0x00, 0x64, 0x00, 0x74, 0x00, 0x68, 0x00, 0x00, 0x00, 0x0a, 0x00,
+  0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x69, 0x00,
+  0x66, 0x00, 0x69, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x94, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0xc8, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03,
+  0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03,
+  0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0xd2, 0x04, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x7f,
+  0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x7f,
+  0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x01, 0x19, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x7c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0xff,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x1d, 0x00, 0xff, 0x00, 0xff,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05, 0x01, 0x17, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x05,
+  0x01, 0xe6, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x0b, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+  0x7b, 0x00, 0x00, 0x00
+};
+unsigned int split_base_arsc_len = 2608;
diff --git a/libs/androidfw/tests/data/split_de_fr_arsc.h b/libs/androidfw/tests/data/split_de_fr_arsc.h
new file mode 100644
index 0000000..6f6a416
--- /dev/null
+++ b/libs/androidfw/tests/data/split_de_fr_arsc.h
@@ -0,0 +1,118 @@
+unsigned char split_de_fr_arsc[] = {
+  0x02, 0x00, 0x0c, 0x00, 0x64, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x2c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00,
+  0x6c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x41, 0x00, 0x63, 0x00, 0x68, 0x00,
+  0x74, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x41, 0x00, 0x50, 0x00, 0x4b, 0x00, 0x20, 0x00, 0x44, 0x00,
+  0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0xe9, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6a, 0x00, 0x6f, 0x00,
+  0x75, 0x00, 0x72, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x4d, 0x00, 0x6f, 0x00,
+  0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x21, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x42, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x68, 0x00, 0x2e, 0x00, 0x2e, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x48, 0x00, 0xe9, 0x00, 0x20, 0x00, 0x6c, 0x00,
+  0xe0, 0x00, 0x00, 0x00, 0x09, 0x00, 0x41, 0x00, 0x75, 0x00, 0x20, 0x00,
+  0x72, 0x00, 0x65, 0x00, 0x76, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x72, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x01, 0xa0, 0x04, 0x00, 0x00,
+  0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+  0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+  0x64, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00, 0x61, 0x00, 0x6d, 0x00,
+  0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x70, 0x00,
+  0x6c, 0x00, 0x69, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x1c, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+  0x4c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
+  0x74, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00,
+  0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00,
+  0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+  0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00,
+  0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x07, 0x00, 0x70, 0x00, 0x6c, 0x00,
+  0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x73, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00,
+  0x00, 0x00, 0x05, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00,
+  0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00,
+  0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+  0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+  0x2e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00,
+  0x5f, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x6c, 0x00, 0x65, 0x00,
+  0x00, 0x00, 0x04, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+  0x00, 0x00, 0x04, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x68, 0x00,
+  0x00, 0x00, 0x0d, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x73, 0x00,
+  0x6f, 0x00, 0x66, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00,
+  0x6e, 0x00, 0x67, 0x00, 0x73, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x64, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+  0x84, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x44, 0x00, 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x01, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned int split_de_fr_arsc_len = 1380;