Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f32c27c authored by Roozbeh Pournader's avatar Roozbeh Pournader
Browse files

Don't match locales with different scripts in ResourceFilter

Previously, AAPT would match locales even if they had different
explicit scripts if the requested locale was just a languages. Now
we require explicit listing of the languages with different explicit
scripts in order for the locale to be included.

Bug: 29412034
Change-Id: Ia118a5a7f9aec49f6c3c53b9195a0ae1a57f53fd
parent 73939d8a
Loading
Loading
Loading
Loading
+53 −5
Original line number Diff line number Diff line
@@ -54,6 +54,46 @@ WeakResourceFilter::parse(const String8& str)
    return NO_ERROR;
}

// Returns true if the locale script of the config should be considered matching
// the locale script of entry.
//
// If both the scripts are empty, the scripts are considered matching for
// backward compatibility reasons.
//
// If only one script is empty, we try to compute it based on the provided
// language and country. If we could not compute it, we assume it's either a
// new language we don't know about, or a private use language. We return true
// since we don't know any better and they might as well be a match.
//
// Finally, when we have two scripts (one of which could be computed), we return
// true if and only if they are an exact match.
inline bool
scriptsMatch(const ResTable_config& config, const ResTable_config& entry) {
    const char* configScript = config.localeScript;
    const char* entryScript = entry.localeScript;
    if (configScript[0] == '\0' && entryScript[0] == '\0') {
        return true;  // both scripts are empty. We match for backward compatibility reasons.
    }

    char scriptBuffer[sizeof(config.localeScript)];
    if (configScript[0] == '\0') {
        localeDataComputeScript(scriptBuffer, config.language, config.country);
        if (scriptBuffer[0] == '\0') {  // We can't compute the script, so we match.
            return true;
        }
        configScript = scriptBuffer;
    } else if (entryScript[0] == '\0') {
        localeDataComputeScript(
                scriptBuffer, entry.language, entry.country);
        if (scriptBuffer[0] == '\0') {  // We can't compute the script, so we match.
            return true;
        }
        entryScript = scriptBuffer;
    }
    return (memcmp(configScript, entryScript, sizeof(config.localeScript)) == 0);
}


bool
WeakResourceFilter::match(const ResTable_config& config) const
{
@@ -75,12 +115,20 @@ WeakResourceFilter::match(const ResTable_config& config) const
            // If the locales differ, but the languages are the same and
            // the locale we are matching only has a language specified,
            // we match.
            if (config.language[0] &&
                    memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
                if (config.country[0] == 0) {
            //
            // Exception: we won't match if a script is specified for at least
            // one of the locales and it's different from the other locale's
            // script. (We will compute the other script if at least one of the
            // scripts were explicitly set. In cases we can't compute an script,
            // we match.)
            if (config.language[0] != '\0' &&
                    config.country[0] == '\0' &&
                    config.localeVariant[0] == '\0' &&
                    config.language[0] == entry.first.language[0] &&
                    config.language[1] == entry.first.language[1] &&
                    scriptsMatch(config, entry.first)) {
                matchedAxis |= ResTable_config::CONFIG_LOCALE;
            }
            }
        } else if ((diff & entry.second) == ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) {
            // Special case if the smallest screen width doesn't match. We check that the
            // config being matched has a smaller screen width than the filter specified.