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 11c3ac87e8SOliver Tappe #include <memory> 1275f15221SOliver Tappe #include <new> 13c3ac87e8SOliver Tappe #include <syslog.h> 14c3ac87e8SOliver Tappe 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> 26c3ac87e8SOliver Tappe 27c3ac87e8SOliver Tappe #include <DefaultCatalog.h> 28c3ac87e8SOliver Tappe #include <LocaleRoster.h> 29c3ac87e8SOliver Tappe 30c3ac87e8SOliver Tappe #include <cstdio> 31c3ac87e8SOliver Tappe 326449afb1SOliver Tappe 33a0352959SOliver Tappe using std::auto_ptr; 34a0352959SOliver Tappe using std::min; 35a0352959SOliver Tappe using std::max; 36a0352959SOliver Tappe using std::pair; 37a0352959SOliver Tappe 38a0352959SOliver Tappe 39f9a80fecSAxel Dörfler /*! This file implements the default catalog-type for the opentracker locale 40f9a80fecSAxel Dörfler kit. Alternatively, this could be used as a full add-on, but currently this 41f9a80fecSAxel Dörfler is provided as part of liblocale.so. 42c3ac87e8SOliver Tappe */ 43c3ac87e8SOliver Tappe 44c3ac87e8SOliver Tappe 45c3ac87e8SOliver Tappe static const char *kCatFolder = "catalogs"; 46c3ac87e8SOliver Tappe static const char *kCatExtension = ".catalog"; 47c3ac87e8SOliver Tappe 48c3ac87e8SOliver Tappe const char *DefaultCatalog::kCatMimeType 49c3ac87e8SOliver Tappe = "locale/x-vnd.Be.locale-catalog.default"; 50c3ac87e8SOliver Tappe 51c3ac87e8SOliver Tappe static int16 kCatArchiveVersion = 1; 52c3ac87e8SOliver Tappe // version of the catalog archive structure, bump this if you change it! 53c3ac87e8SOliver Tappe 54f9a80fecSAxel Dörfler const uint8 DefaultCatalog::kDefaultCatalogAddOnPriority = 1; 55f9a80fecSAxel Dörfler // give highest priority to our embedded catalog-add-on 56c3ac87e8SOliver Tappe 57f9a80fecSAxel Dörfler 58f9a80fecSAxel Dörfler /*! Constructs a DefaultCatalog with given signature and language and reads 59f9a80fecSAxel Dörfler the catalog from disk. 60f9a80fecSAxel Dörfler InitCheck() will be B_OK if catalog could be loaded successfully, it will 61f9a80fecSAxel Dörfler give an appropriate error-code otherwise. 62c3ac87e8SOliver Tappe */ 63c3ac87e8SOliver Tappe DefaultCatalog::DefaultCatalog(const char *signature, const char *language, 6475f15221SOliver Tappe uint32 fingerprint) 65c3ac87e8SOliver Tappe : 6675f15221SOliver Tappe BHashMapCatalog(signature, language, fingerprint) 67c3ac87e8SOliver Tappe { 68c3ac87e8SOliver Tappe // give highest priority to catalog living in sub-folder of app's folder: 69c3ac87e8SOliver Tappe app_info appInfo; 70c3ac87e8SOliver Tappe be_app->GetAppInfo(&appInfo); 71c3ac87e8SOliver Tappe node_ref nref; 72c3ac87e8SOliver Tappe nref.device = appInfo.ref.device; 73c3ac87e8SOliver Tappe nref.node = appInfo.ref.directory; 74c3ac87e8SOliver Tappe BDirectory appDir(&nref); 75c3ac87e8SOliver Tappe BString catalogName("locale/"); 76c3ac87e8SOliver Tappe catalogName << kCatFolder 77c3ac87e8SOliver Tappe << "/" << fSignature 78c3ac87e8SOliver Tappe << "/" << fLanguageName 79c3ac87e8SOliver Tappe << kCatExtension; 80c3ac87e8SOliver Tappe BPath catalogPath(&appDir, catalogName.String()); 81c3ac87e8SOliver Tappe status_t status = ReadFromFile(catalogPath.Path()); 82c3ac87e8SOliver Tappe 83c3ac87e8SOliver Tappe if (status != B_OK) { 84f9a80fecSAxel Dörfler // search in data folders 85c3ac87e8SOliver Tappe 86f9a80fecSAxel Dörfler directory_which which[] = { 87f9a80fecSAxel Dörfler B_USER_DATA_DIRECTORY, 88f9a80fecSAxel Dörfler B_COMMON_DATA_DIRECTORY, 89f9a80fecSAxel Dörfler B_SYSTEM_DATA_DIRECTORY 90f9a80fecSAxel Dörfler }; 91f9a80fecSAxel Dörfler 92f9a80fecSAxel Dörfler for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) { 93f9a80fecSAxel Dörfler BPath path; 94f9a80fecSAxel Dörfler if (find_directory(which[i], &path) == B_OK) { 95f9a80fecSAxel Dörfler catalogName = BString(path.Path()) 96c3ac87e8SOliver Tappe << "/locale/" << kCatFolder 97c3ac87e8SOliver Tappe << "/" << fSignature 98c3ac87e8SOliver Tappe << "/" << fLanguageName 99c3ac87e8SOliver Tappe << kCatExtension; 100c3ac87e8SOliver Tappe status = ReadFromFile(catalogName.String()); 101f9a80fecSAxel Dörfler if (status == B_OK) 102f9a80fecSAxel Dörfler break; 103f9a80fecSAxel Dörfler } 104c3ac87e8SOliver Tappe } 105c3ac87e8SOliver Tappe } 106c3ac87e8SOliver Tappe 107c3ac87e8SOliver Tappe fInitCheck = status; 108c3ac87e8SOliver Tappe log_team(LOG_DEBUG, 109c3ac87e8SOliver Tappe "trying to load default-catalog(sig=%s, lang=%s) results in %s", 110c3ac87e8SOliver Tappe signature, language, strerror(fInitCheck)); 111c3ac87e8SOliver Tappe } 112c3ac87e8SOliver Tappe 113c3ac87e8SOliver Tappe 114f9a80fecSAxel Dörfler /*! Constructs a DefaultCatalog and reads it from the resources of the 115f9a80fecSAxel Dörfler given entry-ref (which usually is an app- or add-on-file). 116f9a80fecSAxel Dörfler InitCheck() will be B_OK if catalog could be loaded successfully, it will 117f9a80fecSAxel Dörfler give an appropriate error-code otherwise. 118c3ac87e8SOliver Tappe */ 119c3ac87e8SOliver Tappe DefaultCatalog::DefaultCatalog(entry_ref *appOrAddOnRef) 120c3ac87e8SOliver Tappe : 12175f15221SOliver Tappe BHashMapCatalog("", "", 0) 122c3ac87e8SOliver Tappe { 123c3ac87e8SOliver Tappe fInitCheck = ReadFromResource(appOrAddOnRef); 124c3ac87e8SOliver Tappe log_team(LOG_DEBUG, 125c3ac87e8SOliver Tappe "trying to load embedded catalog from resources results in %s", 126c3ac87e8SOliver Tappe strerror(fInitCheck)); 127c3ac87e8SOliver Tappe } 128c3ac87e8SOliver Tappe 129c3ac87e8SOliver Tappe 130f9a80fecSAxel Dörfler /*! Constructs an empty DefaultCatalog with given sig and language. 131f9a80fecSAxel Dörfler This is used for editing/testing purposes. 132f9a80fecSAxel Dörfler InitCheck() will always be B_OK. 133c3ac87e8SOliver Tappe */ 134c3ac87e8SOliver Tappe DefaultCatalog::DefaultCatalog(const char *path, const char *signature, 135c3ac87e8SOliver Tappe const char *language) 136c3ac87e8SOliver Tappe : 13775f15221SOliver Tappe BHashMapCatalog(signature, language, 0), 138c3ac87e8SOliver Tappe fPath(path) 139c3ac87e8SOliver Tappe { 140c3ac87e8SOliver Tappe fInitCheck = B_OK; 141c3ac87e8SOliver Tappe } 142c3ac87e8SOliver Tappe 143c3ac87e8SOliver Tappe 144c3ac87e8SOliver Tappe DefaultCatalog::~DefaultCatalog() 145c3ac87e8SOliver Tappe { 146c3ac87e8SOliver Tappe } 147c3ac87e8SOliver Tappe 148c3ac87e8SOliver Tappe 149c3ac87e8SOliver Tappe status_t 150c3ac87e8SOliver Tappe DefaultCatalog::ReadFromFile(const char *path) 151c3ac87e8SOliver Tappe { 152c3ac87e8SOliver Tappe if (!path) 153c3ac87e8SOliver Tappe path = fPath.String(); 154c3ac87e8SOliver Tappe 155c3ac87e8SOliver Tappe BFile catalogFile; 156c3ac87e8SOliver Tappe status_t res = catalogFile.SetTo(path, B_READ_ONLY); 157c3ac87e8SOliver Tappe if (res != B_OK) { 1580a255c0cSAdrien Destugues log_team(LOG_DEBUG, "LocaleKit DefaultCatalog: no catalog at %s", path); 159c3ac87e8SOliver Tappe return B_ENTRY_NOT_FOUND; 160c3ac87e8SOliver Tappe } 161c3ac87e8SOliver Tappe 162c3ac87e8SOliver Tappe fPath = path; 1630a255c0cSAdrien Destugues log_team(LOG_DEBUG, "LocaleKit DefaultCatalog: found catalog at %s", path); 164c3ac87e8SOliver Tappe 165c3ac87e8SOliver Tappe off_t sz = 0; 166c3ac87e8SOliver Tappe res = catalogFile.GetSize(&sz); 167c3ac87e8SOliver Tappe if (res != B_OK) { 1680a255c0cSAdrien Destugues log_team(LOG_ERR, "LocaleKit DefaultCatalog: couldn't get size for " 1690a255c0cSAdrien Destugues "catalog-file %s", path); 170c3ac87e8SOliver Tappe return res; 171c3ac87e8SOliver Tappe } 172c3ac87e8SOliver Tappe 17375f15221SOliver Tappe auto_ptr<char> buf(new(std::nothrow) char [sz]); 17475f15221SOliver Tappe if (buf.get() == NULL) { 1750a255c0cSAdrien Destugues log_team(LOG_ERR, "LocaleKit DefaultCatalog: couldn't allocate array " 1760a255c0cSAdrien Destugues "of %d chars", sz); 17775f15221SOliver Tappe return B_NO_MEMORY; 17875f15221SOliver Tappe } 179c3ac87e8SOliver Tappe res = catalogFile.Read(buf.get(), sz); 180c3ac87e8SOliver Tappe if (res < B_OK) { 1810a255c0cSAdrien Destugues log_team(LOG_ERR, "LocaleKit DefaultCatalog: couldn't read from " 1820a255c0cSAdrien Destugues "catalog-file %s", path); 183c3ac87e8SOliver Tappe return res; 184c3ac87e8SOliver Tappe } 185c3ac87e8SOliver Tappe if (res < sz) { 18675f15221SOliver Tappe log_team(LOG_ERR, 1870a255c0cSAdrien Destugues "LocaleKit DefaultCatalog: only got %lu instead of %Lu bytes from " 1880a255c0cSAdrien Destugues "catalog-file %s", res, sz, path); 189c3ac87e8SOliver Tappe return res; 190c3ac87e8SOliver Tappe } 191c3ac87e8SOliver Tappe BMemoryIO memIO(buf.get(), sz); 192c3ac87e8SOliver Tappe res = Unflatten(&memIO); 193c3ac87e8SOliver Tappe 194c3ac87e8SOliver Tappe if (res == B_OK) { 195c3ac87e8SOliver Tappe // some information living in member variables needs to be copied 196c3ac87e8SOliver Tappe // to attributes. Although these attributes should have been written 197c3ac87e8SOliver Tappe // when creating the catalog, we make sure that they exist there: 198c3ac87e8SOliver Tappe UpdateAttributes(catalogFile); 199c3ac87e8SOliver Tappe } 200c3ac87e8SOliver Tappe 201c3ac87e8SOliver Tappe return res; 202c3ac87e8SOliver Tappe } 203c3ac87e8SOliver Tappe 204c3ac87e8SOliver Tappe 205c3ac87e8SOliver Tappe /* 206c3ac87e8SOliver Tappe * this method is not currently being used, but it may be useful in the future... 207c3ac87e8SOliver Tappe */ 208c3ac87e8SOliver Tappe status_t 209c3ac87e8SOliver Tappe DefaultCatalog::ReadFromAttribute(entry_ref *appOrAddOnRef) 210c3ac87e8SOliver Tappe { 211c3ac87e8SOliver Tappe BNode node; 212c3ac87e8SOliver Tappe status_t res = node.SetTo(appOrAddOnRef); 213c3ac87e8SOliver Tappe if (res != B_OK) { 21475f15221SOliver Tappe log_team(LOG_ERR, 21575f15221SOliver Tappe "couldn't find app or add-on (dev=%lu, dir=%Lu, name=%s)", 216c3ac87e8SOliver Tappe appOrAddOnRef->device, appOrAddOnRef->directory, 217c3ac87e8SOliver Tappe appOrAddOnRef->name); 218c3ac87e8SOliver Tappe return B_ENTRY_NOT_FOUND; 219c3ac87e8SOliver Tappe } 220c3ac87e8SOliver Tappe 221c3ac87e8SOliver Tappe log_team(LOG_DEBUG, 222c3ac87e8SOliver Tappe "looking for embedded catalog-attribute in app/add-on" 223c3ac87e8SOliver Tappe "(dev=%lu, dir=%Lu, name=%s)", appOrAddOnRef->device, 224c3ac87e8SOliver Tappe appOrAddOnRef->directory, appOrAddOnRef->name); 225c3ac87e8SOliver Tappe 226c3ac87e8SOliver Tappe attr_info attrInfo; 227c3ac87e8SOliver Tappe res = node.GetAttrInfo(BLocaleRoster::kEmbeddedCatAttr, &attrInfo); 228c3ac87e8SOliver Tappe if (res != B_OK) { 229c3ac87e8SOliver Tappe log_team(LOG_DEBUG, "no embedded catalog found"); 230c3ac87e8SOliver Tappe return B_NAME_NOT_FOUND; 231c3ac87e8SOliver Tappe } 232c3ac87e8SOliver Tappe if (attrInfo.type != B_MESSAGE_TYPE) { 233c3ac87e8SOliver Tappe log_team(LOG_ERR, "attribute %s has incorrect type and is ignored!", 234c3ac87e8SOliver Tappe BLocaleRoster::kEmbeddedCatAttr); 235c3ac87e8SOliver Tappe return B_BAD_TYPE; 236c3ac87e8SOliver Tappe } 237c3ac87e8SOliver Tappe 238c3ac87e8SOliver Tappe size_t size = attrInfo.size; 23975f15221SOliver Tappe auto_ptr<char> buf(new(std::nothrow) char [size]); 24075f15221SOliver Tappe if (buf.get() == NULL) { 24175f15221SOliver Tappe log_team(LOG_ERR, "couldn't allocate array of %d chars", size); 24275f15221SOliver Tappe return B_NO_MEMORY; 24375f15221SOliver Tappe } 244c3ac87e8SOliver Tappe res = node.ReadAttr(BLocaleRoster::kEmbeddedCatAttr, B_MESSAGE_TYPE, 0, 245c3ac87e8SOliver Tappe buf.get(), size); 246c3ac87e8SOliver Tappe if (res < (ssize_t)size) { 247c3ac87e8SOliver Tappe log_team(LOG_ERR, "unable to read embedded catalog from attribute"); 248c3ac87e8SOliver Tappe return res < B_OK ? res : B_BAD_DATA; 249c3ac87e8SOliver Tappe } 250c3ac87e8SOliver Tappe 251c3ac87e8SOliver Tappe BMemoryIO memIO(buf.get(), size); 252c3ac87e8SOliver Tappe res = Unflatten(&memIO); 253c3ac87e8SOliver Tappe 254c3ac87e8SOliver Tappe return res; 255c3ac87e8SOliver Tappe } 256c3ac87e8SOliver Tappe 257c3ac87e8SOliver Tappe 258c3ac87e8SOliver Tappe status_t 259c3ac87e8SOliver Tappe DefaultCatalog::ReadFromResource(entry_ref *appOrAddOnRef) 260c3ac87e8SOliver Tappe { 261c3ac87e8SOliver Tappe BFile file; 262c3ac87e8SOliver Tappe status_t res = file.SetTo(appOrAddOnRef, B_READ_ONLY); 263c3ac87e8SOliver Tappe if (res != B_OK) { 26475f15221SOliver Tappe log_team(LOG_ERR, 26575f15221SOliver Tappe "couldn't find app or add-on (dev=%lu, dir=%Lu, name=%s)", 266c3ac87e8SOliver Tappe appOrAddOnRef->device, appOrAddOnRef->directory, 267c3ac87e8SOliver Tappe appOrAddOnRef->name); 268c3ac87e8SOliver Tappe return B_ENTRY_NOT_FOUND; 269c3ac87e8SOliver Tappe } 270c3ac87e8SOliver Tappe 271c3ac87e8SOliver Tappe log_team(LOG_DEBUG, 272c3ac87e8SOliver Tappe "looking for embedded catalog-resource in app/add-on" 273c3ac87e8SOliver Tappe "(dev=%lu, dir=%Lu, name=%s)", appOrAddOnRef->device, 274c3ac87e8SOliver Tappe appOrAddOnRef->directory, appOrAddOnRef->name); 275c3ac87e8SOliver Tappe 276c3ac87e8SOliver Tappe BResources rsrc; 277c3ac87e8SOliver Tappe res = rsrc.SetTo(&file); 278c3ac87e8SOliver Tappe if (res != B_OK) { 279c3ac87e8SOliver Tappe log_team(LOG_DEBUG, "file has no resources"); 280c3ac87e8SOliver Tappe return res; 281c3ac87e8SOliver Tappe } 282c3ac87e8SOliver Tappe 283c3ac87e8SOliver Tappe size_t sz; 284c3ac87e8SOliver Tappe const void *buf = rsrc.LoadResource(B_MESSAGE_TYPE, 285c3ac87e8SOliver Tappe BLocaleRoster::kEmbeddedCatResId, &sz); 286c3ac87e8SOliver Tappe if (!buf) { 287c3ac87e8SOliver Tappe log_team(LOG_DEBUG, "file has no catalog-resource"); 288c3ac87e8SOliver Tappe return B_NAME_NOT_FOUND; 289c3ac87e8SOliver Tappe } 290c3ac87e8SOliver Tappe 291c3ac87e8SOliver Tappe BMemoryIO memIO(buf, sz); 292c3ac87e8SOliver Tappe res = Unflatten(&memIO); 293c3ac87e8SOliver Tappe 294c3ac87e8SOliver Tappe return res; 295c3ac87e8SOliver Tappe } 296c3ac87e8SOliver Tappe 297c3ac87e8SOliver Tappe 298c3ac87e8SOliver Tappe status_t 299c3ac87e8SOliver Tappe DefaultCatalog::WriteToFile(const char *path) 300c3ac87e8SOliver Tappe { 301c3ac87e8SOliver Tappe BFile catalogFile; 302c3ac87e8SOliver Tappe if (path) 303c3ac87e8SOliver Tappe fPath = path; 304c3ac87e8SOliver Tappe status_t res = catalogFile.SetTo(fPath.String(), 305c3ac87e8SOliver Tappe B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 306c3ac87e8SOliver Tappe if (res != B_OK) 307c3ac87e8SOliver Tappe return res; 308c3ac87e8SOliver Tappe 309c3ac87e8SOliver Tappe BMallocIO mallocIO; 31075f15221SOliver Tappe mallocIO.SetBlockSize(max(fCatMap.Size() * 20, 256L)); 311c3ac87e8SOliver Tappe // set a largish block-size in order to avoid reallocs 312c3ac87e8SOliver Tappe res = Flatten(&mallocIO); 313c3ac87e8SOliver Tappe if (res == B_OK) { 314c3ac87e8SOliver Tappe ssize_t wsz; 315c3ac87e8SOliver Tappe wsz = catalogFile.Write(mallocIO.Buffer(), mallocIO.BufferLength()); 316c3ac87e8SOliver Tappe if (wsz != (ssize_t)mallocIO.BufferLength()) 317c3ac87e8SOliver Tappe return B_FILE_ERROR; 318c3ac87e8SOliver Tappe 319c3ac87e8SOliver Tappe // set mimetype-, language- and signature-attributes: 320c3ac87e8SOliver Tappe UpdateAttributes(catalogFile); 321c3ac87e8SOliver Tappe } 322c3ac87e8SOliver Tappe if (res == B_OK) 323c3ac87e8SOliver Tappe UpdateAttributes(catalogFile); 324c3ac87e8SOliver Tappe return res; 325c3ac87e8SOliver Tappe } 326c3ac87e8SOliver Tappe 327c3ac87e8SOliver Tappe 328c3ac87e8SOliver Tappe /* 32975f15221SOliver Tappe * this method is not currently being used, but it may be useful in the 33075f15221SOliver Tappe * future... 331c3ac87e8SOliver Tappe */ 332c3ac87e8SOliver Tappe status_t 333c3ac87e8SOliver Tappe DefaultCatalog::WriteToAttribute(entry_ref *appOrAddOnRef) 334c3ac87e8SOliver Tappe { 335c3ac87e8SOliver Tappe BNode node; 336c3ac87e8SOliver Tappe status_t res = node.SetTo(appOrAddOnRef); 337c3ac87e8SOliver Tappe if (res != B_OK) 338c3ac87e8SOliver Tappe return res; 339c3ac87e8SOliver Tappe 340c3ac87e8SOliver Tappe BMallocIO mallocIO; 34175f15221SOliver Tappe mallocIO.SetBlockSize(max(fCatMap.Size() * 20, 256L)); 342c3ac87e8SOliver Tappe // set a largish block-size in order to avoid reallocs 343c3ac87e8SOliver Tappe res = Flatten(&mallocIO); 344c3ac87e8SOliver Tappe 345c3ac87e8SOliver Tappe if (res == B_OK) { 346c3ac87e8SOliver Tappe ssize_t wsz; 347c3ac87e8SOliver Tappe wsz = node.WriteAttr(BLocaleRoster::kEmbeddedCatAttr, B_MESSAGE_TYPE, 0, 348c3ac87e8SOliver Tappe mallocIO.Buffer(), mallocIO.BufferLength()); 349c3ac87e8SOliver Tappe if (wsz < B_OK) 350c3ac87e8SOliver Tappe res = wsz; 351c3ac87e8SOliver Tappe else if (wsz != (ssize_t)mallocIO.BufferLength()) 352c3ac87e8SOliver Tappe res = B_ERROR; 353c3ac87e8SOliver Tappe } 354c3ac87e8SOliver Tappe return res; 355c3ac87e8SOliver Tappe } 356c3ac87e8SOliver Tappe 357c3ac87e8SOliver Tappe 358c3ac87e8SOliver Tappe status_t 359c3ac87e8SOliver Tappe DefaultCatalog::WriteToResource(entry_ref *appOrAddOnRef) 360c3ac87e8SOliver Tappe { 361c3ac87e8SOliver Tappe BFile file; 362c3ac87e8SOliver Tappe status_t res = file.SetTo(appOrAddOnRef, B_READ_WRITE); 363c3ac87e8SOliver Tappe if (res != B_OK) 364c3ac87e8SOliver Tappe return res; 365c3ac87e8SOliver Tappe 366c3ac87e8SOliver Tappe BResources rsrc; 367c3ac87e8SOliver Tappe res = rsrc.SetTo(&file); 368c3ac87e8SOliver Tappe if (res != B_OK) 369c3ac87e8SOliver Tappe return res; 370c3ac87e8SOliver Tappe 371c3ac87e8SOliver Tappe BMallocIO mallocIO; 37275f15221SOliver Tappe mallocIO.SetBlockSize(max(fCatMap.Size() * 20, 256L)); 373c3ac87e8SOliver Tappe // set a largish block-size in order to avoid reallocs 374c3ac87e8SOliver Tappe res = Flatten(&mallocIO); 375c3ac87e8SOliver Tappe 37675f15221SOliver Tappe if (res == B_OK) { 377c3ac87e8SOliver Tappe res = rsrc.AddResource(B_MESSAGE_TYPE, BLocaleRoster::kEmbeddedCatResId, 378c3ac87e8SOliver Tappe mallocIO.Buffer(), mallocIO.BufferLength(), "embedded catalog"); 37975f15221SOliver Tappe } 380c3ac87e8SOliver Tappe 381c3ac87e8SOliver Tappe return res; 382c3ac87e8SOliver Tappe } 383c3ac87e8SOliver Tappe 384c3ac87e8SOliver Tappe 385f9a80fecSAxel Dörfler /*! Writes mimetype, language-name and signature of catalog into the 386f9a80fecSAxel Dörfler catalog-file. 387c3ac87e8SOliver Tappe */ 388c3ac87e8SOliver Tappe void 389c3ac87e8SOliver Tappe DefaultCatalog::UpdateAttributes(BFile& catalogFile) 390c3ac87e8SOliver Tappe { 391c3ac87e8SOliver Tappe static const int bufSize = 256; 392c3ac87e8SOliver Tappe char buf[bufSize]; 39375f15221SOliver Tappe uint32 temp; 39475f15221SOliver Tappe if (catalogFile.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, &buf, 39575f15221SOliver Tappe bufSize) <= 0 396c3ac87e8SOliver Tappe || strcmp(kCatMimeType, buf) != 0) { 397c3ac87e8SOliver Tappe catalogFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, 398c3ac87e8SOliver Tappe kCatMimeType, strlen(kCatMimeType)+1); 399c3ac87e8SOliver Tappe } 400c3ac87e8SOliver Tappe if (catalogFile.ReadAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0, 401c3ac87e8SOliver Tappe &buf, bufSize) <= 0 402c3ac87e8SOliver Tappe || fLanguageName != buf) { 403c3ac87e8SOliver Tappe catalogFile.WriteAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0, 404c3ac87e8SOliver Tappe fLanguageName.String(), fLanguageName.Length()+1); 405c3ac87e8SOliver Tappe } 406c3ac87e8SOliver Tappe if (catalogFile.ReadAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0, 407c3ac87e8SOliver Tappe &buf, bufSize) <= 0 408c3ac87e8SOliver Tappe || fSignature != buf) { 409c3ac87e8SOliver Tappe catalogFile.WriteAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0, 410c3ac87e8SOliver Tappe fSignature.String(), fSignature.Length()+1); 411c3ac87e8SOliver Tappe } 41275f15221SOliver Tappe if (catalogFile.ReadAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE, 41375f15221SOliver Tappe 0, &temp, sizeof(uint32)) <= 0) { 41475f15221SOliver Tappe catalogFile.WriteAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE, 41575f15221SOliver Tappe 0, &fFingerprint, sizeof(uint32)); 41675f15221SOliver Tappe } 417c3ac87e8SOliver Tappe } 418c3ac87e8SOliver Tappe 419c3ac87e8SOliver Tappe 420c3ac87e8SOliver Tappe status_t 421c3ac87e8SOliver Tappe DefaultCatalog::Flatten(BDataIO *dataIO) 422c3ac87e8SOliver Tappe { 423c3ac87e8SOliver Tappe UpdateFingerprint(); 424c3ac87e8SOliver Tappe // make sure we have the correct fingerprint before we flatten it 425c3ac87e8SOliver Tappe 426c3ac87e8SOliver Tappe status_t res; 427c3ac87e8SOliver Tappe BMessage archive; 42875f15221SOliver Tappe int32 count = fCatMap.Size(); 42975f15221SOliver Tappe res = archive.AddString("class", "DefaultCatalog"); 43075f15221SOliver Tappe if (res == B_OK) 43175f15221SOliver Tappe res = archive.AddInt32("c:sz", count); 43275f15221SOliver Tappe if (res == B_OK) 43375f15221SOliver Tappe res = archive.AddInt16("c:ver", kCatArchiveVersion); 43475f15221SOliver Tappe if (res == B_OK) 43575f15221SOliver Tappe res = archive.AddString("c:lang", fLanguageName.String()); 43675f15221SOliver Tappe if (res == B_OK) 43775f15221SOliver Tappe res = archive.AddString("c:sig", fSignature.String()); 43875f15221SOliver Tappe if (res == B_OK) 43975f15221SOliver Tappe res = archive.AddInt32("c:fpr", fFingerprint); 440c3ac87e8SOliver Tappe if (res == B_OK) 441c3ac87e8SOliver Tappe res = archive.Flatten(dataIO); 442c3ac87e8SOliver Tappe 44375f15221SOliver Tappe CatMap::Iterator iter = fCatMap.GetIterator(); 44475f15221SOliver Tappe CatMap::Entry entry; 44575f15221SOliver Tappe while (res == B_OK && iter.HasNext()) { 44675f15221SOliver Tappe entry = iter.Next(); 447c3ac87e8SOliver Tappe archive.MakeEmpty(); 44875f15221SOliver Tappe res = archive.AddString("c:ostr", entry.key.fString.String()); 44975f15221SOliver Tappe if (res == B_OK) 45075f15221SOliver Tappe res = archive.AddString("c:ctxt", entry.key.fContext.String()); 45175f15221SOliver Tappe if (res == B_OK) 45275f15221SOliver Tappe res = archive.AddString("c:comt", entry.key.fComment.String()); 45375f15221SOliver Tappe if (res == B_OK) 45475f15221SOliver Tappe res = archive.AddInt32("c:hash", entry.key.fHashVal); 45575f15221SOliver Tappe if (res == B_OK) 45675f15221SOliver Tappe res = archive.AddString("c:tstr", entry.value.String()); 457c3ac87e8SOliver Tappe if (res == B_OK) 458c3ac87e8SOliver Tappe res = archive.Flatten(dataIO); 459c3ac87e8SOliver Tappe } 46075f15221SOliver Tappe 461c3ac87e8SOliver Tappe return res; 462c3ac87e8SOliver Tappe } 463c3ac87e8SOliver Tappe 464c3ac87e8SOliver Tappe 465c3ac87e8SOliver Tappe status_t 466c3ac87e8SOliver Tappe DefaultCatalog::Unflatten(BDataIO *dataIO) 467c3ac87e8SOliver Tappe { 46875f15221SOliver Tappe fCatMap.Clear(); 469c3ac87e8SOliver Tappe int32 count = 0; 470c3ac87e8SOliver Tappe int16 version; 471c3ac87e8SOliver Tappe BMessage archiveMsg; 472c3ac87e8SOliver Tappe status_t res = archiveMsg.Unflatten(dataIO); 473c3ac87e8SOliver Tappe 474c3ac87e8SOliver Tappe if (res == B_OK) { 475c3ac87e8SOliver Tappe res = archiveMsg.FindInt16("c:ver", &version) 476c3ac87e8SOliver Tappe || archiveMsg.FindInt32("c:sz", &count); 477c3ac87e8SOliver Tappe } 478c3ac87e8SOliver Tappe if (res == B_OK) { 479c3ac87e8SOliver Tappe fLanguageName = archiveMsg.FindString("c:lang"); 480c3ac87e8SOliver Tappe fSignature = archiveMsg.FindString("c:sig"); 48175f15221SOliver Tappe uint32 foundFingerprint = archiveMsg.FindInt32("c:fpr"); 482c3ac87e8SOliver Tappe 48375f15221SOliver Tappe // if a specific fingerprint has been requested and the catalog does in 48475f15221SOliver Tappe // fact have a fingerprint, both are compared. If they mismatch, we do 48575f15221SOliver Tappe // not accept this catalog: 486c3ac87e8SOliver Tappe if (foundFingerprint != 0 && fFingerprint != 0 487c3ac87e8SOliver Tappe && foundFingerprint != fFingerprint) { 488c3ac87e8SOliver Tappe log_team(LOG_INFO, "default-catalog(sig=%s, lang=%s) " 489c3ac87e8SOliver Tappe "has mismatching fingerprint (%ld instead of the requested %ld), " 490c3ac87e8SOliver Tappe "so this catalog is skipped.", 491c3ac87e8SOliver Tappe fSignature.String(), fLanguageName.String(), foundFingerprint, 492c3ac87e8SOliver Tappe fFingerprint); 493c3ac87e8SOliver Tappe res = B_MISMATCHED_VALUES; 494c3ac87e8SOliver Tappe } else 495c3ac87e8SOliver Tappe fFingerprint = foundFingerprint; 496c3ac87e8SOliver Tappe } 497c3ac87e8SOliver Tappe 498c3ac87e8SOliver Tappe if (res == B_OK && count > 0) { 499c3ac87e8SOliver Tappe CatKey key; 500c3ac87e8SOliver Tappe const char *keyStr; 50175f15221SOliver Tappe const char *keyCtx; 50275f15221SOliver Tappe const char *keyCmt; 503c3ac87e8SOliver Tappe const char *translated; 50475f15221SOliver Tappe 50575f15221SOliver Tappe // fCatMap.resize(count); 50675f15221SOliver Tappe // There is no resize method in Haiku's HashMap to preallocate 50775f15221SOliver Tappe // memory. 508c3ac87e8SOliver Tappe for (int i=0; res == B_OK && i < count; ++i) { 509c3ac87e8SOliver Tappe res = archiveMsg.Unflatten(dataIO); 51075f15221SOliver Tappe if (res == B_OK) 51175f15221SOliver Tappe res = archiveMsg.FindString("c:ostr", &keyStr); 51275f15221SOliver Tappe if (res == B_OK) 51375f15221SOliver Tappe res = archiveMsg.FindString("c:ctxt", &keyCtx); 51475f15221SOliver Tappe if (res == B_OK) 51575f15221SOliver Tappe res = archiveMsg.FindString("c:comt", &keyCmt); 51675f15221SOliver Tappe if (res == B_OK) 51775f15221SOliver Tappe res = archiveMsg.FindInt32("c:hash", (int32*)&key.fHashVal); 51875f15221SOliver Tappe if (res == B_OK) 51975f15221SOliver Tappe res = archiveMsg.FindString("c:tstr", &translated); 520c3ac87e8SOliver Tappe if (res == B_OK) { 52175f15221SOliver Tappe key.fString = keyStr; 52275f15221SOliver Tappe key.fContext = keyCtx; 52375f15221SOliver Tappe key.fComment = keyCmt; 52475f15221SOliver Tappe fCatMap.Put(key, translated); 525c3ac87e8SOliver Tappe } 526c3ac87e8SOliver Tappe } 52775f15221SOliver Tappe uint32 checkFP = ComputeFingerprint(); 528c3ac87e8SOliver Tappe if (fFingerprint != checkFP) { 529c3ac87e8SOliver Tappe log_team(LOG_WARNING, "default-catalog(sig=%s, lang=%s) " 530c3ac87e8SOliver Tappe "has wrong fingerprint after load (%ld instead of the %ld). " 531c3ac87e8SOliver Tappe "The catalog data may be corrupted, so this catalog is skipped.", 532c3ac87e8SOliver Tappe fSignature.String(), fLanguageName.String(), checkFP, 533c3ac87e8SOliver Tappe fFingerprint); 534c3ac87e8SOliver Tappe return B_BAD_DATA; 535c3ac87e8SOliver Tappe } 536c3ac87e8SOliver Tappe } 537c3ac87e8SOliver Tappe return res; 538c3ac87e8SOliver Tappe } 539c3ac87e8SOliver Tappe 540c3ac87e8SOliver Tappe 541c3ac87e8SOliver Tappe BCatalogAddOn * 542c3ac87e8SOliver Tappe DefaultCatalog::Instantiate(const char *signature, const char *language, 54375f15221SOliver Tappe uint32 fingerprint) 544c3ac87e8SOliver Tappe { 54575f15221SOliver Tappe DefaultCatalog *catalog 54675f15221SOliver Tappe = new(std::nothrow) DefaultCatalog(signature, language, fingerprint); 547c3ac87e8SOliver Tappe if (catalog && catalog->InitCheck() != B_OK) { 548c3ac87e8SOliver Tappe delete catalog; 549c3ac87e8SOliver Tappe return NULL; 550c3ac87e8SOliver Tappe } 551c3ac87e8SOliver Tappe return catalog; 552c3ac87e8SOliver Tappe } 553c3ac87e8SOliver Tappe 554c3ac87e8SOliver Tappe 555c3ac87e8SOliver Tappe BCatalogAddOn * 556c3ac87e8SOliver Tappe DefaultCatalog::InstantiateEmbedded(entry_ref *appOrAddOnRef) 557c3ac87e8SOliver Tappe { 55875f15221SOliver Tappe DefaultCatalog *catalog = new(std::nothrow) DefaultCatalog(appOrAddOnRef); 559c3ac87e8SOliver Tappe if (catalog && catalog->InitCheck() != B_OK) { 560c3ac87e8SOliver Tappe delete catalog; 561c3ac87e8SOliver Tappe return NULL; 562c3ac87e8SOliver Tappe } 563c3ac87e8SOliver Tappe return catalog; 564c3ac87e8SOliver Tappe } 565c3ac87e8SOliver Tappe 566c3ac87e8SOliver Tappe 567c3ac87e8SOliver Tappe BCatalogAddOn * 568c3ac87e8SOliver Tappe DefaultCatalog::Create(const char *signature, const char *language) 569c3ac87e8SOliver Tappe { 57075f15221SOliver Tappe DefaultCatalog *catalog 57175f15221SOliver Tappe = new(std::nothrow) DefaultCatalog("", signature, language); 572c3ac87e8SOliver Tappe if (catalog && catalog->InitCheck() != B_OK) { 573c3ac87e8SOliver Tappe delete catalog; 574c3ac87e8SOliver Tappe return NULL; 575c3ac87e8SOliver Tappe } 576c3ac87e8SOliver Tappe return catalog; 577c3ac87e8SOliver Tappe } 578*80254771SAdrien Destugues 579*80254771SAdrien Destugues extern "C" status_t 580*80254771SAdrien Destugues default_catalog_get_available_languages(BMessage* availableLanguages, 581*80254771SAdrien Destugues const char* sigPattern, const char* langPattern = NULL, 582*80254771SAdrien Destugues int32 fingerprint = 0) 583*80254771SAdrien Destugues { 584*80254771SAdrien Destugues if (availableLanguages == NULL || sigPattern == NULL) 585*80254771SAdrien Destugues return B_BAD_DATA; 586*80254771SAdrien Destugues 587*80254771SAdrien Destugues app_info appInfo; 588*80254771SAdrien Destugues be_app->GetAppInfo(&appInfo); 589*80254771SAdrien Destugues node_ref nref; 590*80254771SAdrien Destugues nref.device = appInfo.ref.device; 591*80254771SAdrien Destugues nref.node = appInfo.ref.directory; 592*80254771SAdrien Destugues BDirectory appDir(&nref); 593*80254771SAdrien Destugues BString catalogName("locale/"); 594*80254771SAdrien Destugues catalogName << kCatFolder 595*80254771SAdrien Destugues << "/" << sigPattern ; 596*80254771SAdrien Destugues BPath catalogPath(&appDir, catalogName.String()); 597*80254771SAdrien Destugues BEntry file(catalogPath.Path()); 598*80254771SAdrien Destugues BDirectory dir(&file); 599*80254771SAdrien Destugues 600*80254771SAdrien Destugues char fileName[B_FILE_NAME_LENGTH]; 601*80254771SAdrien Destugues while(dir.GetNextEntry(&file) == B_OK) { 602*80254771SAdrien Destugues file.GetName(fileName); 603*80254771SAdrien Destugues BString langName(fileName); 604*80254771SAdrien Destugues langName.Replace(kCatExtension,"",1); 605*80254771SAdrien Destugues availableLanguages->AddString("langs",langName); 606*80254771SAdrien Destugues } 607*80254771SAdrien Destugues 608*80254771SAdrien Destugues // search in data folders 609*80254771SAdrien Destugues 610*80254771SAdrien Destugues directory_which which[] = { 611*80254771SAdrien Destugues B_USER_DATA_DIRECTORY, 612*80254771SAdrien Destugues B_COMMON_DATA_DIRECTORY, 613*80254771SAdrien Destugues B_SYSTEM_DATA_DIRECTORY 614*80254771SAdrien Destugues }; 615*80254771SAdrien Destugues 616*80254771SAdrien Destugues for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) { 617*80254771SAdrien Destugues BPath path; 618*80254771SAdrien Destugues if (find_directory(which[i], &path) == B_OK) { 619*80254771SAdrien Destugues catalogName = BString("locale/") 620*80254771SAdrien Destugues << kCatFolder 621*80254771SAdrien Destugues << "/" << sigPattern; 622*80254771SAdrien Destugues 623*80254771SAdrien Destugues BPath catalogPath(path.Path(), catalogName.String()); 624*80254771SAdrien Destugues BEntry file(catalogPath.Path()); 625*80254771SAdrien Destugues BDirectory dir(&file); 626*80254771SAdrien Destugues 627*80254771SAdrien Destugues char fileName[B_FILE_NAME_LENGTH]; 628*80254771SAdrien Destugues while(dir.GetNextEntry(&file) == B_OK) { 629*80254771SAdrien Destugues file.GetName(fileName); 630*80254771SAdrien Destugues BString langName(fileName); 631*80254771SAdrien Destugues langName.Replace(kCatExtension,"",1); 632*80254771SAdrien Destugues availableLanguages->AddString("langs",langName); 633*80254771SAdrien Destugues } 634*80254771SAdrien Destugues } 635*80254771SAdrien Destugues } 636*80254771SAdrien Destugues 637*80254771SAdrien Destugues return B_OK; 638*80254771SAdrien Destugues } 639