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

Contents of /trunk/src/OENLS.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations)
Sun Jun 4 10:12:47 2006 UTC (18 years, 11 months ago) by twoaday
File MIME type: text/plain
File size: 8873 byte(s)
Prepare new release.


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 DWORD
95 hash_string (const char *str_param)
96 {
97 unsigned long int hval, g;
98 const char *str = str_param;
99
100 hval = 0;
101 while (*str != '\0') {
102 hval <<= 4;
103 hval += (unsigned long int) *str++;
104 g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
105 if (g != 0) {
106 hval ^= g >> (HASHWORDBITS - 8);
107 hval ^= g;
108 }
109 }
110 return hval;
111 }
112
113
114 static struct loaded_domain *
115 load_domain( const char *filename )
116 {
117 FILE *fp;
118 size_t size;
119 struct stat st;
120 struct mo_file_header *data = NULL;
121 struct loaded_domain *domain = NULL;
122 size_t to_read;
123 char *read_ptr;
124
125 fp = fopen( filename, "rb" );
126 if( !fp )
127 return NULL; /* can't open the file */
128 /* we must know about the size of the file */
129 if( fstat( fileno(fp ), &st )
130 || (size = (size_t)st.st_size) != (size_t)st.st_size
131 || size < sizeof (struct mo_file_header) ) {
132 fclose( fp );
133 return NULL;
134 }
135
136 data = (struct mo_file_header *) xcalloc (1, size);
137 if( !data ) {
138 fclose( fp );
139 return NULL; /* out of memory */
140 }
141
142 to_read = size;
143 read_ptr = (char *) data;
144 do {
145 size_t nb = fread( read_ptr, 1, to_read, fp );
146 if( nb < to_read ) {
147 fclose (fp);
148 free(data);
149 return NULL; /* read error */
150
151 }
152 read_ptr += nb;
153 to_read -= nb;
154 } while( to_read > 0 );
155 fclose (fp);
156
157 /* Using the magic number we can test whether it really is a message
158 * catalog file. */
159 if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
160 /* The magic number is wrong: not a message catalog file. */
161 free( data );
162 return NULL;
163 }
164
165 domain = (struct loaded_domain *)xcalloc( 1, sizeof *domain );
166 if( !domain ) {
167 free( data );
168 return NULL;
169 }
170 domain->data = (char *) data;
171 domain->must_swap = data->magic != MAGIC;
172
173 /* Fill in the information about the available tables. */
174 switch( SWAPIT(domain->must_swap, data->revision) ) {
175 case 0:
176 domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
177 domain->orig_tab = (struct string_desc *)
178 ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
179 domain->trans_tab = (struct string_desc *)
180 ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
181 domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);
182 domain->hash_tab = (DWORD *)
183 ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));
184 break;
185
186 default: /* This is an invalid revision. */
187 free( data );
188 free( domain );
189 return NULL;
190 }
191
192 /* allocate an array to keep track of code page mappings */
193 domain->mapped = (char *)xcalloc( 1, domain->nstrings );
194 if( !domain->mapped ) {
195 free( data );
196 free( domain );
197 return NULL;
198 }
199
200 return domain;
201 } /* load_domain */
202
203
204 static const char*
205 get_string( struct loaded_domain *domain, DWORD idx )
206 {
207 char *p = domain->data + SWAPIT(domain->must_swap,
208 domain->trans_tab[idx].offset);
209 if( !domain->mapped[idx] ) {
210 domain->mapped[idx] = 1;
211 }
212 return (const char*)p;
213 }
214
215
216 const char *
217 gettext( const char *msgid )
218 {
219 struct loaded_domain *domain;
220 size_t act = 0;
221 size_t top, bottom;
222
223 if( !(domain = the_domain) )
224 goto not_found;
225
226 /* Locate the MSGID and its translation. */
227 if( domain->hash_size > 2 && domain->hash_tab ) {
228 /* Use the hashing table. */
229 DWORD len = strlen (msgid);
230 DWORD hash_val = hash_string (msgid);
231 DWORD idx = hash_val % domain->hash_size;
232 DWORD incr = 1 + (hash_val % (domain->hash_size - 2));
233 DWORD nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
234
235 if ( !nstr ) /* Hash table entry is empty. */
236 goto not_found;
237
238
239 if( SWAPIT(domain->must_swap,
240 domain->orig_tab[nstr - 1].length) == len
241 && !strcmp( msgid,
242 domain->data + SWAPIT(domain->must_swap,
243 domain->orig_tab[nstr - 1].offset)) )
244 return get_string( domain, nstr - 1 );
245 for(;;) {
246 if (idx >= domain->hash_size - incr)
247 idx -= domain->hash_size - incr;
248 else
249 idx += incr;
250 nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
251 if( !nstr )
252 goto not_found; /* Hash table entry is empty. */
253
254 if ( SWAPIT(domain->must_swap,
255 domain->orig_tab[nstr - 1].length) == len
256 && !strcmp (msgid,
257 domain->data + SWAPIT(domain->must_swap,
258 domain->orig_tab[nstr - 1].offset)))
259
260 return get_string( domain, nstr-1 );
261 } /* NOTREACHED */
262 }
263
264 /* Now we try the default method: binary search in the sorted
265 array of messages. */
266 bottom = 0;
267 top = domain->nstrings;
268 while( bottom < top ) {
269 int cmp_val;
270
271 act = (bottom + top) / 2;
272 cmp_val = strcmp(msgid, domain->data + SWAPIT(domain->must_swap,
273 domain->orig_tab[act].offset));
274 if (cmp_val < 0)
275 top = act;
276 else if (cmp_val > 0)
277 bottom = act + 1;
278 else
279 return get_string( domain, act );
280 }
281
282 not_found:
283 return msgid;
284 }
285
286
287 /* Set the file used for translations. Pass a NULL to disable translation.
288 A new filename may be set at anytime. */
289 int
290 set_gettext_file (const char *filename)
291 {
292 struct loaded_domain *domain = NULL;
293
294 if (!filename)
295 return 0;
296
297 domain = load_domain (filename);
298 if (the_domain) {
299 free (the_domain->data);
300 free (the_domain->mapped);
301 free (the_domain);
302 the_domain = NULL;
303 }
304 the_domain = domain;
305 return 0;
306 }
307
308
309 int
310 read_gettext_entry (char *path, DWORD pathlen)
311 {
312 HKEY hkey;
313 LONG err;
314 DWORD type = 0;
315
316 err = RegOpenKeyEx (HKEY_CURRENT_USER, "Control Panel\\MingW32\\NLS", 0,
317 KEY_READ, &hkey);
318 if (err != ERROR_SUCCESS)
319 return -1;
320 err = RegQueryValueEx (hkey, "MODir", NULL, &type, (BYTE*)path, &pathlen);
321 RegCloseKey (hkey);
322 if (err != ERROR_SUCCESS)
323 return -1;
324 return 0;
325 }
326
327
328 int
329 setup_gettext (void)
330 {
331 struct stat st;
332 char modir[MAX_PATH+1+32];
333
334 memset (modir, 0, sizeof (modir));
335 if (read_gettext_entry (modir, MAX_PATH-1))
336 return -1;
337 strcat (modir, "\\gpgoe.mo");
338 if (stat (modir, &st))
339 return -1;
340 set_gettext_file (modir);
341 return 0;
342 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26