/[gpgoe]/trunk/src/OENLS.c
ViewVC logotype

Contents of /trunk/src/OENLS.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Fri Apr 7 10:46:41 2006 UTC (19 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 9026 byte(s)


1 /* wptNLS.c - 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 based on the simple-gettext.c code from the GnuPG
6 * by Ulrich Drepper.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser 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 * This software 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 * You should have received a copy of the GNU Lesser General Public License
19 * along with this software; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <windows.h>
31
32 #include "gpgme.h"
33 #include "GPGOE.h"
34
35
36 /* The magic number of the GNU message catalog format. */
37 #define MAGIC 0x950412de
38 #define MAGIC_SWAPPED 0xde120495
39
40 /* Revision number of the currently used .mo (binary) file format. */
41 #define MO_REVISION_NUMBER 0
42
43 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )
44
45
46 /* We assume to have `unsigned long int' value with at least 32 bits. */
47 #define HASHWORDBITS 32
48
49 /* The so called `hashpjw' function by P.J. Weinberger
50 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
51 1986, 1987 Bell Telephone Laboratories, Inc.] */
52
53 /* Header for binary .mo file format. */
54 struct mo_file_header {
55 DWORD magic; /* The magic number. */
56 DWORD revision; /* The revision number of the file format. */
57 DWORD nstrings; /* The number of strings pairs. */
58 DWORD orig_tab_offset; /* Offset of table with start offsets of original
59 strings. */
60 DWORD trans_tab_offset; /* Offset of table with start offsets of translation
61 strings. */
62 DWORD hash_tab_size; /* Size of hashing table. */
63 DWORD hash_tab_offset; /* Offset of first hashing entry. */
64 };
65
66 struct string_desc {
67 DWORD length; /* Length of addressed string. */
68 DWORD offset; /* Offset of string in file. */
69 };
70
71 struct loaded_domain {
72 char *data;
73 int must_swap;
74 DWORD nstrings;
75 char *mapped;
76 struct string_desc *orig_tab;
77 struct string_desc *trans_tab;
78 DWORD hash_size;
79 DWORD *hash_tab;
80 };
81
82
83 /* The current domain. */
84 static struct loaded_domain *the_domain;
85
86
87 static DWORD
88 do_swap_u32 (DWORD i)
89 {
90 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
91 }
92
93
94 /* Missing W32 functions. */
95 static char*
96 w32_stpcpy (char *a,const char *b)
97 {
98 while (*b)
99 *a++ = *b++;
100 *a = 0;
101 return (char*)a;
102 }
103
104
105
106 static DWORD
107 hash_string (const char *str_param)
108 {
109 unsigned long int hval, g;
110 const char *str = str_param;
111
112 hval = 0;
113 while (*str != '\0') {
114 hval <<= 4;
115 hval += (unsigned long int) *str++;
116 g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
117 if (g != 0) {
118 hval ^= g >> (HASHWORDBITS - 8);
119 hval ^= g;
120 }
121 }
122 return hval;
123 }
124
125
126 static struct loaded_domain *
127 load_domain( const char *filename )
128 {
129 FILE *fp;
130 size_t size;
131 struct stat st;
132 struct mo_file_header *data = NULL;
133 struct loaded_domain *domain = NULL;
134 size_t to_read;
135 char *read_ptr;
136
137 fp = fopen( filename, "rb" );
138 if( !fp )
139 return NULL; /* can't open the file */
140 /* we must know about the size of the file */
141 if( fstat( fileno(fp ), &st )
142 || (size = (size_t)st.st_size) != (size_t)st.st_size
143 || size < sizeof (struct mo_file_header) ) {
144 fclose( fp );
145 return NULL;
146 }
147
148 data = (struct mo_file_header *) xcalloc (1, size);
149 if( !data ) {
150 fclose( fp );
151 return NULL; /* out of memory */
152 }
153
154 to_read = size;
155 read_ptr = (char *) data;
156 do {
157 size_t nb = fread( read_ptr, 1, to_read, fp );
158 if( nb < to_read ) {
159 fclose (fp);
160 free(data);
161 return NULL; /* read error */
162
163 }
164 read_ptr += nb;
165 to_read -= nb;
166 } while( to_read > 0 );
167 fclose (fp);
168
169 /* Using the magic number we can test whether it really is a message
170 * catalog file. */
171 if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
172 /* The magic number is wrong: not a message catalog file. */
173 free( data );
174 return NULL;
175 }
176
177 domain = (struct loaded_domain *)xcalloc( 1, sizeof *domain );
178 if( !domain ) {
179 free( data );
180 return NULL;
181 }
182 domain->data = (char *) data;
183 domain->must_swap = data->magic != MAGIC;
184
185 /* Fill in the information about the available tables. */
186 switch( SWAPIT(domain->must_swap, data->revision) ) {
187 case 0:
188 domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
189 domain->orig_tab = (struct string_desc *)
190 ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
191 domain->trans_tab = (struct string_desc *)
192 ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
193 domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);
194 domain->hash_tab = (DWORD *)
195 ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));
196 break;
197
198 default: /* This is an invalid revision. */
199 free( data );
200 free( domain );
201 return NULL;
202 }
203
204 /* allocate an array to keep track of code page mappings */
205 domain->mapped = (char *)xcalloc( 1, domain->nstrings );
206 if( !domain->mapped ) {
207 free( data );
208 free( domain );
209 return NULL;
210 }
211
212 return domain;
213 } /* load_domain */
214
215
216 static const char*
217 get_string( struct loaded_domain *domain, DWORD idx )
218 {
219 char *p = domain->data + SWAPIT(domain->must_swap,
220 domain->trans_tab[idx].offset);
221 if( !domain->mapped[idx] ) {
222 domain->mapped[idx] = 1;
223 }
224 return (const char*)p;
225 }
226
227
228 const char *
229 gettext( const char *msgid )
230 {
231 struct loaded_domain *domain;
232 size_t act = 0;
233 size_t top, bottom;
234
235 if( !(domain = the_domain) )
236 goto not_found;
237
238 /* Locate the MSGID and its translation. */
239 if( domain->hash_size > 2 && domain->hash_tab ) {
240 /* Use the hashing table. */
241 DWORD len = strlen (msgid);
242 DWORD hash_val = hash_string (msgid);
243 DWORD idx = hash_val % domain->hash_size;
244 DWORD incr = 1 + (hash_val % (domain->hash_size - 2));
245 DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
246
247 if ( !nstr ) /* Hash table entry is empty. */
248 goto not_found;
249
250
251 if( SWAPIT(domain->must_swap,
252 domain->orig_tab[nstr - 1].length) == len
253 && !strcmp( msgid,
254 domain->data + SWAPIT(domain->must_swap,
255 domain->orig_tab[nstr - 1].offset)) )
256 return get_string( domain, nstr - 1 );
257 for(;;) {
258 if (idx >= domain->hash_size - incr)
259 idx -= domain->hash_size - incr;
260 else
261 idx += incr;
262 nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
263 if( !nstr )
264 goto not_found; /* Hash table entry is empty. */
265
266 if ( SWAPIT(domain->must_swap,
267 domain->orig_tab[nstr - 1].length) == len
268 && !strcmp (msgid,
269 domain->data + SWAPIT(domain->must_swap,
270 domain->orig_tab[nstr - 1].offset)))
271
272 return get_string( domain, nstr-1 );
273 } /* NOTREACHED */
274 }
275
276 /* Now we try the default method: binary search in the sorted
277 array of messages. */
278 bottom = 0;
279 top = domain->nstrings;
280 while( bottom < top ) {
281 int cmp_val;
282
283 act = (bottom + top) / 2;
284 cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,
285 domain->orig_tab[act].offset));
286 if (cmp_val < 0)
287 top = act;
288 else if (cmp_val > 0)
289 bottom = act + 1;
290 else
291 return get_string( domain, act );
292 }
293
294 not_found:
295 return msgid;
296 }
297
298
299 /* Set the file used for translations. Pass a NULL to disable translation.
300 A new filename may be set at anytime. */
301 int
302 set_gettext_file (const char *filename)
303 {
304 struct loaded_domain *domain = NULL;
305
306 if (!filename)
307 return 0;
308
309 domain = load_domain (filename);
310 if (the_domain) {
311 free (the_domain->data);
312 free (the_domain->mapped);
313 free (the_domain);
314 the_domain = NULL;
315 }
316 the_domain = domain;
317 return 0;
318 }
319
320
321 int
322 read_gettext_entry (char *path, DWORD pathlen)
323 {
324 HKEY hkey;
325 LONG err;
326 DWORD type = 0;
327
328 err = RegOpenKeyEx (HKEY_CURRENT_USER, "Control Panel\\MingW32\\NLS", 0,
329 KEY_READ, &hkey);
330 if (err != ERROR_SUCCESS)
331 return -1;
332 err = RegQueryValueEx (hkey, "MODir", NULL, &type, (BYTE*)path, &pathlen);
333 RegCloseKey (hkey);
334 if (err != ERROR_SUCCESS)
335 return -1;
336 return 0;
337 }
338
339
340 int
341 setup_gettext (void)
342 {
343 struct stat st;
344 char modir[MAX_PATH+1+32];
345
346 memset (modir, 0, sizeof (modir));
347 if (read_gettext_entry (modir, MAX_PATH-1))
348 return -1;
349 strcat (modir, "\\gpgoe.mo");
350 if (stat (modir, &st))
351 return -1;
352 set_gettext_file (modir);
353 return 0;
354 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26