]> git.saurik.com Git - android/aapt.git/commitdiff
Dedupe resource config pointers
authorKenny Root <kroot@google.com>
Wed, 10 Mar 2010 00:55:23 +0000 (16:55 -0800)
committerKenny Root <kroot@google.com>
Wed, 10 Mar 2010 04:56:41 +0000 (20:56 -0800)
When there are two configs in a StringPool that would match a string ID
only keep the more generic entry to save some space. This means that if
you have both "es" and "es_US" translations that have the same
translation, the string entry would be removed from the "es_US" config.

Change-Id: I4d619942d35ddb477e2eabe4437b7f02697c24de

ResourceTable.cpp
ResourceTable.h

index ab5e9376f3283a2369904287ea43b09cc97e2bd1..85665e0c17b371ec318267368a1230fe40b9143d 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdarg.h>
 
 #define NOISY(x) //x
+#define NOISY_REF(x) //x
 
 status_t compileXmlFile(const sp<AaptAssets>& assets,
                         const sp<AaptFile>& target,
@@ -1933,7 +1934,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
         // information we have already processed that string!
         outValue->size = sizeof(Res_value);
         outValue->res0 = 0;
-        outValue->dataType = outValue->TYPE_STRING;
+        outValue->dataType = Res_value::TYPE_STRING;
         outValue->data = 0;
         finalStr = str;
     }
@@ -1942,7 +1943,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
         return false;
     }
 
