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 |
|
|
37 |
|
|
|
/* Missing W32 functions. */ |
|
|
static char * |
|
|
w32_stpcpy (char *a,const char *b) |
|
|
{ |
|
|
while( *b ) |
|
|
*a++ = *b++; |
|
|
*a = 0; |
|
|
return (char*)a; |
|
|
} |
|
|
|
|
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 |
40 |
#define MAGIC_SWAPPED 0xde120495 |
#define MAGIC_SWAPPED 0xde120495 |
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 |
|
/* The so called `hashpjw' function by P.J. Weinberger |
52 |
|
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, |
53 |
|
1986, 1987 Bell Telephone Laboratories, Inc.] */ |
54 |
|
|
55 |
/* Header for binary .mo file format. */ |
/* Header for binary .mo file format. */ |
56 |
struct mo_file_header { |
struct mo_file_header { |
57 |
u32 magic; /* The magic number. */ |
DWORD magic; /* The magic number. */ |
58 |
u32 revision; /* The revision number of the file format. */ |
DWORD revision; /* The revision number of the file format. */ |
59 |
u32 nstrings; /* The number of strings pairs. */ |
DWORD nstrings; /* The number of strings pairs. */ |
60 |
u32 orig_tab_offset; /* Offset of table with start offsets of original |
DWORD orig_tab_offset; /* Offset of table with start offsets of original |
61 |
strings. */ |
strings. */ |
62 |
u32 trans_tab_offset; /* Offset of table with start offsets of translation |
DWORD trans_tab_offset; /* Offset of table with start offsets of translation |
63 |
strings. */ |
strings. */ |
64 |
u32 hash_tab_size; /* Size of hashing table. */ |
DWORD hash_tab_size; /* Size of hashing table. */ |
65 |
u32 hash_tab_offset; /* Offset of first hashing entry. */ |
DWORD hash_tab_offset; /* Offset of first hashing entry. */ |
66 |
}; |
}; |
67 |
|
|
68 |
struct string_desc { |
struct string_desc { |
69 |
u32 length; /* Length of addressed string. */ |
DWORD length; /* Length of addressed string. */ |
70 |
u32 offset; /* Offset of string in file. */ |
DWORD offset; /* Offset of string in file. */ |
71 |
}; |
}; |
72 |
|
|
73 |
struct loaded_domain { |
struct loaded_domain { |
74 |
char *data; |
char *data; |
75 |
int must_swap; |
int must_swap; |
76 |
u32 nstrings; |
DWORD nstrings; |
77 |
char *mapped; |
char *mapped; |
78 |
struct string_desc *orig_tab; |
struct string_desc *orig_tab; |
79 |
struct string_desc *trans_tab; |
struct string_desc *trans_tab; |
80 |
u32 hash_size; |
DWORD hash_size; |
81 |
u32 *hash_tab; |
DWORD *hash_tab; |
82 |
|
}; |
83 |
|
|
84 |
|
/* List of all available languages. */ |
85 |
|
struct lang_table_s lang_list[] = { |
86 |
|
{"en", "English", LANG_ENGLISH}, |
87 |
|
{"de", "German", LANG_GERMAN}, |
88 |
|
{"fr", "French", LANG_FRENCH}, |
89 |
|
{"jp", "Japanese", LANG_JAPANESE}, |
90 |
|
{NULL, 0} |
91 |
}; |
}; |
92 |
|
|
93 |
|
/* The current domain. */ |
94 |
static struct loaded_domain *the_domain; |
static struct loaded_domain *the_domain; |
95 |
|
|
96 |
static u32 |
|
97 |
do_swap_u32( u32 i ) |
static DWORD |
98 |
|
do_swap_u32 (DWORD i) |
99 |
{ |
{ |
100 |
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); |
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); |
101 |
} |
} |
102 |
|
|
|
#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) |
|
103 |
|
|
104 |
|
/* Missing W32 functions. */ |
105 |
|
static char* |
106 |
|
w32_stpcpy (char *a,const char *b) |
107 |
|
{ |
108 |
|
while (*b) |
109 |
|
*a++ = *b++; |
110 |
|
*a = 0; |
111 |
|
return (char*)a; |
112 |
|
} |
113 |
|
|
|
/* We assume to have `unsigned long int' value with at least 32 bits. */ |
|
|
#define HASHWORDBITS 32 |
|
114 |
|
|
|
/* The so called `hashpjw' function by P.J. Weinberger |
|
|
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, |
|
|
1986, 1987 Bell Telephone Laboratories, Inc.] */ |
|
115 |
|
|
116 |
static u32 |
static DWORD |
117 |
hash_string( const char *str_param ) |
hash_string (const char *str_param) |
118 |
{ |
{ |
119 |
unsigned long int hval, g; |
unsigned long int hval, g; |
120 |
const char *str = str_param; |
const char *str = str_param; |
130 |
} |
} |
131 |
} |
} |
132 |
return hval; |
return hval; |
133 |
} /* hash_string */ |
} |
134 |
|
|
135 |
|
|
136 |
static struct loaded_domain * |
static struct loaded_domain * |
149 |
return NULL; /* can't open the file */ |
return NULL; /* can't open the file */ |
150 |
/* we must know about the size of the file */ |
/* we must know about the size of the file */ |
151 |
if( fstat( fileno(fp ), &st ) |
if( fstat( fileno(fp ), &st ) |
152 |
|| (size = (size_t)st.st_size) != st.st_size |
|| (size = (size_t)st.st_size) != (size_t)st.st_size |
153 |
|| size < sizeof (struct mo_file_header) ) { |
|| size < sizeof (struct mo_file_header) ) { |
154 |
fclose( fp ); |
fclose( fp ); |
155 |
return NULL; |
return NULL; |
164 |
to_read = size; |
to_read = size; |
165 |
read_ptr = (char *) data; |
read_ptr = (char *) data; |
166 |
do { |
do { |
167 |
long int nb = fread( read_ptr, 1, to_read, fp ); |
size_t nb = fread( read_ptr, 1, to_read, fp ); |
168 |
if( nb < to_read ) { |
if( nb < to_read ) { |
169 |
fclose (fp); |
fclose (fp); |
170 |
free(data); |
free(data); |
201 |
domain->trans_tab = (struct string_desc *) |
domain->trans_tab = (struct string_desc *) |
202 |
((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); |
((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); |
203 |
domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); |
domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); |
204 |
domain->hash_tab = (u32 *) |
domain->hash_tab = (DWORD *) |
205 |
((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); |
((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); |
206 |
break; |
break; |
207 |
|
|
223 |
} /* load_domain */ |
} /* load_domain */ |
224 |
|
|
225 |
|
|
226 |
/**************** |
/* Set the file used for translations. Pass a NULL to disable translation. |
227 |
* 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(). |
|
|
*/ |
|
228 |
int |
int |
229 |
set_gettext_file( const char *filename, const char *nls_dir ) |
set_gettext_file( const char *filename, const char *nls_dir ) |
230 |
{ |
{ |
263 |
} |
} |
264 |
the_domain = domain; |
the_domain = domain; |
265 |
return 0; |
return 0; |
266 |
} /* set_gettext_file */ |
} |
267 |
|
|
268 |
|
|
269 |
static const char* |
static const char* |
270 |
get_string( struct loaded_domain *domain, u32 idx ) |
get_string( struct loaded_domain *domain, DWORD idx ) |
271 |
{ |
{ |
272 |
char *p = domain->data + SWAPIT(domain->must_swap, |
char *p = domain->data + SWAPIT(domain->must_swap, |
273 |
domain->trans_tab[idx].offset); |
domain->trans_tab[idx].offset); |
275 |
domain->mapped[idx] = 1; |
domain->mapped[idx] = 1; |
276 |
} |
} |
277 |
return (const char*)p; |
return (const char*)p; |
278 |
} /* get_string */ |
} |
279 |
|
|
280 |
|
|
281 |
const char * |
const char * |
282 |
gettext( const char *msgid ) |
gettext( const char *msgid ) |
291 |
/* Locate the MSGID and its translation. */ |
/* Locate the MSGID and its translation. */ |
292 |
if( domain->hash_size > 2 && domain->hash_tab ) { |
if( domain->hash_size > 2 && domain->hash_tab ) { |
293 |
/* Use the hashing table. */ |
/* Use the hashing table. */ |
294 |
u32 len = strlen (msgid); |
DWORD len = strlen (msgid); |
295 |
u32 hash_val = hash_string (msgid); |
DWORD hash_val = hash_string (msgid); |
296 |
u32 idx = hash_val % domain->hash_size; |
DWORD idx = hash_val % domain->hash_size; |
297 |
u32 incr = 1 + (hash_val % (domain->hash_size - 2)); |
DWORD incr = 1 + (hash_val % (domain->hash_size - 2)); |
298 |
u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); |
DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); |
299 |
|
|
300 |
if ( !nstr ) /* Hash table entry is empty. */ |
if ( !nstr ) /* Hash table entry is empty. */ |
301 |
goto not_found; |
goto not_found; |
349 |
} /* gettext */ |
} /* gettext */ |
350 |
|
|
351 |
|
|
352 |
/* Map the user specific language ID to a |
/* Map the user specific language ID to a gettext conform language string. |
|
gettext conform language string. |
|
353 |
Example: LANG_GERMAN -> "de" */ |
Example: LANG_GERMAN -> "de" */ |
354 |
const char* |
const char* |
355 |
get_gettext_langid (void) |
get_gettext_langid (void) |
356 |
{ |
{ |
|
struct { |
|
|
const char *id; |
|
|
int langid; |
|
|
} lang_table[] = { |
|
|
{"de", LANG_GERMAN}, |
|
|
{NULL, 0}, |
|
|
}; |
|
357 |
LANGID lang; |
LANGID lang; |
358 |
int i; |
int i; |
359 |
|
|
360 |
lang = GetUserDefaultLangID (); |
lang = GetUserDefaultLangID (); |
361 |
|
if (PRIMARYLANGID (lang) == LANG_ENGLISH) |
362 |
|
return NULL; |
363 |
|
|
364 |
for (i=0; lang_table[i].id; i++) { |
for (i=0; lang_list[i].id; i++) { |
365 |
if (PRIMARYLANGID (lang) == lang_table[i].langid) |
if (PRIMARYLANGID (lang) == lang_list[i].langid) |
366 |
return lang_table[i].id; |
return lang_list[i].id; |
367 |
} |
} |
368 |
return NULL; |
return NULL; |
369 |
} |
} |