• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeutils API Reference
  • KDE Home
  • Contact Us
 

superkaramba

  • sources
  • kde-4.12
  • kdeutils
  • superkaramba
  • src
themelocale.cpp
Go to the documentation of this file.
1 /*
2  * languageList from klocale.cpp
3  * Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
4  * Copyright (c) 1999 Preston Brown <pbrown@kde.org>
5  * Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
6  * Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
7  *
8  * libintl.cpp -- gettext related functions from glibc-2.0.5
9  * Copyright (C) 1995 Software Foundation, Inc.
10  *
11  * This file is part of SuperKaramba.
12  * Copyright (c) 2005 Petri Damstén <damu@iki.fi>
13  *
14  * SuperKaramba is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * SuperKaramba is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with SuperKaramba; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  ****************************************************************************/
28 
29 #include "themelocale.h"
30 #include "themefile.h"
31 
32 #include <stdlib.h>
33 
34 #include <KGlobal>
35 #include <KLocale>
36 
37 #include <QBuffer>
38 
39 #include <config-superkaramba.h>
40 
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
43 #endif
44 
45 #ifndef W
46 # define W(flag, data) ((flag) ? SWAP (data) : (data))
47 #endif
48 
49 typedef quint32 nls_uint32;
50 
51 struct loaded_domain
52 {
53  const char *data;
54  int must_swap;
55  nls_uint32 nstrings;
56  struct string_desc *orig_tab;
57  struct string_desc *trans_tab;
58  nls_uint32 hash_size;
59  nls_uint32 *hash_tab;
60 };
61 
62 static inline nls_uint32 SWAP(nls_uint32 i)
63 {
64  return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
65 }
66 
67 /* @@ end of prolog @@ */
68 
69 /* The magic number of the GNU message catalog format. */
70 #define _MAGIC 0x950412de
71 #define _MAGIC_SWAPPED 0xde120495
72 
73 /* Revision number of the currently used .mo (binary) file format. */
74 #define MO_REVISION_NUMBER 0
75 
76 
77 /* Defines the so called `hashpjw' function by P.J. Weinberger
78  [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
79  1986, 1987 Bell Telephone Laboratories, Inc.] */
80 static inline unsigned long hash_string(const char *__str_param);
81 
82 /* @@ end of prolog @@ */
83 
84 /* Header for binary .mo file format. */
85 struct mo_file_header
86 {
87  /* The magic number. */
88  nls_uint32 magic;
89  /* The revision number of the file format. */
90  nls_uint32 revision;
91  /* The number of strings pairs. */
92  nls_uint32 nstrings;
93  /* Offset of table with start offsets of original strings. */
94  nls_uint32 orig_tab_offset;
95  /* Offset of table with start offsets of translation strings. */
96  nls_uint32 trans_tab_offset;
97  /* Size of hashing table. */
98  nls_uint32 hash_tab_size;
99  /* Offset of first hashing entry. */
100  nls_uint32 hash_tab_offset;
101 };
102 
103 struct string_desc
104 {
105  /* Length of addressed string. */
106  nls_uint32 length;
107  /* Offset of string in file. */
108  nls_uint32 offset;
109 };
110 
111 void tl_nl_load_domain(QIODevice* device, int size,
112  struct sk_kde_loaded_l10nfile *domain_file);
113 char* tl_nl_find_msg(const struct sk_kde_loaded_l10nfile *domain_file,
114  const char *msgid);
115 void tl_nl_unload_domain(struct loaded_domain *domain);
116 
117 ThemeLocale::ThemeLocale(ThemeFile* theme)
118  : m_theme(theme)
119 {
120  setLanguage(languageList());
121 }
122 
123 ThemeLocale::~ThemeLocale()
124 {
125  unload();
126 }
127 
128 void ThemeLocale::unload()
129 {
130  if (m_domain.data) {
131  tl_nl_unload_domain((struct loaded_domain *)m_domain.data);
132  m_domain.data = 0;
133  }
134 }
135 
136 QString ThemeLocale::translate(const QString &text) const
137 {
138  if (text == 0)
139  return QString();
140  if (m_domain.data) {
141  QString result = QString::fromUtf8(tl_nl_find_msg(&m_domain, text.toAscii().constData()));
142  if (result.isEmpty())
143  return text;
144  else
145  return result;
146  }
147  return text;
148 }
149 
150 void ThemeLocale::setLanguage(const QStringList &languages)
151 {
152  unload();
153  for (QStringList::ConstIterator it = languages.begin();
154  it != languages.end();
155  ++it) {
156  QString file =
157  QString("locale/%1/LC_MESSAGES/%2.mo").arg(*it).arg(m_theme->mo());
158 
159  if (m_theme->fileExists(file)) {
160  QByteArray array = m_theme->readThemeFile(file);
161  QBuffer buffer(&array);
162  tl_nl_load_domain(&buffer, buffer.size(), &m_domain);
163  m_language = *it;
164  return;
165  }
166  }
167 }
168 
169 QStringList ThemeLocale::languageList()
170 {
171  // config calls replaced with
172  // KGlobal::locale()->languageList()
173 
174  //KSharedConfigPtr config = KGlobal::config();
175  // Reset the list and add the new languages
176  QStringList languageList;
177  languageList += QFile::decodeName(::getenv("KDE_LANG")).split(':');
178 
179  //languageList += config->readEntry("Language", QString()).split(':');
180  languageList += KGlobal::locale()->languageList();
181 
182  // same order as setlocale use
183  // HPB: Only run splitLocale on the environment variables..
184  QList<QString> langs;
185 
186  langs.append(QFile::decodeName(::getenv("LC_ALL")));
187  langs.append(QFile::decodeName(::getenv("LC_MESSAGES")));
188  langs.append(QFile::decodeName(::getenv("LANG")));
189 
190  foreach(const QString &lang, langs) {
191  QString ln, ct, modf, chrset;
192  KLocale::splitLocale(lang, ln, ct, modf, chrset);
193  /*
194  We don't use these in zip themes...
195  if (!ct.isEmpty())
196  {
197  langs.insert(it, ln + '_' + ct);
198  if (!chrset.isEmpty())
199  langs.insert(it, ln + '_' + ct + '.' + chrset);
200  }
201  */
202  langs.insert(0, ln);
203  }
204  languageList += langs;
205 
206  // Remove empty strings
207  for (QStringList::Iterator it = languageList.begin(); it != languageList.end();) {
208  if ((*it).isEmpty()) {
209  it = languageList.erase(it);
210  } else {
211  ++it;
212  }
213  }
214 
215  return languageList;
216 }
217 
218 char* tl_nl_find_msg(const struct sk_kde_loaded_l10nfile *domain_file,
219  const char *msgid)
220 {
221  size_t top, act, bottom;
222  struct loaded_domain *domain;
223 
224  if (domain_file->decided == 0)
225  return NULL;
226 
227  if (domain_file->data == NULL)
228  return NULL;
229 
230  domain = (struct loaded_domain *) domain_file->data;
231 
232  /* Locate the MSGID and its translation. */
233  if (domain->hash_size > 2 && domain->hash_tab != NULL)
234  {
235  /* Use the hashing table. */
236  nls_uint32 len = strlen(msgid);
237  nls_uint32 hash_val = hash_string(msgid);
238  nls_uint32 idx = hash_val % domain->hash_size;
239  nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
240  nls_uint32 nstr = W(domain->must_swap, domain->hash_tab[idx]);
241 
242  if (nstr == 0)
243  /* Hash table entry is empty. */
244  return NULL;
245 
246  if (W(domain->must_swap, domain->orig_tab[nstr - 1].length) == len
247  && strcmp(msgid,
248  domain->data + W(domain->must_swap,
249  domain->orig_tab[nstr - 1].offset)) == 0)
250  return (char *) domain->data + W(domain->must_swap,
251  domain->trans_tab[nstr - 1].offset);
252 
253  while (1) {
254  if (idx >= domain->hash_size - incr)
255  idx -= domain->hash_size - incr;
256  else
257  idx += incr;
258 
259  nstr = W(domain->must_swap, domain->hash_tab[idx]);
260  if (nstr == 0)
261  /* Hash table entry is empty. */
262  return NULL;
263 
264  if (W(domain->must_swap, domain->orig_tab[nstr - 1].length) == len
265  && strcmp(msgid,
266  domain->data + W(domain->must_swap,
267  domain->orig_tab[nstr - 1].offset))
268  == 0)
269  return (char *) domain->data
270  + W(domain->must_swap, domain->trans_tab[nstr - 1].offset);
271  }
272  /* NOTREACHED */
273  }
274 
275  /* Now we try the default method: binary search in the sorted
276  array of messages. */
277  bottom = 0;
278  top = domain->nstrings;
279  act = top;
280  while (bottom < top)
281  {
282  int cmp_val;
283 
284  act = (bottom + top) / 2;
285  cmp_val = strcmp(msgid, domain->data
286  + W(domain->must_swap,
287  domain->orig_tab[act].offset));
288  if (cmp_val < 0)
289  top = act;
290  else if (cmp_val > 0)
291  bottom = act + 1;
292  else
293  break;
294  }
295 
296  /* If an translation is found return this. */
297  return bottom >= top ? NULL : (char *) domain->data
298  + W(domain->must_swap,
299  domain->trans_tab[act].offset);
300 }
301 
302 /* @@ begin of epilog @@ */
303 /* We assume to have `unsigned long int' value with at least 32 bits. */
304 #define HASHWORDBITS 32
305 
306 static inline unsigned long
307 hash_string(const char *str_param)
308 {
309  unsigned long int hval, g;
310  const char *str = str_param;
311 
312  /* Compute the hash value for the given string. */
313  hval = 0;
314  while (*str != '\0') {
315  hval <<= 4;
316  hval += (unsigned long) * str++;
317  g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
318  if (g != 0) {
319  hval ^= g >> (HASHWORDBITS - 8);
320  hval ^= g;
321  }
322  }
323  return hval;
324 }
325 
326 /* Load the message catalogs specified by device. If it is no valid
327  message catalog do nothing. */
328 void tl_nl_load_domain(QIODevice* device, int size,
329  struct sk_kde_loaded_l10nfile *domain_file)
330 {
331  struct mo_file_header *data = (struct mo_file_header *) - 1;
332  struct loaded_domain *domain;
333 
334  domain_file->decided = 1;
335  domain_file->data = NULL;
336 
337  /* If the record does not represent a valid locale the FILENAME
338  might be NULL. This can happen when according to the given
339  specification the locale file name is different for XPG and CEN
340  syntax. */
341  if (device == NULL)
342  return;
343 
344  /* Try to open the addressed file. */
345  if (device->open(QIODevice::ReadOnly) == false)
346  return;
347 
348  /* We must know about the size of the file. */
349  if (size < (off_t) sizeof(struct mo_file_header))
350  {
351  /* Something went wrong. */
352  device->close();
353  return;
354  }
355 
356  /* If the data is not yet available (i.e. mmap'ed) we try to load
357  it manually. */
358  if (data == (struct mo_file_header *) - 1)
359  {
360  off_t to_read;
361  char *read_ptr;
362 
363  data = (struct mo_file_header *) malloc(size);
364  if (data == NULL)
365  return;
366 
367  to_read = size;
368  read_ptr = (char *) data;
369  do
370  {
371  long int nb = (long int) device->read(read_ptr, to_read);
372  if (nb == -1) {
373  device->close();
374  free(data);
375  return;
376  }
377 
378  read_ptr += nb;
379  to_read -= nb;
380  } while (to_read > 0);
381 
382  device->close();
383  }
384 
385  /* Using the magic number we can test whether it really is a message
386  catalog file. */
387  if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
388  {
389  /* The magic number is wrong: not a message catalog file. */
390  free(data);
391  return;
392  }
393 
394  domain_file->data
395  = (struct loaded_domain *) malloc(sizeof(struct loaded_domain));
396  if (domain_file->data == NULL)
397  return;
398 
399  domain = (struct loaded_domain *) domain_file->data;
400  domain->data = (char *) data;
401  domain->must_swap = data->magic != _MAGIC;
402 
403  /* Fill in the information about the available tables. */
404  switch (W(domain->must_swap, data->revision))
405  {
406  case 0:
407  domain->nstrings = W(domain->must_swap, data->nstrings);
408  domain->orig_tab = (struct string_desc *)
409  ((char *) data + W(domain->must_swap,
410  data->orig_tab_offset));
411  domain->trans_tab = (struct string_desc *)
412  ((char *) data + W(domain->must_swap,
413  data->trans_tab_offset));
414  domain->hash_size = W(domain->must_swap, data->hash_tab_size);
415  domain->hash_tab = (nls_uint32 *)
416  ((char *) data + W(domain->must_swap,
417  data->hash_tab_offset));
418  break;
419  default:
420  /* This is an illegal revision. */
421  free(data);
422  free(domain);
423  domain_file->data = NULL;
424  return;
425  }
426 }
427 
428 void tl_nl_unload_domain(struct loaded_domain *domain)
429 {
430  free((void *) domain->data);
431  free(domain);
432 }
hash_string
static unsigned long hash_string(const char *__str_param)
Definition: themelocale.cpp:307
sk_kde_loaded_l10nfile::decided
int decided
Definition: themelocale.h:34
tl_nl_find_msg
char * tl_nl_find_msg(const struct sk_kde_loaded_l10nfile *domain_file, const char *msgid)
Definition: themelocale.cpp:218
ThemeFile
Definition: themefile.h:41
sk_kde_loaded_l10nfile::data
const void * data
Definition: themelocale.h:35
ThemeLocale::translate
SUPERKARAMBA_EXPORT QString translate(const QString &text) const
Definition: themelocale.cpp:136
themelocale.h
ThemeLocale::languageList
static QStringList languageList()
Definition: themelocale.cpp:169
_MAGIC_SWAPPED
#define _MAGIC_SWAPPED
Definition: themelocale.cpp:71
_MAGIC
#define _MAGIC
Definition: themelocale.cpp:70
tl_nl_unload_domain
void tl_nl_unload_domain(struct loaded_domain *domain)
Definition: themelocale.cpp:428
tl_nl_load_domain
void tl_nl_load_domain(QIODevice *device, int size, struct sk_kde_loaded_l10nfile *domain_file)
Definition: themelocale.cpp:328
themefile.h
SWAP
static nls_uint32 SWAP(nls_uint32 i)
Definition: themelocale.cpp:62
HASHWORDBITS
#define HASHWORDBITS
Definition: themelocale.cpp:304
sk_kde_loaded_l10nfile
Definition: themelocale.h:32
W
#define W(flag, data)
Definition: themelocale.cpp:46
ThemeLocale::ThemeLocale
ThemeLocale(ThemeFile *theme)
Definition: themelocale.cpp:117
ThemeFile::mo
const QString & mo() const
Definition: themefile.cpp:556
nls_uint32
quint32 nls_uint32
Definition: themelocale.cpp:49
ThemeLocale::~ThemeLocale
~ThemeLocale()
Definition: themelocale.cpp:123
ThemeLocale::setLanguage
void setLanguage(const QStringList &languages)
Definition: themelocale.cpp:150
ThemeFile::readThemeFile
QByteArray readThemeFile(const QString &filename) const
Definition: themefile.cpp:443
ThemeFile::fileExists
bool fileExists(const QString &filename) const
Definition: themefile.cpp:431
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:07:20 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

superkaramba

Skip menu "superkaramba"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeutils API Reference

Skip menu "kdeutils API Reference"
  • ark
  • filelight
  • kcalc
  • kcharselect
  • kdf
  • kfloppy
  • kgpg
  • kremotecontrol
  • ktimer
  • kwallet
  • superkaramba
  • sweeper

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal