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

Diff of /trunk/Src/wptNLS.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.22  
changed lines
  Added in v.36

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26