#include "il2cpp-config.h"
|
#include <string>
|
#include <algorithm>
|
#include "il2cpp-api.h"
|
#include "il2cpp-object-internals.h"
|
#include "il2cpp-class-internals.h"
|
#include "utils/Memory.h"
|
#include "utils/StringUtils.h"
|
#include "vm/Array.h"
|
#include "vm/Exception.h"
|
#include "vm/String.h"
|
#include "os/Locale.h"
|
#include "icalls/mscorlib/System.Globalization/CultureInfo.h"
|
#include "CultureInfoInternals.h"
|
#include "CultureInfoTables.h"
|
|
|
/*
|
* The following methods is modified from the ICU source code. (http://oss.software.ibm.com/icu)
|
* Copyright (c) 1995-2003 International Business Machines Corporation and others
|
* All rights reserved.
|
*/
|
static std::string get_current_locale_name(void)
|
{
|
char* locale;
|
char* corrected = NULL;
|
const char* p;
|
|
std::string locale_str = il2cpp::os::Locale::GetLocale();
|
|
if (locale_str.empty())
|
return std::string();
|
|
locale = il2cpp::utils::StringUtils::StringDuplicate(locale_str.c_str());
|
|
if ((p = strchr(locale, '.')) != NULL)
|
{
|
/* assume new locale can't be larger than old one? */
|
corrected = (char*)IL2CPP_MALLOC(strlen(locale));
|
strncpy(corrected, locale, p - locale);
|
corrected[p - locale] = 0;
|
|
/* do not copy after the @ */
|
if ((p = strchr(corrected, '@')) != NULL)
|
corrected[p - corrected] = 0;
|
}
|
|
/* Note that we scan the *uncorrected* ID. */
|
if ((p = strrchr(locale, '@')) != NULL)
|
{
|
/*
|
* Mono we doesn't handle the '@' modifier because it does
|
* not have any cultures that use it. Just trim it
|
* off of the end of the name.
|
*/
|
|
if (corrected == NULL)
|
{
|
corrected = (char*)IL2CPP_MALLOC(strlen(locale));
|
strncpy(corrected, locale, p - locale);
|
corrected[p - locale] = 0;
|
}
|
}
|
|
if (corrected == NULL)
|
corrected = locale;
|
else
|
IL2CPP_FREE(locale);
|
|
char* c;
|
if ((c = strchr(corrected, '_')) != NULL)
|
*c = '-';
|
|
std::string result(corrected);
|
IL2CPP_FREE(corrected);
|
|
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
|
return result;
|
}
|
|
namespace il2cpp
|
{
|
namespace icalls
|
{
|
namespace mscorlib
|
{
|
namespace System
|
{
|
namespace Globalization
|
{
|
static Il2CppArray* culture_info_create_names_array_idx(const uint16_t* names, int max)
|
{
|
if (names == NULL)
|
return NULL;
|
|
int len = 0;
|
for (int i = 0; i < max; i++)
|
{
|
if (names[i] == 0)
|
break;
|
len++;
|
}
|
|
Il2CppArray* ret = il2cpp_array_new_specific(il2cpp_array_class_get(il2cpp_defaults.string_class, 1), len);
|
|
for (int i = 0; i < len; i++)
|
il2cpp_array_setref(ret, i, il2cpp_string_new(dtidx2string(names[i])));
|
|
return ret;
|
}
|
|
static bool construct_culture(Il2CppCultureInfo* cultureInfo, const CultureInfoEntry *ci)
|
{
|
cultureInfo->lcid = ci->lcid;
|
IL2CPP_OBJECT_SETREF(cultureInfo, name, il2cpp_string_new(idx2string(ci->name)));
|
IL2CPP_OBJECT_SETREF(cultureInfo, englishname, il2cpp_string_new(idx2string(ci->englishname)));
|
IL2CPP_OBJECT_SETREF(cultureInfo, nativename, il2cpp_string_new(idx2string(ci->nativename)));
|
IL2CPP_OBJECT_SETREF(cultureInfo, win3lang, il2cpp_string_new(idx2string(ci->win3lang)));
|
IL2CPP_OBJECT_SETREF(cultureInfo, iso3lang, il2cpp_string_new(idx2string(ci->iso3lang)));
|
IL2CPP_OBJECT_SETREF(cultureInfo, iso2lang, il2cpp_string_new(idx2string(ci->iso2lang)));
|
|
// It's null for neutral cultures
|
if (ci->territory > 0)
|
IL2CPP_OBJECT_SETREF(cultureInfo, territory, il2cpp_string_new(idx2string(ci->territory)));
|
cultureInfo->parent_lcid = ci->parent_lcid;
|
cultureInfo->datetime_index = ci->datetime_format_index;
|
cultureInfo->number_index = ci->number_format_index;
|
cultureInfo->text_info_data = &ci->text_info;
|
|
IL2CPP_OBJECT_SETREF(cultureInfo, native_calendar_names, culture_info_create_names_array_idx(ci->native_calendar_names, NUM_CALENDARS));
|
cultureInfo->default_calendar_type = ci->calendar_type;
|
|
return true;
|
}
|
|
static int culture_info_culture_name_locator(const void *a, const void *b)
|
{
|
const char* aa = (const char*)a;
|
const CultureInfoNameEntry* bb = (const CultureInfoNameEntry*)b;
|
int ret;
|
|
ret = strcmp(aa, idx2string(bb->name));
|
|
return ret;
|
}
|
|
static int culture_lcid_locator(const void *a, const void *b)
|
{
|
const CultureInfoEntry *aa = (const CultureInfoEntry*)a;
|
const CultureInfoEntry *bb = (const CultureInfoEntry*)b;
|
|
return (aa->lcid - bb->lcid);
|
}
|
|
static const CultureInfoEntry* culture_info_entry_from_lcid(int lcid)
|
{
|
CultureInfoEntry key;
|
key.lcid = lcid;
|
return (const CultureInfoEntry*)bsearch(&key, culture_entries, NUM_CULTURE_ENTRIES, sizeof(CultureInfoEntry), culture_lcid_locator);
|
}
|
|
static Il2CppArray* culture_info_create_group_sizes_array(const int *gs, int ml)
|
{
|
int i, len = 0;
|
|
for (i = 0; i < ml; i++)
|
{
|
if (gs[i] == -1)
|
break;
|
len++;
|
}
|
|
Il2CppArray* ret = il2cpp_array_new_specific(il2cpp_array_class_get(il2cpp_defaults.int32_class, 1), len);
|
|
for (i = 0; i < len; i++)
|
il2cpp_array_set(ret, int32_t, i, gs[i]);
|
|
return ret;
|
}
|
|
bool CultureInfo::construct_internal_locale_from_lcid(Il2CppCultureInfo* cultureInfo, int lcid)
|
{
|
const CultureInfoEntry* ci = culture_info_entry_from_lcid(lcid);
|
if (ci == NULL)
|
return false;
|
|
return construct_culture(cultureInfo, ci);
|
}
|
|
bool CultureInfo::construct_internal_locale_from_name(Il2CppCultureInfo* cultureInfo, Il2CppString* name)
|
{
|
std::string cultureName = il2cpp::utils::StringUtils::Utf16ToUtf8(name->chars);
|
const CultureInfoNameEntry* ne = (const CultureInfoNameEntry*)bsearch(cultureName.c_str(), culture_name_entries, NUM_CULTURE_ENTRIES, sizeof(CultureInfoNameEntry), culture_info_culture_name_locator);
|
|
if (ne == NULL)
|
return false;
|
|
return construct_culture(cultureInfo, &culture_entries[ne->culture_entry_index]);
|
}
|
|
static bool IsMatchingCultureInfoEntry(const CultureInfoEntry& entry, bool neutral, bool specific, bool installed)
|
{
|
const bool isNeutral = entry.territory == 0;
|
return ((neutral && isNeutral) || (specific && !isNeutral));
|
}
|
|
Il2CppArray* CultureInfo::internal_get_cultures(bool neutral, bool specific, bool installed)
|
{
|
// Count culture infos that match.
|
int numMatchingCultures = 0;
|
for (int i = 0; i < NUM_CULTURE_ENTRIES; ++i)
|
{
|
const CultureInfoEntry& entry = culture_entries[i];
|
if (IsMatchingCultureInfoEntry(entry, neutral, specific, installed))
|
++numMatchingCultures;
|
}
|
|
if (neutral)
|
++numMatchingCultures;
|
|
// Allocate result array.
|
Il2CppClass* cultureInfoClass = il2cpp_defaults.culture_info;
|
Il2CppArray* array = il2cpp_array_new(cultureInfoClass, numMatchingCultures);
|
|
int index = 0;
|
|
// InvariantCulture is not in culture table. We reserve the first
|
// array element for it.
|
if (neutral)
|
il2cpp_array_setref(array, index++, NULL);
|
|
// Populate CultureInfo entries.
|
for (int i = 0; i < NUM_CULTURE_ENTRIES; ++i)
|
{
|
const CultureInfoEntry& entry = culture_entries[i];
|
if (!IsMatchingCultureInfoEntry(entry, neutral, specific, installed))
|
continue;
|
|
Il2CppCultureInfo* info = reinterpret_cast<Il2CppCultureInfo*>(il2cpp_object_new(cultureInfoClass));
|
construct_culture(info, &entry);
|
|
il2cpp_array_setref(array, index++, info);
|
}
|
|
return array;
|
}
|
|
bool CultureInfo::internal_is_lcid_neutral(int32_t lcid, bool* is_neutral)
|
{
|
NOT_SUPPORTED_IL2CPP(CultureInfo::internal_is_lcid_neutral, "This icall is not supported by il2cpp.");
|
|
return false;
|
}
|
|
Il2CppString* CultureInfo::get_current_locale_name()
|
{
|
return vm::String::New(::get_current_locale_name().c_str());
|
}
|
} /* namespace Globalization */
|
} /* namespace System */
|
} /* namespace mscorlib */
|
} /* namespace icalls */
|
} /* namespace il2cpp */
|