From 788fa41482b9d398591b7db8b0b01839029611ad Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Tue, 21 Jan 2014 15:32:36 +0000 Subject: Extended locales in AAPT / AssetManager. Support 3 letter language codes, script codes & variants. The bulk of the changes are related to the implementation of command line filtering of locales etc. The previous code assumed that the value of each "axis" (locale, density, size etc.) could be represented by a 4 byte type. This is no longer the case. This change introduces a new class, AaptLocaleValue which holds a (normalized) locale parsed from a directory name or a filter string. This class takes responsibility for parsing locales as well as writing them to ResTable_config structures, which is their representation in the resource table. This includes minor changes at the java / JNI level for AssetManager. We now call locale.toLanguageTag() to give the native layer a well formed BCP-47 tag. I've removed some duplicated parsing code in AssetManager.cpp and replaced them with functions on ResTable_config. The native getLocales function has been changed to return well formed BCP-47 locales as well, so that the corresponding java function can use Locale.forLanguageTag to construct a Locale object out of it. Finally, this change introduces default and copy constructors for ResTable_config to prevent having to memset() the associated memory to 0 on every stack allocation. (cherry-picked from commit 91447d88f2bdf9c2bf8d1a53570efef6172fba74) Change-Id: I1b43086860661012f949fb8e5deb7df44519b854 --- libs/androidfw/AssetManager.cpp | 30 ++------- libs/androidfw/ResourceTypes.cpp | 95 ++++++++++++++++++++++------- libs/androidfw/tests/ResourceTypes_test.cpp | 35 +++++++++++ 3 files changed, 114 insertions(+), 46 deletions(-) (limited to 'libs') diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 5069958ee1d2..b4d482ad0a54 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -386,17 +386,8 @@ void AssetManager::setConfiguration(const ResTable_config& config, const char* l if (locale) { setLocaleLocked(locale); } else if (config.language[0] != 0) { - char spec[9]; - spec[0] = config.language[0]; - spec[1] = config.language[1]; - if (config.country[0] != 0) { - spec[2] = '_'; - spec[3] = config.country[0]; - spec[4] = config.country[1]; - spec[5] = 0; - } else { - spec[3] = 0; - } + char spec[RESTABLE_MAX_LOCALE_LEN]; + config.getBcp47Locale(spec); setLocaleLocked(spec); } else { updateResourceParamsLocked(); @@ -668,20 +659,11 @@ void AssetManager::updateResourceParamsLocked() const return; } - size_t llen = mLocale ? strlen(mLocale) : 0; - mConfig->language[0] = 0; - mConfig->language[1] = 0; - mConfig->country[0] = 0; - mConfig->country[1] = 0; - if (llen >= 2) { - mConfig->language[0] = mLocale[0]; - mConfig->language[1] = mLocale[1]; - } - if (llen >= 5) { - mConfig->country[0] = mLocale[3]; - mConfig->country[1] = mLocale[4]; + if (mLocale) { + mConfig->setBcp47Locale(mLocale); + } else { + mConfig->clearLocale(); } - mConfig->size = sizeof(*mConfig); res->setParameters(mConfig); } diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 0c356b696d0a..efb589a6dc20 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -1592,9 +1592,9 @@ void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { return 0; } -/* static */ void packLanguageOrRegion(const char in[3], const char base, +/* static */ void packLanguageOrRegion(const char* in, const char base, char out[2]) { - if (in[2] == 0) { + if (in[2] == 0 || in[2] == '-') { out[0] = in[0]; out[1] = in[1]; } else { @@ -1608,11 +1608,11 @@ void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { } -void ResTable_config::packLanguage(const char language[3]) { +void ResTable_config::packLanguage(const char* language) { packLanguageOrRegion(language, 'a', this->language); } -void ResTable_config::packRegion(const char region[3]) { +void ResTable_config::packRegion(const char* region) { packLanguageOrRegion(region, '0', this->country); } @@ -2320,7 +2320,7 @@ bool ResTable_config::match(const ResTable_config& settings) const { return true; } -void ResTable_config::getLocale(char str[RESTABLE_MAX_LOCALE_LEN]) const { +void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const { memset(str, 0, RESTABLE_MAX_LOCALE_LEN); // This represents the "any" locale value, which has traditionally been @@ -2331,34 +2331,83 @@ void ResTable_config::getLocale(char str[RESTABLE_MAX_LOCALE_LEN]) const { size_t charsWritten = 0; if (language[0]) { - unpackLanguage(str); + charsWritten += unpackLanguage(str); } - if (country[0]) { + if (localeScript[0]) { if (charsWritten) { - str[charsWritten++] = '_'; - str[charsWritten++] = 'r'; + str[charsWritten++] = '-'; } - charsWritten += unpackRegion(str + charsWritten); + memcpy(str + charsWritten, localeScript, sizeof(localeScript)); + charsWritten += sizeof(localeScript); } - if (localeScript[0]) { + if (country[0]) { if (charsWritten) { - str[charsWritten++] = '_'; - str[charsWritten++] = '_s'; + str[charsWritten++] = '-'; } - memcpy(str + charsWritten, localeScript, sizeof(localeScript)); + charsWritten += unpackRegion(str + charsWritten); } if (localeVariant[0]) { if (charsWritten) { - str[charsWritten++] = '_'; - str[charsWritten++] = 'v'; + str[charsWritten++] = '-'; } memcpy(str + charsWritten, localeVariant, sizeof(localeVariant)); } } +/* static */ inline bool assignLocaleComponent(ResTable_config* config, + const char* start, size_t size) { + + switch (size) { + case 0: + return false; + case 2: + case 3: + config->language[0] ? config->packRegion(start) : config->packLanguage(start); + break; + case 4: + config->localeScript[0] = toupper(start[0]); + for (size_t i = 1; i < 4; ++i) { + config->localeScript[i] = tolower(start[i]); + } + break; + case 5: + case 6: + case 7: + case 8: + for (size_t i = 0; i < size; ++i) { + config->localeVariant[i] = tolower(start[i]); + } + break; + default: + return false; + } + + return true; +} + +void ResTable_config::setBcp47Locale(const char* in) { + locale = 0; + memset(localeScript, 0, sizeof(localeScript)); + memset(localeVariant, 0, sizeof(localeVariant)); + + const char* separator = in; + const char* start = in; + while ((separator = strchr(start, '-')) != NULL) { + const size_t size = separator - start; + if (!assignLocaleComponent(this, start, size)) { + fprintf(stderr, "Invalid BCP-47 locale string: %s", in); + } + + start = (separator + 1); + } + + const size_t size = in + strlen(in) - start; + assignLocaleComponent(this, start, size); +} + String8 ResTable_config::toString() const { String8 res; @@ -2371,7 +2420,7 @@ String8 ResTable_config::toString() const { res.appendFormat("%dmnc", dtohs(mnc)); } char localeStr[RESTABLE_MAX_LOCALE_LEN]; - getLocale(localeStr); + getBcp47Locale(localeStr); res.append(localeStr); if ((screenLayout&MASK_LAYOUTDIR) != 0) { @@ -5126,18 +5175,20 @@ void ResTable::getConfigurations(Vector* configs) const const size_t L = type->configs.size(); for (size_t l=0; lconfigs[l]; - const ResTable_config* cfg = &config->config; + 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; madd(*cfg); + configs->add(cfg); } } } @@ -5155,7 +5206,7 @@ void ResTable::getLocales(Vector* locales) const char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; isize(); size_t j; for (j=0; j