HaikuDepot: notify work status from main window
[haiku.git] / src / tools / locale / DefaultCatalog.cpp
blob7c97d07918156299dae9b7cbf7ca8c23d6562dbd
1 /*
2 * Copyright 2003-2009, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Oliver Tappe, zooey@hirschkaefer.de
7 * Adrien Destugues, pulkomandy@gmail.com
8 */
11 #include <memory>
12 #include <new>
13 #include <syslog.h>
15 #include <AppFileInfo.h>
16 #include <Application.h>
17 #include <DataIO.h>
18 #include <Directory.h>
19 #include <File.h>
20 #include <FindDirectory.h>
21 #include <fs_attr.h>
22 #include <Message.h>
23 #include <Mime.h>
24 #include <Path.h>
25 #include <Resources.h>
26 #include <Roster.h>
28 #include <DefaultCatalog.h>
29 #include <LocaleRoster.h>
31 #include <cstdio>
34 using BPrivate::DefaultCatalog;
35 using std::auto_ptr;
38 /*! This file implements the default catalog-type for the opentracker locale
39 kit. Alternatively, this could be used as a full add-on, but currently this
40 is provided as part of liblocale.so.
44 namespace BPrivate {
47 // several attributes/resource-IDs used within the Locale Kit:
49 const char *kCatLangAttr = "BEOS:LOCALE_LANGUAGE";
50 // name of catalog language, lives in every catalog file
51 const char *kCatSigAttr = "BEOS:LOCALE_SIGNATURE";
52 // catalog signature, lives in every catalog file
53 const char *kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT";
54 // catalog fingerprint, may live in catalog file
56 const char *DefaultCatalog::kCatMimeType
57 = "locale/x-vnd.Be.locale-catalog.default";
59 static int16 kCatArchiveVersion = 1;
60 // version of the catalog archive structure, bump this if you change it!
63 /*! Constructs a DefaultCatalog with given signature and language and reads
64 the catalog from disk.
65 InitCheck() will be B_OK if catalog could be loaded successfully, it will
66 give an appropriate error-code otherwise.
68 DefaultCatalog::DefaultCatalog(const entry_ref &catalogOwner,
69 const char *language, uint32 fingerprint)
71 HashMapCatalog("", language, fingerprint)
73 fInitCheck = B_NOT_SUPPORTED;
74 fprintf(stderr,
75 "trying to load default-catalog(lang=%s) results in %s",
76 language, strerror(fInitCheck));
80 /*! Constructs a DefaultCatalog and reads it from the resources of the
81 given entry-ref (which usually is an app- or add-on-file).
82 InitCheck() will be B_OK if catalog could be loaded successfully, it will
83 give an appropriate error-code otherwise.
85 DefaultCatalog::DefaultCatalog(entry_ref *appOrAddOnRef)
87 HashMapCatalog("", "", 0)
89 fInitCheck = ReadFromResource(*appOrAddOnRef);
90 // fprintf(stderr,
91 // "trying to load embedded catalog from resources results in %s",
92 // strerror(fInitCheck));
96 /*! Constructs an empty DefaultCatalog with given sig and language.
97 This is used for editing/testing purposes.
98 InitCheck() will always be B_OK.
100 DefaultCatalog::DefaultCatalog(const char *path, const char *signature,
101 const char *language)
103 HashMapCatalog(signature, language, 0),
104 fPath(path)
106 fInitCheck = B_OK;
110 DefaultCatalog::~DefaultCatalog()
115 void
116 DefaultCatalog::SetSignature(const entry_ref &catalogOwner)
118 // Not allowed for the build-tool version.
119 return;
123 status_t
124 DefaultCatalog::SetRawString(const CatKey& key, const char *translated)
126 return fCatMap.Put(key, translated);
130 status_t
131 DefaultCatalog::ReadFromFile(const char *path)
133 if (!path)
134 path = fPath.String();
136 BFile catalogFile;
137 status_t res = catalogFile.SetTo(path, B_READ_ONLY);
138 if (res != B_OK) {
139 fprintf(stderr, "no catalog at %s\n", path);
140 return B_ENTRY_NOT_FOUND;
143 fPath = path;
144 fprintf(stderr, "found catalog at %s\n", path);
146 off_t sz = 0;
147 res = catalogFile.GetSize(&sz);
148 if (res != B_OK) {
149 fprintf(stderr, "couldn't get size for catalog-file %s\n", path);
150 return res;
153 auto_ptr<char> buf(new(std::nothrow) char [sz]);
154 if (buf.get() == NULL) {
155 fprintf(stderr, "couldn't allocate array of %Ld chars\n", sz);
156 return B_NO_MEMORY;
158 res = catalogFile.Read(buf.get(), sz);
159 if (res < B_OK) {
160 fprintf(stderr, "couldn't read from catalog-file %s\n", path);
161 return res;
163 if (res < sz) {
164 fprintf(stderr,
165 "only got %u instead of %Lu bytes from catalog-file %s\n", res, sz,
166 path);
167 return res;
169 BMemoryIO memIO(buf.get(), sz);
170 res = Unflatten(&memIO);
172 if (res == B_OK) {
173 // some information living in member variables needs to be copied
174 // to attributes. Although these attributes should have been written
175 // when creating the catalog, we make sure that they exist there:
176 UpdateAttributes(catalogFile);
179 return res;
183 /*! This method is not currently being used, but it may be useful in the
184 future...
186 status_t
187 DefaultCatalog::ReadFromAttribute(const entry_ref &appOrAddOnRef)
189 return B_NOT_SUPPORTED;
193 status_t
194 DefaultCatalog::ReadFromResource(const entry_ref &appOrAddOnRef)
196 return B_NOT_SUPPORTED;
200 status_t
201 DefaultCatalog::WriteToFile(const char *path)
203 BFile catalogFile;
204 if (path)
205 fPath = path;
206 status_t status = catalogFile.SetTo(fPath.String(),
207 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
208 if (status != B_OK)
209 return status;
211 BMallocIO mallocIO;
212 mallocIO.SetBlockSize(max_c(fCatMap.Size() * 20, 256));
213 // set a largish block-size in order to avoid reallocs
214 status = Flatten(&mallocIO);
215 if (status != B_OK)
216 return status;
218 ssize_t bytesWritten
219 = catalogFile.Write(mallocIO.Buffer(), mallocIO.BufferLength());
220 if (bytesWritten < 0)
221 return bytesWritten;
222 if (bytesWritten != (ssize_t)mallocIO.BufferLength())
223 return B_IO_ERROR;
225 // set mimetype-, language- and signature-attributes:
226 UpdateAttributes(catalogFile);
228 return B_OK;
232 /*! This method is not currently being used, but it may be useful in the
233 future...
235 status_t
236 DefaultCatalog::WriteToAttribute(const entry_ref &appOrAddOnRef)
238 return B_NOT_SUPPORTED;
242 status_t
243 DefaultCatalog::WriteToResource(const entry_ref &appOrAddOnRef)
245 return B_NOT_SUPPORTED;
249 /*! Writes mimetype, language-name and signature of catalog into the
250 catalog-file.
252 void
253 DefaultCatalog::UpdateAttributes(BFile& catalogFile)
255 static const int bufSize = 256;
256 char buf[bufSize];
257 uint32 temp;
258 if (catalogFile.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, &buf,
259 bufSize) <= 0
260 || strcmp(kCatMimeType, buf) != 0) {
261 catalogFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0,
262 kCatMimeType, strlen(kCatMimeType)+1);
264 if (catalogFile.ReadAttr(kCatLangAttr, B_STRING_TYPE, 0,
265 &buf, bufSize) <= 0
266 || fLanguageName != buf) {
267 catalogFile.WriteAttr(kCatLangAttr, B_STRING_TYPE, 0,
268 fLanguageName.String(), fLanguageName.Length()+1);
270 if (catalogFile.ReadAttr(kCatSigAttr, B_STRING_TYPE, 0,
271 &buf, bufSize) <= 0
272 || fSignature != buf) {
273 catalogFile.WriteAttr(kCatSigAttr, B_STRING_TYPE, 0,
274 fSignature.String(), fSignature.Length()+1);
276 if (catalogFile.ReadAttr(kCatFingerprintAttr, B_UINT32_TYPE,
277 0, &temp, sizeof(uint32)) <= 0) {
278 catalogFile.WriteAttr(kCatFingerprintAttr, B_UINT32_TYPE,
279 0, &fFingerprint, sizeof(uint32));
284 status_t
285 DefaultCatalog::Flatten(BDataIO *dataIO)
287 UpdateFingerprint();
288 // make sure we have the correct fingerprint before we flatten it
290 status_t res;
291 BMessage archive;
292 uint32 count = fCatMap.Size();
293 res = archive.AddString("class", "DefaultCatalog");
294 if (res == B_OK)
295 res = archive.AddInt32("c:sz", count);
296 if (res == B_OK)
297 res = archive.AddInt16("c:ver", kCatArchiveVersion);
298 if (res == B_OK)
299 res = archive.AddString("c:lang", fLanguageName.String());
300 if (res == B_OK)
301 res = archive.AddString("c:sig", fSignature.String());
302 if (res == B_OK)
303 res = archive.AddInt32("c:fpr", fFingerprint);
304 if (res == B_OK)
305 res = archive.Flatten(dataIO);
307 CatMap::Iterator iter = fCatMap.GetIterator();
308 CatMap::Entry entry;
309 while (res == B_OK && iter.HasNext()) {
310 entry = iter.Next();
311 archive.MakeEmpty();
312 res = archive.AddString("c:ostr", entry.key.fString.String());
313 if (res == B_OK)
314 res = archive.AddString("c:ctxt", entry.key.fContext.String());
315 if (res == B_OK)
316 res = archive.AddString("c:comt", entry.key.fComment.String());
317 if (res == B_OK)
318 res = archive.AddInt32("c:hash", entry.key.fHashVal);
319 if (res == B_OK)
320 res = archive.AddString("c:tstr", entry.value.String());
321 if (res == B_OK)
322 res = archive.Flatten(dataIO);
324 return res;
328 status_t
329 DefaultCatalog::Unflatten(BDataIO *dataIO)
331 fCatMap.Clear();
332 int32 count = 0;
333 int16 version;
334 BMessage archiveMsg;
335 status_t res = archiveMsg.Unflatten(dataIO);
337 if (res == B_OK) {
338 res = archiveMsg.FindInt16("c:ver", &version)
339 || archiveMsg.FindInt32("c:sz", &count);
341 if (res == B_OK) {
342 fLanguageName = archiveMsg.FindString("c:lang");
343 fSignature = archiveMsg.FindString("c:sig");
344 uint32 foundFingerprint = archiveMsg.FindInt32("c:fpr");
346 // if a specific fingerprint has been requested and the catalog does in
347 // fact have a fingerprint, both are compared. If they mismatch, we do
348 // not accept this catalog:
349 if (foundFingerprint != 0 && fFingerprint != 0
350 && foundFingerprint != fFingerprint) {
351 fprintf(stderr, "default-catalog(sig=%s, lang=%s) "
352 "has mismatching fingerprint (%d instead of the requested %d)"
353 ", so this catalog is skipped.\n",
354 fSignature.String(), fLanguageName.String(), foundFingerprint,
355 fFingerprint);
356 res = B_MISMATCHED_VALUES;
357 } else
358 fFingerprint = foundFingerprint;
361 if (res == B_OK && count > 0) {
362 CatKey key;
363 const char *keyStr;
364 const char *keyCtx;
365 const char *keyCmt;
366 const char *translated;
368 // fCatMap.resize(count);
369 // There is no resize method in Haiku Hash Map to prealloc space
370 for (int i=0; res == B_OK && i < count; ++i) {
371 res = archiveMsg.Unflatten(dataIO);
372 if (res == B_OK)
373 res = archiveMsg.FindString("c:ostr", &keyStr);
374 if (res == B_OK)
375 res = archiveMsg.FindString("c:ctxt", &keyCtx);
376 if (res == B_OK)
377 res = archiveMsg.FindString("c:comt", &keyCmt);
378 if (res == B_OK)
379 res = archiveMsg.FindInt32("c:hash", (int32*)&key.fHashVal);
380 if (res == B_OK)
381 res = archiveMsg.FindString("c:tstr", &translated);
382 if (res == B_OK) {
383 key.fString = keyStr;
384 key.fContext = keyCtx;
385 key.fComment = keyCmt;
386 fCatMap.Put(key, translated);
389 uint32 checkFP = ComputeFingerprint();
390 if (fFingerprint != checkFP) {
391 fprintf(stderr, "default-catalog(sig=%s, lang=%s) "
392 "has wrong fingerprint after load (%d instead of %d). "
393 "The catalog data may be corrupted, so this catalog is "
394 "skipped.\n",
395 fSignature.String(), fLanguageName.String(), checkFP,
396 fFingerprint);
397 return B_BAD_DATA;
400 return res;
404 BCatalogData *
405 DefaultCatalog::Instantiate(const entry_ref &catalogOwner, const char *language,
406 uint32 fingerprint)
408 DefaultCatalog *catalog
409 = new(std::nothrow) DefaultCatalog(catalogOwner, language, fingerprint);
410 if (catalog && catalog->InitCheck() != B_OK) {
411 delete catalog;
412 return NULL;
414 return catalog;
418 BCatalogData *
419 DefaultCatalog::Create(const char *signature, const char *language)
421 DefaultCatalog *catalog
422 = new(std::nothrow) DefaultCatalog("", signature, language);
423 if (catalog && catalog->InitCheck() != B_OK) {
424 delete catalog;
425 return NULL;
427 return catalog;
431 const uint8 DefaultCatalog::kDefaultCatalogAddOnPriority = 1;
432 // give highest priority to our embedded catalog-add-on
435 } // namespace BPrivate