• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • superkaramba
 

superkaramba

  • superkaramba
  • src
themelocale.cpp
1 /*
2  * languageList from tdelocale.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 Damsten <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 #include <config.h>
29 
30 #include "themelocale.h"
31 #include "themefile.h"
32 #include <kdebug.h>
33 #include <tdeconfig.h>
34 #include <tdeglobal.h>
35 #include <tdelocale.h>
36 #include <tqbuffer.h>
37 #include <tqglobal.h>
38 #include <tqiodevice.h>
39 #include <stdlib.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 TQ_UINT32 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(TQIODevice* 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  {
132  tl_nl_unload_domain((struct loaded_domain *)m_domain.data);
133  m_domain.data = 0;
134  }
135 }
136 
137 TQString ThemeLocale::translate(TQString text) const
138 {
139  if(text == 0)
140  return TQString();
141  if(m_domain.data)
142  {
143  TQString result = TQString::fromUtf8(tl_nl_find_msg(&m_domain, text.ascii()));
144  if(result.isEmpty())
145  return text;
146  else
147  return result;
148  }
149  return text;
150 }
151 
152 void ThemeLocale::setLanguage(const TQStringList &languages)
153 {
154  unload();
155  for(TQStringList::ConstIterator it = languages.begin();
156  it != languages.end();
157  ++it)
158  {
159  TQString file =
160  TQString("locale/%1/LC_MESSAGES/%2.mo").arg(*it).arg(m_theme->mo());
161 
162  if(m_theme->fileExists(file))
163  {
164  TQBuffer buffer(m_theme->readThemeFile(file));
165  tl_nl_load_domain(&buffer, buffer.size(), &m_domain);
166  m_language = *it;
167  return;
168  }
169  }
170 }
171 
172 TQStringList ThemeLocale::languageList()
173 {
174  TDEConfig* config = TDEGlobal::instance()->config();
175  // Reset the list and add the new languages
176  TQStringList languageList;
177  languageList +=
178  TQStringList::split(':', TQFile::decodeName(::getenv("TDE_LANG")));
179 
180  languageList += config->readListEntry("Language", ':');
181 
182  // same order as setlocale use
183  // HPB: Only run splitLocale on the environment variables..
184  TQStringList langs;
185 
186  langs << TQFile::decodeName(::getenv("LC_ALL"));
187  langs << TQFile::decodeName(::getenv("LC_MESSAGES"));
188  langs << TQFile::decodeName(::getenv("LANG"));
189 
190  for(TQStringList::Iterator it = langs.begin();
191  it != langs.end();
192  ++it )
193  {
194  TQString ln, ct, chrset;
195  TDELocale::splitLocale(*it, ln, ct, chrset);
196  /*
197  We don't use these in zip themes...
198  if (!ct.isEmpty())
199  {
200  langs.insert(it, ln + '_' + ct);
201  if (!chrset.isEmpty())
202  langs.insert(it, ln + '_' + ct + '.' + chrset);
203  }
204  */
205  langs.insert(it, ln);
206  }
207  languageList += langs;
208  // Remove empty strings
209  TQStringList::Iterator end( languageList.end() );
210  for(TQStringList::Iterator it=languageList.begin(); it!=end;)
211  {
212  if((*it).isEmpty())
213  it = languageList.remove(it);
214  else
215  ++it;
216  }
217  return languageList;
218 }
219 
220 char* tl_nl_find_msg (const struct sk_kde_loaded_l10nfile *domain_file,
221  const char *msgid)
222 {
223  size_t top, act, bottom;
224  struct loaded_domain *domain;
225 
226  if (domain_file->decided == 0)
227  return NULL;
228 
229  if (domain_file->data == NULL)
230  return NULL;
231 
232  domain = (struct loaded_domain *) domain_file->data;
233 
234  /* Locate the MSGID and its translation. */
235  if (domain->hash_size > 2 && domain->hash_tab != NULL)
236  {
237  /* Use the hashing table. */
238  nls_uint32 len = strlen (msgid);
239  nls_uint32 hash_val = hash_string (msgid);
240  nls_uint32 idx = hash_val % domain->hash_size;
241  nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
242  nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
243 
244  if (nstr == 0)
245  /* Hash table entry is empty. */
246  return NULL;
247 
248  if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
249  && strcmp (msgid,
250  domain->data + W (domain->must_swap,
251  domain->orig_tab[nstr - 1].offset)) == 0)
252  return (char *) domain->data + W (domain->must_swap,
253  domain->trans_tab[nstr - 1].offset);
254 
255  while (1)
256  {
257  if (idx >= domain->hash_size - incr)
258  idx -= domain->hash_size - incr;
259  else
260  idx += incr;
261 
262  nstr = W (domain->must_swap, domain->hash_tab[idx]);
263  if (nstr == 0)
264  /* Hash table entry is empty. */
265  return NULL;
266 
267  if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
268  && strcmp (msgid,
269  domain->data + W (domain->must_swap,
270  domain->orig_tab[nstr - 1].offset))
271  == 0)
272  return (char *) domain->data
273  + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
274  }
275  /* NOTREACHED */
276  }
277 
278  /* Now we try the default method: binary search in the sorted
279  array of messages. */
280  bottom = 0;
281  top = domain->nstrings;
282  act = top;
283  while (bottom < top)
284  {
285  int cmp_val;
286 
287  act = (bottom + top) / 2;
288  cmp_val = strcmp (msgid, domain->data
289  + W (domain->must_swap,
290  domain->orig_tab[act].offset));
291  if (cmp_val < 0)
292  top = act;
293  else if (cmp_val > 0)
294  bottom = act + 1;
295  else
296  break;
297  }
298 
299  /* If an translation is found return this. */
300  return bottom >= top ? NULL : (char *) domain->data
301  + W (domain->must_swap,
302  domain->trans_tab[act].offset);
303 }
304 
305 /* @@ begin of epilog @@ */
306 /* We assume to have `unsigned long int' value with at least 32 bits. */
307 #define HASHWORDBITS 32
308 
309 static inline unsigned long
310 hash_string (const char *str_param)
311 {
312  unsigned long int hval, g;
313  const char *str = str_param;
314 
315  /* Compute the hash value for the given string. */
316  hval = 0;
317  while (*str != '\0')
318  {
319  hval <<= 4;
320  hval += (unsigned long) *str++;
321  g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
322  if (g != 0)
323  {
324  hval ^= g >> (HASHWORDBITS - 8);
325  hval ^= g;
326  }
327  }
328  return hval;
329 }
330 
331 /* Load the message catalogs specified by device. If it is no valid
332  message catalog do nothing. */
333 void tl_nl_load_domain (TQIODevice* device, int size,
334  struct sk_kde_loaded_l10nfile *domain_file)
335 {
336  struct mo_file_header *data = (struct mo_file_header *) -1;
337  struct loaded_domain *domain;
338 
339  domain_file->decided = 1;
340  domain_file->data = NULL;
341 
342  /* If the record does not represent a valid locale the FILENAME
343  might be NULL. This can happen when according to the given
344  specification the locale file name is different for XPG and CEN
345  syntax. */
346  if (device == NULL)
347  return;
348 
349  /* Try to open the addressed file. */
350  if (device->open(IO_ReadOnly) == false)
351  return;
352 
353  /* We must know about the size of the file. */
354  if (size < (off_t) sizeof (struct mo_file_header))
355  {
356  /* Something went wrong. */
357  device->close();
358  return;
359  }
360 
361  /* If the data is not yet available (i.e. mmap'ed) we try to load
362  it manually. */
363  if (data == (struct mo_file_header *) -1)
364  {
365  off_t to_read;
366  char *read_ptr;
367 
368  data = (struct mo_file_header *) malloc (size);
369  if (data == NULL)
370  return;
371 
372  to_read = size;
373  read_ptr = (char *) data;
374  do
375  {
376  long int nb = (long int) device->readBlock (read_ptr, to_read);
377  if (nb == -1)
378  {
379  device->close();
380  return;
381  }
382 
383  read_ptr += nb;
384  to_read -= nb;
385  }
386  while (to_read > 0);
387 
388  device->close();
389  }
390 
391  /* Using the magic number we can test whether it really is a message
392  catalog file. */
393  if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
394  {
395  /* The magic number is wrong: not a message catalog file. */
396  free (data);
397  return;
398  }
399 
400  domain_file->data
401  = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
402  if (domain_file->data == NULL)
403  return;
404 
405  domain = (struct loaded_domain *) domain_file->data;
406  domain->data = (char *) data;
407  domain->must_swap = data->magic != _MAGIC;
408 
409  /* Fill in the information about the available tables. */
410  switch (W (domain->must_swap, data->revision))
411  {
412  case 0:
413  domain->nstrings = W (domain->must_swap, data->nstrings);
414  domain->orig_tab = (struct string_desc *)
415  ((char *) data + W (domain->must_swap,
416  data->orig_tab_offset));
417  domain->trans_tab = (struct string_desc *)
418  ((char *) data + W (domain->must_swap,
419  data->trans_tab_offset));
420  domain->hash_size = W (domain->must_swap, data->hash_tab_size);
421  domain->hash_tab = (nls_uint32 *)
422  ((char *) data + W (domain->must_swap,
423  data->hash_tab_offset));
424  break;
425  default:
426  /* This is an illegal revision. */
427  free (data);
428  free (domain);
429  domain_file->data = NULL;
430  return;
431  }
432 }
433 
434 void tl_nl_unload_domain (struct loaded_domain *domain)
435 {
436  free ((void *) domain->data);
437  free (domain);
438 }
ThemeFile
Definition: themefile.h:42
sk_kde_loaded_l10nfile
Definition: themelocale.h:32

superkaramba

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

superkaramba

Skip menu "superkaramba"
  • kcalc
  •   knumber
  • superkaramba
Generated for superkaramba by doxygen 1.8.13
This website is maintained by Timothy Pearson.