1 /* 2 * Copyright 2003-2012, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Oliver Tappe, zooey@hirschkaefer.de 8 */ 9 10 11 #include <MutableLocaleRoster.h> 12 13 #include <pthread.h> 14 15 #include <Application.h> 16 #include <Autolock.h> 17 #include <Catalog.h> 18 #include <CatalogData.h> 19 #include <Debug.h> 20 #include <Entry.h> 21 #include <FormattingConventions.h> 22 #include <Language.h> 23 #include <LocaleRosterData.h> 24 #include <String.h> 25 26 27 namespace BPrivate { 28 29 30 namespace { 31 32 33 static MutableLocaleRoster* sLocaleRoster; 34 35 static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT; 36 37 38 } // anonymous namespace 39 40 41 static void 42 InitializeLocaleRoster() 43 { 44 sLocaleRoster = new (std::nothrow) MutableLocaleRoster(); 45 } 46 47 48 MutableLocaleRoster::MutableLocaleRoster() 49 { 50 } 51 52 53 MutableLocaleRoster::~MutableLocaleRoster() 54 { 55 } 56 57 58 /*static*/ MutableLocaleRoster* 59 MutableLocaleRoster::Default() 60 { 61 if (sLocaleRoster == NULL) 62 pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster); 63 64 return sLocaleRoster; 65 } 66 67 68 status_t 69 MutableLocaleRoster::SetDefaultFormattingConventions( 70 const BFormattingConventions& newFormattingConventions) 71 { 72 return fData->SetDefaultFormattingConventions(newFormattingConventions); 73 } 74 75 76 status_t 77 MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone) 78 { 79 return fData->SetDefaultTimeZone(newZone); 80 } 81 82 83 status_t 84 MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages) 85 { 86 return fData->SetPreferredLanguages(languages); 87 } 88 89 90 status_t 91 MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred) 92 { 93 return fData->SetFilesystemTranslationPreferred(preferred); 94 } 95 96 97 status_t 98 MutableLocaleRoster::LoadSystemCatalog(BCatalog* catalog) const 99 { 100 if (!catalog) 101 return B_BAD_VALUE; 102 103 // figure out libbe-image (shared object) by name 104 image_info info; 105 int32 cookie = 0; 106 bool found = false; 107 108 while (get_next_image_info(0, &cookie, &info) == B_OK) { 109 if (info.data < (void*)&be_app 110 && (char*)info.data + info.data_size > (void*)&be_app) { 111 found = true; 112 break; 113 } 114 } 115 116 if (!found) 117 return B_ERROR; 118 119 // load the catalog for libbe into the given catalog 120 entry_ref ref; 121 status_t status = BEntry(info.name).GetRef(&ref); 122 if (status != B_OK) 123 return status; 124 125 return catalog->SetTo(ref); 126 } 127 128 129 /* 130 * creates a new (empty) catalog of the given type (the request is dispatched 131 * to the appropriate add-on). 132 * If the add-on doesn't support catalog-creation or if the creation fails, 133 * NULL is returned, otherwise a pointer to the freshly created catalog. 134 * Any created catalog will be initialized with the given signature and 135 * language-name. 136 */ 137 BCatalogData* 138 MutableLocaleRoster::CreateCatalog(const char* type, const char* signature, 139 const char* language) 140 { 141 if (!type || !signature || !language) 142 return NULL; 143 144 BAutolock lock(fData->fLock); 145 if (!lock.IsLocked()) 146 return NULL; 147 148 int32 count = fData->fCatalogAddOnInfos.CountItems(); 149 for (int32 i = 0; i < count; ++i) { 150 CatalogAddOnInfo* info = (CatalogAddOnInfo*) 151 fData->fCatalogAddOnInfos.ItemAt(i); 152 if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded() 153 || !info->fCreateFunc) 154 continue; 155 156 BCatalogData* catalog = info->fCreateFunc(signature, language); 157 if (catalog) { 158 info->fLoadedCatalogs.AddItem(catalog); 159 info->UnloadIfPossible(); 160 return catalog; 161 } 162 } 163 164 return NULL; 165 } 166 167 168 /* 169 * Loads a catalog for the given signature, language and fingerprint. 170 * The request to load this catalog is dispatched to all add-ons in turn, 171 * until an add-on reports success. 172 * If a catalog depends on another language (as 'english-british' depends 173 * on 'english') the dependant catalogs are automatically loaded, too. 174 * So it is perfectly possible that this method returns a catalog-chain 175 * instead of a single catalog. 176 * NULL is returned if no matching catalog could be found. 177 */ 178 BCatalogData* 179 MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner, 180 const char* language, int32 fingerprint) const 181 { 182 BAutolock lock(fData->fLock); 183 if (!lock.IsLocked()) 184 return NULL; 185 186 int32 count = fData->fCatalogAddOnInfos.CountItems(); 187 for (int32 i = 0; i < count; ++i) { 188 CatalogAddOnInfo* info = (CatalogAddOnInfo*) 189 fData->fCatalogAddOnInfos.ItemAt(i); 190 191 if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc) 192 continue; 193 BMessage languages; 194 if (language) 195 // try to load catalogs for the given language: 196 languages.AddString("language", language); 197 else 198 // try to load catalogs for one of the preferred languages: 199 GetPreferredLanguages(&languages); 200 201 BCatalogData* catalog = NULL; 202 const char* lang; 203 for (int32 l=0; languages.FindString("language", l, &lang)==B_OK; ++l) { 204 catalog = info->fInstantiateFunc(catalogOwner, lang, fingerprint); 205 if (catalog) 206 info->fLoadedCatalogs.AddItem(catalog); 207 // Chain-load catalogs for languages that depend on 208 // other languages. 209 // The current implementation uses the filename in order to 210 // detect dependencies (parenthood) between languages (it 211 // traverses from "english_british_oxford" to "english_british" 212 // to "english"): 213 int32 pos; 214 BString langName(lang); 215 BCatalogData* currCatalog = catalog; 216 BCatalogData* nextCatalog = NULL; 217 while ((pos = langName.FindLast('_')) >= 0) { 218 // language is based on parent, so we load that, too: 219 // (even if the parent catalog was not found) 220 langName.Truncate(pos); 221 nextCatalog = info->fInstantiateFunc(catalogOwner, 222 langName.String(), fingerprint); 223 if (nextCatalog) { 224 info->fLoadedCatalogs.AddItem(nextCatalog); 225 if(currCatalog) 226 currCatalog->SetNext(nextCatalog); 227 else 228 catalog = nextCatalog; 229 currCatalog = nextCatalog; 230 } 231 } 232 if (catalog != NULL) 233 return catalog; 234 } 235 info->UnloadIfPossible(); 236 } 237 238 return NULL; 239 } 240 241 242 /* 243 * unloads the given catalog (or rather: catalog-chain). 244 * Every single catalog of the chain will be deleted automatically. 245 * Add-ons that have no more current catalogs are unloaded, too. 246 */ 247 status_t 248 MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog) 249 { 250 if (!catalog) 251 return B_BAD_VALUE; 252 253 BAutolock lock(fData->fLock); 254 if (!lock.IsLocked()) 255 return B_ERROR; 256 257 status_t res = B_ERROR; 258 BCatalogData* nextCatalog; 259 260 while (catalog != NULL) { 261 nextCatalog = catalog->Next(); 262 int32 count = fData->fCatalogAddOnInfos.CountItems(); 263 for (int32 i = 0; i < count; ++i) { 264 CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>( 265 fData->fCatalogAddOnInfos.ItemAt(i)); 266 if (info->fLoadedCatalogs.HasItem(catalog)) { 267 info->fLoadedCatalogs.RemoveItem(catalog); 268 delete catalog; 269 info->UnloadIfPossible(); 270 res = B_OK; 271 break; 272 } 273 } 274 catalog = nextCatalog; 275 } 276 return res; 277 } 278 279 280 } // namespace BPrivate 281