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