Fix relying on order of static object destruction in Locale Kit.

* use only a single static object (MutableLocaleRoster) instead of
  two, which avoids any problems if the order of static object
  destruction would destroy RosterData before MutableLocaleRoster
* rename BPrivate::RosterData to BPrivate::LocaleRosterData and move
  it into a header and implementation file of its own
This should hopefully fix problems encountered with a clang-compiled
Locale Kit.
This commit is contained in:
Oliver Tappe 2012-11-26 01:18:57 +01:00
parent a22e8c6fe2
commit 52cdfde04b
8 changed files with 899 additions and 846 deletions

View File

@ -21,14 +21,19 @@ class BMessage;
class BTimeZone;
namespace BPrivate {
class LocaleRosterData;
}
enum {
B_LOCALE_CHANGED = '_LCC',
};
class BLocaleRoster {
public:
BLocaleRoster();
~BLocaleRoster();
static BLocaleRoster* Default();
@ -70,6 +75,8 @@ public:
// Get the catalog for the calling image
// (that needs to link with liblocalestub.a)
const BLocale* GetDefaultLocale() const;
bool IsFilesystemTranslationPreferred() const;
status_t GetLocalizedFileName(BString& localizedFileName,
@ -83,6 +90,12 @@ public:
static const char* kEmbeddedCatAttr;
static int32 kEmbeddedCatResId;
protected:
BLocaleRoster();
protected:
BPrivate::LocaleRosterData* fData;
private:
static BCatalog* _GetCatalog(BCatalog* catalog,
vint32* catalogInitStatus);
@ -90,6 +103,7 @@ private:
status_t _PrepareCatalogEntry(const entry_ref& ref,
BString& signature, BString& context,
BString& string, bool traverse);
};

View File

@ -0,0 +1,142 @@
/*
* Copyright 2010-2012, Haiku. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _LOCALE_ROSTER_DATA_H_
#define _LOCALE_ROSTER_DATA_H_
#include <Collator.h>
#include <FormattingConventions.h>
#include <image.h>
#include <Language.h>
#include <List.h>
#include <Locale.h>
#include <Locker.h>
#include <Message.h>
#include <Resources.h>
#include <TimeZone.h>
class BCatalogData;
class BLocale;
struct entry_ref;
namespace BPrivate {
/*
* Struct containing the actual locale data.
*/
struct LocaleRosterData {
BLocker fLock;
BList fCatalogAddOnInfos;
BMessage fPreferredLanguages;
BLocale fDefaultLocale;
BTimeZone fDefaultTimeZone;
bool fIsFilesystemTranslationPreferred;
LocaleRosterData(const BLanguage& language,
const BFormattingConventions& conventions);
~LocaleRosterData();
status_t InitCheck() const;
status_t Refresh();
static int CompareInfos(const void* left,
const void* right);
status_t GetResources(BResources** resources);
status_t SetDefaultFormattingConventions(
const BFormattingConventions& convetions);
status_t SetDefaultTimeZone(const BTimeZone& zone);
status_t SetPreferredLanguages(const BMessage* msg);
status_t SetFilesystemTranslationPreferred(
bool preferred);
private:
status_t _Initialize();
status_t _InitializeCatalogAddOns();
void _CleanupCatalogAddOns();
status_t _LoadLocaleSettings();
status_t _SaveLocaleSettings();
status_t _LoadTimeSettings();
status_t _SaveTimeSettings();
status_t _SetDefaultFormattingConventions(
const BFormattingConventions& conventions);
status_t _SetDefaultTimeZone(const BTimeZone& zone);
status_t _SetPreferredLanguages(const BMessage* msg);
void _SetFilesystemTranslationPreferred(
bool preferred);
status_t _AddDefaultFormattingConventionsToMessage(
BMessage* message) const;
status_t _AddDefaultTimeZoneToMessage(
BMessage* message) const;
status_t _AddPreferredLanguagesToMessage(
BMessage* message) const;
status_t _AddFilesystemTranslationPreferenceToMessage(
BMessage* message) const;
private:
status_t fInitStatus;
bool fAreResourcesLoaded;
BResources fResources;
};
typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner,
const char* language, uint32 fingerprint);
typedef BCatalogData* (*CreateCatalogFunc)(const char* name,
const char* language);
typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)(
entry_ref* appOrAddOnRef);
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
const char*, int32);
/*
* info about a single catalog-add-on (representing a catalog type):
*/
struct CatalogAddOnInfo {
InstantiateCatalogFunc fInstantiateFunc;
CreateCatalogFunc fCreateFunc;
GetAvailableLanguagesFunc fLanguagesFunc;
BString fName;
BString fPath;
image_id fAddOnImage;
uint8 fPriority;
BList fLoadedCatalogs;
bool fIsEmbedded;
// an embedded add-on actually isn't an
// add-on, it is included as part of the
// library.
// The DefaultCatalog is such a beast!
CatalogAddOnInfo(const BString& name,
const BString& path, uint8 priority);
~CatalogAddOnInfo();
bool MakeSureItsLoaded();
void UnloadIfPossible();
};
} // namespace BPrivate
#endif // _LOCALE_ROSTER_DATA_H_

