X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/d38cd880626e1508ffec8d891a8e61b8f5c8cb7d..293ee8612544d656b9b63097011a1fd7333b382e:/ResourceTable.cpp?ds=sidebyside diff --git a/ResourceTable.cpp b/ResourceTable.cpp index 85665e0..6d5fcc2 100644 --- a/ResourceTable.cpp +++ b/ResourceTable.cpp @@ -13,7 +13,6 @@ #include #define NOISY(x) //x -#define NOISY_REF(x) //x status_t compileXmlFile(const sp& assets, const sp& target, @@ -574,6 +573,8 @@ status_t parseAndAddBag(Bundle* bundle, const String16& parentIdent, const String16& itemIdent, int32_t curFormat, + bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -584,7 +585,7 @@ status_t parseAndAddBag(Bundle* bundle, String16 str; Vector spans; err = parseStyledString(bundle, in->getPrintableSource().string(), - block, item16, &str, &spans, + block, item16, &str, &spans, isFormatted, pseudolocalize); if (err != NO_ERROR) { return err; @@ -606,6 +607,32 @@ status_t parseAndAddBag(Bundle* bundle, return err; } +/* + * Returns true if needle is one of the elements in the comma-separated list + * haystack, false otherwise. + */ +bool isInProductList(const String16& needle, const String16& haystack) { + const char16_t *needle2 = needle.string(); + const char16_t *haystack2 = haystack.string(); + size_t needlesize = needle.size(); + + while (*haystack2 != '\0') { + if (strncmp16(haystack2, needle2, needlesize) == 0) { + if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') { + return true; + } + } + + while (*haystack2 != '\0' && *haystack2 != ',') { + haystack2++; + } + if (*haystack2 == ',') { + haystack2++; + } + } + + return false; +} status_t parseAndAddEntry(Bundle* bundle, const sp& in, @@ -617,6 +644,8 @@ status_t parseAndAddEntry(Bundle* bundle, const String16& curTag, bool curIsStyled, int32_t curFormat, + bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -627,12 +656,53 @@ status_t parseAndAddEntry(Bundle* bundle, Vector spans; err = parseStyledString(bundle, in->getPrintableSource().string(), block, curTag, &str, curIsStyled ? &spans : NULL, - pseudolocalize); + isFormatted, pseudolocalize); if (err < NO_ERROR) { return err; } + /* + * If a product type was specified on the command line + * and also in the string, and the two are not the same, + * return without adding the string. + */ + + const char *bundleProduct = bundle->getProduct(); + if (bundleProduct == NULL) { + bundleProduct = ""; + } + + if (product.size() != 0) { + /* + * If the command-line-specified product is empty, only "default" + * matches. Other variants are skipped. This is so generation + * of the R.java file when the product is not known is predictable. + */ + + if (bundleProduct[0] == '\0') { + if (strcmp16(String16("default").string(), product.string()) != 0) { + return NO_ERROR; + } + } else { + /* + * The command-line product is not empty. + * If the product for this string is on the command-line list, + * it matches. "default" also matches, but only if nothing + * else has matched already. + */ + + if (isInProductList(product, String16(bundleProduct))) { + ; + } else if (strcmp16(String16("default").string(), product.string()) == 0 && + !outTable->hasBagOrEntry(myPackage, curType, ident)) { + ; + } else { + return NO_ERROR; + } + } + } + NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n", config.language[0], config.language[1], config.country[0], config.country[1], @@ -710,12 +780,18 @@ status_t compileResourceFile(Bundle* bundle, // useful attribute names and special values const String16 name16("name"); const String16 translatable16("translatable"); + const String16 formatted16("formatted"); const String16 false16("false"); const String16 myPackage(assets->getPackage()); bool hasErrors = false; - + + bool fileIsTranslatable = true; + if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) { + fileIsTranslatable = false; + } + DefaultKeyedVector nextPublicId(0); ResXMLTree::event_code_t code; @@ -752,6 +828,7 @@ status_t compileResourceFile(Bundle* bundle, bool curIsBagReplaceOnOverwrite = false; bool curIsStyled = false; bool curIsPseudolocalizable = false; + bool curIsFormatted = fileIsTranslatable; bool localHasErrors = false; if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { @@ -1137,6 +1214,7 @@ status_t compileResourceFile(Bundle* bundle, String8 locale(rawLocale); String16 name; String16 translatable; + String16 formatted; size_t n = block.getAttributeCount(); for (size_t i = 0; i < n; i++) { @@ -1146,11 +1224,14 @@ status_t compileResourceFile(Bundle* bundle, name.setTo(block.getAttributeStringValue(i, &length)); } else if (strcmp16(attr, translatable16.string()) == 0) { translatable.setTo(block.getAttributeStringValue(i, &length)); + } else if (strcmp16(attr, formatted16.string()) == 0) { + formatted.setTo(block.getAttributeStringValue(i, &length)); } } if (name.size() > 0) { if (translatable == false16) { + curIsFormatted = false; // Untranslatable strings must only exist in the default [empty] locale if (locale.size() > 0) { fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists" @@ -1168,6 +1249,10 @@ status_t compileResourceFile(Bundle* bundle, } else { outTable->addLocalization(name, locale); } + + if (formatted == false16) { + curIsFormatted = false; + } } curTag = &string16; @@ -1237,6 +1322,22 @@ status_t compileResourceFile(Bundle* bundle, } } } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) { + // Check whether these strings need valid formats. + // (simplified form of what string16 does above) + size_t n = block.getAttributeCount(); + for (size_t i = 0; i < n; i++) { + size_t length; + const uint16_t* attr = block.getAttributeName(i, &length); + if (strcmp16(attr, translatable16.string()) == 0 + || strcmp16(attr, formatted16.string()) == 0) { + const uint16_t* value = block.getAttributeStringValue(i, &length); + if (strcmp16(value, false16.string()) == 0) { + curIsFormatted = false; + break; + } + } + } + curTag = &string_array16; curType = array16; curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; @@ -1267,6 +1368,12 @@ status_t compileResourceFile(Bundle* bundle, hasErrors = localHasErrors = true; } + String16 product; + identIdx = block.indexOfAttribute(NULL, "product"); + if (identIdx >= 0) { + product = String16(block.getAttributeStringValue(identIdx, &len)); + } + String16 comment(block.getComment(&len) ? block.getComment(&len) : nulStr); if (curIsBag) { @@ -1357,8 +1464,8 @@ status_t compileResourceFile(Bundle* bundle, block.getPosition(&parserPosition); err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, - ident, parentIdent, itemIdent, curFormat, - false, overwrite, outTable); + ident, parentIdent, itemIdent, curFormat, curIsFormatted, + product, false, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) && bundle->getPseudolocalize()) { @@ -1366,8 +1473,8 @@ status_t compileResourceFile(Bundle* bundle, #if 1 block.setPosition(parserPosition); err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, - curType, ident, parentIdent, itemIdent, curFormat, true, - overwrite, outTable); + curType, ident, parentIdent, itemIdent, curFormat, + curIsFormatted, product, true, overwrite, outTable); #endif } } @@ -1390,7 +1497,8 @@ status_t compileResourceFile(Bundle* bundle, block.getPosition(&parserPosition); err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, - *curTag, curIsStyled, curFormat, false, overwrite, outTable); + *curTag, curIsStyled, curFormat, curIsFormatted, + product, false, overwrite, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; @@ -1401,7 +1509,9 @@ status_t compileResourceFile(Bundle* bundle, // pseudolocalize here block.setPosition(parserPosition); err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, true, overwrite, outTable); + ident, *curTag, curIsStyled, curFormat, + curIsFormatted, product, + true, overwrite, outTable); if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -1630,13 +1740,6 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos, // If a parent is explicitly specified, set it. if (bagParent.size() > 0) { - String16 curPar = e->getParent(); - if (curPar.size() > 0 && curPar != bagParent) { - sourcePos.error("Conflicting parents specified, was '%s', now '%s'\n", - String8(e->getParent()).string(), - String8(bagParent).string()); - return UNKNOWN_ERROR; - } e->setParent(bagParent); } @@ -1684,13 +1787,6 @@ status_t ResourceTable::addBag(const SourcePos& sourcePos, // If a parent is explicitly specified, set it. if (bagParent.size() > 0) { - String16 curPar = e->getParent(); - if (curPar.size() > 0 && curPar != bagParent) { - sourcePos.error("Conflicting parents specified, was '%s', now '%s'\n", - String8(e->getParent()).string(), - String8(bagParent).string()); - return UNKNOWN_ERROR; - } e->setParent(bagParent); } @@ -1934,7 +2030,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 = Res_value::TYPE_STRING; + outValue->dataType = outValue->TYPE_STRING; outValue->data = 0; finalStr = str; } @@ -1943,7 +2039,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, return false; } - if (outValue->dataType == Res_value::TYPE_STRING) { + if (outValue->dataType == outValue->TYPE_STRING) { // Should do better merging styles. if (pool) { if (style != NULL && style->size() > 0) { @@ -2348,7 +2444,7 @@ ResourceTable::validateLocalizations(void) if (configSet.count(defaultLocale) == 0) { fprintf(stdout, "aapt: warning: string '%s' has no default translation in %s; found:", String8(nameIter->first).string(), mBundle->getResourceSourceDirs()[0]); - for (set::iterator locales = configSet.begin(); + for (set::const_iterator locales = configSet.begin(); locales != configSet.end(); locales++) { fprintf(stdout, " %s", (*locales).string()); @@ -2459,7 +2555,7 @@ ResourceFilter::parse(const char* arg) } bool -ResourceFilter::match(int axis, uint32_t value) +ResourceFilter::match(int axis, uint32_t value) const { if (value == 0) { // they didn't specify anything so take everything @@ -2475,7 +2571,7 @@ ResourceFilter::match(int axis, uint32_t value) } bool -ResourceFilter::match(const ResTable_config& config) +ResourceFilter::match(const ResTable_config& config) const { if (config.locale) { uint32_t locale = (config.country[1] << 24) | (config.country[0] << 16) @@ -2528,10 +2624,13 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) const size_t N = mOrderedPackages.size(); size_t pi; + const static String16 mipmap16("mipmap"); + + bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO); + // Iterate through all data, collecting all values (strings, // references, etc). - StringPool valueStrings = StringPool(false, bundle->getUTF8()); - ResourceConfigReferences configRefs; + StringPool valueStrings = StringPool(false, useUTF8); for (pi=0; pi p = mOrderedPackages.itemAt(pi); if (p->getTypes().size() == 0) { @@ -2539,8 +2638,8 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) continue; } - StringPool typeStrings = StringPool(false, bundle->getUTF8()); - StringPool keyStrings = StringPool(false, bundle->getUTF8()); + StringPool typeStrings = StringPool(false, useUTF8); + StringPool keyStrings = StringPool(false, useUTF8); const size_t N = p->getOrderedTypes().size(); for (size_t ti=0; ti& dest) typeStrings.add(String16(""), false); continue; } - typeStrings.add(t->getName(), false); + const String16 typeName(t->getName()); + typeStrings.add(typeName, false); + + const bool filterable = (typeName != mipmap16); const size_t N = t->getOrderedConfigs().size(); for (size_t ci=0; ci& dest) const size_t N = c->getEntries().size(); for (size_t ei=0; eigetEntries().keyAt(ei); - if (!filter.match(config)) { + if (filterable && !filter.match(config)) { continue; } sp e = c->getEntries().valueAt(ei); @@ -2572,13 +2674,6 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& 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); - } - } } } } @@ -2587,70 +2682,6 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& 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 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 t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - size_t CN = t->getOrderedConfigs().size(); - for (size_t ci=0; ci c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - DefaultKeyedVector > newEntries; - size_t EN = c->getEntries().size(); - for (size_t ei=0; eigetEntries().keyAt(ei); - if (!filter.match(config)) { - continue; - } - sp 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. @@ -2711,6 +2742,8 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) "Type name %s not found", String8(typeName).string()); + const bool filterable = (typeName != mipmap16); + const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0; // First write the typeSpec chunk, containing information about @@ -2735,7 +2768,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) (((uint8_t*)data->editData()) + typeSpecStart + sizeof(ResTable_typeSpec)); memset(typeSpecFlags, 0, sizeof(uint32_t)*N); - + for (size_t ei=0; ei cl = t->getOrderedConfigs().itemAt(ei); if (cl->getPublic()) { @@ -2743,11 +2776,11 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) } const size_t CN = cl->getEntries().size(); for (size_t ci=0; cigetEntries().keyAt(ci))) { + if (filterable && !filter.match(cl->getEntries().keyAt(ci))) { continue; } for (size_t cj=ci+1; cjgetEntries().keyAt(cj))) { + if (filterable && !filter.match(cl->getEntries().keyAt(cj))) { continue; } typeSpecFlags[ei] |= htodl( @@ -2784,7 +2817,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) config.screenWidth, config.screenHeight)); - if (!filter.match(config)) { + if (filterable && !filter.match(config)) { continue; } @@ -3648,7 +3681,9 @@ sp ResourceTable::getPackage(const String16& package) { sp p = mPackages.valueFor(package); if (p == NULL) { - if (mIsAppPackage) { + if (mBundle->getIsOverlayPackage()) { + p = new Package(package, 0x00); + } else if (mIsAppPackage) { if (mHaveAppPackage) { fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n" "Use -x to create extended resources.\n"); @@ -3805,95 +3840,3 @@ 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()); - } - Vector& configRoots = mRoots.editValueFor(id); - - if (!configRoots.isEmpty()) { - ssize_t NR = configRoots.size(); - for (int ri=0; rimatch(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& configRoots = mRoots.valueAt(ri); - printf(" String %d\n", mRoots.keyAt(ri)); - const ssize_t NC = configRoots.size(); - for (int ci=0; ci& configRoots = mRoots.editValueFor(id); - const ssize_t NR = configRoots.size(); - for (int ri = 0; rimatch(config)) { - return true; - } - } - return false; -} - -ResourceConfigReferences::~ResourceConfigReferences() -{ - const ssize_t NR = mRoots.size(); - for (int ri=0; ri configRoots = mRoots.editValueAt(ri); - const ssize_t NC = configRoots.size(); - for (int ci=0; ci(configRoots[ci]); - free(config); - } - } -}