-    if (outValue->dataType == outValue->TYPE_STRING) {
+    if (outValue->dataType == Res_value::TYPE_STRING) {
         // Should do better merging styles.
         if (pool) {
             if (style != NULL && style->size() > 0) {
@@ -2530,6 +2531,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
     // Iterate through all data, collecting all values (strings,
     // references, etc).
     StringPool valueStrings = StringPool(false, bundle->getUTF8());
+    ResourceConfigReferences configRefs;
     for (pi=0; pi<N; pi++) {
         sp<Package> p = mOrderedPackages.itemAt(pi);
         if (p->getTypes().size() == 0) {
@@ -2570,6 +2572,13 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
                     if (err != NO_ERROR) {
                         return err;
                     }
+                    if (e->getType() == Entry::TYPE_ITEM) {
+                        const Item* item = e->getItem();
+                        if (item != NULL) {
+                            uint32_t poolIndex = item->parsedValue.data;
+                            configRefs.add(poolIndex, config);
+                        }
+                    }
                 }
             }
         }
@@ -2578,6 +2587,70 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
         p->setKeyStrings(keyStrings.createStringBlock());
     }
 
+    NOISY_REF(configRefs.dump();)
+
+    // Trim all entries in config tables that are not roots for that string.
+    // i.e., rely on the resource system to grab the string from the more
+    // generic pool during runtime to save space.
+    for (pi=0; pi<N; pi++) {
+        sp<Package> p = mOrderedPackages.itemAt(pi);
+        if (p->getTypes().size() == 0) {
+            // Empty, skip!
+            continue;
+        }
+        const size_t TN = p->getOrderedTypes().size();
+        for (size_t ti=0; ti<TN; ti++) {
+            sp<Type> t = p->getOrderedTypes().itemAt(ti);
+            if (t == NULL) {
+                continue;
+            }
+            size_t CN = t->getOrderedConfigs().size();
+            for (size_t ci=0; ci<CN; ci++) {
+                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
+                if (c == NULL) {
+                    continue;
+                }
+                DefaultKeyedVector<ConfigDescription, sp<Entry> > newEntries;
+                size_t EN = c->getEntries().size();
+                for (size_t ei=0; ei<EN; ++ei) {
+                    ConfigDescription config = c->getEntries().keyAt(ei);
+                    if (!filter.match(config)) {
+                        continue;
+                    }
+                    sp<Entry> e = c->getEntries().valueAt(ei);
+                    if (e == NULL) {
+                        continue;
+                    }
+                    if (e->getType() == Entry::TYPE_ITEM) {
+                        const Item* item = e->getItem();
+                        if (item != NULL) {
+                            uint32_t poolIndex = item->parsedValue.data;
+                            if (!configRefs.isRoot(poolIndex, config)) {
+                                NOISY_REF(
+                                    printf("  ConfigRef %d: removing ", poolIndex);
+                                    DEBUG_LANG(config)
+                                    printf("\n");
+                                )
+                                c->removeEntryAt(ei);
+                                t->removeUniqueConfig(config);
+                                --ei; --EN;
+                            }
+                        }
+                    }
+                }
+                if (EN == 0) {
+                    // We removed all the entries from a config, so remove the
+                    // config itself.
+                    NOISY_REF(
+                        printf("  ConfigRef REMOVED ENTIRE CONFIG\n");
+                    )
+                    t->removeOrderedConfigAt(ci);
+                    --ci; --CN;
+                }
+            }
+        }
+    }
+
     ssize_t strAmt = 0;
     
     // Now build the array of package chunks.
@@ -3732,3 +3805,95 @@ bool ResourceTable::getItemValue(
     }
     return res;
 }
+
+#define DEBUG_LANG(x) printf("lang=%c%c cnt=%c%c ", \
+        (x).language[0] ? (x).language[0] : '-', \
+        (x).language[1] ? (x).language[1] : '-', \
+        (x).country[0] ? (x).country[0] : '-', \
+        (x).country[1] ? (x).country[1] : '-');
+
+status_t ResourceConfigReferences::add(uint32_t id, const ResTable_config& config)
+{
+    ssize_t index = mRoots.indexOfKey(id);
+    if (index < 0) {
+        index = mRoots.add(id, Vector<const ResTable_config*>());
+    }
+    Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);
+
+    if (!configRoots.isEmpty()) {
+        ssize_t NR = configRoots.size();
+        for (int ri=0; ri<NR; ++ri) {
+            const ResTable_config* current = configRoots[ri];
+
+            if (config.match(*current)) {
+                // We already have something more generic than our incoming string.
+                NOISY_REF(
+                    printf("  ConfigRef %d: ignoring ", id);
+                    DEBUG_LANG(config)
+                    printf("\n");
+                )
+                return NO_ERROR;
+            } else if (current->match(config)) {
+                // more generic
+                NOISY_REF(
+                    printf("  ConfigRef %d: remove ", id);
+                    DEBUG_LANG(current)
+                    printf("\n");
+                )
+                configRoots.removeItemsAt(ri);
+                --ri; --NR;
+            }
+        }
+    }
+    NOISY_REF(
+        printf("  ConfigRef %d: add ", id);
+        DEBUG_LANG(config)
+        printf("\n");
+    )
+    ResTable_config *configCopy = (ResTable_config*)malloc(sizeof(ResTable_config));
+    memcpy(configCopy, &config, sizeof(ResTable_config));
+    configRoots.add(configCopy);
+
+    return NO_ERROR;
+}
+
+void ResourceConfigReferences::dump()
+{
+    printf("ResourceConfigReferences\n");
+    const ssize_t NR = mRoots.size();
+    for (int ri=0; ri<NR; ++ri) {
+        const Vector<const ResTable_config*>& configRoots = mRoots.valueAt(ri);
+        printf("  String %d\n", mRoots.keyAt(ri));
+        const ssize_t NC = configRoots.size();
+        for (int ci=0; ci<NC; ++ci) {
+            printf("    ");
+            DEBUG_LANG(*configRoots[ci])
+            printf("\n");
+        }
+    }
+}
+
+bool ResourceConfigReferences::isRoot(uint32_t id, const ResTable_config& config)
+{
+    const Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);
+    const ssize_t NR = configRoots.size();
+    for (int ri = 0; ri<NR; ++ri) {
+        if (configRoots[ri]->match(config)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+ResourceConfigReferences::~ResourceConfigReferences()
+{
+    const ssize_t NR = mRoots.size();
+    for (int ri=0; ri<NR; ++ri) {
+        Vector<const ResTable_config*> configRoots = mRoots.editValueAt(ri);
+        const ssize_t NC = configRoots.size();
+        for (int ci=0; ci<NC; ++ci) {
+            ResTable_config* config = const_cast<ResTable_config*>(configRoots[ci]);
+            free(config);
+        }
+    }
+}
index 186c7ca8fdd8d1b7d4731e76812434f52ddf3274..cc2a42924a8de738e8f2b78bcedad6bbdf96a132 100644 (file)
@@ -376,6 +376,10 @@ public:
         void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
             mEntries.add(config, entry);
         }
+
+        void removeEntryAt(int32_t index) {
+            mEntries.removeItemsAt(index);
+        }
         
         const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
     private:
@@ -448,6 +452,9 @@ public:
         const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
         const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
 
+        void removeUniqueConfig(ConfigDescription& config) { mUniqueConfigs.remove(config); }
+        void removeOrderedConfigAt(uint32_t index) { mOrderedConfigs.removeItemsAt(index); }
+
         const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
         
         const SourcePos& getPos() const { return mPos; }
@@ -558,5 +565,17 @@ private:
     bool mContainsPseudo;
 };
 
+class ResourceConfigReferences
+{
+public:
+    ResourceConfigReferences() : mRoots() {}
+    ~ResourceConfigReferences();
+    status_t add(uint32_t id, const ResTable_config& config);
+    bool isRoot(uint32_t id, const ResTable_config& config);
+    void dump();
+
+private:
+    KeyedVector<uint32_t, Vector<const ResTable_config*> > mRoots;
+};
 
 #endif