View File

@ -60,113 +60,6 @@ public:
};
typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner,
const char* language, uint32 fingerprint);
typedef BCatalogData* (*CreateCatalogFunc)(const char* name,
const char* language);
typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)(
entry_ref* appOrAddOnRef);
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
const char*, int32);
/*
* info about a single catalog-add-on (representing a catalog type):
*/
struct CatalogAddOnInfo {
InstantiateCatalogFunc fInstantiateFunc;
CreateCatalogFunc fCreateFunc;
GetAvailableLanguagesFunc fLanguagesFunc;
BString fName;
BString fPath;
image_id fAddOnImage;
uint8 fPriority;
BList fLoadedCatalogs;
bool fIsEmbedded;
// an embedded add-on actually isn't an
// add-on, it is included as part of the
// library.
// The DefaultCatalog is such a beast!
CatalogAddOnInfo(const BString& name,
const BString& path, uint8 priority);
~CatalogAddOnInfo();
bool MakeSureItsLoaded();
void UnloadIfPossible();
};
/*
* The global data that is shared between all roster-objects of a process.
*/
struct RosterData {
BLocker fLock;
BList fCatalogAddOnInfos;
BMessage fPreferredLanguages;
BLocale fDefaultLocale;
BTimeZone fDefaultTimeZone;
bool fIsFilesystemTranslationPreferred;
bool fAreResourcesLoaded;
BResources fResources;
status_t fInitStatus;
RosterData(const BLanguage& language,
const BFormattingConventions& conventions);
~RosterData();
static RosterData* Default();
status_t InitCheck() const;
status_t Refresh();
static int CompareInfos(const void* left,
const void* right);
status_t SetDefaultFormattingConventions(
const BFormattingConventions& convetions);
status_t SetDefaultTimeZone(const BTimeZone& zone);
status_t SetPreferredLanguages(const BMessage* msg);
status_t SetFilesystemTranslationPreferred(
bool preferred);
private:
status_t _Initialize();
status_t _InitializeCatalogAddOns();
void _CleanupCatalogAddOns();
status_t _LoadLocaleSettings();
status_t _SaveLocaleSettings();
status_t _LoadTimeSettings();
status_t _SaveTimeSettings();
status_t _SetDefaultFormattingConventions(
const BFormattingConventions& conventions);
status_t _SetDefaultTimeZone(const BTimeZone& zone);
status_t _SetPreferredLanguages(const BMessage* msg);
void _SetFilesystemTranslationPreferred(
bool preferred);
status_t _AddDefaultFormattingConventionsToMessage(
BMessage* message) const;
status_t _AddDefaultTimeZoneToMessage(
BMessage* message) const;
status_t _AddPreferredLanguagesToMessage(
BMessage* message) const;
status_t _AddFilesystemTranslationPreferenceToMessage(
BMessage* message) const;
};
} // namespace BPrivate

View File

@ -19,6 +19,7 @@ local sources =
Language.cpp
Locale.cpp
LocaleRoster.cpp
LocaleRosterData.cpp
MutableLocaleRoster.cpp
TimeZone.cpp

View File

