xref: /haiku/src/kits/locale/Catalog.cpp (revision c0cd8cf1999b2266ed949f079916c1d35cd387fa)
1 /*
2  * Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de
3  * Copyright 2003-2004, Oliver Tappe, zooey@hirschkaefer.de
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include <Catalog.h>
8 
9 #include <syslog.h>
10 
11 #include <Application.h>
12 #include <Locale.h>
13 #include <LocaleRoster.h>
14 #include <Node.h>
15 #include <Roster.h>
16 
17 
18 BCatalog* be_catalog = NULL;
19 	// catalog used by translation macros
20 BCatalog* be_app_catalog = NULL;
21 	// app-catalog (useful for accessing app's catalog from inside an add-on,
22 	// since in an add-on, be_catalog will hold the add-on's catalog.
23 
24 
25 //#pragma mark - BCatalog
26 BCatalog::BCatalog()
27 	:
28 	fCatalog(NULL)
29 {
30 }
31 
32 
33 BCatalog::BCatalog(const char *signature, const char *language,
34 	uint32 fingerprint)
35 {
36 	fCatalog = be_locale_roster->LoadCatalog(signature, language, fingerprint);
37 }
38 
39 
40 BCatalog::~BCatalog()
41 {
42 	if (be_catalog == this)
43 		be_app_catalog = be_catalog = NULL;
44 	be_locale_roster->UnloadCatalog(fCatalog);
45 }
46 
47 
48 const char *
49 BCatalog::GetString(const char *string, const char *context,
50 	const char *comment)
51 {
52 	const char *translated;
53 	for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
54 		translated = cat->GetString(string, context, comment);
55 		if (translated)
56 			return translated;
57 	}
58 	return string;
59 }
60 
61 
62 const char *
63 BCatalog::GetString(uint32 id)
64 {
65 	const char *translated;
66 	for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
67 		translated = cat->GetString(id);
68 		if (translated)
69 			return translated;
70 	}
71 	return "";
72 }
73 
74 
75 status_t
76 BCatalog::GetData(const char *name, BMessage *msg)
77 {
78 	if (!fCatalog)
79 		return B_NO_INIT;
80 	status_t res;
81 	for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
82 		res = cat->GetData(name, msg);
83 		if (res != B_NAME_NOT_FOUND && res != EOPNOTSUPP)
84 			return res;	// return B_OK if found, or specific error-code
85 	}
86 	return B_NAME_NOT_FOUND;
87 }
88 
89 
90 status_t
91 BCatalog::GetData(uint32 id, BMessage *msg)
92 {
93 	if (!fCatalog)
94 		return B_NO_INIT;
95 	status_t res;
96 	for (BCatalogAddOn* cat = fCatalog; cat != NULL; cat = cat->fNext) {
97 		res = cat->GetData(id, msg);
98 		if (res != B_NAME_NOT_FOUND && res != EOPNOTSUPP)
99 			return res;	// return B_OK if found, or specific error-code
100 	}
101 	return B_NAME_NOT_FOUND;
102 }
103 
104 
105 status_t
106 BCatalog::GetAppCatalog(BCatalog* catalog)
107 {
108 	app_info appInfo;
109 	if (!be_app || be_app->GetAppInfo(&appInfo) != B_OK)
110 		return B_ENTRY_NOT_FOUND;
111 	BString sig(appInfo.signature);
112 
113 	// drop supertype from mimetype (should be "application/"):
114 	int32 pos = sig.FindFirst('/');
115 	if (pos >= 0)
116 		sig.Remove(0, pos+1);
117 
118 	// try to fetch fingerprint from app-file (attribute):
119 	uint32 fingerprint = 0;
120 	BNode appNode(&appInfo.ref);
121 	appNode.ReadAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE, 0,
122 		&fingerprint, sizeof(uint32));
123 	// try to load catalog (with given fingerprint):
124 	// TODO: Not so nice C++ design here, leading to such bugs: The previous
125 	// fCatalog is leaked here. (The whole chain, it looks like.) There should
126 	// be a SetCatalog() method (it can be private), and that should take care
127 	// that internal members are always properly maintained.
128 	catalog->fCatalog
129 		= be_locale_roster->LoadCatalog(sig.String(), NULL,	fingerprint);
130 
131 	// load native embedded id-based catalog. If such a catalog exists,
132 	// we can fall back to native strings for id-based access, too.
133 	BCatalogAddOn *embeddedCatalog
134 		= be_locale_roster->LoadEmbeddedCatalog(&appInfo.ref);
135 	if (embeddedCatalog) {
136 		if (!catalog->fCatalog)
137 			// embedded catalog is the only catalog that was found:
138 			catalog->fCatalog = embeddedCatalog;
139 		else {
140 			// append embedded catalog to list of loaded catalogs:
141 			BCatalogAddOn *currCat = catalog->fCatalog;
142 			while (currCat->fNext)
143 				currCat = currCat->fNext;
144 			currCat->fNext = embeddedCatalog;
145 		}
146 	}
147 
148 	// make app-catalog the current catalog for translation-macros:
149 	be_app_catalog = be_catalog = catalog;
150 
151 	return catalog->InitCheck();
152 }
153 
154 
155 //#pragma mark - BCatalogAddOn
156 BCatalogAddOn::BCatalogAddOn(const char *signature, const char *language,
157 	uint32 fingerprint)
158 	:
159 	fInitCheck(B_NO_INIT),
160 	fSignature(signature),
161 	fLanguageName(language),
162 	fFingerprint(fingerprint),
163 	fNext(NULL)
164 {
165 	fLanguageName.ToLower();
166 		// canonicalize language-name to lowercase
167 }
168 
169 
170 BCatalogAddOn::~BCatalogAddOn()
171 {
172 }
173 
174 
175 void
176 BCatalogAddOn::UpdateFingerprint()
177 {
178 	fFingerprint = 0;
179 		// base implementation always yields the same fingerprint,
180 		// which means that no version-mismatch detection is possible.
181 }
182 
183 
184 status_t
185 BCatalogAddOn::InitCheck() const
186 {
187 	return fInitCheck;
188 }
189 
190 
191 bool
192 BCatalogAddOn::CanHaveData() const
193 {
194 	return false;
195 }
196 
197 
198 status_t
199 BCatalogAddOn::GetData(const char *name, BMessage *msg)
200 {
201 	return EOPNOTSUPP;
202 }
203 
204 
205 status_t
206 BCatalogAddOn::GetData(uint32 id, BMessage *msg)
207 {
208 	return EOPNOTSUPP;
209 }
210 
211 
212 status_t
213 BCatalogAddOn::SetString(const char *string, const char *translated,
214 	const char *context, const char *comment)
215 {
216 	return EOPNOTSUPP;
217 }
218 
219 
220 status_t
221 BCatalogAddOn::SetString(int32 id, const char *translated)
222 {
223 	return EOPNOTSUPP;
224 }
225 
226 
227 bool
228 BCatalogAddOn::CanWriteData() const
229 {
230 	return false;
231 }
232 
233 
234 status_t
235 BCatalogAddOn::SetData(const char *name, BMessage *msg)
236 {
237 	return EOPNOTSUPP;
238 }
239 
240 
241 status_t
242 BCatalogAddOn::SetData(uint32 id, BMessage *msg)
243 {
244 	return EOPNOTSUPP;
245 }
246 
247 
248 status_t
249 BCatalogAddOn::ReadFromFile(const char *path)
250 {
251 	return EOPNOTSUPP;
252 }
253 
254 
255 status_t
256 BCatalogAddOn::ReadFromAttribute(entry_ref *appOrAddOnRef)
257 {
258 	return EOPNOTSUPP;
259 }
260 
261 
262 status_t
263 BCatalogAddOn::ReadFromResource(entry_ref *appOrAddOnRef)
264 {
265 	return EOPNOTSUPP;
266 }
267 
268 
269 status_t
270 BCatalogAddOn::WriteToFile(const char *path)
271 {
272 	return EOPNOTSUPP;
273 }
274 
275 
276 status_t
277 BCatalogAddOn::WriteToAttribute(entry_ref *appOrAddOnRef)
278 {
279 	return EOPNOTSUPP;
280 }
281 
282 
283 status_t
284 BCatalogAddOn::WriteToResource(entry_ref *appOrAddOnRef)
285 {
286 	return EOPNOTSUPP;
287 }
288 
289 
290 void BCatalogAddOn::MakeEmpty()
291 {
292 }
293 
294 
295 int32
296 BCatalogAddOn::CountItems() const
297 {
298 	return 0;
299 }
300 
301 
302 //#pragma mark - EditableCatalog
303 namespace BPrivate {
304 EditableCatalog::EditableCatalog(const char *type, const char *signature,
305 	const char *language)
306 {
307 	fCatalog = be_locale_roster->CreateCatalog(type, signature, language);
308 }
309 
310 
311 EditableCatalog::~EditableCatalog()
312 {
313 }
314 
315 
316 status_t
317 EditableCatalog::SetString(const char *string, const char *translated,
318 	const char *context, const char *comment)
319 {
320 	if (!fCatalog)
321 		return B_NO_INIT;
322 	return fCatalog->SetString(string, translated, context, comment);
323 }
324 
325 
326 status_t
327 EditableCatalog::SetString(int32 id, const char *translated)
328 {
329 	if (!fCatalog)
330 		return B_NO_INIT;
331 	return fCatalog->SetString(id, translated);
332 }
333 
334 
335 bool
336 EditableCatalog::CanWriteData() const
337 {
338 	if (!fCatalog)
339 		return false;
340 	return fCatalog->CanWriteData();
341 }
342 
343 
344 status_t
345 EditableCatalog::SetData(const char *name, BMessage *msg)
346 {
347 	if (!fCatalog)
348 		return B_NO_INIT;
349 	return fCatalog->SetData(name, msg);
350 }
351 
352 
353 status_t
354 EditableCatalog::SetData(uint32 id, BMessage *msg)
355 {
356 	if (!fCatalog)
357 		return B_NO_INIT;
358 	return fCatalog->SetData(id, msg);
359 }
360 
361 
362 status_t
363 EditableCatalog::ReadFromFile(const char *path)
364 {
365 	if (!fCatalog)
366 		return B_NO_INIT;
367 	return fCatalog->ReadFromFile(path);
368 }
369 
370 
371 status_t
372 EditableCatalog::ReadFromAttribute(entry_ref *appOrAddOnRef)
373 {
374 	if (!fCatalog)
375 		return B_NO_INIT;
376 	return fCatalog->ReadFromAttribute(appOrAddOnRef);
377 }
378 
379 
380 status_t
381 EditableCatalog::ReadFromResource(entry_ref *appOrAddOnRef)
382 {
383 	if (!fCatalog)
384 		return B_NO_INIT;
385 	return fCatalog->ReadFromResource(appOrAddOnRef);
386 }
387 
388 
389 status_t
390 EditableCatalog::WriteToFile(const char *path)
391 {
392 	if (!fCatalog)
393 		return B_NO_INIT;
394 	return fCatalog->WriteToFile(path);
395 }
396 
397 
398 status_t
399 EditableCatalog::WriteToAttribute(entry_ref *appOrAddOnRef)
400 {
401 	if (!fCatalog)
402 		return B_NO_INIT;
403 	return fCatalog->WriteToAttribute(appOrAddOnRef);
404 }
405 
406 
407 status_t
408 EditableCatalog::WriteToResource(entry_ref *appOrAddOnRef)
409 {
410 	if (!fCatalog)
411 		return B_NO_INIT;
412 	return fCatalog->WriteToResource(appOrAddOnRef);
413 }
414 
415 
416 void EditableCatalog::MakeEmpty()
417 {
418 	if (fCatalog)
419 		fCatalog->MakeEmpty();
420 }
421 
422 
423 } // namespace BPrivate
424