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 }