@ -14,7 +14,6 @@
#include <LanguagePrivate.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <TimeZone.h>
#include <ICUWrapper.h>
@ -59,7 +58,7 @@ BLocale::BLocale(const BLocale& other)
/*static*/ const BLocale*
BLocale::Default()
{
return &BPrivate::RosterData::Default()->fDefaultLocale;
return BLocaleRoster::Default()->GetDefaultLocale();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2010, Haiku. All rights reserved.
* Copyright 2003-2012, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -10,27 +10,23 @@
#include <LocaleRoster.h>
#include <ctype.h>
#include <set>
#include <assert.h>
#include <ctype.h>
#include <new>
#include <Autolock.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <Collator.h>
#include <DefaultCatalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FormattingConventions.h>
#include <fs_attr.h>
#include <IconUtils.h>
#include <Language.h>
#include <Locale.h>
#include <LocaleRosterData.h>
#include <MutableLocaleRoster.h>
#include <Node.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <TimeZone.h>
@ -45,7 +41,6 @@
using BPrivate::CatalogAddOnInfo;
using BPrivate::MutableLocaleRoster;
using BPrivate::RosterData;
/*
@ -67,26 +62,6 @@ int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
// this may live in an app- or add-on-file
static status_t
load_resources_if_needed(RosterData* rosterData)
{
if (rosterData->fAreResourcesLoaded)
return B_OK;
status_t result = rosterData->fResources.SetToImage(
(const void*)&BLocaleRoster::Default);
if (result != B_OK)
return result;
result = rosterData->fResources.PreloadResourceType();
if (result != B_OK)
return result;
rosterData->fAreResourcesLoaded = true;
return B_OK;
}
static const char*
country_code_for_language(const BLanguage& language)
{
@ -149,12 +124,16 @@ country_code_for_language(const BLanguage& language)
BLocaleRoster::BLocaleRoster()
:
fData(new(std::nothrow) BPrivate::LocaleRosterData(BLanguage("en_US"),
BFormattingConventions("en_US")))
{
}
BLocaleRoster::~BLocaleRoster()
{
delete fData;
}
@ -168,7 +147,7 @@ BLocaleRoster::Default()
status_t
BLocaleRoster::Refresh()
{
return RosterData::Default()->Refresh();
return fData->Refresh();
}
@ -178,17 +157,22 @@ BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const
if (!timezone)
return B_BAD_VALUE;
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
*timezone = rosterData->fDefaultTimeZone;
*timezone = fData->fDefaultTimeZone;
return B_OK;
}
const BLocale*
BLocaleRoster::GetDefaultLocale() const
{
return &fData->fDefaultLocale;
}
status_t
BLocaleRoster::GetLanguage(const char* languageCode,
BLanguage** _language) const
@ -211,12 +195,11 @@ BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
if (!languages)
return B_BAD_VALUE;
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
*languages = rosterData->fPreferredLanguages;
*languages = fData->fPreferredLanguages;
return B_OK;
}
@ -367,12 +350,12 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
if (countryCode == NULL)
return B_BAD_VALUE;
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
status_t status = load_resources_if_needed(rosterData);
BResources* resources;
status_t status = fData->GetResources(&resources);
if (status != B_OK)
return status;
@ -389,8 +372,8 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
normalizedCode[2] = '\0';
size_t size;
const void* buffer = rosterData->fResources.LoadResource(
B_VECTOR_ICON_TYPE, normalizedCode, &size);
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
normalizedCode, &size);
if (buffer == NULL || size == 0)
return B_NAME_NOT_FOUND;
@ -407,12 +390,12 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
|| languageCode[1] == '\0')
return B_BAD_VALUE;
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
status_t status = load_resources_if_needed(rosterData);
BResources* resources;
status_t status = fData->GetResources(&resources);
if (status != B_OK)
return status;
@ -424,8 +407,8 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
normalizedCode[2] = '\0';
size_t size;
const void* buffer = rosterData->fResources.LoadResource(
B_VECTOR_ICON_TYPE, normalizedCode, &size);
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
normalizedCode, &size);
if (buffer != NULL && size != 0) {
return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer),
size, flagIcon);
@ -450,15 +433,14 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
if (languageList == NULL)
return B_BAD_VALUE;
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
int32 count = rosterData->fCatalogAddOnInfos.CountItems();
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info
= (CatalogAddOnInfo*)rosterData->fCatalogAddOnInfos.ItemAt(i);
= (CatalogAddOnInfo*)fData->fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
continue;
@ -474,12 +456,11 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
bool
BLocaleRoster::IsFilesystemTranslationPreferred() const
{
RosterData* rosterData = RosterData::Default();
BAutolock lock(rosterData->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
return rosterData->fIsFilesystemTranslationPreferred;
return fData->fIsFilesystemTranslationPreferred;
}

View File

@ -0,0 +1,682 @@
/*
* Copyright 2003-2012, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Oliver Tappe, zooey@hirschkaefer.de
*/
#include <LocaleRosterData.h>
#include <Autolock.h>
#include <Catalog.h>
#include <Collator.h>
#include <Debug.h>
#include <DefaultCatalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <FormattingConventions.h>
#include <Language.h>
#include <Locale.h>
#include <Node.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <TimeZone.h>
// ICU includes
#include <unicode/locid.h>
#include <unicode/timezone.h>
namespace BPrivate {
// #pragma mark - CatalogAddOnInfo
CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path,
uint8 priority)
:
fInstantiateFunc(NULL),
fCreateFunc(NULL),
fLanguagesFunc(NULL),
fName(name),
fPath(path),
fAddOnImage(B_NO_INIT),
fPriority(priority),
fIsEmbedded(path.Length()==0)
{
}
CatalogAddOnInfo::~CatalogAddOnInfo()
{
int32 count = fLoadedCatalogs.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogData* cat
= static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i));
delete cat;
}
fLoadedCatalogs.MakeEmpty();
UnloadIfPossible();
}
bool
CatalogAddOnInfo::MakeSureItsLoaded()
{
if (!fIsEmbedded && fAddOnImage < B_OK) {
// add-on has not been loaded yet, so we try to load it:
BString fullAddOnPath(fPath);
fullAddOnPath << "/" << fName;
fAddOnImage = load_add_on(fullAddOnPath.String());
if (fAddOnImage >= B_OK) {
get_image_symbol(fAddOnImage, "instantiate_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc);
get_image_symbol(fAddOnImage, "create_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc);
get_image_symbol(fAddOnImage, "get_available_languages",
B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc);
} else
return false;
} else if (fIsEmbedded) {
// The built-in catalog still has to provide this function
fLanguagesFunc = default_catalog_get_available_languages;
}
return true;
}
void
CatalogAddOnInfo::UnloadIfPossible()
{
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
unload_add_on(fAddOnImage);
fAddOnImage = B_NO_INIT;
fInstantiateFunc = NULL;
fCreateFunc = NULL;
fLanguagesFunc = NULL;
}
}
// #pragma mark - LocaleRosterData
namespace {
static const char* kPriorityAttr = "ADDON:priority";
static const char* kLanguageField = "language";
static const char* kTimezoneField = "timezone";
static const char* kTranslateFilesystemField = "filesys";
} // anonymous namespace
LocaleRosterData::LocaleRosterData(const BLanguage& language,
const BFormattingConventions& conventions)
:
fLock("LocaleRosterData"),
fDefaultLocale(&language, &conventions),
fIsFilesystemTranslationPreferred(false),
fAreResourcesLoaded(false)
{
fInitStatus = _Initialize();
}
LocaleRosterData::~LocaleRosterData()
{
BAutolock lock(fLock);
_CleanupCatalogAddOns();
}
status_t
LocaleRosterData::InitCheck() const
{
return fAreResourcesLoaded ? B_OK : B_NO_INIT;
}
status_t
LocaleRosterData::Refresh()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
_LoadLocaleSettings();
_LoadTimeSettings();
return B_OK;
}
int
LocaleRosterData::CompareInfos(const void* left, const void* right)
{
return ((CatalogAddOnInfo*)right)->fPriority
- ((CatalogAddOnInfo*)left)->fPriority;
}
status_t
LocaleRosterData::SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultFormattingConventions(newFormattingConventions);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultFormattingConventionsToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
LocaleRosterData::SetDefaultTimeZone(const BTimeZone& newZone)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultTimeZone(newZone);
if (status == B_OK)
status = _SaveTimeSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultTimeZoneToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
LocaleRosterData::SetPreferredLanguages(const BMessage* languages)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetPreferredLanguages(languages);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddPreferredLanguagesToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
LocaleRosterData::SetFilesystemTranslationPreferred(bool preferred)
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
_SetFilesystemTranslationPreferred(preferred);
status_t status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
LocaleRosterData::GetResources(BResources** resources)
{
if (resources == NULL)
return B_BAD_VALUE;
if (!fAreResourcesLoaded) {
status_t result
= fResources.SetToImage((const void*)&BLocaleRoster::Default);
if (result != B_OK)
return result;
result = fResources.PreloadResourceType();
if (result != B_OK)
return result;
fAreResourcesLoaded = true;
}
*resources = &fResources;
return B_OK;
}
status_t
LocaleRosterData::_Initialize()
{
status_t result = _InitializeCatalogAddOns();
if (result != B_OK)
return result;
if ((result = Refresh()) != B_OK)
return result;
fInitStatus = B_OK;
return B_OK;
}
/*
iterate over add-on-folders and collect information about each
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
*/
status_t
LocaleRosterData::_InitializeCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
// add info about embedded default catalog:
CatalogAddOnInfo* defaultCatalogAddOnInfo
= new(std::nothrow) CatalogAddOnInfo("Default", "",
DefaultCatalog::kDefaultCatalogAddOnPriority);
if (!defaultCatalogAddOnInfo)
return B_NO_MEMORY;
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
directory_which folders[] = {
B_USER_ADDONS_DIRECTORY,
B_COMMON_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
};
BPath addOnPath;
BDirectory addOnFolder;
char buf[4096];
status_t err;
for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) {
find_directory(folders[f], &addOnPath);
BString addOnFolderName(addOnPath.Path());
addOnFolderName << "/locale/catalogs";
system_info info;
if (get_system_info(&info) == B_OK
&& (info.abi & B_HAIKU_ABI_MAJOR)
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
case B_HAIKU_ABI_GCC_2:
addOnFolderName << "/gcc2";
break;
case B_HAIKU_ABI_GCC_4:
addOnFolderName << "/gcc4";
break;
}
}
err = addOnFolder.SetTo(addOnFolderName.String());
if (err != B_OK)
continue;
// scan through all the folder's entries for catalog add-ons:
int32 count;
int8 priority;
entry_ref eref;
BNode node;
BEntry entry;
dirent* dent;
while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) {
dent = (dirent*)buf;
while (count-- > 0) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
&& strcmp(dent->d_name, "gcc2")
&& strcmp(dent->d_name, "gcc4")) {
// we have found (what should be) a catalog-add-on:
eref.device = dent->d_pdev;
eref.directory = dent->d_pino;
eref.set_name(dent->d_name);
entry.SetTo(&eref, true);
// traverse through any links to get to the real thang!
node.SetTo(&entry);
priority = -1;
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8)) <= 0) {
// add-on has no priority-attribute yet, so we load it
// to fetch the priority from the corresponding
// symbol...
BString fullAddOnPath(addOnFolderName);
fullAddOnPath << "/" << dent->d_name;
image_id image = load_add_on(fullAddOnPath.String());
if (image >= B_OK) {
uint8* prioPtr;
if (get_image_symbol(image, "gCatalogAddOnPriority",
B_SYMBOL_TYPE_DATA,
(void**)&prioPtr) == B_OK) {
priority = *prioPtr;
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8));
}
unload_add_on(image);
}
}
if (priority >= 0) {
// add-ons with priority < 0 will be ignored
CatalogAddOnInfo* addOnInfo
= new(std::nothrow) CatalogAddOnInfo(dent->d_name,
addOnFolderName, priority);
if (addOnInfo)
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
}
}
// Bump the dirent-pointer by length of the dirent just handled:
dent = (dirent*)((char*)dent + dent->d_reclen);
}
}
}
fCatalogAddOnInfos.SortItems(CompareInfos);
return B_OK;
}
/*
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
*/
void
LocaleRosterData::_CleanupCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return;
int32 count = fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i<count; ++i) {
CatalogAddOnInfo* info
= static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
delete info;
}
fCatalogAddOnInfos.MakeEmpty();
}
status_t
LocaleRosterData::_LoadLocaleSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK) {
BFormattingConventions conventions(&settings);
fDefaultLocale.SetFormattingConventions(conventions);
_SetPreferredLanguages(&settings);
bool preferred;
if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK)
_SetFilesystemTranslationPreferred(preferred);
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
fPreferredLanguages.MakeEmpty();
fPreferredLanguages.AddString(kLanguageField, "en");
BLanguage defaultLanguage("en_US");
fDefaultLocale.SetLanguage(defaultLanguage);
BFormattingConventions conventions("en_US");
fDefaultLocale.SetFormattingConventions(conventions);
return status;
}
status_t
LocaleRosterData::_LoadTimeSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK) {
BString timeZoneID;
if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK)
_SetDefaultTimeZone(BTimeZone(timeZoneID.String()));
else
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
return status;
}
status_t
LocaleRosterData::_SaveLocaleSettings()
{
BMessage settings;
status_t status = _AddDefaultFormattingConventionsToMessage(&settings);
if (status == B_OK)
_AddPreferredLanguagesToMessage(&settings);
if (status == B_OK)
_AddFilesystemTranslationPreferenceToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
LocaleRosterData::_SaveTimeSettings()
{
BMessage settings;
status_t status = _AddDefaultTimeZoneToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
LocaleRosterData::_SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
fDefaultLocale.SetFormattingConventions(newFormattingConventions);
UErrorCode icuError = U_ZERO_ERROR;
Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID());
if (icuLocale.isBogus())
return B_ERROR;
Locale::setDefault(icuLocale, icuError);
if (!U_SUCCESS(icuError))
return B_ERROR;
return B_OK;
}
status_t
LocaleRosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
{
fDefaultTimeZone = newZone;
TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String());
if (timeZone == NULL)
return B_ERROR;
TimeZone::adoptDefault(timeZone);
return B_OK;
}
status_t
LocaleRosterData::_SetPreferredLanguages(const BMessage* languages)
{
BString langName;
if (languages != NULL
&& languages->FindString(kLanguageField, &langName) == B_OK) {
fDefaultLocale.SetCollator(BCollator(langName.String()));
fDefaultLocale.SetLanguage(BLanguage(langName.String()));
fPreferredLanguages.RemoveName(kLanguageField);
for (int i = 0; languages->FindString(kLanguageField, i, &langName)
== B_OK; i++) {
fPreferredLanguages.AddString(kLanguageField, langName);
}
} else {
fPreferredLanguages.MakeEmpty();
fPreferredLanguages.AddString(kLanguageField, "en");
fDefaultLocale.SetCollator(BCollator("en"));
}
return B_OK;
}
void
LocaleRosterData::_SetFilesystemTranslationPreferred(bool preferred)
{
fIsFilesystemTranslationPreferred = preferred;
}
status_t
LocaleRosterData::_AddDefaultFormattingConventionsToMessage(
BMessage* message) const
{
BFormattingConventions conventions;
fDefaultLocale.GetFormattingConventions(&conventions);
return conventions.Archive(message);
}
status_t
LocaleRosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
{
return message->AddString(kTimezoneField, fDefaultTimeZone.ID());
}
status_t
LocaleRosterData::_AddPreferredLanguagesToMessage(BMessage* message) const
{
status_t status = B_OK;
BString langName;
for (int i = 0; fPreferredLanguages.FindString("language", i,
&langName) == B_OK; i++) {
status = message->AddString(kLanguageField, langName);
if (status != B_OK)
break;
}
return status;
}
status_t
LocaleRosterData::_AddFilesystemTranslationPreferenceToMessage(
BMessage* message) const
{
return message->AddBool(kTranslateFilesystemField,
fIsFilesystemTranslationPreferred);
}
} // namespace BPrivate

