/[winpt]/trunk/Src/wptNLS.cpp
ViewVC logotype

Contents of /trunk/Src/wptNLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 278 - (show annotations)
Mon Jan 15 22:02:04 2007 UTC (18 years, 1 month ago) by twoaday
File size: 9761 byte(s)
See ChangeLog.


1 /* wptNLS.cpp - W32 Native Language Support
2 * Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz
3 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
4 *
5 * This code is a stripped down version of simple-gettext.c
6 * written by by Ulrich Drepper from the GPG project.
7 *
8 * WinPT is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * WinPT is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <windows.h>
29
30 #include "wptNLS.h"
31 #include "wptTypes.h"
32
33
34 /* The magic number of the GNU message catalog format. */
35 #define MAGIC 0x950412de
36 #define MAGIC_SWAPPED 0xde120495
37
38 /* Revision number of the currently used .mo (binary) file format. */
39 #define MO_REVISION_NUMBER 0
40
41 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )
42
43
44 /* We assume to have `unsigned long int' value with at least 32 bits. */
45 #define HASHWORDBITS 32
46
47 /* Header for binary .mo file format. */
48 struct mo_file_header {
49 DWORD magic; /* The magic number. */
50 DWORD revision; /* The revision number of the file format. */
51 DWORD nstrings; /* The number of strings pairs. */
52 DWORD orig_tab_offset; /* Offset of table with start offsets of original
53 strings. */
54 DWORD trans_tab_offset; /* Offset of table with start offsets of translation
55 strings. */
56 DWORD hash_tab_size; /* Size of hashing table. */
57 DWORD hash_tab_offset; /* Offset of first hashing entry. */
58 };
59
60 struct string_desc {
61 DWORD length; /* Length of addressed string. */
62 DWORD offset; /* Offset of string in file. */
63 };
64
65 struct loaded_domain {
66 char *data;
67 int must_swap;
68 DWORD nstrings;
69 char *mapped;
70 struct string_desc *orig_tab;
71 struct string_desc *trans_tab;
72 DWORD hash_size;
73 DWORD *hash_tab;
74 };
75
76 /* List of all available languages. */
77 struct lang_table_s lang_list[] = {
78 {"en", "English", LANG_ENGLISH},
79 {"de", "German", LANG_GERMAN},
80 {"fr", "French", LANG_FRENCH},
81 {"jp", "Japanese", LANG_JAPANESE},
82 // XXX: add new languages.
83 {"pt_BR", "Portuguese (Brazil)", SUBLANG_PORTUGUESE_BRAZILIAN},
84 {NULL, 0}
85 };
86
87
88 /* The current domain. */
89 static struct loaded_domain *the_domain;
90
91
92 static DWORD
93 do_swap_u32 (DWORD i)
94 {
95 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
96 }
97
98
99 /* The so called `hashpjw' function by P.J. Weinberger
100 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
101 1986, 1987 Bell Telephone Laboratories, Inc.] */
102 static DWORD
103 hash_string (const char *str_param)
104 {
105 DWORD hval, g;
106 const char *str = str_param;
107
108 hval = 0;
109 while (*str != '\0') {
110 hval <<= 4;
111 hval += (DWORD) *str++;
112 g = hval & ((DWORD) 0xf << (HASHWORDBITS - 4));
113 if (g != 0) {
114 hval ^= g >> (HASHWORDBITS - 8);
115 hval ^= g;
116 }
117 }
118 return hval;
119 }
120
121
122 /* Missing W32 functions. */
123 static char*
124 w32_stpcpy (char *a,const char *b)
125 {
126 while (*b)
127 *a++ = *b++;
128 *a = 0;
129 return (char*)a;
130 }
131
132
133 static struct loaded_domain*
134 load_domain (const char *filename)
135 {
136 FILE *fp;
137 size_t size;
138 struct stat st;
139 struct mo_file_header *data = NULL;
140 struct loaded_domain *domain = NULL;
141 size_t to_read;
142 char *read_ptr;
143
144 fp = fopen (filename, "rb");
145 if (!fp)
146 return NULL;
147 /* we must know about the size of the file */
148 if( fstat( fileno(fp ), &st )
149 || (size = (size_t)st.st_size) != (size_t)st.st_size
150 || size < sizeof (struct mo_file_header) ) {
151 fclose( fp );
152 return NULL;
153 }
154
155 data = (struct mo_file_header *) malloc (size);
156 if (!data)
157 BUG (0);
158
159 to_read = size;
160 read_ptr = (char *) data;
161 do {
162 size_t nb = fread( read_ptr, 1, to_read, fp );
163 if( nb < to_read ) {
164 fclose (fp);
165 free(data);
166 return NULL; /* read error */
167
168 }
169 read_ptr += nb;
170 to_read -= nb;
171 } while( to_read > 0 );
172 fclose (fp);
173
174 /* Using the magic number we can test whether it really is a message
175 * catalog file. */
176 if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
177 /* The magic number is wrong: not a message catalog file. */
178 free( data );
179 return NULL;
180 }
181
182 domain = (struct loaded_domain *)calloc( 1, sizeof *domain );
183 if (!domain)
184 BUG (0);
185 domain->data = (char *) data;
186 domain->must_swap = data->magic != MAGIC;
187
188 /* Fill in the information about the available tables. */
189 switch( SWAPIT(domain->must_swap, data->revision) ) {
190 case 0:
191 domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
192 domain->orig_tab = (struct string_desc *)
193 ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
194 domain->trans_tab = (struct string_desc *)
195 ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
196 domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);
197 domain->hash_tab = (DWORD *)
198 ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));
199 break;
200
201 default: /* This is an invalid revision. */
202 free( data );
203 free( domain );
204 return NULL;
205 }
206
207 /* allocate an array to keep track of code page mappings */
208 domain->mapped = (char *)calloc( 1, domain->nstrings );
209 if (!domain->mapped)
210 BUG (0);
211
212 return domain;
213 }
214
215
216 /* Deallocate static resources. */
217 void
218 gettext_free_current_domain (void)
219 {
220 if (!the_domain)
221 return;
222 free (the_domain->data);
223 free (the_domain->mapped);
224 free (the_domain);
225 the_domain = NULL;
226 }
227
228
229 /* Set the file used for translations. Pass a NULL to disable translation.
230 A new filename may be set at anytime. */
231 int
232 gettext_set_file (const char *filename, const char *nls_dir)
233 {
234 struct loaded_domain *domain = NULL;
235
236 if (filename && *filename) {
237 if (filename[1] == ':' && filename[2] == '\\')
238 domain = load_domain (filename); /* absolute path - use it as is */
239 else { /* relative path - append ".mo" and get dir from the environment */
240 char *buf, *dir;
241
242 dir = strdup (nls_dir);
243 if (!dir)
244 BUG (0);
245 buf= (char *)malloc (strlen (dir) + strlen (filename)+1+3+1);
246 if (!buf)
247 BUG (0);
248
249 strcpy (w32_stpcpy (w32_stpcpy (
250 w32_stpcpy (buf, dir),"\\"), filename),".mo");
251 domain = load_domain(buf);
252 free (buf);
253 free (dir);
254 }
255 if (!domain)
256 return -1;
257 }
258
259 gettext_free_current_domain ();
260 the_domain = domain;
261 return 0;
262 }
263
264
265 static const char*
266 get_string( struct loaded_domain *domain, DWORD idx )
267 {
268 char *p = domain->data + SWAPIT(domain->must_swap,
269 domain->trans_tab[idx].offset);
270 if( !domain->mapped[idx] ) {
271 domain->mapped[idx] = 1;
272 }
273 return (const char*)p;
274 }
275
276
277 const char *
278 gettext( const char *msgid )
279 {
280 struct loaded_domain *domain;
281 size_t act = 0;
282 size_t top, bottom;
283
284 if (!(domain = the_domain))
285 goto not_found;
286
287 /* Locate the MSGID and its translation. */
288 if( domain->hash_size > 2 && domain->hash_tab ) {
289 /* Use the hashing table. */
290 DWORD len = strlen (msgid);
291 DWORD hash_val = hash_string (msgid);
292 DWORD idx = hash_val % domain->hash_size;
293 DWORD incr = 1 + (hash_val % (domain->hash_size - 2));
294 DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
295
296 if ( !nstr ) /* Hash table entry is empty. */
297 goto not_found;
298
299
300 if( SWAPIT(domain->must_swap,
301 domain->orig_tab[nstr - 1].length) == len
302 && !strcmp( msgid,
303 domain->data + SWAPIT(domain->must_swap,
304 domain->orig_tab[nstr - 1].offset)) )
305 return get_string( domain, nstr - 1 );
306 for(;;) {
307 if (idx >= domain->hash_size - incr)
308 idx -= domain->hash_size - incr;
309 else
310 idx += incr;
311 nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
312 if( !nstr )
313 goto not_found; /* Hash table entry is empty. */
314
315 if ( SWAPIT(domain->must_swap,
316 domain->orig_tab[nstr - 1].length) == len
317 && !strcmp (msgid,
318 domain->data + SWAPIT(domain->must_swap,
319 domain->orig_tab[nstr - 1].offset)))
320
321 return get_string( domain, nstr-1 );
322 } /* NOTREACHED */
323 }
324
325 /* Now we try the default method: binary search in the sorted
326 array of messages. */
327 bottom = 0;
328 top = domain->nstrings;
329 while( bottom < top ) {
330 int cmp_val;
331
332 act = (bottom + top) / 2;
333 cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,
334 domain->orig_tab[act].offset));
335 if (cmp_val < 0)
336 top = act;
337 else if (cmp_val > 0)
338 bottom = act + 1;
339 else
340 return get_string( domain, act );
341 }
342
343 not_found:
344 return msgid;
345 }
346
347
348 /* Map the user specific language ID to a gettext conform language string.
349 Example: LANG_GERMAN -> "de" */
350 const char*
351 gettext_get_langid (void)
352 {
353 LANGID lang;
354 int i;
355
356 lang = GetUserDefaultLangID ();
357 if (PRIMARYLANGID (lang) == LANG_ENGLISH)
358 return NULL;
359
360 for (i=0; lang_list[i].id; i++) {
361 if (PRIMARYLANGID (lang) == lang_list[i].langid)
362 return lang_list[i].id;
363 }
364 return NULL;
365 }
366
367
368 /* Take a table with control item IDs and their translation
369 and set each text to the translated value. */
370 void
371 gettext_localize_dialog (HWND dlg, struct gettext_tab_s *tab,
372 const char *title)
373 {
374 int i;
375
376 for (i=0; tab[i].trans != NULL; i++)
377 SetDlgItemText (dlg, tab[i].ctlid, tab[i].trans);
378 if (title)
379 SetWindowText (dlg, title);
380 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26