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/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index ae35f7b..593a197 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -105,7 +105,7 @@
 
         uint32_t cached_target_crc, cached_overlay_crc;
         String8 cached_target_path, cached_overlay_path;
-        if (!ResTable::getIdmapInfo(buf, N, &cached_target_crc, &cached_overlay_crc,
+        if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc,
                     &cached_target_path, &cached_overlay_path)) {
             return true;
         }
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 46c0edc..90cfa2c 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -66,26 +66,32 @@
       Display an idmap file: \n\
 \n\
       $ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\
-      SECTION      ENTRY        VALUE      OFFSET    COMMENT \n\
-      IDMAP HEADER magic        0x706d6469 0x0 \n\
-                   base crc     0x484aa77f 0x1 \n\
-                   overlay crc  0x03c66fa5 0x2 \n\
-                   base path    .......... 0x03-0x42 /system/app/target.apk \n\
-                   overlay path .......... 0x43-0x82 /vendor/overlay/overlay.apk \n\
-      DATA HEADER  types count  0x00000003 0x83 \n\
-                   padding      0x00000000 0x84 \n\
-                   type offset  0x00000004 0x85      absolute offset 0x87, xml \n\
-                   type offset  0x00000007 0x86      absolute offset 0x8a, string \n\
-      DATA BLOCK   entry count  0x00000001 0x87 \n\
-                   entry offset 0x00000000 0x88 \n\
-                   entry        0x7f020000 0x89      xml/integer \n\
-      DATA BLOCK   entry count  0x00000002 0x8a \n\
-                   entry offset 0x00000000 0x8b \n\
-                   entry        0x7f030000 0x8c      string/str \n\
-                   entry        0x7f030001 0x8d      string/str2 \n\
+      SECTION      ENTRY        VALUE      COMMENT \n\
+      IDMAP HEADER magic        0x706d6469 \n\
+                   base crc     0xb65a383f \n\
+                   overlay crc  0x7b9675e8 \n\
+                   base path    .......... /path/to/target.apk \n\
+                   overlay path .......... /path/to/overlay.apk \n\
+      DATA HEADER  target pkg   0x0000007f \n\
+                   types count  0x00000003 \n\
+      DATA BLOCK   target type  0x00000002 \n\
+                   overlay type 0x00000002 \n\
+                   entry count  0x00000001 \n\
+                   entry offset 0x00000000 \n\
+                   entry        0x00000000 drawable/drawable \n\
+      DATA BLOCK   target type  0x00000003 \n\
+                   overlay type 0x00000003 \n\
+                   entry count  0x00000001 \n\
+                   entry offset 0x00000000 \n\
+                   entry        0x00000000 xml/integer \n\
+      DATA BLOCK   target type  0x00000004 \n\
+                   overlay type 0x00000004 \n\
+                   entry count  0x00000001 \n\
+                   entry offset 0x00000000 \n\
+                   entry        0x00000000 raw/lorem_ipsum \n\
 \n\
       In this example, the overlay package provides three alternative resource values:\n\
-      xml/integer, string/str and string/str2.\n\
+      drawable/drawable, xml/integer, and raw/lorem_ipsum \n\
 \n\
 NOTES \n\
       This tool and its expected invocation from installd is modelled on dexopt.";
diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp
index a59f5d3..b9ac8a5 100644
--- a/cmds/idmap/inspect.cpp
+++ b/cmds/idmap/inspect.cpp
@@ -10,92 +10,108 @@
 
 using namespace android;
 
