xref: /haiku/src/kits/locale/LocaleRoster.cpp (revision e7d5c75dce28921de0dc981ed840205a67a0c0e5)
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