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

Annotation of /trunk/Src/wptNLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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


1 twoaday 273 /* 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 twoaday 278 * This code is a stripped down version of simple-gettext.c
6     * written by by Ulrich Drepper from the GPG project.
7 twoaday 273 *
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 twoaday 278 #include "wptTypes.h"
32 twoaday 273
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 twoaday 278 // XXX: add new languages.
83 twoaday 273 {"pt_BR", "Portuguese (Brazil)", SUBLANG_PORTUGUESE_BRAZILIAN},
84     {NULL, 0}
85     };
86    
87 twoaday 278
88 twoaday 273 /* 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 twoaday 278
122 twoaday 273 /* 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 twoaday 278 static struct loaded_domain*
134     load_domain (const char *filename)
135 twoaday 273 {
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 twoaday 278 fp = fopen (filename, "rb");
145     if (!fp)
146     return NULL;
147 twoaday 273 /* 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 twoaday 278 data = (struct mo_file_header *) malloc (size);
156     if (!data)
157     BUG (0);
158 twoaday 273
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 twoaday 278 if (!domain)
184     BUG (0);
185 twoaday 273 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 twoaday 278 if (!domain->mapped)
210     BUG (0);
211 twoaday 273
212     return domain;
213 twoaday 278 }
214 twoaday 273
215    
216 twoaday 278 /* 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 twoaday 273 /* Set the file used for translations. Pass a NULL to disable translation.
230     A new filename may be set at anytime. */
231     int
232 twoaday 278 gettext_set_file (const char *filename, const char *nls_dir)
233 twoaday 273 {
234     struct loaded_domain *domain = NULL;
235    
236 twoaday 278 if (filename && *filename) {
237     if (filename[1] == ':' && filename[2] == '\\')
238     domain = load_domain (filename); /* absolute path - use it as is */
239 twoaday 273 else { /* relative path - append ".mo" and get dir from the environment */
240 twoaday 278 char *buf, *dir;
241 twoaday 273
242 twoaday 278 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 twoaday 273 }
255 twoaday 278 if (!domain)
256 twoaday 273 return -1;
257     }
258    
259 twoaday 278 gettext_free_current_domain ();
260 twoaday 273 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 twoaday 278 gettext_get_langid (void)
352 twoaday 273 {
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