View File

@ -10,702 +10,41 @@
#include <MutableLocaleRoster.h>
#include <set>
#include <pthread.h>
#include <AppFileInfo.h>
#include <Application.h>
#include <Autolock.h>
#include <Catalog.h>
#include <Collator.h>
#include <CatalogData.h>
#include <Debug.h>
#include <DefaultCatalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <FormattingConventions.h>
#include <Language.h>
#include <Locale.h>
#include <Node.h>
#include <Path.h>
#include <Roster.h>
#include <LocaleRosterData.h>
#include <String.h>
#include <TimeZone.h>
#include <ICUWrapper.h>
// ICU includes
#include <unicode/locid.h>
#include <unicode/timezone.h>
namespace BPrivate {
// #pragma mark - CatalogAddOnInfo
CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path,
uint8 priority)
:
fInstantiateFunc(NULL),
fCreateFunc(NULL),
fLanguagesFunc(NULL),
fName(name),
fPath(path),
fAddOnImage(B_NO_INIT),
fPriority(priority),
fIsEmbedded(path.Length()==0)
{
}
CatalogAddOnInfo::~CatalogAddOnInfo()
{
int32 count = fLoadedCatalogs.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogData* cat
= static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i));
delete cat;
}
fLoadedCatalogs.MakeEmpty();
UnloadIfPossible();
}
bool
CatalogAddOnInfo::MakeSureItsLoaded()
{
if (!fIsEmbedded && fAddOnImage < B_OK) {
// add-on has not been loaded yet, so we try to load it:
BString fullAddOnPath(fPath);
fullAddOnPath << "/" << fName;
fAddOnImage = load_add_on(fullAddOnPath.String());
if (fAddOnImage >= B_OK) {
get_image_symbol(fAddOnImage, "instantiate_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc);
get_image_symbol(fAddOnImage, "create_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc);
get_image_symbol(fAddOnImage, "get_available_languages",
B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc);
} else
return false;
} else if (fIsEmbedded) {
// The built-in catalog still has to provide this function
fLanguagesFunc = default_catalog_get_available_languages;
}
return true;
}
void
CatalogAddOnInfo::UnloadIfPossible()
{
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
unload_add_on(fAddOnImage);
fAddOnImage = B_NO_INIT;
fInstantiateFunc = NULL;
fCreateFunc = NULL;
fLanguagesFunc = NULL;
}
}
// #pragma mark - RosterData
namespace {
static const char* kPriorityAttr = "ADDON:priority";
static MutableLocaleRoster* sLocaleRoster;
static const char* kLanguageField = "language";
static const char* kTimezoneField = "timezone";
static const char* kTranslateFilesystemField = "filesys";
static RosterData* sRosterData = NULL;
static pthread_once_t sRosterDataInitOnce = PTHREAD_ONCE_INIT;
static struct RosterDataReaper {
~RosterDataReaper()
{
delete sRosterData;
sRosterData = NULL;
}
} sRosterDataReaper;
static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT;
} // anonymous namespace
static void
InitializeRosterData()
InitializeLocaleRoster()
{
sRosterData = new (std::nothrow) RosterData(BLanguage("en_US"),
BFormattingConventions("en_US"));
sLocaleRoster = new (std::nothrow) MutableLocaleRoster();
}
RosterData::RosterData(const BLanguage& language,
const BFormattingConventions& conventions)
:
fLock("LocaleRosterData"),
fDefaultLocale(&language, &conventions),
fIsFilesystemTranslationPreferred(false),
fAreResourcesLoaded(false)
{
fInitStatus = _Initialize();
}
RosterData::~RosterData()
{
BAutolock lock(fLock);
_CleanupCatalogAddOns();
}
/*static*/ RosterData*
RosterData::Default()
{
if (sRosterData == NULL)
pthread_once(&sRosterDataInitOnce, &BPrivate::InitializeRosterData);
return sRosterData;
}
status_t
RosterData::InitCheck() const
{
return fAreResourcesLoaded ? B_OK : B_NO_INIT;
}
status_t
RosterData::Refresh()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
_LoadLocaleSettings();
_LoadTimeSettings();
return B_OK;
}
int
RosterData::CompareInfos(const void* left, const void* right)
{
return ((CatalogAddOnInfo*)right)->fPriority
- ((CatalogAddOnInfo*)left)->fPriority;
}
status_t
RosterData::SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultFormattingConventions(newFormattingConventions);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultFormattingConventionsToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::SetDefaultTimeZone(const BTimeZone& newZone)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultTimeZone(newZone);
if (status == B_OK)
status = _SaveTimeSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultTimeZoneToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::SetPreferredLanguages(const BMessage* languages)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetPreferredLanguages(languages);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddPreferredLanguagesToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::SetFilesystemTranslationPreferred(bool preferred)
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
_SetFilesystemTranslationPreferred(preferred);
status_t status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::_Initialize()
{
status_t result = _InitializeCatalogAddOns();
if (result != B_OK)
return result;
if ((result = Refresh()) != B_OK)
return result;
fInitStatus = B_OK;
return B_OK;
}
/*
iterate over add-on-folders and collect information about each
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
*/
status_t
RosterData::_InitializeCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
// add info about embedded default catalog:
CatalogAddOnInfo* defaultCatalogAddOnInfo
= new(std::nothrow) CatalogAddOnInfo("Default", "",
DefaultCatalog::kDefaultCatalogAddOnPriority);
if (!defaultCatalogAddOnInfo)
return B_NO_MEMORY;
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
directory_which folders[] = {
B_USER_ADDONS_DIRECTORY,
B_COMMON_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
};
BPath addOnPath;
BDirectory addOnFolder;
char buf[4096];
status_t err;
for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) {
find_directory(folders[f], &addOnPath);
BString addOnFolderName(addOnPath.Path());
addOnFolderName << "/locale/catalogs";
system_info info;
if (get_system_info(&info) == B_OK
&& (info.abi & B_HAIKU_ABI_MAJOR)
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
case B_HAIKU_ABI_GCC_2:
addOnFolderName << "/gcc2";
break;
case B_HAIKU_ABI_GCC_4:
addOnFolderName << "/gcc4";
break;
}
}
err = addOnFolder.SetTo(addOnFolderName.String());
if (err != B_OK)
continue;
// scan through all the folder's entries for catalog add-ons:
int32 count;
int8 priority;
entry_ref eref;
BNode node;
BEntry entry;
dirent* dent;
while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) {
dent = (dirent*)buf;
while (count-- > 0) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
&& strcmp(dent->d_name, "gcc2")
&& strcmp(dent->d_name, "gcc4")) {
// we have found (what should be) a catalog-add-on:
eref.device = dent->d_pdev;
eref.directory = dent->d_pino;
eref.set_name(dent->d_name);
entry.SetTo(&eref, true);
// traverse through any links to get to the real thang!
node.SetTo(&entry);
priority = -1;
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8)) <= 0) {
// add-on has no priority-attribute yet, so we load it
// to fetch the priority from the corresponding
// symbol...
BString fullAddOnPath(addOnFolderName);
fullAddOnPath << "/" << dent->d_name;
image_id image = load_add_on(fullAddOnPath.String());
if (image >= B_OK) {
uint8* prioPtr;
if (get_image_symbol(image, "gCatalogAddOnPriority",
B_SYMBOL_TYPE_DATA,
(void**)&prioPtr) == B_OK) {
priority = *prioPtr;
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8));
}
unload_add_on(image);
}
}
if (priority >= 0) {
// add-ons with priority < 0 will be ignored
CatalogAddOnInfo* addOnInfo
= new(std::nothrow) CatalogAddOnInfo(dent->d_name,
addOnFolderName, priority);
if (addOnInfo)
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
}
}
// Bump the dirent-pointer by length of the dirent just handled:
dent = (dirent*)((char*)dent + dent->d_reclen);
}
}
}
fCatalogAddOnInfos.SortItems(CompareInfos);
return B_OK;
}
/*
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
*/
void
RosterData::_CleanupCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return;
int32 count = fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i<count; ++i) {
CatalogAddOnInfo* info
= static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
delete info;
}
fCatalogAddOnInfos.MakeEmpty();
}
status_t
RosterData::_LoadLocaleSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK) {
BFormattingConventions conventions(&settings);
fDefaultLocale.SetFormattingConventions(conventions);
_SetPreferredLanguages(&settings);
bool preferred;
if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK)
_SetFilesystemTranslationPreferred(preferred);
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
fPreferredLanguages.MakeEmpty();
fPreferredLanguages.AddString(kLanguageField, "en");
BLanguage defaultLanguage("en_US");
fDefaultLocale.SetLanguage(defaultLanguage);
BFormattingConventions conventions("en_US");
fDefaultLocale.SetFormattingConventions(conventions);
return status;
}
status_t
RosterData::_LoadTimeSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK) {
BString timeZoneID;
if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK)
_SetDefaultTimeZone(BTimeZone(timeZoneID.String()));
else
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
return status;
}
status_t
RosterData::_SaveLocaleSettings()
{
BMessage settings;
status_t status = _AddDefaultFormattingConventionsToMessage(&settings);
if (status == B_OK)
_AddPreferredLanguagesToMessage(&settings);
if (status == B_OK)
_AddFilesystemTranslationPreferenceToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
RosterData::_SaveTimeSettings()
{
BMessage settings;
status_t status = _AddDefaultTimeZoneToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
RosterData::_SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
fDefaultLocale.SetFormattingConventions(newFormattingConventions);
UErrorCode icuError = U_ZERO_ERROR;
Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID());
if (icuLocale.isBogus())
return B_ERROR;
Locale::setDefault(icuLocale, icuError);
if (!U_SUCCESS(icuError))
return B_ERROR;
return B_OK;
}
status_t
RosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
{
fDefaultTimeZone = newZone;
TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String());
if (timeZone == NULL)
return B_ERROR;
TimeZone::adoptDefault(timeZone);
return B_OK;
}
status_t
RosterData::_SetPreferredLanguages(const BMessage* languages)
{
BString langName;
if (languages != NULL
&& languages->FindString(kLanguageField, &langName) == B_OK) {
fDefaultLocale.SetCollator(BCollator(langName.String()));
fDefaultLocale.SetLanguage(BLanguage(langName.String()));
fPreferredLanguages.RemoveName(kLanguageField);
for (int i = 0; languages->FindString(kLanguageField, i, &langName)
== B_OK; i++) {
fPreferredLanguages.AddString(kLanguageField, langName);
}
} else {
fPreferredLanguages.MakeEmpty();
fPreferredLanguages.AddString(kLanguageField, "en");
fDefaultLocale.SetCollator(BCollator("en"));
}
return B_OK;
}
void
RosterData::_SetFilesystemTranslationPreferred(bool preferred)
{
fIsFilesystemTranslationPreferred = preferred;
}
status_t
RosterData::_AddDefaultFormattingConventionsToMessage(BMessage* message) const
{
BFormattingConventions conventions;
fDefaultLocale.GetFormattingConventions(&conventions);
return conventions.Archive(message);
}
status_t
RosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
{
return message->AddString(kTimezoneField, fDefaultTimeZone.ID());
}
status_t
RosterData::_AddPreferredLanguagesToMessage(BMessage* message) const
{
status_t status = B_OK;
BString langName;
for (int i = 0; fPreferredLanguages.FindString("language", i,
&langName) == B_OK; i++) {
status = message->AddString(kLanguageField, langName);
if (status != B_OK)
break;
}
return status;
}
status_t
RosterData::_AddFilesystemTranslationPreferenceToMessage(BMessage* message)
const
{
return message->AddBool(kTranslateFilesystemField,
fIsFilesystemTranslationPreferred);
}
// #pragma mark - MutableLocaleRoster
namespace {
static MutableLocaleRoster sLocaleRoster;
} // anonymous namespace
MutableLocaleRoster::MutableLocaleRoster()
{
}
@ -719,7 +58,10 @@ MutableLocaleRoster::~MutableLocaleRoster()
/*static*/ MutableLocaleRoster*
MutableLocaleRoster::Default()
{
return &sLocaleRoster;
if (sLocaleRoster == NULL)
pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster);
return sLocaleRoster;
}
@ -727,29 +69,28 @@ status_t
MutableLocaleRoster::SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
return RosterData::Default()->SetDefaultFormattingConventions(
newFormattingConventions);
return fData->SetDefaultFormattingConventions(newFormattingConventions);
}
status_t
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
{
return RosterData::Default()->SetDefaultTimeZone(newZone);
return fData->SetDefaultTimeZone(newZone);
}
status_t
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
{
return RosterData::Default()->SetPreferredLanguages(languages);
return fData->SetPreferredLanguages(languages);
}
status_t
MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred)
{
return RosterData::Default()->SetFilesystemTranslationPreferred(preferred);
return fData->SetFilesystemTranslationPreferred(preferred);
}
@ -800,14 +141,14 @@ MutableLocaleRoster::CreateCatalog(const char* type, const char* signature,
if (!type || !signature || !language)
return NULL;
BAutolock lock(RosterData::Default()->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return NULL;
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
fData->fCatalogAddOnInfos.ItemAt(i);
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|| !info->fCreateFunc)
continue;
@ -838,14 +179,14 @@ BCatalogData*
MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner,
const char* language, int32 fingerprint) const
{
BAutolock lock(RosterData::Default()->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return NULL;
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
fData->fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
continue;
@ -909,7 +250,7 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
if (!catalog)
return B_BAD_VALUE;
BAutolock lock(RosterData::Default()->fLock);
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
@ -918,10 +259,10 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
while (catalog != NULL) {
nextCatalog = catalog->Next();
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i));
fData->fCatalogAddOnInfos.ItemAt(i));
if (info->fLoadedCatalogs.HasItem(catalog)) {
info->fLoadedCatalogs.RemoveItem(catalog);
delete catalog;