Locale error checking is now more robust.

This commit is contained in:
jet 2010-10-07 16:32:59 -06:00
parent 8feb5a8124
commit cddc305a75

View File

@ -18,6 +18,7 @@
#include "jni-util.h" #include "jni-util.h"
#include "errno.h" #include "errno.h"
#include "fcntl.h" #include "fcntl.h"
#include "ctype.h"
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
@ -132,6 +133,59 @@ namespace {
#endif #endif
} }
class Locale {
static const unsigned MINLEN = 2;
static const unsigned MAXLEN = 3;
static const unsigned FIELDSIZE = MAXLEN + 1;
static const char* DEFAULT_LANGUAGE;
static const char* DEFAULT_REGION;
char language[FIELDSIZE];
char region[FIELDSIZE];
bool isLanguage(const char* language) {
if (!language) return false;
unsigned len = strlen(language);
if (len < MINLEN || len > MAXLEN) return false;
const char* p = language - 1;
while (islower(*++p));
if (*p != '\0') return false;
return true;
}
bool isRegion(const char* region) {
if (!region) return false;
unsigned len = strlen(region);
if ((len != 0 && len < MINLEN) || len > MAXLEN) return false;
const char* p = region - 1;
while (isupper(*++p));
if (*p != '\0') return false;
return true;
}
public:
Locale(const char* language = "", const char* region = "") {
if (!isLanguage(language) || !isRegion(region)) {
language = DEFAULT_LANGUAGE;
region = DEFAULT_REGION;
}
memcpy(this->language, language, strlen(language) + 1);
memcpy(this->region, region, strlen(region) + 1);
}
Locale& operator=(const Locale& l) {
memcpy(language, l.language, FIELDSIZE);
memcpy(region, l.region, FIELDSIZE);
return *this;
}
const char* getLanguage() { return reinterpret_cast<const char*>(language); }
const char* getRegion() { return reinterpret_cast<const char*>(region); }
};
const char* Locale::DEFAULT_LANGUAGE = "en";
const char* Locale::DEFAULT_REGION = "";
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
Java_java_lang_Runtime_exec(JNIEnv* e, jclass, Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
@ -230,14 +284,12 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid)
return exitCode; return exitCode;
} }
void getLocale(char* language, char* region) { Locale getLocale() {
const char dummy = '\0'; const char* lang = "";
const char* lang = &dummy; const char* reg = "";
const char* reg = &dummy; unsigned langid = GetUserDefaultUILanguage();
unsigned prilang = langid & 0x3ff;
unsigned locale = GetUserDefaultUILanguage(); unsigned sublang = langid >> 10;
unsigned prilang = locale & 0x3ff;
unsigned sublang = locale >> 10;
switch (prilang) { switch (prilang) {
case 0x004: { case 0x004: {
@ -301,10 +353,11 @@ void getLocale(char* language, char* region) {
case 0x018: lang = "ro"; reg = "RO"; break; case 0x018: lang = "ro"; reg = "RO"; break;
case 0x019: lang = "ru"; reg = "RU"; break; case 0x019: lang = "ru"; reg = "RU"; break;
case 0x01d: lang = "sv"; reg = "SE"; break; case 0x01d: lang = "sv"; reg = "SE"; break;
default: lang = "en";
} }
if (language) memcpy(language, lang, (strlen(lang) + 1) * sizeof(char)); Locale locale(lang, reg);
if (region) memcpy(region, reg, (strlen(reg) + 1) * sizeof(char)); return locale;
} }
#else #else
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
@ -430,25 +483,30 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid)
return exitCode; return exitCode;
} }
void getLocale(char* language, char* region) { Locale getLocale() {
unsigned langlen = 0, reglen = 0; Locale fallback;
const char* LANG = getenv("LANG"); const char* LANG = getenv("LANG");
if (!LANG || strcmp(LANG, "C") == 0) return fallback;
if (LANG) { int len = strlen(LANG);
while (langlen < strlen(LANG) && *(LANG + langlen) != '_') ++langlen; char buf[len];
unsigned regend = langlen + 1; memcpy(buf, LANG, len);
while (regend < strlen(LANG) && *(LANG + regend) != '.') ++regend;
reglen = regend - langlen - 1;
}
if (language) { char* tracer = buf;
memcpy(language, LANG, langlen * sizeof(char)); const char* reg;
language[langlen] = '\0';
} while (*tracer && *tracer != '_') ++tracer;
if (region) { if (!*tracer) return fallback;
memcpy(region, LANG + langlen + 1, reglen * sizeof(char)); *tracer = '\0';
region[reglen] = '\0'; reg = tracer++ + 1;
}
while (*tracer && *tracer != '.') ++tracer;
if (tracer == reg) return fallback;
*tracer = '\0';
Locale locale(buf, reg);
return locale;
} }
#endif #endif
@ -551,13 +609,11 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name,
} }
#endif #endif
else if (strcmp(chars, "user.language") == 0) { else if (strcmp(chars, "user.language") == 0) {
char lang[16]; Locale locale = getLocale();
getLocale(lang, 0); if (strlen(locale.getLanguage())) r = e->NewStringUTF(locale.getLanguage());
if (strlen(lang)) r = e->NewStringUTF(lang);
} else if (strcmp(chars, "user.region") == 0) { } else if (strcmp(chars, "user.region") == 0) {
char reg[16]; Locale locale = getLocale();
getLocale(0, reg); if (strlen(locale.getRegion())) r = e->NewStringUTF(locale.getRegion());
if (strlen(reg)) r = e->NewStringUTF(reg);
} }
e->ReleaseStringUTFChars(name, chars); e->ReleaseStringUTFChars(name, chars);