KDECore
libintl.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include "kdelibs_export.h"
00051 #include "kde_file.h"
00052 #include <config.h>
00053
00054 #include <qglobal.h>
00055
00056 #include <stdlib.h>
00057
00058 #if defined HAVE_STRING_H
00059 # include <string.h>
00060 #else
00061 # include <strings.h>
00062 #endif
00063
00064 #include <sys/types.h>
00065 #include <fcntl.h>
00066 #include <sys/stat.h>
00067
00068 #if defined HAVE_UNISTD_H
00069 # include <unistd.h>
00070 #endif
00071
00072 #if (defined HAVE_MMAP && defined HAVE_MUNMAP)
00073 # include <sys/mman.h>
00074 #endif
00075
00076 #ifndef W
00077 # define W(flag, data) ((flag) ? SWAP (data) : (data))
00078 #endif
00079
00080 typedef Q_UINT32 nls_uint32;
00081
00082 struct loaded_domain
00083 {
00084 const char *data;
00085 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00086 int use_mmap;
00087 size_t mmap_size;
00088 #endif
00089 int must_swap;
00090 nls_uint32 nstrings;
00091 struct string_desc *orig_tab;
00092 struct string_desc *trans_tab;
00093 nls_uint32 hash_size;
00094 nls_uint32 *hash_tab;
00095 };
00096
00097 struct kde_loaded_l10nfile
00098 {
00099 const char *filename;
00100 int decided;
00101
00102 const void *data;
00103
00104 kde_loaded_l10nfile() : filename(0), decided(0), data(0) {}
00105 };
00106
00107 void k_nl_load_domain(struct kde_loaded_l10nfile *__domain);
00108
00109 static inline nls_uint32
00110 SWAP (nls_uint32 i)
00111 {
00112 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
00113 }
00114
00115
00116
00117
00118 #define _MAGIC 0x950412de
00119 #define _MAGIC_SWAPPED 0xde120495
00120
00121
00122 #define MO_REVISION_NUMBER 0
00123
00124
00125
00126
00127
00128 static inline unsigned long hash_string (const char *__str_param);
00129
00130
00131
00132
00133 struct mo_file_header
00134 {
00135
00136 nls_uint32 magic;
00137
00138 nls_uint32 revision;
00139
00140 nls_uint32 nstrings;
00141
00142 nls_uint32 orig_tab_offset;
00143
00144 nls_uint32 trans_tab_offset;
00145
00146 nls_uint32 hash_tab_size;
00147
00148 nls_uint32 hash_tab_offset;
00149 };
00150
00151 struct string_desc
00152 {
00153
00154 nls_uint32 length;
00155
00156 nls_uint32 offset;
00157 };
00158
00159
00160 char *k_nl_find_msg (struct kde_loaded_l10nfile *domain_file,
00161 const char *msgid);
00162
00163 char *
00164 k_nl_find_msg (struct kde_loaded_l10nfile *domain_file, const char *msgid)
00165 {
00166 size_t top, act, bottom;
00167 struct loaded_domain *domain;
00168
00169 if (domain_file->decided == 0)
00170 k_nl_load_domain (domain_file);
00171
00172 if (domain_file->data == NULL)
00173 return NULL;
00174
00175 domain = (struct loaded_domain *) domain_file->data;
00176
00177
00178 if (domain->hash_size > 2 && domain->hash_tab != NULL)
00179 {
00180
00181 nls_uint32 len = strlen (msgid);
00182 nls_uint32 hash_val = hash_string (msgid);
00183 nls_uint32 idx = hash_val % domain->hash_size;
00184 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
00185 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
00186
00187 if (nstr == 0)
00188
00189 return NULL;
00190
00191 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
00192 && strcmp (msgid,
00193 domain->data + W (domain->must_swap,
00194 domain->orig_tab[nstr - 1].offset)) == 0)
00195 return (char *) domain->data + W (domain->must_swap,
00196 domain->trans_tab[nstr - 1].offset);
00197
00198 while (1)
00199 {
00200 if (idx >= domain->hash_size - incr)
00201 idx -= domain->hash_size - incr;
00202 else
00203 idx += incr;
00204
00205 nstr = W (domain->must_swap, domain->hash_tab[idx]);
00206 if (nstr == 0)
00207
00208 return NULL;
00209
00210 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
00211 && strcmp (msgid,
00212 domain->data + W (domain->must_swap,
00213 domain->orig_tab[nstr - 1].offset))
00214 == 0)
00215 return (char *) domain->data
00216 + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
00217 }
00218
00219 }
00220
00221
00222
00223 bottom = 0;
00224 top = domain->nstrings;
00225 act = top;
00226 while (bottom < top)
00227 {
00228 int cmp_val;
00229
00230 act = (bottom + top) / 2;
00231 cmp_val = strcmp (msgid, domain->data
00232 + W (domain->must_swap,
00233 domain->orig_tab[act].offset));
00234 if (cmp_val < 0)
00235 top = act;
00236 else if (cmp_val > 0)
00237 bottom = act + 1;
00238 else
00239 break;
00240 }
00241
00242
00243 return bottom >= top ? NULL : (char *) domain->data
00244 + W (domain->must_swap,
00245 domain->trans_tab[act].offset);
00246 }
00247
00248
00249
00250 #define HASHWORDBITS 32
00251
00252 static inline unsigned long
00253 hash_string (const char *str_param)
00254 {
00255 unsigned long int hval, g;
00256 const char *str = str_param;
00257
00258
00259 hval = 0;
00260 while (*str != '\0')
00261 {
00262 hval <<= 4;
00263 hval += (unsigned long) *str++;
00264 g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
00265 if (g != 0)
00266 {
00267 hval ^= g >> (HASHWORDBITS - 8);
00268 hval ^= g;
00269 }
00270 }
00271 return hval;
00272 }
00273
00274
00275
00276 void
00277 k_nl_load_domain (struct kde_loaded_l10nfile *domain_file)
00278 {
00279 int fd;
00280 struct stat st;
00281 struct mo_file_header *data = (struct mo_file_header *) -1;
00282 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00283 int use_mmap = 0;
00284 #endif
00285 struct loaded_domain *domain;
00286
00287 domain_file->decided = 1;
00288 domain_file->data = NULL;
00289
00290
00291
00292
00293
00294 if (domain_file->filename == NULL)
00295 return;
00296
00297
00298 fd = KDE_open (domain_file->filename, O_RDONLY);
00299 if (fd == -1)
00300 return;
00301
00302
00303 if (fstat (fd, &st) != 0
00304 || st.st_size < (off_t) sizeof (struct mo_file_header))
00305 {
00306
00307 close (fd);
00308 return;
00309 }
00310
00311 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00312
00313
00314 data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ,
00315 MAP_PRIVATE, fd, 0);
00316
00317 if (data != (struct mo_file_header *) -1)
00318 {
00319
00320 close (fd);
00321 use_mmap = 1;
00322 }
00323 #endif
00324
00325
00326
00327 if (data == (struct mo_file_header *) -1)
00328 {
00329 off_t to_read;
00330 char *read_ptr;
00331
00332 data = (struct mo_file_header *) malloc (st.st_size);
00333 if (data == NULL)
00334 return;
00335
00336 to_read = st.st_size;
00337 read_ptr = (char *) data;
00338 do
00339 {
00340 long int nb = (long int) read (fd, read_ptr, to_read);
00341 if (nb == -1)
00342 {
00343 close (fd);
00344 return;
00345 }
00346
00347 read_ptr += nb;
00348 to_read -= nb;
00349 }
00350 while (to_read > 0);
00351
00352 close (fd);
00353 }
00354
00355
00356
00357 if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
00358 {
00359
00360 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00361 if (use_mmap)
00362 munmap ((char *) data, st.st_size);
00363 else
00364 #endif
00365 free (data);
00366 return;
00367 }
00368
00369 domain_file->data
00370 = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
00371 if (domain_file->data == NULL)
00372 return;
00373
00374 domain = (struct loaded_domain *) domain_file->data;
00375 domain->data = (char *) data;
00376 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00377 domain->use_mmap = use_mmap;
00378 domain->mmap_size = st.st_size;
00379 #endif
00380 domain->must_swap = data->magic != _MAGIC;
00381
00382
00383 switch (W (domain->must_swap, data->revision))
00384 {
00385 case 0:
00386 domain->nstrings = W (domain->must_swap, data->nstrings);
00387 domain->orig_tab = (struct string_desc *)
00388 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
00389 domain->trans_tab = (struct string_desc *)
00390 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
00391 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
00392 domain->hash_tab = (nls_uint32 *)
00393 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
00394 break;
00395 default:
00396
00397 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00398 if (use_mmap)
00399 munmap ((char *) data, st.st_size);
00400 else
00401 #endif
00402 free (data);
00403 free (domain);
00404 domain_file->data = NULL;
00405 return;
00406 }
00407 }
00408
00409 void
00410 k_nl_unload_domain (struct loaded_domain *domain)
00411 {
00412 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00413 if (domain->use_mmap)
00414 munmap ((caddr_t) domain->data, domain->mmap_size);
00415 else
00416 # endif
00417 free ((void *) domain->data);
00418
00419 free (domain);
00420 }