X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/d25ea7e18ee381dd2e4107200c4cb18355276f81..78063da3d3092ea172859981719c461dc15a622c:/ResourceTable.cpp diff --git a/ResourceTable.cpp b/ResourceTable.cpp index 81b924a..f59bba2 100644 --- a/ResourceTable.cpp +++ b/ResourceTable.cpp @@ -7,6 +7,7 @@ #include "ResourceTable.h" #include "XMLNode.h" +#include "ResourceFilter.h" #include #include @@ -695,7 +696,7 @@ status_t parseAndAddEntry(Bundle* bundle, if (isInProductList(product, String16(bundleProduct))) { ; } else if (strcmp16(String16("default").string(), product.string()) == 0 && - !outTable->hasBagOrEntry(myPackage, curType, ident)) { + !outTable->hasBagOrEntry(myPackage, curType, ident, config)) { ; } else { return NO_ERROR; @@ -1823,6 +1824,37 @@ bool ResourceTable::hasBagOrEntry(const String16& package, return false; } +bool ResourceTable::hasBagOrEntry(const String16& package, + const String16& type, + const String16& name, + const ResTable_config& config) const +{ + // First look for this in the included resources... + uint32_t rid = mAssets->getIncludedResources() + .identifierForName(name.string(), name.size(), + type.string(), type.size(), + package.string(), package.size()); + if (rid != 0) { + return true; + } + + sp p = mPackages.valueFor(package); + if (p != NULL) { + sp t = p->getTypes().valueFor(type); + if (t != NULL) { + sp c = t->getConfigs().valueFor(name); + if (c != NULL) { + sp e = c->getEntries().valueFor(config); + if (e != NULL) { + return true; + } + } + } + } + + return false; +} + bool ResourceTable::hasBagOrEntry(const String16& ref, const String16* defType, const String16* defPackage) @@ -2015,7 +2047,8 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, uint32_t attrID, const Vector* style, String16* outStr, void* accessorCookie, - uint32_t attrType) + uint32_t attrType, const String8* configTypeName, + const ConfigDescription* config) { String16 finalStr; @@ -2043,10 +2076,19 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, if (outValue->dataType == outValue->TYPE_STRING) { // Should do better merging styles. if (pool) { + String8 configStr; + if (config != NULL) { + configStr = config->toString(); + } else { + configStr = "(null)"; + } + NOISY(printf("Adding to pool string style #%d config %s: %s\n", + style != NULL ? style->size() : 0, + configStr.string(), String8(finalStr).string())); if (style != NULL && style->size() > 0) { - outValue->data = pool->add(finalStr, *style); + outValue->data = pool->add(finalStr, *style, configTypeName, config); } else { - outValue->data = pool->add(finalStr, true); + outValue->data = pool->add(finalStr, true, configTypeName, config); } } else { // Caller will fill this in later. @@ -2497,135 +2539,6 @@ ResourceTable::validateLocalizations(void) return err; } - -status_t -ResourceFilter::parse(const char* arg) -{ - if (arg == NULL) { - return 0; - } - - const char* p = arg; - const char* q; - - while (true) { - q = strchr(p, ','); - if (q == NULL) { - q = p + strlen(p); - } - - String8 part(p, q-p); - - if (part == "zz_ZZ") { - mContainsPseudo = true; - } - int axis; - uint32_t value; - if (AaptGroupEntry::parseNamePart(part, &axis, &value)) { - fprintf(stderr, "Invalid configuration: %s\n", arg); - fprintf(stderr, " "); - for (int i=0; i()); - } - SortedVector& sv = mData.editValueFor(axis); - sv.add(value); - // if it's a locale with a region, also match an unmodified locale of the - // same language - if (axis == AXIS_LANGUAGE) { - if (value & 0xffff0000) { - sv.add(value & 0x0000ffff); - } - } - p = q; - if (!*p) break; - p++; - } - - return NO_ERROR; -} - -bool -ResourceFilter::match(int axis, uint32_t value) const -{ - if (value == 0) { - // they didn't specify anything so take everything - return true; - } - ssize_t index = mData.indexOfKey(axis); - if (index < 0) { - // we didn't request anything on this axis so take everything - return true; - } - const SortedVector& sv = mData.valueAt(index); - return sv.indexOf(value) >= 0; -} - -bool -ResourceFilter::match(const ResTable_config& config) const -{ - if (config.locale) { - uint32_t locale = (config.country[1] << 24) | (config.country[0] << 16) - | (config.language[1] << 8) | (config.language[0]); - if (!match(AXIS_LANGUAGE, locale)) { - return false; - } - } - if (!match(AXIS_ORIENTATION, config.orientation)) { - return false; - } - if (!match(AXIS_UIMODETYPE, (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE))) { - return false; - } - if (!match(AXIS_UIMODENIGHT, (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT))) { - return false; - } - if (!match(AXIS_DENSITY, config.density)) { - return false; - } - if (!match(AXIS_TOUCHSCREEN, config.touchscreen)) { - return false; - } - if (!match(AXIS_KEYSHIDDEN, config.inputFlags)) { - return false; - } - if (!match(AXIS_KEYBOARD, config.keyboard)) { - return false; - } - if (!match(AXIS_NAVIGATION, config.navigation)) { - return false; - } - if (!match(AXIS_SCREENSIZE, config.screenSize)) { - return false; - } - if (!match(AXIS_SMALLESTSCREENWIDTHDP, config.smallestScreenWidthDp)) { - return false; - } - if (!match(AXIS_SCREENWIDTHDP, config.screenWidthDp)) { - return false; - } - if (!match(AXIS_SCREENHEIGHTDP, config.screenHeightDp)) { - return false; - } - if (!match(AXIS_SCREENLAYOUTSIZE, config.screenLayout&ResTable_config::MASK_SCREENSIZE)) { - return false; - } - if (!match(AXIS_VERSION, config.version)) { - return false; - } - return true; -} - status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) { ResourceFilter filter; @@ -2634,16 +2547,19 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) return err; } + const ConfigDescription nullConfig; + const size_t N = mOrderedPackages.size(); size_t pi; const static String16 mipmap16("mipmap"); - bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO); + bool useUTF8 = !bundle->getUTF16StringsOption(); // Iterate through all data, collecting all values (strings, // references, etc). StringPool valueStrings = StringPool(false, useUTF8); + Vector > allEntries; for (pi=0; pi p = mOrderedPackages.itemAt(pi); if (p->getTypes().size() == 0) { @@ -2664,6 +2580,19 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) const String16 typeName(t->getName()); typeStrings.add(typeName, false); + // This is a hack to tweak the sorting order of the final strings, + // to put stuff that is generally not language-specific first. + String8 configTypeName(typeName); + if (configTypeName == "drawable" || configTypeName == "layout" + || configTypeName == "color" || configTypeName == "anim" + || configTypeName == "interpolator" || configTypeName == "animator" + || configTypeName == "xml" || configTypeName == "menu" + || configTypeName == "mipmap" || configTypeName == "raw") { + configTypeName = "1complex"; + } else { + configTypeName = "2value"; + } + const bool filterable = (typeName != mipmap16); const size_t N = t->getOrderedConfigs().size(); @@ -2683,10 +2612,21 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) continue; } e->setNameIndex(keyStrings.add(e->getName(), true)); - status_t err = e->prepareFlatten(&valueStrings, this); + + // If this entry has no values for other configs, + // and is the default config, then it is special. Otherwise + // we want to add it with the config info. + ConfigDescription* valueConfig = NULL; + if (N != 1 || config == nullConfig) { + valueConfig = &config; + } + + status_t err = e->prepareFlatten(&valueStrings, this, + &configTypeName, &config); if (err != NO_ERROR) { return err; } + allEntries.add(e); } } } @@ -2695,6 +2635,17 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) p->setKeyStrings(keyStrings.createStringBlock()); } + if (bundle->getOutputAPKFile() != NULL) { + // Now we want to sort the value strings for better locality. This will + // cause the positions of the strings to change, so we need to go back + // through out resource entries and update them accordingly. Only need + // to do this if actually writing the output file. + valueStrings.sortByConfig(); + for (pi=0; piremapStringValue(&valueStrings); + } + } + ssize_t strAmt = 0; // Now build the array of package chunks. @@ -3234,14 +3185,16 @@ status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table, return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } -status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table) +status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table, + const String8* configTypeName, const ConfigDescription* config) { if (mType == TYPE_ITEM) { Item& it = mItem; AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value)); if (!table->stringToValue(&it.parsedValue, strings, it.value, false, true, 0, - &it.style, NULL, &ac, mItemFormat)) { + &it.style, NULL, &ac, mItemFormat, + configTypeName, config)) { return UNKNOWN_ERROR; } } else if (mType == TYPE_BAG) { @@ -3252,7 +3205,8 @@ status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable AccessorCookie ac(it.sourcePos, String8(key), String8(it.value)); if (!table->stringToValue(&it.parsedValue, strings, it.value, false, true, it.bagKeyId, - &it.style, NULL, &ac, it.format)) { + &it.style, NULL, &ac, it.format, + configTypeName, config)) { return UNKNOWN_ERROR; } } @@ -3264,6 +3218,29 @@ status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable return NO_ERROR; } +status_t ResourceTable::Entry::remapStringValue(StringPool* strings) +{ + if (mType == TYPE_ITEM) { + Item& it = mItem; + if (it.parsedValue.dataType == Res_value::TYPE_STRING) { + it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data); + } + } else if (mType == TYPE_BAG) { + const size_t N = mBag.size(); + for (size_t i=0; imapOriginalPosToNewPos(it.parsedValue.data); + } + } + } else { + mPos.error("Error: entry %s is not a single item or a bag.\n", + String8(mName).string()); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp& data, bool isPublic) { size_t amt = 0;