xref: /haiku/src/kits/locale/DefaultCatalog.cpp (revision 41853a8bbf90c34c7a219e95c4e2d1ccd0c17baf)
1c3ac87e8SOliver Tappe /*
275f15221SOliver Tappe  * Copyright 2003-2009, Haiku.
3c3ac87e8SOliver Tappe  * Distributed under the terms of the MIT License.
475f15221SOliver Tappe  *
575f15221SOliver Tappe  * Authors:
675f15221SOliver Tappe  *		Oliver Tappe, zooey@hirschkaefer.de
775f15221SOliver Tappe  *		Adrien Destugues, pulkomandy@gmail.com
8c3ac87e8SOliver Tappe  */
9c3ac87e8SOliver Tappe 
10c3ac87e8SOliver Tappe 
1126b2733aSMurai Takashi #include <algorithm>
1275f15221SOliver Tappe #include <new>
13c3ac87e8SOliver Tappe 
1454fad654SAdrien Destugues #include <AppFileInfo.h>
15c3ac87e8SOliver Tappe #include <Application.h>
16c3ac87e8SOliver Tappe #include <DataIO.h>
17c3ac87e8SOliver Tappe #include <Directory.h>
18c3ac87e8SOliver Tappe #include <File.h>
19c3ac87e8SOliver Tappe #include <FindDirectory.h>
20c3ac87e8SOliver Tappe #include <fs_attr.h>
21c3ac87e8SOliver Tappe #include <Message.h>
22c3ac87e8SOliver Tappe #include <Mime.h>
23c3ac87e8SOliver Tappe #include <Path.h>
24c3ac87e8SOliver Tappe #include <Resources.h>
25c3ac87e8SOliver Tappe #include <Roster.h>
2626b2733aSMurai Takashi #include <StackOrHeapArray.h>
27c3ac87e8SOliver Tappe 
28c3ac87e8SOliver Tappe #include <DefaultCatalog.h>
2938ac8defSOliver Tappe #include <MutableLocaleRoster.h>
30c3ac87e8SOliver Tappe 
3126b2733aSMurai Takashi 
32c3ac87e8SOliver Tappe #include <cstdio>
33c3ac87e8SOliver Tappe 
346449afb1SOliver Tappe 
35a0352959SOliver Tappe using std::min;
36a0352959SOliver Tappe using std::max;
37a0352959SOliver Tappe using std::pair;
38a0352959SOliver Tappe 
39a0352959SOliver Tappe 
40f9a80fecSAxel Dörfler /*!	This file implements the default catalog-type for the opentracker locale
41f9a80fecSAxel Dörfler 	kit. Alternatively, this could be used as a full add-on, but currently this
42f9a80fecSAxel Dörfler 	is provided as part of liblocale.so.
43c3ac87e8SOliver Tappe */
44c3ac87e8SOliver Tappe 
45c3ac87e8SOliver Tappe 
46c3ac87e8SOliver Tappe static const char *kCatFolder = "catalogs";
47c3ac87e8SOliver Tappe static const char *kCatExtension = ".catalog";
48c3ac87e8SOliver Tappe 
495ac65b7fSOliver Tappe 
505ac65b7fSOliver Tappe namespace BPrivate {
515ac65b7fSOliver Tappe 
525ac65b7fSOliver Tappe 
53c3ac87e8SOliver Tappe const char *DefaultCatalog::kCatMimeType
54c3ac87e8SOliver Tappe 	= "locale/x-vnd.Be.locale-catalog.default";
55c3ac87e8SOliver Tappe 
56c3ac87e8SOliver Tappe static int16 kCatArchiveVersion = 1;
57c3ac87e8SOliver Tappe 	// version of the catalog archive structure, bump this if you change it!
58c3ac87e8SOliver Tappe 
59f9a80fecSAxel Dörfler const uint8 DefaultCatalog::kDefaultCatalogAddOnPriority = 1;
60f9a80fecSAxel Dörfler 	// give highest priority to our embedded catalog-add-on
61c3ac87e8SOliver Tappe 
62f9a80fecSAxel Dörfler 
63f9a80fecSAxel Dörfler /*!	Constructs a DefaultCatalog with given signature and language and reads
64f9a80fecSAxel Dörfler 	the catalog from disk.
65f9a80fecSAxel Dörfler 	InitCheck() will be B_OK if catalog could be loaded successfully, it will
66f9a80fecSAxel Dörfler 	give an appropriate error-code otherwise.
67c3ac87e8SOliver Tappe */
DefaultCatalog(const entry_ref & catalogOwner,const char * language,uint32 fingerprint)68*41853a8bSAdrien Destugues DefaultCatalog::DefaultCatalog(const entry_ref &catalogOwner,
69*41853a8bSAdrien Destugues 	const char *language, uint32 fingerprint)
70c3ac87e8SOliver Tappe 	:
715ac65b7fSOliver Tappe 	HashMapCatalog("", language, fingerprint)
72c3ac87e8SOliver Tappe {
7354fad654SAdrien Destugues 	// We created the catalog with an invalid signature, but we fix that now.
7454fad654SAdrien Destugues 	SetSignature(catalogOwner);
7592bae21aSAdrien Destugues 	status_t status;
7692bae21aSAdrien Destugues 
7792bae21aSAdrien Destugues 	// search for catalog living in sub-folder of app's folder:
78c3ac87e8SOliver Tappe 	node_ref nref;
791a5c1f9eSAdrien Destugues 	nref.device = catalogOwner.device;
801a5c1f9eSAdrien Destugues 	nref.node = catalogOwner.directory;
81c3ac87e8SOliver Tappe 	BDirectory appDir(&nref);
82c3ac87e8SOliver Tappe 	BString catalogName("locale/");
83c3ac87e8SOliver Tappe 	catalogName << kCatFolder
84c3ac87e8SOliver Tappe 		<< "/" << fSignature
85c3ac87e8SOliver Tappe 		<< "/" << fLanguageName
86c3ac87e8SOliver Tappe 		<< kCatExtension;
87c3ac87e8SOliver Tappe 	BPath catalogPath(&appDir, catalogName.String());
8892bae21aSAdrien Destugues 	status = ReadFromFile(catalogPath.Path());
89c3ac87e8SOliver Tappe 
90*41853a8bSAdrien Destugues 	// search for catalogs in the standard ../data/locale/ directories
91*41853a8bSAdrien Destugues 	// (packaged/non-packaged and system/home)
92*41853a8bSAdrien Destugues 	if (status != B_OK)
93*41853a8bSAdrien Destugues 		status = ReadFromStandardLocations();
94c3ac87e8SOliver Tappe 
951a5c1f9eSAdrien Destugues 	if (status != B_OK) {
961a5c1f9eSAdrien Destugues 		// give lowest priority to catalog embedded as resource in application
971a5c1f9eSAdrien Destugues 		// executable, so they can be overridden easily.
981a5c1f9eSAdrien Destugues 		status = ReadFromResource(catalogOwner);
991a5c1f9eSAdrien Destugues 	}
1001a5c1f9eSAdrien Destugues 
101c3ac87e8SOliver Tappe 	fInitCheck = status;
102c3ac87e8SOliver Tappe }
103c3ac87e8SOliver Tappe 
104c3ac87e8SOliver Tappe 
105f9a80fecSAxel Dörfler /*!	Constructs a DefaultCatalog and reads it from the resources of the
106f9a80fecSAxel Dörfler 	given entry-ref (which usually is an app- or add-on-file).
107f9a80fecSAxel Dörfler 	InitCheck() will be B_OK if catalog could be loaded successfully, it will
108f9a80fecSAxel Dörfler 	give an appropriate error-code otherwise.
109c3ac87e8SOliver Tappe */
DefaultCatalog(entry_ref * appOrAddOnRef)110c3ac87e8SOliver Tappe DefaultCatalog::DefaultCatalog(entry_ref *appOrAddOnRef)
111c3ac87e8SOliver Tappe 	:
1125ac65b7fSOliver Tappe 	HashMapCatalog("", "", 0)
113c3ac87e8SOliver Tappe {
1141a5c1f9eSAdrien Destugues 	fInitCheck = ReadFromResource(*appOrAddOnRef);
115c3ac87e8SOliver Tappe }
116c3ac87e8SOliver Tappe 
117c3ac87e8SOliver Tappe 
118f9a80fecSAxel Dörfler /*!	Constructs an empty DefaultCatalog with given sig and language.
119f9a80fecSAxel Dörfler 	This is used for editing/testing purposes.
120f9a80fecSAxel Dörfler 	InitCheck() will always be B_OK.
121c3ac87e8SOliver Tappe */
DefaultCatalog(const char * path,const char * signature,const char * language)122c3ac87e8SOliver Tappe DefaultCatalog::DefaultCatalog(const char *path, const char *signature,
123c3ac87e8SOliver Tappe 	const char *language)
124c3ac87e8SOliver Tappe 	:
1255ac65b7fSOliver Tappe 	HashMapCatalog(signature, language, 0),
126c3ac87e8SOliver Tappe 	fPath(path)
127c3ac87e8SOliver Tappe {
128c3ac87e8SOliver Tappe 	fInitCheck = B_OK;
129c3ac87e8SOliver Tappe }
130c3ac87e8SOliver Tappe 
131c3ac87e8SOliver Tappe 
~DefaultCatalog()132c3ac87e8SOliver Tappe DefaultCatalog::~DefaultCatalog()
133c3ac87e8SOliver Tappe {
134c3ac87e8SOliver Tappe }
135c3ac87e8SOliver Tappe 
136c3ac87e8SOliver Tappe 
137924ead9aSAdrien Destugues void
SetSignature(const entry_ref & catalogOwner)138924ead9aSAdrien Destugues DefaultCatalog::SetSignature(const entry_ref &catalogOwner)
139924ead9aSAdrien Destugues {
140924ead9aSAdrien Destugues 	// figure out mimetype from image
141924ead9aSAdrien Destugues 	BFile objectFile(&catalogOwner, B_READ_ONLY);
142924ead9aSAdrien Destugues 	BAppFileInfo objectInfo(&objectFile);
143924ead9aSAdrien Destugues 	char objectSignature[B_MIME_TYPE_LENGTH];
144924ead9aSAdrien Destugues 	if (objectInfo.GetSignature(objectSignature) != B_OK) {
145924ead9aSAdrien Destugues 		fSignature = "";
146924ead9aSAdrien Destugues 		return;
147924ead9aSAdrien Destugues 	}
148924ead9aSAdrien Destugues 
149924ead9aSAdrien Destugues 	// drop supertype from mimetype (should be "application/"):
150924ead9aSAdrien Destugues 	char* stripSignature = objectSignature;
151924ead9aSAdrien Destugues 	while (*stripSignature != '/' && *stripSignature != '\0')
152924ead9aSAdrien Destugues 		stripSignature ++;
153924ead9aSAdrien Destugues 
154924ead9aSAdrien Destugues 	if (*stripSignature == '\0')
155924ead9aSAdrien Destugues 		stripSignature = objectSignature;
156924ead9aSAdrien Destugues 	else
157924ead9aSAdrien Destugues 		stripSignature ++;
158924ead9aSAdrien Destugues 
159924ead9aSAdrien Destugues 	fSignature = stripSignature;
160924ead9aSAdrien Destugues }
161924ead9aSAdrien Destugues 
162924ead9aSAdrien Destugues 
163c3ac87e8SOliver Tappe status_t
SetRawString(const CatKey & key,const char * translated)1642a06b5bdSOliver Tappe DefaultCatalog::SetRawString(const CatKey& key, const char *translated)
1652a06b5bdSOliver Tappe {
1662a06b5bdSOliver Tappe 	return fCatMap.Put(key, translated);
1672a06b5bdSOliver Tappe }
1682a06b5bdSOliver Tappe 
1692a06b5bdSOliver Tappe 
1702a06b5bdSOliver Tappe status_t
ReadFromStandardLocations()171*41853a8bSAdrien Destugues DefaultCatalog::ReadFromStandardLocations()
172*41853a8bSAdrien Destugues {
173*41853a8bSAdrien Destugues 	// search in data folders
174*41853a8bSAdrien Destugues 
175*41853a8bSAdrien Destugues 	directory_which which[] = {
176*41853a8bSAdrien Destugues 		B_USER_NONPACKAGED_DATA_DIRECTORY,
177*41853a8bSAdrien Destugues 		B_USER_DATA_DIRECTORY,
178*41853a8bSAdrien Destugues 		B_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
179*41853a8bSAdrien Destugues 		B_SYSTEM_DATA_DIRECTORY
180*41853a8bSAdrien Destugues 	};
181*41853a8bSAdrien Destugues 
182*41853a8bSAdrien Destugues 	status_t status = B_ENTRY_NOT_FOUND;
183*41853a8bSAdrien Destugues 
184*41853a8bSAdrien Destugues 	for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
185*41853a8bSAdrien Destugues 		BPath path;
186*41853a8bSAdrien Destugues 		if (find_directory(which[i], &path) == B_OK) {
187*41853a8bSAdrien Destugues 			BString catalogName(path.Path());
188*41853a8bSAdrien Destugues 			catalogName << "/locale/" << kCatFolder
189*41853a8bSAdrien Destugues 				<< "/" << fSignature
190*41853a8bSAdrien Destugues 				<< "/" << fLanguageName
191*41853a8bSAdrien Destugues 				<< kCatExtension;
192*41853a8bSAdrien Destugues 			status = ReadFromFile(catalogName.String());
193*41853a8bSAdrien Destugues 			if (status == B_OK)
194*41853a8bSAdrien Destugues 				break;
195*41853a8bSAdrien Destugues 		}
196*41853a8bSAdrien Destugues 	}
197*41853a8bSAdrien Destugues 
198*41853a8bSAdrien Destugues 	return status;
199*41853a8bSAdrien Destugues }
200*41853a8bSAdrien Destugues 
201*41853a8bSAdrien Destugues 
202*41853a8bSAdrien Destugues status_t
ReadFromFile(const char * path)203c3ac87e8SOliver Tappe DefaultCatalog::ReadFromFile(const char *path)
204c3ac87e8SOliver Tappe {
205c3ac87e8SOliver Tappe 	if (!path)
206c3ac87e8SOliver Tappe 		path = fPath.String();
207c3ac87e8SOliver Tappe 
208c3ac87e8SOliver Tappe 	BFile catalogFile;
209c3ac87e8SOliver Tappe 	status_t res = catalogFile.SetTo(path, B_READ_ONLY);
21093b5e561SOliver Tappe 	if (res != B_OK)
211c3ac87e8SOliver Tappe 		return B_ENTRY_NOT_FOUND;
212c3ac87e8SOliver Tappe 
213c3ac87e8SOliver Tappe 	fPath = path;
214c3ac87e8SOliver Tappe 
215c3ac87e8SOliver Tappe 	off_t sz = 0;
216c3ac87e8SOliver Tappe 	res = catalogFile.GetSize(&sz);
217c3ac87e8SOliver Tappe 	if (res != B_OK) {
218c3ac87e8SOliver Tappe 		return res;
219c3ac87e8SOliver Tappe 	}
220c3ac87e8SOliver Tappe 
22126b2733aSMurai Takashi 	BStackOrHeapArray<char, 0> buf(sz);
22226b2733aSMurai Takashi 	if (!buf.IsValid())
22375f15221SOliver Tappe 		return B_NO_MEMORY;
22426b2733aSMurai Takashi 	res = catalogFile.Read(buf, sz);
22593b5e561SOliver Tappe 	if (res < B_OK)
226c3ac87e8SOliver Tappe 		return res;
22793b5e561SOliver Tappe 	if (res < sz)
228c3ac87e8SOliver Tappe 		return res;
22926b2733aSMurai Takashi 	BMemoryIO memIO(buf, sz);
230c3ac87e8SOliver Tappe 	res = Unflatten(&memIO);
231c3ac87e8SOliver Tappe 
232c3ac87e8SOliver Tappe 	if (res == B_OK) {
233c3ac87e8SOliver Tappe 		// some information living in member variables needs to be copied
234c3ac87e8SOliver Tappe 		// to attributes. Although these attributes should have been written
235c3ac87e8SOliver Tappe 		// when creating the catalog, we make sure that they exist there:
236c3ac87e8SOliver Tappe 		UpdateAttributes(catalogFile);
237c3ac87e8SOliver Tappe 	}
238c3ac87e8SOliver Tappe 
239c3ac87e8SOliver Tappe 	return res;
240c3ac87e8SOliver Tappe }
241c3ac87e8SOliver Tappe 
242c3ac87e8SOliver Tappe 
243c3ac87e8SOliver Tappe status_t
ReadFromResource(const entry_ref & appOrAddOnRef)2441a5c1f9eSAdrien Destugues DefaultCatalog::ReadFromResource(const entry_ref &appOrAddOnRef)
245c3ac87e8SOliver Tappe {
246c3ac87e8SOliver Tappe 	BFile file;
2471a5c1f9eSAdrien Destugues 	status_t res = file.SetTo(&appOrAddOnRef, B_READ_ONLY);
24893b5e561SOliver Tappe 	if (res != B_OK)
249c3ac87e8SOliver Tappe 		return B_ENTRY_NOT_FOUND;
250c3ac87e8SOliver Tappe 
251c3ac87e8SOliver Tappe 	BResources rsrc;
252c3ac87e8SOliver Tappe 	res = rsrc.SetTo(&file);
25393b5e561SOliver Tappe 	if (res != B_OK)
254c3ac87e8SOliver Tappe 		return res;
255c3ac87e8SOliver Tappe 
256c3ac87e8SOliver Tappe 	size_t sz;
257f139447dSAdrien Destugues - PulkoMandy 	const void *buf = rsrc.LoadResource('CADA', fLanguageName, &sz);
25893b5e561SOliver Tappe 	if (!buf)
259c3ac87e8SOliver Tappe 		return B_NAME_NOT_FOUND;
260c3ac87e8SOliver Tappe 
261c3ac87e8SOliver Tappe 	BMemoryIO memIO(buf, sz);
262c3ac87e8SOliver Tappe 	res = Unflatten(&memIO);
263c3ac87e8SOliver Tappe 
264c3ac87e8SOliver Tappe 	return res;
265c3ac87e8SOliver Tappe }
266c3ac87e8SOliver Tappe 
267c3ac87e8SOliver Tappe 
268c3ac87e8SOliver Tappe status_t
WriteToFile(const char * path)269c3ac87e8SOliver Tappe DefaultCatalog::WriteToFile(const char *path)
270c3ac87e8SOliver Tappe {
271c3ac87e8SOliver Tappe 	BFile catalogFile;
272c3ac87e8SOliver Tappe 	if (path)
273c3ac87e8SOliver Tappe 		fPath = path;
274c3ac87e8SOliver Tappe 	status_t res = catalogFile.SetTo(fPath.String(),
275c3ac87e8SOliver Tappe 		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
276c3ac87e8SOliver Tappe 	if (res != B_OK)
277c3ac87e8SOliver Tappe 		return res;
278c3ac87e8SOliver Tappe 
279c3ac87e8SOliver Tappe 	BMallocIO mallocIO;
2809be774b5SAlex Smith 	mallocIO.SetBlockSize(max(fCatMap.Size() * 20, (int32)256));
281c3ac87e8SOliver Tappe 		// set a largish block-size in order to avoid reallocs
282c3ac87e8SOliver Tappe 	res = Flatten(&mallocIO);
283c3ac87e8SOliver Tappe 	if (res == B_OK) {
284c3ac87e8SOliver Tappe 		ssize_t wsz;
285c3ac87e8SOliver Tappe 		wsz = catalogFile.Write(mallocIO.Buffer(), mallocIO.BufferLength());
286c3ac87e8SOliver Tappe 		if (wsz != (ssize_t)mallocIO.BufferLength())
287c3ac87e8SOliver Tappe 			return B_FILE_ERROR;
288c3ac87e8SOliver Tappe 
289c3ac87e8SOliver Tappe 		// set mimetype-, language- and signature-attributes:
290c3ac87e8SOliver Tappe 		UpdateAttributes(catalogFile);
291c3ac87e8SOliver Tappe 	}
292c3ac87e8SOliver Tappe 	if (res == B_OK)
293c3ac87e8SOliver Tappe 		UpdateAttributes(catalogFile);
294c3ac87e8SOliver Tappe 	return res;
295c3ac87e8SOliver Tappe }
296c3ac87e8SOliver Tappe 
297c3ac87e8SOliver Tappe 
298c3ac87e8SOliver Tappe status_t
WriteToResource(const entry_ref & appOrAddOnRef)2991a5c1f9eSAdrien Destugues DefaultCatalog::WriteToResource(const entry_ref &appOrAddOnRef)
300c3ac87e8SOliver Tappe {
301c3ac87e8SOliver Tappe 	BFile file;
3021a5c1f9eSAdrien Destugues 	status_t res = file.SetTo(&appOrAddOnRef, B_READ_WRITE);
303c3ac87e8SOliver Tappe 	if (res != B_OK)
304c3ac87e8SOliver Tappe 		return res;
305c3ac87e8SOliver Tappe 
306c3ac87e8SOliver Tappe 	BResources rsrc;
307c3ac87e8SOliver Tappe 	res = rsrc.SetTo(&file);
308c3ac87e8SOliver Tappe 	if (res != B_OK)
309c3ac87e8SOliver Tappe 		return res;
310c3ac87e8SOliver Tappe 
311c3ac87e8SOliver Tappe 	BMallocIO mallocIO;
3129be774b5SAlex Smith 	mallocIO.SetBlockSize(max(fCatMap.Size() * 20, (int32)256));
313c3ac87e8SOliver Tappe 		// set a largish block-size in order to avoid reallocs
314c3ac87e8SOliver Tappe 	res = Flatten(&mallocIO);
315c3ac87e8SOliver Tappe 
3161a5c1f9eSAdrien Destugues 	int mangledLanguage = CatKey::HashFun(fLanguageName.String(), 0);
3171a5c1f9eSAdrien Destugues 
31875f15221SOliver Tappe 	if (res == B_OK) {
3191a5c1f9eSAdrien Destugues 		res = rsrc.AddResource('CADA', mangledLanguage,
3201a5c1f9eSAdrien Destugues 			mallocIO.Buffer(), mallocIO.BufferLength(),
321f139447dSAdrien Destugues - PulkoMandy 			BString(fLanguageName));
32275f15221SOliver Tappe 	}
323c3ac87e8SOliver Tappe 
324c3ac87e8SOliver Tappe 	return res;
325c3ac87e8SOliver Tappe }
326c3ac87e8SOliver Tappe 
327c3ac87e8SOliver Tappe 
328f9a80fecSAxel Dörfler /*!	Writes mimetype, language-name and signature of catalog into the
329f9a80fecSAxel Dörfler 	catalog-file.
330c3ac87e8SOliver Tappe */
331c3ac87e8SOliver Tappe void
UpdateAttributes(BFile & catalogFile)332c3ac87e8SOliver Tappe DefaultCatalog::UpdateAttributes(BFile& catalogFile)
333c3ac87e8SOliver Tappe {
334c3ac87e8SOliver Tappe 	static const int bufSize = 256;
335c3ac87e8SOliver Tappe 	char buf[bufSize];
33675f15221SOliver Tappe 	uint32 temp;
33775f15221SOliver Tappe 	if (catalogFile.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, &buf,
33875f15221SOliver Tappe 			bufSize) <= 0
339c3ac87e8SOliver Tappe 		|| strcmp(kCatMimeType, buf) != 0) {
340c3ac87e8SOliver Tappe 		catalogFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0,
341c3ac87e8SOliver Tappe 			kCatMimeType, strlen(kCatMimeType)+1);
342c3ac87e8SOliver Tappe 	}
343c3ac87e8SOliver Tappe 	if (catalogFile.ReadAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0,
344c3ac87e8SOliver Tappe 			&buf, bufSize) <= 0
345c3ac87e8SOliver Tappe 		|| fLanguageName != buf) {
346c3ac87e8SOliver Tappe 		catalogFile.WriteAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0,
347c3ac87e8SOliver Tappe 			fLanguageName.String(), fLanguageName.Length()+1);
348c3ac87e8SOliver Tappe 	}
349c3ac87e8SOliver Tappe 	if (catalogFile.ReadAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0,
350c3ac87e8SOliver Tappe 			&buf, bufSize) <= 0
351c3ac87e8SOliver Tappe 		|| fSignature != buf) {
352c3ac87e8SOliver Tappe 		catalogFile.WriteAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0,
353c3ac87e8SOliver Tappe 			fSignature.String(), fSignature.Length()+1);
354c3ac87e8SOliver Tappe 	}
35575f15221SOliver Tappe 	if (catalogFile.ReadAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE,
35675f15221SOliver Tappe 		0, &temp, sizeof(uint32)) <= 0) {
35775f15221SOliver Tappe 		catalogFile.WriteAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE,
35875f15221SOliver Tappe 			0, &fFingerprint, sizeof(uint32));
35975f15221SOliver Tappe 	}
360c3ac87e8SOliver Tappe }
361c3ac87e8SOliver Tappe 
362c3ac87e8SOliver Tappe 
363c3ac87e8SOliver Tappe status_t
Flatten(BDataIO * dataIO)364c3ac87e8SOliver Tappe DefaultCatalog::Flatten(BDataIO *dataIO)
365c3ac87e8SOliver Tappe {
366c3ac87e8SOliver Tappe 	UpdateFingerprint();
367c3ac87e8SOliver Tappe 		// make sure we have the correct fingerprint before we flatten it
368c3ac87e8SOliver Tappe 
369c3ac87e8SOliver Tappe 	status_t res;
370c3ac87e8SOliver Tappe 	BMessage archive;
37175f15221SOliver Tappe 	int32 count = fCatMap.Size();
37275f15221SOliver Tappe 	res = archive.AddString("class", "DefaultCatalog");
37375f15221SOliver Tappe 	if (res == B_OK)
37475f15221SOliver Tappe 		res = archive.AddInt32("c:sz", count);
37575f15221SOliver Tappe 	if (res == B_OK)
37675f15221SOliver Tappe 		res = archive.AddInt16("c:ver", kCatArchiveVersion);
37775f15221SOliver Tappe 	if (res == B_OK)
37875f15221SOliver Tappe 		res = archive.AddString("c:lang", fLanguageName.String());
37975f15221SOliver Tappe 	if (res == B_OK)
38075f15221SOliver Tappe 		res = archive.AddString("c:sig", fSignature.String());
38175f15221SOliver Tappe 	if (res == B_OK)
38275f15221SOliver Tappe 		res = archive.AddInt32("c:fpr", fFingerprint);
383c3ac87e8SOliver Tappe 	if (res == B_OK)
384c3ac87e8SOliver Tappe 		res = archive.Flatten(dataIO);
385c3ac87e8SOliver Tappe 
38675f15221SOliver Tappe 	CatMap::Iterator iter = fCatMap.GetIterator();
38775f15221SOliver Tappe 	CatMap::Entry entry;
38875f15221SOliver Tappe 	while (res == B_OK && iter.HasNext()) {
38975f15221SOliver Tappe 		entry = iter.Next();
390c3ac87e8SOliver Tappe 		archive.MakeEmpty();
39175f15221SOliver Tappe 		res = archive.AddString("c:ostr", entry.key.fString.String());
39275f15221SOliver Tappe 		if (res == B_OK)
39375f15221SOliver Tappe 			res = archive.AddString("c:ctxt", entry.key.fContext.String());
39475f15221SOliver Tappe 		if (res == B_OK)
39575f15221SOliver Tappe 			res = archive.AddString("c:comt", entry.key.fComment.String());
39675f15221SOliver Tappe 		if (res == B_OK)
39775f15221SOliver Tappe 			res = archive.AddInt32("c:hash", entry.key.fHashVal);
39875f15221SOliver Tappe 		if (res == B_OK)
39975f15221SOliver Tappe 			res = archive.AddString("c:tstr", entry.value.String());
400c3ac87e8SOliver Tappe 		if (res == B_OK)
401c3ac87e8SOliver Tappe 			res = archive.Flatten(dataIO);
402c3ac87e8SOliver Tappe 	}
40375f15221SOliver Tappe 
404c3ac87e8SOliver Tappe 	return res;
405c3ac87e8SOliver Tappe }
406c3ac87e8SOliver Tappe 
407c3ac87e8SOliver Tappe 
408c3ac87e8SOliver Tappe status_t
Unflatten(BDataIO * dataIO)409c3ac87e8SOliver Tappe DefaultCatalog::Unflatten(BDataIO *dataIO)
410c3ac87e8SOliver Tappe {
41175f15221SOliver Tappe 	fCatMap.Clear();
412c3ac87e8SOliver Tappe 	int32 count = 0;
413c3ac87e8SOliver Tappe 	int16 version;
414c3ac87e8SOliver Tappe 	BMessage archiveMsg;
415c3ac87e8SOliver Tappe 	status_t res = archiveMsg.Unflatten(dataIO);
416c3ac87e8SOliver Tappe 
417c3ac87e8SOliver Tappe 	if (res == B_OK) {
418c3ac87e8SOliver Tappe 		res = archiveMsg.FindInt16("c:ver", &version)
419c3ac87e8SOliver Tappe 			|| archiveMsg.FindInt32("c:sz", &count);
420c3ac87e8SOliver Tappe 	}
421c3ac87e8SOliver Tappe 	if (res == B_OK) {
422c3ac87e8SOliver Tappe 		fLanguageName = archiveMsg.FindString("c:lang");
423c3ac87e8SOliver Tappe 		fSignature = archiveMsg.FindString("c:sig");
42475f15221SOliver Tappe 		uint32 foundFingerprint = archiveMsg.FindInt32("c:fpr");
425c3ac87e8SOliver Tappe 
42675f15221SOliver Tappe 		// if a specific fingerprint has been requested and the catalog does in
42775f15221SOliver Tappe 		// fact have a fingerprint, both are compared. If they mismatch, we do
42875f15221SOliver Tappe 		// not accept this catalog:
429c3ac87e8SOliver Tappe 		if (foundFingerprint != 0 && fFingerprint != 0
430c3ac87e8SOliver Tappe 			&& foundFingerprint != fFingerprint) {
431c3ac87e8SOliver Tappe 			res = B_MISMATCHED_VALUES;
432c3ac87e8SOliver Tappe 		} else
433c3ac87e8SOliver Tappe 			fFingerprint = foundFingerprint;
434c3ac87e8SOliver Tappe 	}
435c3ac87e8SOliver Tappe 
436c3ac87e8SOliver Tappe 	if (res == B_OK && count > 0) {
437c3ac87e8SOliver Tappe 		CatKey key;
438c3ac87e8SOliver Tappe 		const char *keyStr;
43975f15221SOliver Tappe 		const char *keyCtx;
44075f15221SOliver Tappe 		const char *keyCmt;
441c3ac87e8SOliver Tappe 		const char *translated;
44275f15221SOliver Tappe 
44375f15221SOliver Tappe 		// fCatMap.resize(count);
44475f15221SOliver Tappe 			// There is no resize method in Haiku's HashMap to preallocate
44575f15221SOliver Tappe 			// memory.
446c3ac87e8SOliver Tappe 		for (int i=0; res == B_OK && i < count; ++i) {
447c3ac87e8SOliver Tappe 			res = archiveMsg.Unflatten(dataIO);
44875f15221SOliver Tappe 			if (res == B_OK)
44975f15221SOliver Tappe 				res = archiveMsg.FindString("c:ostr", &keyStr);
45075f15221SOliver Tappe 			if (res == B_OK)
45175f15221SOliver Tappe 				res = archiveMsg.FindString("c:ctxt", &keyCtx);
45275f15221SOliver Tappe 			if (res == B_OK)
45375f15221SOliver Tappe 				res = archiveMsg.FindString("c:comt", &keyCmt);
45475f15221SOliver Tappe 			if (res == B_OK)
45575f15221SOliver Tappe 				res = archiveMsg.FindInt32("c:hash", (int32*)&key.fHashVal);
45675f15221SOliver Tappe 			if (res == B_OK)
45775f15221SOliver Tappe 				res = archiveMsg.FindString("c:tstr", &translated);
458c3ac87e8SOliver Tappe 			if (res == B_OK) {
45975f15221SOliver Tappe 				key.fString = keyStr;
46075f15221SOliver Tappe 				key.fContext = keyCtx;
46175f15221SOliver Tappe 				key.fComment = keyCmt;
46275f15221SOliver Tappe 				fCatMap.Put(key, translated);
463c3ac87e8SOliver Tappe 			}
464c3ac87e8SOliver Tappe 		}
46575f15221SOliver Tappe 		uint32 checkFP = ComputeFingerprint();
46693b5e561SOliver Tappe 		if (fFingerprint != checkFP)
467c3ac87e8SOliver Tappe 			return B_BAD_DATA;
468c3ac87e8SOliver Tappe 	}
469c3ac87e8SOliver Tappe 	return res;
470c3ac87e8SOliver Tappe }
471c3ac87e8SOliver Tappe 
472c3ac87e8SOliver Tappe 
473541ff51aSOliver Tappe BCatalogData *
Instantiate(const entry_ref & catalogOwner,const char * language,uint32 fingerprint)47454fad654SAdrien Destugues DefaultCatalog::Instantiate(const entry_ref &catalogOwner, const char *language,
47575f15221SOliver Tappe 	uint32 fingerprint)
476c3ac87e8SOliver Tappe {
47775f15221SOliver Tappe 	DefaultCatalog *catalog
47854fad654SAdrien Destugues 		= new(std::nothrow) DefaultCatalog(catalogOwner, language, fingerprint);
479c3ac87e8SOliver Tappe 	if (catalog && catalog->InitCheck() != B_OK) {
480c3ac87e8SOliver Tappe 		delete catalog;
481c3ac87e8SOliver Tappe 		return NULL;
482c3ac87e8SOliver Tappe 	}
483c3ac87e8SOliver Tappe 	return catalog;
484c3ac87e8SOliver Tappe }
485c3ac87e8SOliver Tappe 
486c3ac87e8SOliver Tappe 
487541ff51aSOliver Tappe BCatalogData *
Create(const char * signature,const char * language)488c3ac87e8SOliver Tappe DefaultCatalog::Create(const char *signature, const char *language)
489c3ac87e8SOliver Tappe {
49075f15221SOliver Tappe 	DefaultCatalog *catalog
49175f15221SOliver Tappe 		= new(std::nothrow) DefaultCatalog("", signature, language);
492c3ac87e8SOliver Tappe 	if (catalog && catalog->InitCheck() != B_OK) {
493c3ac87e8SOliver Tappe 		delete catalog;
494c3ac87e8SOliver Tappe 		return NULL;
495c3ac87e8SOliver Tappe 	}
496c3ac87e8SOliver Tappe 	return catalog;
497c3ac87e8SOliver Tappe }
49880254771SAdrien Destugues 
4995ac65b7fSOliver Tappe 
5005ac65b7fSOliver Tappe } // namespace BPrivate
5015ac65b7fSOliver Tappe 
5025ac65b7fSOliver Tappe 
50380254771SAdrien Destugues extern "C" status_t
default_catalog_get_available_languages(BMessage * availableLanguages,const char * sigPattern,const char * langPattern,int32 fingerprint)50480254771SAdrien Destugues default_catalog_get_available_languages(BMessage* availableLanguages,
5055ac65b7fSOliver Tappe 	const char* sigPattern, const char* langPattern, int32 fingerprint)
50680254771SAdrien Destugues {
50780254771SAdrien Destugues 	if (availableLanguages == NULL || sigPattern == NULL)
50880254771SAdrien Destugues 		return B_BAD_DATA;
50980254771SAdrien Destugues 
51080254771SAdrien Destugues 	app_info appInfo;
51180254771SAdrien Destugues 	be_app->GetAppInfo(&appInfo);
51280254771SAdrien Destugues 	node_ref nref;
51380254771SAdrien Destugues 	nref.device = appInfo.ref.device;
51480254771SAdrien Destugues 	nref.node = appInfo.ref.directory;
51580254771SAdrien Destugues 	BDirectory appDir(&nref);
51680254771SAdrien Destugues 	BString catalogName("locale/");
51780254771SAdrien Destugues 	catalogName << kCatFolder
51880254771SAdrien Destugues 		<< "/" << sigPattern ;
51980254771SAdrien Destugues 	BPath catalogPath(&appDir, catalogName.String());
52080254771SAdrien Destugues 	BEntry file(catalogPath.Path());
52180254771SAdrien Destugues 	BDirectory dir(&file);
52280254771SAdrien Destugues 
52380254771SAdrien Destugues 	char fileName[B_FILE_NAME_LENGTH];
52480254771SAdrien Destugues 	while(dir.GetNextEntry(&file) == B_OK) {
52580254771SAdrien Destugues 		file.GetName(fileName);
52680254771SAdrien Destugues 		BString langName(fileName);
52780254771SAdrien Destugues 		langName.Replace(kCatExtension, "", 1);
5286f43fabaSOliver Tappe 		availableLanguages->AddString("language", langName);
52980254771SAdrien Destugues 	}
53080254771SAdrien Destugues 
53180254771SAdrien Destugues 	// search in data folders
53280254771SAdrien Destugues 
53380254771SAdrien Destugues 	directory_which which[] = {
53438fa81bfSIngo Weinhold 		B_USER_NONPACKAGED_DATA_DIRECTORY,
53580254771SAdrien Destugues 		B_USER_DATA_DIRECTORY,
53638fa81bfSIngo Weinhold 		B_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
53780254771SAdrien Destugues 		B_SYSTEM_DATA_DIRECTORY
53880254771SAdrien Destugues 	};
53980254771SAdrien Destugues 
54080254771SAdrien Destugues 	for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
54180254771SAdrien Destugues 		BPath path;
54280254771SAdrien Destugues 		if (find_directory(which[i], &path) == B_OK) {
54380254771SAdrien Destugues 			catalogName = BString("locale/")
54480254771SAdrien Destugues 				<< kCatFolder
54580254771SAdrien Destugues 				<< "/" << sigPattern;
54680254771SAdrien Destugues 
54780254771SAdrien Destugues 			BPath catalogPath(path.Path(), catalogName.String());
54880254771SAdrien Destugues 			BEntry file(catalogPath.Path());
54980254771SAdrien Destugues 			BDirectory dir(&file);
55080254771SAdrien Destugues 
55180254771SAdrien Destugues 			char fileName[B_FILE_NAME_LENGTH];
55280254771SAdrien Destugues 			while(dir.GetNextEntry(&file) == B_OK) {
55380254771SAdrien Destugues 				file.GetName(fileName);
55480254771SAdrien Destugues 				BString langName(fileName);
55580254771SAdrien Destugues 				langName.Replace(kCatExtension, "", 1);
5566f43fabaSOliver Tappe 				availableLanguages->AddString("language", langName);
55780254771SAdrien Destugues 			}
55880254771SAdrien Destugues 		}
55980254771SAdrien Destugues 	}
56080254771SAdrien Destugues 
56180254771SAdrien Destugues 	return B_OK;
56280254771SAdrien Destugues }
563