1 /* 2 * Copyright 2003-2010, 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 <LocaleRoster.h> 12 13 #include <set> 14 15 #include <assert.h> 16 #include <syslog.h> 17 18 #include <Autolock.h> 19 #include <AppFileInfo.h> 20 #include <Catalog.h> 21 #include <Collator.h> 22 #include <Country.h> 23 #include <DefaultCatalog.h> 24 #include <Directory.h> 25 #include <Entry.h> 26 #include <File.h> 27 #include <Language.h> 28 #include <Locale.h> 29 #include <MutableLocaleRoster.h> 30 #include <Node.h> 31 #include <Path.h> 32 #include <String.h> 33 #include <TimeZone.h> 34 35 #include <ICUWrapper.h> 36 37 // ICU includes 38 #include <unicode/locid.h> 39 #include <unicode/timezone.h> 40 41 42 using BPrivate::CatalogAddOnInfo; 43 44 45 /* 46 * several attributes/resource-IDs used within the Locale Kit: 47 */ 48 const char* BLocaleRoster::kCatLangAttr = "BEOS:LOCALE_LANGUAGE"; 49 // name of catalog language, lives in every catalog file 50 const char* BLocaleRoster::kCatSigAttr = "BEOS:LOCALE_SIGNATURE"; 51 // catalog signature, lives in every catalog file 52 const char* BLocaleRoster::kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT"; 53 // catalog fingerprint, may live in catalog file 54 55 const char* BLocaleRoster::kEmbeddedCatAttr = "BEOS:LOCALE_EMBEDDED_CATALOG"; 56 // attribute which contains flattened data of embedded catalog 57 // this may live in an app- or add-on-file 58 int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA; 59 // a unique value used to identify the resource (=> embedded CAtalog DAta) 60 // which contains flattened data of embedded catalog. 61 // this may live in an app- or add-on-file 62 63 64 BLocaleRoster::BLocaleRoster() 65 { 66 } 67 68 69 BLocaleRoster::~BLocaleRoster() 70 { 71 } 72 73 74 status_t 75 BLocaleRoster::Refresh() 76 { 77 return gRosterData.Refresh(); 78 } 79 80 81 status_t 82 BLocaleRoster::GetDefaultCollator(BCollator* collator) const 83 { 84 if (!collator) 85 return B_BAD_VALUE; 86 87 BAutolock lock(gRosterData.fLock); 88 if (!lock.IsLocked()) 89 return B_ERROR; 90 91 *collator = *gRosterData.fDefaultLocale.Collator(); 92 93 return B_OK; 94 } 95 96 97 status_t 98 BLocaleRoster::GetDefaultLanguage(BLanguage* language) const 99 { 100 if (!language) 101 return B_BAD_VALUE; 102 103 BAutolock lock(gRosterData.fLock); 104 if (!lock.IsLocked()) 105 return B_ERROR; 106 107 *language = gRosterData.fDefaultLanguage; 108 109 return B_OK; 110 } 111 112 113 status_t 114 BLocaleRoster::GetDefaultCountry(BCountry* country) const 115 { 116 if (!country) 117 return B_BAD_VALUE; 118 119 BAutolock lock(gRosterData.fLock); 120 if (!lock.IsLocked()) 121 return B_ERROR; 122 123 *country = *gRosterData.fDefaultLocale.Country(); 124 125 return B_OK; 126 } 127 128 129 status_t 130 BLocaleRoster::GetDefaultLocale(BLocale* locale) const 131 { 132 if (!locale) 133 return B_BAD_VALUE; 134 135 BAutolock lock(gRosterData.fLock); 136 if (!lock.IsLocked()) 137 return B_ERROR; 138 139 *locale = gRosterData.fDefaultLocale; 140 141 return B_OK; 142 } 143 144 145 status_t 146 BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const 147 { 148 if (!timezone) 149 return B_BAD_VALUE; 150 151 BAutolock lock(gRosterData.fLock); 152 if (!lock.IsLocked()) 153 return B_ERROR; 154 155 *timezone = gRosterData.fDefaultTimeZone; 156 157 return B_OK; 158 } 159 160 161 status_t 162 BLocaleRoster::GetLanguage(const char* languageCode, 163 BLanguage** _language) const 164 { 165 if (_language == NULL || languageCode == NULL || languageCode[0] == '\0') 166 return B_BAD_VALUE; 167 168 BLanguage* language = new(std::nothrow) BLanguage(languageCode); 169 if (language == NULL) 170 return B_NO_MEMORY; 171 172 *_language = language; 173 return B_OK; 174 } 175 176 177 status_t 178 BLocaleRoster::GetPreferredLanguages(BMessage* languages) const 179 { 180 if (!languages) 181 return B_BAD_VALUE; 182 183 BAutolock lock(gRosterData.fLock); 184 if (!lock.IsLocked()) 185 return B_ERROR; 186 187 *languages = gRosterData.fPreferredLanguages; 188 189 return B_OK; 190 } 191 192 193 status_t 194 BLocaleRoster::GetInstalledLanguages(BMessage* languages) const 195 { 196 if (!languages) 197 return B_BAD_VALUE; 198 199 int32 i; 200 UnicodeString icuLanguageName; 201 BString languageName; 202 203 int32_t localeCount; 204 const Locale* icuLocaleList 205 = Locale::getAvailableLocales(localeCount); 206 207 // TODO: Loop over the strings and add them to a std::set to remove 208 // duplicates? 209 for (i = 0; i < localeCount; i++) 210 languages->AddString("langs", icuLocaleList[i].getName()); 211 212 return B_OK; 213 } 214 215 216 status_t 217 BLocaleRoster::GetAvailableCountries(BMessage* countries) const 218 { 219 if (!countries) 220 return B_BAD_VALUE; 221 222 int32 i; 223 const char* const* countryList = uloc_getISOCountries(); 224 225 for (i = 0; countryList[i] != NULL; i++) 226 countries->AddString("countries", countryList[i]); 227 228 return B_OK; 229 } 230 231 232 status_t 233 BLocaleRoster::GetInstalledCatalogs(BMessage* languageList, 234 const char* sigPattern, const char* langPattern, int32 fingerprint) const 235 { 236 if (languageList == NULL) 237 return B_BAD_VALUE; 238 239 BAutolock lock(gRosterData.fLock); 240 if (!lock.IsLocked()) 241 return B_ERROR; 242 243 int32 count = gRosterData.fCatalogAddOnInfos.CountItems(); 244 for (int32 i = 0; i < count; ++i) { 245 CatalogAddOnInfo* info 246 = (CatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i); 247 248 if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc) 249 continue; 250 251 info->fLanguagesFunc(languageList, sigPattern, langPattern, 252 fingerprint); 253 } 254 255 return B_OK; 256 } 257 258 259 BCatalog* 260 BLocaleRoster::_GetCatalog(BCatalog* catalog, vint32* catalogInitStatus) 261 { 262 // This function is used in the translation macros, so it can't return a 263 // status_t. Maybe it could throw exceptions ? 264 265 if (*catalogInitStatus == true) { 266 // Catalog already loaded - nothing else to do 267 return catalog; 268 } 269 270 // figure out image (shared object) from catalog address 271 image_info info; 272 int32 cookie = 0; 273 bool found = false; 274 275 while (get_next_image_info(0, &cookie, &info) == B_OK) { 276 if ((char*)info.data < (char*)catalog && (char*)info.data 277 + info.data_size > (char*)catalog) { 278 found = true; 279 break; 280 } 281 } 282 283 if (!found) { 284 log_team(LOG_DEBUG, "Catalog %x doesn't belong to any image !", 285 catalog); 286 return catalog; 287 } 288 // figure out mimetype from image 289 BFile objectFile(info.name, B_READ_ONLY); 290 BAppFileInfo objectInfo(&objectFile); 291 char objectSignature[B_MIME_TYPE_LENGTH]; 292 if (objectInfo.GetSignature(objectSignature) != B_OK) { 293 log_team(LOG_ERR, "File %s has no mimesignature, so it can't use" 294 "localization.", info.name); 295 return catalog; 296 } 297 298 // drop supertype from mimetype (should be "application/"): 299 char* stripSignature = objectSignature; 300 while (*stripSignature != '/') 301 stripSignature ++; 302 stripSignature ++; 303 304 log_team(LOG_DEBUG, 305 "Image %s (address %x) requested catalog with mimetype %s", 306 info.name, catalog, stripSignature); 307 308 // load the catalog for this mimetype and return it to the app 309 catalog->SetCatalog(stripSignature, 0); 310 *catalogInitStatus = true; 311 312 return catalog; 313 } 314