-#define NEXT(b, i, o) do { if (buf.next(&i, &o) < 0) { return -1; } } while (0)
-
 namespace {
-    static const uint32_t IDMAP_MAGIC = 0x706d6469;
+    static const uint32_t IDMAP_MAGIC = 0x504D4449;
     static const size_t PATH_LENGTH = 256;
-    static const uint32_t IDMAP_HEADER_SIZE = (3 + 2 * (PATH_LENGTH / sizeof(uint32_t)));
 
     void printe(const char *fmt, ...);
 
     class IdmapBuffer {
         private:
-            char *buf_;
+            const char* buf_;
             size_t len_;
-            mutable size_t pos_;
+            size_t pos_;
         public:
-            IdmapBuffer() : buf_((char *)MAP_FAILED), len_(0), pos_(0) {}
+            IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
 
             ~IdmapBuffer() {
                 if (buf_ != MAP_FAILED) {
-                    munmap(buf_, len_);
+                    munmap(const_cast<char*>(buf_), len_);
                 }
             }
 
-            int init(const char *idmap_path)
-            {
+            status_t init(const char *idmap_path) {
                 struct stat st;
                 int fd;
 
                 if (stat(idmap_path, &st) < 0) {
                     printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
                 len_ = st.st_size;
                 if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
                     printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
-                if ((buf_ = (char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+                if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
                     close(fd);
                     printe("failed to mmap idmap: %s\n", strerror(errno));
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
                 close(fd);
-                return 0;
+                return NO_ERROR;
             }
 
-            int next(uint32_t *i, uint32_t *offset) const
-            {
+            status_t nextUint32(uint32_t* i) {
                 if (!buf_) {
                     printe("failed to read next uint32_t: buffer not initialized\n");
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
-                if (pos_ + 4 > len_) {
+
+                if (pos_ + sizeof(uint32_t) > len_) {
                     printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
                             pos_);
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
-                *offset = pos_ / sizeof(uint32_t);
-                char a = buf_[pos_++];
-                char b = buf_[pos_++];
-                char c = buf_[pos_++];
-                char d = buf_[pos_++];
-                *i = (d << 24) | (c << 16) | (b << 8) | a;
-                return 0;
+
+                if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) {
+                    printe("failed to read next uint32_t: not aligned on 4-byte boundary\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_));
+                pos_ += sizeof(uint32_t);
+                return NO_ERROR;
             }
 
-            int nextPath(char *b, uint32_t *offset_start, uint32_t *offset_end) const
-            {
+            status_t nextUint16(uint16_t* i) {
+                if (!buf_) {
+                    printe("failed to read next uint16_t: buffer not initialized\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                if (pos_ + sizeof(uint16_t) > len_) {
+                    printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n",
+                            pos_);
+                    return UNKNOWN_ERROR;
+                }
+
+                if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) {
+                    printe("failed to read next uint32_t: not aligned on 2-byte boundary\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_));
+                pos_ += sizeof(uint16_t);
+                return NO_ERROR;
+            }
+
+            status_t nextPath(char *b) {
                 if (!buf_) {
                     printe("failed to read next path: buffer not initialized\n");
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
                 if (pos_ + PATH_LENGTH > len_) {
                     printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
-                    return -1;
+                    return UNKNOWN_ERROR;
                 }
                 memcpy(b, buf_ + pos_, PATH_LENGTH);
-                *offset_start = pos_ / sizeof(uint32_t);
                 pos_ += PATH_LENGTH;
-                *offset_end = pos_ / sizeof(uint32_t) - 1;
-                return 0;
+                return NO_ERROR;
             }
     };
 
-    void printe(const char *fmt, ...)
-    {
+    void printe(const char *fmt, ...) {
         va_list ap;
 
         va_start(ap, fmt);
@@ -104,44 +120,37 @@
         va_end(ap);
     }
 
-    void print_header()
-    {
-        printf("SECTION      ENTRY        VALUE      OFFSET    COMMENT\n");
+    void print_header() {
+        printf("SECTION      ENTRY        VALUE      COMMENT\n");
     }
 
-    void print(const char *section, const char *subsection, uint32_t value, uint32_t offset,
-            const char *fmt, ...)
-    {
+    void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
         va_list ap;
 
         va_start(ap, fmt);
-        printf("%-12s %-12s 0x%08x 0x%-4x    ", section, subsection, value, offset);
+        printf("%-12s %-12s 0x%08x ", section, subsection, value);
         vprintf(fmt, ap);
         printf("\n");
         va_end(ap);
     }
 
-    void print_path(const char *section, const char *subsection, uint32_t offset_start,
-            uint32_t offset_end, const char *fmt, ...)
-    {
+    void print_path(const char *section, const char *subsection, const char *fmt, ...) {
         va_list ap;
 
         va_start(ap, fmt);
-        printf("%-12s %-12s .......... 0x%02x-0x%02x ", section, subsection, offset_start,
-                offset_end);
+        printf("%-12s %-12s .......... ", section, subsection);
         vprintf(fmt, ap);
         printf("\n");
         va_end(ap);
     }
 
-    int resource_metadata(const AssetManager& am, uint32_t res_id,
-            String8 *package, String8 *type, String8 *name)
-    {
+    status_t resource_metadata(const AssetManager& am, uint32_t res_id,
+            String8 *package, String8 *type, String8 *name) {
         const ResTable& rt = am.getResources();
         struct ResTable::resource_name data;
         if (!rt.getResourceName(res_id, false, &data)) {
             printe("failed to get resource name id=0x%08x\n", res_id);
-            return -1;
+            return UNKNOWN_ERROR;
         }
         if (package) {
             *package = String8(String16(data.package, data.packageLen));
@@ -152,140 +161,150 @@
         if (name) {
             *name = String8(String16(data.name, data.nameLen));
         }
-        return 0;
+        return NO_ERROR;
     }
 
-    int package_id(const AssetManager& am)
-    {
-        return (am.getResources().getBasePackageId(0)) << 24;
-    }
-
-    int parse_idmap_header(const IdmapBuffer& buf, AssetManager& am)
-    {
-        uint32_t i, o, e;
+    status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
+        uint32_t i;
         char path[PATH_LENGTH];
 
-        NEXT(buf, i, o);
+        status_t err = buf.nextUint32(&i);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
         if (i != IDMAP_MAGIC) {
             printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
                     "constant 0x%08x\n", i, IDMAP_MAGIC);
-            return -1;
+            return UNKNOWN_ERROR;
         }
+
         print_header();
-        print("IDMAP HEADER", "magic", i, o, "");
+        print("IDMAP HEADER", "magic", i, "");
 
-        NEXT(buf, i, o);
-        print("", "base crc", i, o, "");
-
-        NEXT(buf, i, o);
-        print("", "overlay crc", i, o, "");
-
-        if (buf.nextPath(path, &o, &e) < 0) {
-            // printe done from IdmapBuffer::nextPath
-            return -1;
+        err = buf.nextUint32(&i);
+        if (err != NO_ERROR) {
+            return err;
         }
-        print_path("", "base path", o, e, "%s", path);
+        print("", "version", i, "");
+
+        err = buf.nextUint32(&i);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        print("", "base crc", i, "");
+
+        err = buf.nextUint32(&i);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        print("", "overlay crc", i, "");
+
+        err = buf.nextPath(path);
+        if (err != NO_ERROR) {
+            // printe done from IdmapBuffer::nextPath
+            return err;
+        }
+        print_path("", "base path", "%s", path);
+
         if (!am.addAssetPath(String8(path), NULL)) {
             printe("failed to add '%s' as asset path\n", path);
-            return -1;
+            return UNKNOWN_ERROR;
         }
 
-        if (buf.nextPath(path, &o, &e) < 0) {
+        err = buf.nextPath(path);
+        if (err != NO_ERROR) {
             // printe done from IdmapBuffer::nextPath
-            return -1;
+            return err;
         }
-        print_path("", "overlay path", o, e, "%s", path);
+        print_path("", "overlay path", "%s", path);
 
-        return 0;
+        return NO_ERROR;
     }
 
-    int parse_data_header(const IdmapBuffer& buf, const AssetManager& am, Vector<uint32_t>& types)
-    {
-        uint32_t i, o;
-        const uint32_t numeric_package = package_id(am);
+    status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
+        const uint32_t packageId = am.getResources().getBasePackageId(0);
 
-        NEXT(buf, i, o);
-        print("DATA HEADER", "types count", i, o, "");
-        const uint32_t N = i;
+        uint16_t data16;
+        status_t err = buf.nextUint16(&data16);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), "");
 
-        for (uint32_t j = 0; j < N; ++j) {
-            NEXT(buf, i, o);
-            if (i == 0) {
-                print("", "padding", i, o, "");
-            } else {
+        err = buf.nextUint16(&data16);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        print("", "types count", static_cast<uint32_t>(data16), "");
+
+        uint32_t typeCount = static_cast<uint32_t>(data16);
+        while (typeCount > 0) {
+            typeCount--;
+
+            err = buf.nextUint16(&data16);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            const uint32_t targetTypeId = static_cast<uint32_t>(data16);
+            print("DATA BLOCK", "target type", targetTypeId, "");
+
+            err = buf.nextUint16(&data16);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            print("", "overlay type", static_cast<uint32_t>(data16), "");
+
+            err = buf.nextUint16(&data16);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            const uint32_t entryCount = static_cast<uint32_t>(data16);
+            print("", "entry count", entryCount, "");
+
+            err = buf.nextUint16(&data16);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            const uint32_t entryOffset = static_cast<uint32_t>(data16);
+            print("", "entry offset", entryOffset, "");
+
+            for (uint32_t i = 0; i < entryCount; i++) {
+                uint32_t data32;
+                err = buf.nextUint32(&data32);
+                if (err != NO_ERROR) {
+                    return err;
+                }
+
+                uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i);
                 String8 type;
-                const uint32_t numeric_type = (j + 1) << 16;
-                const uint32_t res_id = numeric_package | numeric_type;
-                if (resource_metadata(am, res_id, NULL, &type, NULL) < 0) {
-                    // printe done from resource_metadata
-                    return -1;
+                String8 name;
+                err = resource_metadata(am, resID, NULL, &type, &name);
+                if (err != NO_ERROR) {
+                    return err;
                 }
-                print("", "type offset", i, o, "absolute offset 0x%02x, %s",
-                        i + IDMAP_HEADER_SIZE, type.string());
-                types.add(numeric_type);
+                print("", "entry", data32, "%s/%s", type.string(), name.string());
             }
         }
 
-        return 0;
-    }
-
-    int parse_data_block(const IdmapBuffer& buf, const AssetManager& am, size_t numeric_type)
-    {
-        uint32_t i, o, n, id_offset;
-        const uint32_t numeric_package = package_id(am);
-
-        NEXT(buf, i, o);
-        print("DATA BLOCK", "entry count", i, o, "");
-        n = i;
-
-        NEXT(buf, i, o);
-        print("", "entry offset", i, o, "");
-        id_offset = i;
-
-        for ( ; n > 0; --n) {
-            String8 type, name;
-
-            NEXT(buf, i, o);
-            if (i == 0) {
-                print("", "padding", i, o, "");
-            } else {
-                uint32_t res_id = numeric_package | numeric_type | id_offset;
-                if (resource_metadata(am, res_id, NULL, &type, &name) < 0) {
-                    // printe done from resource_metadata
-                    return -1;
-                }
-                print("", "entry", i, o, "%s/%s", type.string(), name.string());
-            }
-            ++id_offset;
-        }
-
-        return 0;
+        return NO_ERROR;
     }
 }
 
-int idmap_inspect(const char *idmap_path)
-{
+int idmap_inspect(const char *idmap_path) {
     IdmapBuffer buf;
     if (buf.init(idmap_path) < 0) {
         // printe done from IdmapBuffer::init
         return EXIT_FAILURE;
     }
     AssetManager am;
-    if (parse_idmap_header(buf, am) < 0) {
+    if (parse_idmap_header(buf, am) != NO_ERROR) {
         // printe done from parse_idmap_header
         return EXIT_FAILURE;
     }
-    Vector<uint32_t> types;
-    if (parse_data_header(buf, am, types) < 0) {
+    if (parse_data(buf, am) != NO_ERROR) {
         // printe done from parse_data_header
         return EXIT_FAILURE;
     }
-    const size_t N = types.size();
-    for (size_t i = 0; i < N; ++i) {
-        if (parse_data_block(buf, am, types.itemAt(i)) < 0) {
-            // printe done from parse_data_block
-            return EXIT_FAILURE;
-        }
-    }
     return EXIT_SUCCESS;
 }
diff --git a/include/androidfw/ByteBucketArray.h b/include/androidfw/ByteBucketArray.h
new file mode 100644
index 0000000..87c6b12
--- /dev/null
+++ b/include/androidfw/ByteBucketArray.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef __BYTE_BUCKET_ARRAY_H
+#define __BYTE_BUCKET_ARRAY_H
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <string.h>
+
+namespace android {
+
+/**
+ * Stores a sparsely populated array. Has a fixed size of 256
+ * (number of entries that a byte can represent).
+ */
+template<typename T>
+class ByteBucketArray {
+public:
+    ByteBucketArray() : mDefault() {
+        memset(mBuckets, 0, sizeof(mBuckets));
+    }
+
+    ~ByteBucketArray() {
+        for (size_t i = 0; i < NUM_BUCKETS; i++) {
+            if (mBuckets[i] != NULL) {
+                delete [] mBuckets[i];
+            }
+        }
+        memset(mBuckets, 0, sizeof(mBuckets));
+    }
+
+    inline size_t size() const {
+        return NUM_BUCKETS * BUCKET_SIZE;
+    }
+
+    inline const T& get(size_t index) const {
+        return (*this)[index];
+    }
+
+    const T& operator[](size_t index) const {
+        if (index >= size()) {
+            return mDefault;
+        }
+
+        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
+        T* bucket = mBuckets[bucketIndex];
+        if (bucket == NULL) {
+            return mDefault;
+        }
+        return bucket[0x0f & static_cast<uint8_t>(index)];
+    }
+
+    T& editItemAt(size_t index) {
+        ALOG_ASSERT(index < size(), "ByteBucketArray.getOrCreate(index=%u) with size=%u",
+                (uint32_t) index, (uint32_t) size());
+
+        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
+        T* bucket = mBuckets[bucketIndex];
+        if (bucket == NULL) {
+            bucket = mBuckets[bucketIndex] = new T[BUCKET_SIZE]();
+        }
+        return bucket[0x0f & static_cast<uint8_t>(index)];
+    }
+
+    bool set(size_t index, const T& value) {
+        if (index >= size()) {
+            return false;
+        }
+
+        editItemAt(index) = value;
+        return true;
+    }
+
+private:
+    enum { NUM_BUCKETS = 16, BUCKET_SIZE = 16 };
+
+    T*  mBuckets[NUM_BUCKETS];
+    T   mDefault;
+};
+
+} // namespace android
+
+#endif // __BYTE_BUCKET_ARRAY_H
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 4d8e512..e612c0a 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -237,6 +237,7 @@
 #define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF))
 
 #define Res_MAXPACKAGE 255
+#define Res_MAXTYPE 255
 
 /**
  * Representation of a value in a resource, supplying type
@@ -510,6 +511,23 @@
     uint32_t                    mStylePoolSize;    // number of uint32_t
 };
 
+/**
+ * Wrapper class that allows the caller to retrieve a string from
+ * a string pool without knowing which string pool to look.
+ */
+class StringPoolRef {
+public:
+    StringPoolRef();
+    StringPoolRef(const ResStringPool* pool, uint32_t index);
+
+    const char* string8(size_t* outLen) const;
+    const char16_t* string16(size_t* outLen) const;
+
+private:
+    const ResStringPool*        mPool;
+    uint32_t                    mIndex;
+};
+
 /** ********************************************************************
  *  XML Tree
  *
@@ -835,6 +853,8 @@
 
     // Last index into keyStrings that is for public use by others.
     uint32_t lastPublicKey;
+
+    uint32_t typeIdOffset;
 };
 
 // The most specific locale can consist of:
@@ -1469,9 +1489,13 @@
              bool copyData=false);
     ~ResTable();
 
-    status_t add(Asset* asset, const int32_t cookie, bool copyData,
-                 const void* idmap = NULL);
-    status_t add(const void *data, size_t size);
+    status_t add(const void* data, size_t size, const int32_t cookie=-1, bool copyData=false);
+    status_t add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
+            const int32_t cookie=-1, bool copyData=false);
+
+    status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
+    status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false);
+
     status_t add(ResTable* src);
     status_t addEmpty(const int32_t cookie);
 
@@ -1610,13 +1634,14 @@
             uint32_t typeSpecFlags;
             Res_value value;
         };
+
         struct type_info {
             size_t numEntries;
             theme_entry* entries;
         };
+
         struct package_info {
-            size_t numTypes;
-            type_info types[];
+            type_info types[Res_MAXTYPE + 1];
         };
 
         void free_package(package_info* pi);
@@ -1711,6 +1736,7 @@
     size_t getBasePackageCount() const;
     const String16 getBasePackageName(size_t idx) const;
     uint32_t getBasePackageId(size_t idx) const;
+    uint32_t getLastTypeIdForPackage(size_t idx) const;
 
     // Return the number of resource tables that the object contains.
     size_t getTableCount() const;
@@ -1740,13 +1766,15 @@
             void** outData, size_t* outSize) const;
 
     enum {
-        IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t) + 2 * 256,
+        IDMAP_HEADER_SIZE_BYTES = 4 * sizeof(uint32_t) + 2 * 256,
     };
+
     // Retrieve idmap meta-data.
     //
     // This function only requires the idmap header (the first
     // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
     static bool getIdmapInfo(const void* idmap, size_t size,
+            uint32_t* pVersion,
             uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
             String8* pTargetPath, String8* pOverlayPath);
 
@@ -1756,21 +1784,24 @@
 private:
     struct Header;
     struct Type;
+    struct Entry;
     struct Package;
     struct PackageGroup;
     struct bag_set;
+    typedef Vector<Type*> TypeList;
 
-    status_t addInternal(const void* data, size_t size, const int32_t cookie,
-                 bool copyData, const Asset* idmap);
+    status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
+            const int32_t cookie, bool copyData);
 
     ssize_t getResourcePackageIndex(uint32_t resID) const;
-    ssize_t getEntry(
-        const Package* package, int typeIndex, int entryIndex,
+
+    status_t getEntry(
+        const PackageGroup* packageGroup, int typeIndex, int entryIndex,
         const ResTable_config* config,
-        const ResTable_type** outType, const ResTable_entry** outEntry,
-        const Type** outTypeClass) const;
+        Entry* outEntry) const;
+
     status_t parsePackage(
-        const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);
+        const ResTable_package* const pkg, const Header* const header);
 
     void print_value(const Package* pkg, const Res_value& value) const;
     
diff --git a/include/androidfw/TypeWrappers.h b/include/androidfw/TypeWrappers.h
new file mode 100644
index 0000000..7bdf8af
--- /dev/null
+++ b/include/androidfw/TypeWrappers.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef __TYPE_WRAPPERS_H
+#define __TYPE_WRAPPERS_H
+
+#include <androidfw/ResourceTypes.h>
+
+namespace android {
+
+struct TypeVariant {
+    TypeVariant(const ResTable_type* data)
+        : data(data) {}
+
+    class iterator {
+    public:
+        iterator& operator=(const iterator& rhs) {
+            mTypeVariant = rhs.mTypeVariant;
+            mIndex = rhs.mIndex;
+        }
+
+        bool operator==(const iterator& rhs) const {
+            return mTypeVariant == rhs.mTypeVariant && mIndex == rhs.mIndex;
+        }
+
+        bool operator!=(const iterator& rhs) const {
+            return mTypeVariant != rhs.mTypeVariant || mIndex != rhs.mIndex;
+        }
+
+        iterator operator++(int) {
+            uint32_t prevIndex = mIndex;
+            operator++();
+            return iterator(mTypeVariant, prevIndex);
+        }
+
+        const ResTable_entry* operator->() const {
+            return operator*();
+        }
+
+        uint32_t index() const {
+            return mIndex;
+        }
+
+        iterator& operator++();
+        const ResTable_entry* operator*() const;
+
+    private:
+        friend struct TypeVariant;
+        iterator(const TypeVariant* tv, uint32_t index)
+            : mTypeVariant(tv), mIndex(index) {}
+        const TypeVariant* mTypeVariant;
+        uint32_t mIndex;
+    };
+
+    iterator beginEntries() const {
+        return iterator(this, 0);
+    }
+
+    iterator endEntries() const {
+        return iterator(this, dtohl(data->entryCount));
+    }
+
+    const ResTable_type* data;
+};
+
+} // namespace android
+
+#endif // __TYPE_WRAPPERS_H
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;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index f10904c..3d93bbe 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -589,11 +589,11 @@
                 if (bundle->getVerbose()) {
                     printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string());
                 }
-                size_t baseIndex = UNKNOWN_ERROR;
+                ssize_t baseIndex = -1;
                 if (baseSet->get() != NULL) {
                     baseIndex = (*baseSet)->indexOfKey(overlaySet->keyAt(overlayIndex));
                 }
-                if (baseIndex < UNKNOWN_ERROR) {
+                if (baseIndex >= 0) {
                     // look for same flavor.  For a given file (strings.xml, for example)
                     // there may be a locale specific or other flavors - we want to match
                     // the same flavor.
@@ -619,10 +619,10 @@
                     for (size_t overlayGroupIndex = 0;
                             overlayGroupIndex<overlayGroupSize;
                             overlayGroupIndex++) {
-                        size_t baseFileIndex =
+                        ssize_t baseFileIndex =
                                 baseGroup->getFiles().indexOfKey(overlayFiles.
                                 keyAt(overlayGroupIndex));
-                        if (baseFileIndex < UNKNOWN_ERROR) {
+                        if (baseFileIndex >= 0) {
                             if (bundle->getVerbose()) {
                                 printf("found a match (" ZD ") for overlay file %s, for flavor %s\n",
                                         (ZD_TYPE) baseFileIndex,
@@ -1363,7 +1363,11 @@
 
             if (split->isBase()) {
                 resFile = flattenedTable;
-                finalResTable.add(flattenedTable->getData(), flattenedTable->getSize());
+                err = finalResTable.add(flattenedTable->getData(), flattenedTable->getSize());
+                if (err != NO_ERROR) {
+                    fprintf(stderr, "Generated resource table is corrupt.\n");
+                    return err;
+                }
             } else {
                 sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
                         AaptGroupEntry(), String8());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index efbba40..1a9f1b9 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2292,8 +2292,14 @@
     if (resId != 0 || !createIfNotFound) {
         return resId;
     }
-    String16 value("false");
 
+    if (mAssetsPackage != package) {
+        mCurrentXmlPos.warning("creating resource for external package %s: %s/%s.",
+                String8(package).string(), String8(type).string(), String8(name).string());
+        mCurrentXmlPos.printf("This will be an error in a future version of AAPT.");
+    }
+
+    String16 value("false");
     status_t status = addEntry(mCurrentXmlPos, package, type, name, value, NULL, NULL, true);
     if (status == NO_ERROR) {
         resId = getResId(package, type, name);
@@ -3062,8 +3068,9 @@
             for (size_t i = 0; i < N; ++i) {
                 if (!validResources[i]) {
                     sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
-                    fprintf(stderr, "%s: no entries written for %s/%s\n", log_prefix,
-                            String8(typeName).string(), String8(c->getName()).string());
+                    fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
+                            String8(typeName).string(), String8(c->getName()).string(),
+                            Res_MAKEID(p->getAssignedId() - 1, ti, i));
                     missing_entry = true;
                 }
             }