* 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 <MutableLocaleRoster.h>
#include <pthread.h>
#include <Application.h>
#include <Autolock.h>
#include <Catalog.h>
#include <CatalogData.h>
#include <DefaultCatalog.h>
#include <Debug.h>
#include <Entry.h>
#include <FormattingConventions.h>
#include <Language.h>
#include <LocaleRosterData.h>
#include <String.h>
namespace BPrivate {
namespace {
static MutableLocaleRoster* sLocaleRoster;
static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT;
}
static void
InitializeLocaleRoster()
{
sLocaleRoster = new (std::nothrow) MutableLocaleRoster();
}
MutableLocaleRoster::MutableLocaleRoster()
{
}
MutableLocaleRoster::~MutableLocaleRoster()
{
}
MutableLocaleRoster*
MutableLocaleRoster::Default()
{
if (sLocaleRoster == NULL)
pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster);
return sLocaleRoster;
}
status_t
MutableLocaleRoster::SetDefaultFormattingConventions(
const BFormattingConventions& newFormattingConventions)
{
return fData->SetDefaultFormattingConventions(newFormattingConventions);
}
status_t
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
{
return fData->SetDefaultTimeZone(newZone);
}
status_t
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
{
return fData->SetPreferredLanguages(languages);
}
status_t
MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred)
{
return fData->SetFilesystemTranslationPreferred(preferred);
}
status_t
MutableLocaleRoster::LoadSystemCatalog(BCatalog* catalog) const
{
if (!catalog)
return B_BAD_VALUE;
image_info info;
int32 cookie = 0;
bool found = false;
while (get_next_image_info(0, &cookie, &info) == B_OK) {
if (info.data < (void*)&be_app
&& (char*)info.data + info.data_size > (void*)&be_app) {
found = true;
break;
}
}
if (!found)
return B_ERROR;
entry_ref ref;
status_t status = BEntry(info.name).GetRef(&ref);
if (status != B_OK)
return status;
return catalog->SetTo(ref);
}
* creates a new (empty) catalog of the given type (the request is dispatched
* to the appropriate add-on).
* If the add-on doesn't support catalog-creation or if the creation fails,
* NULL is returned, otherwise a pointer to the freshly created catalog.
* Any created catalog will be initialized with the given signature and
* language-name.
*/
BCatalogData*
MutableLocaleRoster::CreateCatalog(const char* type, const char* signature,
const char* language)
{
if (!type || !signature || !language)
return NULL;
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return NULL;
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
fData->fCatalogAddOnInfos.ItemAt(i);
if (info->fName.ICompare(type) != 0 || !info->fCreateFunc)
continue;
BCatalogData* catalog = info->fCreateFunc(signature, language);
if (catalog != NULL) {
info->fLoadedCatalogs.AddItem(catalog);
return catalog;
}
}
return NULL;
}
* Loads a catalog for the given signature, language and fingerprint.
* The request to load this catalog is dispatched to all add-ons in turn,
* until an add-on reports success.
* If a catalog depends on another language (as 'english-british' depends
* on 'english') the dependant catalogs are automatically loaded, too.
* So it is perfectly possible that this method returns a catalog-chain
* instead of a single catalog.
* NULL is returned if no matching catalog could be found.
*/
BCatalogData*
MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner,
const char* language, int32 fingerprint) const
{
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return NULL;
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
fData->fCatalogAddOnInfos.ItemAt(i);
if (!info->fInstantiateFunc)
continue;
BMessage languages;
if (language != NULL) {
languages.AddString("language", language);
} else {
GetPreferredLanguages(&languages);
}
BCatalogData* catalog = NULL;
const char* lang;
for (int32 l = 0; languages.FindString("language", l, &lang) == B_OK;
++l) {
catalog = info->fInstantiateFunc(catalogOwner, lang, fingerprint);
if (catalog != NULL)
info->fLoadedCatalogs.AddItem(catalog);
int32 pos;
BString langName(lang);
BCatalogData* currentCatalog = catalog;
BCatalogData* nextCatalog = NULL;
while ((pos = langName.FindLast('_')) >= 0) {
langName.Truncate(pos);
nextCatalog = info->fInstantiateFunc(catalogOwner,
langName.String(), fingerprint);
if (nextCatalog != NULL) {
info->fLoadedCatalogs.AddItem(nextCatalog);
if (currentCatalog != NULL)
currentCatalog->SetNext(nextCatalog);
else
catalog = nextCatalog;
currentCatalog = nextCatalog;
}
}
if (catalog != NULL)
return catalog;
}
}
return NULL;
}
* Loads a catalog for the given signature and language.
*
* Only the default catalog type is searched, and only the standard system
* directories.
*
* If a catalog depends on another language (as 'english-british' depends
* on 'english') the dependant catalogs are automatically loaded, too.
* So it is perfectly possible that this method returns a catalog-chain
* instead of a single catalog.
* NULL is returned if no matching catalog could be found.
*/
BCatalogData*
MutableLocaleRoster::LoadCatalog(const char* signature,
const char* language) const
{
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return NULL;
BMessage languages;
if (language != NULL) {
languages.AddString("language", language);
} else {
GetPreferredLanguages(&languages);
}
int32 count = fData->fCatalogAddOnInfos.CountItems();
CatalogAddOnInfo* defaultCatalogInfo = NULL;
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
fData->fCatalogAddOnInfos.ItemAt(i);
if (info->fInstantiateFunc
== BPrivate::DefaultCatalog::Instantiate) {
defaultCatalogInfo = info;
break;
}
}
if (defaultCatalogInfo == NULL)
return NULL;
BPrivate::DefaultCatalog* catalog = NULL;
const char* lang;
for (int32 l = 0; languages.FindString("language", l, &lang) == B_OK; ++l) {
catalog = new (std::nothrow) BPrivate::DefaultCatalog(NULL, signature,
lang);
if (catalog != NULL) {
if (catalog->InitCheck() != B_OK
|| catalog->ReadFromStandardLocations() != B_OK) {
delete catalog;
catalog = NULL;
} else {
defaultCatalogInfo->fLoadedCatalogs.AddItem(catalog);
}
}
int32 pos;
BString langName(lang);
BCatalogData* currentCatalog = catalog;
BPrivate::DefaultCatalog* nextCatalog = NULL;
while ((pos = langName.FindLast('_')) >= 0) {
langName.Truncate(pos);
nextCatalog = new (std::nothrow) BPrivate::DefaultCatalog(NULL,
signature, langName.String());
if (nextCatalog == NULL)
continue;
if (nextCatalog->InitCheck() != B_OK
|| nextCatalog->ReadFromStandardLocations() != B_OK) {
delete nextCatalog;
continue;
}
defaultCatalogInfo->fLoadedCatalogs.AddItem(nextCatalog);
if (currentCatalog != NULL)
currentCatalog->SetNext(nextCatalog);
else
catalog = nextCatalog;
currentCatalog = nextCatalog;
}
if (catalog != NULL)
return catalog;
}
return NULL;
}
* unloads the given catalog (or rather: catalog-chain).
* Every single catalog of the chain will be deleted automatically.
*/
status_t
MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
{
if (!catalog)
return B_BAD_VALUE;
BAutolock lock(fData->fLock);
if (!lock.IsLocked())
return B_ERROR;
status_t res = B_ERROR;
BCatalogData* nextCatalog;
while (catalog != NULL) {
nextCatalog = catalog->Next();
int32 count = fData->fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
fData->fCatalogAddOnInfos.ItemAt(i));
if (info->fLoadedCatalogs.HasItem(catalog)) {
info->fLoadedCatalogs.RemoveItem(catalog);
delete catalog;
res = B_OK;
break;
}
}
catalog = nextCatalog;
}
return res;
}
}