1 |
/* wptNLS.cpp - W32 Native Language Support |
/* wptNLS.cpp - W32 Native Language Support |
2 |
* Copyright (C) 2001, 2002, 2003 Timo Schulz |
* Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz |
3 |
* Copyright (C) 1995-1999 Free Software Foundation, Inc. |
* Copyright (C) 1995-1999 Free Software Foundation, Inc. |
4 |
* |
* |
5 |
* This code based on the simple-gettext.c code from the GnuPG |
* This code based on the simple-gettext.c code from the GnuPG |
25 |
#endif |
#endif |
26 |
|
|
27 |
#include <stdio.h> |
#include <stdio.h> |
|
#include <stdio.h> |
|
28 |
#include <string.h> |
#include <string.h> |
29 |
#include <ctype.h> |
#include <ctype.h> |
30 |
#include <errno.h> |
#include <errno.h> |
32 |
#include <sys/stat.h> |
#include <sys/stat.h> |
33 |
#include <windows.h> |
#include <windows.h> |
34 |
|
|
|
#include "wptTypes.h" |
|
35 |
#include "wptNLS.h" |
#include "wptNLS.h" |
36 |
|
|
|
/* Missing W32 functions. */ |
|
|
static char * |
|
|
w32_stpcpy (char *a,const char *b) |
|
|
{ |
|
|
while (*b) |
|
|
*a++ = *b++; |
|
|
*a = 0; |
|
|
return (char*)a; |
|
|
} |
|
|
|
|
37 |
|
|
38 |
/* The magic number of the GNU message catalog format. */ |
/* The magic number of the GNU message catalog format. */ |
39 |
#define MAGIC 0x950412de |
#define MAGIC 0x950412de |
42 |
/* Revision number of the currently used .mo (binary) file format. */ |
/* Revision number of the currently used .mo (binary) file format. */ |
43 |
#define MO_REVISION_NUMBER 0 |
#define MO_REVISION_NUMBER 0 |
44 |
|
|
45 |
|
#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) |
46 |
|
|
47 |
|
|
48 |
|
/* We assume to have `unsigned long int' value with at least 32 bits. */ |
49 |
|
#define HASHWORDBITS 32 |
50 |
|
|
51 |
/* Header for binary .mo file format. */ |
/* Header for binary .mo file format. */ |
52 |
struct mo_file_header { |
struct mo_file_header { |
53 |
u32 magic; /* The magic number. */ |
DWORD magic; /* The magic number. */ |
54 |
u32 revision; /* The revision number of the file format. */ |
DWORD revision; /* The revision number of the file format. */ |
55 |
u32 nstrings; /* The number of strings pairs. */ |
DWORD nstrings; /* The number of strings pairs. */ |
56 |
u32 orig_tab_offset; /* Offset of table with start offsets of original |
DWORD orig_tab_offset; /* Offset of table with start offsets of original |
57 |
strings. */ |
strings. */ |
58 |
u32 trans_tab_offset; /* Offset of table with start offsets of translation |
DWORD trans_tab_offset; /* Offset of table with start offsets of translation |
59 |
strings. */ |
strings. */ |
60 |
u32 hash_tab_size; /* Size of hashing table. */ |
DWORD hash_tab_size; /* Size of hashing table. */ |
61 |
u32 hash_tab_offset; /* Offset of first hashing entry. */ |
DWORD hash_tab_offset; /* Offset of first hashing entry. */ |
62 |
}; |
}; |
63 |
|
|
64 |
struct string_desc { |
struct string_desc { |
65 |
u32 length; /* Length of addressed string. */ |
DWORD length; /* Length of addressed string. */ |
66 |
u32 offset; /* Offset of string in file. */ |
DWORD offset; /* Offset of string in file. */ |
67 |
}; |
}; |
68 |
|
|
69 |
struct loaded_domain { |
struct loaded_domain { |
70 |
char *data; |
char *data; |
71 |
int must_swap; |
int must_swap; |
72 |
u32 nstrings; |
DWORD nstrings; |
73 |
char *mapped; |
char *mapped; |
74 |
struct string_desc *orig_tab; |
struct string_desc *orig_tab; |
75 |
struct string_desc *trans_tab; |
struct string_desc *trans_tab; |
76 |
u32 hash_size; |
DWORD hash_size; |
77 |
u32 *hash_tab; |
DWORD *hash_tab; |
78 |
}; |
}; |
79 |
|
|
80 |
|
/* List of all available languages. */ |
81 |
|
struct lang_table_s lang_list[] = { |
82 |
|
{"en", "English", LANG_ENGLISH}, |
83 |
|
{"de", "German", LANG_GERMAN}, |
84 |
|
{"fr", "French", LANG_FRENCH}, |
85 |
|
{"jp", "Japanese", LANG_JAPANESE}, |
86 |
|
{NULL, 0} |
87 |
|
}; |
88 |
|
|
89 |
|
/* The current domain. */ |
90 |
static struct loaded_domain *the_domain; |
static struct loaded_domain *the_domain; |
91 |
|
|
92 |
static u32 |
|
93 |
do_swap_u32( u32 i ) |
static DWORD |
94 |
|
do_swap_u32 (DWORD i) |
95 |
{ |
{ |
96 |
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); |
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); |
97 |
} |
} |
98 |
|
|
|
#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) |
|
|
|
|
|
|
|
|
/* We assume to have `unsigned long int' value with at least 32 bits. */ |
|
|
#define HASHWORDBITS 32 |
|
99 |
|
|
100 |
/* The so called `hashpjw' function by P.J. Weinberger |
/* The so called `hashpjw' function by P.J. Weinberger |
101 |
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, |
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, |
102 |
1986, 1987 Bell Telephone Laboratories, Inc.] */ |
1986, 1987 Bell Telephone Laboratories, Inc.] */ |
103 |
|
|
104 |
static u32 |
static DWORD |
105 |
hash_string( const char *str_param ) |
hash_string (const char *str_param) |
106 |
{ |
{ |
107 |
unsigned long int hval, g; |
unsigned long int hval, g; |
108 |
const char *str = str_param; |
const char *str = str_param; |
118 |
} |
} |
119 |
} |
} |
120 |
return hval; |
return hval; |
121 |
} /* hash_string */ |
} |
122 |
|
|
123 |
|
/* Missing W32 functions. */ |
124 |
|
static char* |
125 |
|
w32_stpcpy (char *a,const char *b) |
126 |
|
{ |
127 |
|
while (*b) |
128 |
|
*a++ = *b++; |
129 |
|
*a = 0; |
130 |
|
return (char*)a; |
131 |
|
} |
132 |
|
|
133 |
|
|
134 |
|
|
135 |
static struct loaded_domain * |
static struct loaded_domain * |
148 |
return NULL; /* can't open the file */ |
return NULL; /* can't open the file */ |
149 |
/* we must know about the size of the file */ |
/* we must know about the size of the file */ |
150 |
if( fstat( fileno(fp ), &st ) |
if( fstat( fileno(fp ), &st ) |
151 |
|| (size = (size_t)st.st_size) != st.st_size |
|| (size = (size_t)st.st_size) != (size_t)st.st_size |
152 |
|| size < sizeof (struct mo_file_header) ) { |
|| size < sizeof (struct mo_file_header) ) { |
153 |
fclose( fp ); |
fclose( fp ); |
154 |
return NULL; |
return NULL; |
163 |
to_read = size; |
to_read = size; |
164 |
read_ptr = (char *) data; |
read_ptr = (char *) data; |
165 |
do { |
do { |
166 |
long int nb = fread( read_ptr, 1, to_read, fp ); |
size_t nb = fread( read_ptr, 1, to_read, fp ); |
167 |
if( nb < to_read ) { |
if( nb < to_read ) { |
168 |
fclose (fp); |
fclose (fp); |
169 |
free(data); |
free(data); |
200 |
domain->trans_tab = (struct string_desc *) |
domain->trans_tab = (struct string_desc *) |
201 |
((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); |
((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); |
202 |
domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); |
domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); |
203 |
domain->hash_tab = (u32 *) |
domain->hash_tab = (DWORD *) |
204 |
((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); |
((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); |
205 |
break; |
break; |
206 |
|
|
222 |
} /* load_domain */ |
} /* load_domain */ |
223 |
|
|
224 |
|
|
225 |
/**************** |
/* Set the file used for translations. Pass a NULL to disable translation. |
226 |
* Set the file used for translations. Pass a NULL to disable |
A new filename may be set at anytime. */ |
|
* translation. A new filename may be set at anytime. |
|
|
* WARNING: After changing the filename you shoudl not access any data |
|
|
* retrieved by gettext(). |
|
|
*/ |
|
227 |
int |
int |
228 |
set_gettext_file( const char *filename, const char *nls_dir ) |
set_gettext_file( const char *filename, const char *nls_dir ) |
229 |
{ |
{ |
262 |
} |
} |
263 |
the_domain = domain; |
the_domain = domain; |
264 |
return 0; |
return 0; |
265 |
} /* set_gettext_file */ |
} |
266 |
|
|
267 |
|
|
268 |
static const char* |
static const char* |
269 |
get_string( struct loaded_domain *domain, u32 idx ) |
get_string( struct loaded_domain *domain, DWORD idx ) |
270 |
{ |
{ |
271 |
char *p = domain->data + SWAPIT(domain->must_swap, |
char *p = domain->data + SWAPIT(domain->must_swap, |
272 |
domain->trans_tab[idx].offset); |
domain->trans_tab[idx].offset); |
274 |
domain->mapped[idx] = 1; |
domain->mapped[idx] = 1; |
275 |
} |
} |
276 |
return (const char*)p; |
return (const char*)p; |
277 |
} /* get_string */ |
} |
278 |
|
|
279 |
|
|
280 |
const char * |
const char * |
284 |
size_t act = 0; |
size_t act = 0; |
285 |
size_t top, bottom; |
size_t top, bottom; |
286 |
|
|
287 |
if( !(domain = the_domain) ) |
if (!(domain = the_domain)) |
288 |
goto not_found; |
goto not_found; |
289 |
|
|
290 |
/* Locate the MSGID and its translation. */ |
/* Locate the MSGID and its translation. */ |
291 |
if( domain->hash_size > 2 && domain->hash_tab ) { |
if( domain->hash_size > 2 && domain->hash_tab ) { |
292 |
/* Use the hashing table. */ |
/* Use the hashing table. */ |
293 |
u32 len = strlen (msgid); |
DWORD len = strlen (msgid); |
294 |
u32 hash_val = hash_string (msgid); |
DWORD hash_val = hash_string (msgid); |
295 |
u32 idx = hash_val % domain->hash_size; |
DWORD idx = hash_val % domain->hash_size; |
296 |
u32 incr = 1 + (hash_val % (domain->hash_size - 2)); |
DWORD incr = 1 + (hash_val % (domain->hash_size - 2)); |
297 |
u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); |
DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); |
298 |
|
|
299 |
if ( !nstr ) /* Hash table entry is empty. */ |
if ( !nstr ) /* Hash table entry is empty. */ |
300 |
goto not_found; |
goto not_found; |
347 |
return msgid; |
return msgid; |
348 |
} /* gettext */ |
} /* gettext */ |
349 |
|
|
350 |
/* Map the user specific language ID to a |
|
351 |
gettext conform language string. |
/* Map the user specific language ID to a gettext conform language string. |
352 |
Example: LANG_GERMAN -> "de" */ |
Example: LANG_GERMAN -> "de" */ |
353 |
const char* |
const char* |
354 |
get_gettext_langid (void) |
get_gettext_langid (void) |
355 |
{ |
{ |
|
struct { |
|
|
const char *id; |
|
|
int langid; |
|
|
} lang_table[] = { |
|
|
{"de", LANG_GERMAN}, |
|
|
{NULL, 0}, |
|
|
}; |
|
356 |
LANGID lang; |
LANGID lang; |
357 |
int i; |
int i; |
358 |
|
|
359 |
lang = GetUserDefaultLangID (); |
lang = GetUserDefaultLangID (); |
360 |
|
if (PRIMARYLANGID (lang) == LANG_ENGLISH) |
361 |
for (i=0; lang_table[i].id; i++) { |
return NULL; |
362 |
if (PRIMARYLANGID (lang) == lang_table[i].langid) |
|
363 |
return lang_table[i].id; |
for (i=0; lang_list[i].id; i++) { |
364 |
|
if (PRIMARYLANGID (lang) == lang_list[i].langid) |
365 |
|
return lang_list[i].id; |
366 |
} |
} |
367 |
return NULL; |
return NULL; |
368 |
} |
} |
369 |
|
|
370 |
|
|
371 |
|
/* Take a table with control item IDs and their translation |
372 |
|
and set each text to the translated value. */ |
373 |
|
void |
374 |
|
gettext_localize_dialog (HWND dlg, struct gettext_tab_s *tab, |
375 |
|
const char *title) |
376 |
|
{ |
377 |
|
int i; |
378 |
|
|
379 |
|
for (i=0; tab[i].trans != NULL; i++) |
380 |
|
SetDlgItemText (dlg, tab[i].ctlid, tab[i].trans); |
381 |
|
if (title) |
382 |
|
SetWindowText (dlg, title); |
383 |
|
} |
384 |
|
|
385 |
|
|
386 |
/* XXX: this has to be placed in a .c file but not here */ |
/* XXX: this has to be placed in a .c file but not here */ |
387 |
#include <shlobj.h> |
#include <shlobj.h> |
388 |
|
|