/[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 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 69 by twoaday, Sat Nov 5 12:28:12 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 */  
23    #ifdef HAVE_CONFIG_H
24  #include <stdio.h>  #include <config.h>
25  #include <string.h>  #endif
26  #include <ctype.h>  
27  #include <errno.h>  #include <stdio.h>
28  #include <sys/types.h>  #include <stdio.h>
29  #include <sys/stat.h>  #include <string.h>
30  #include <windows.h>  #include <ctype.h>
31    #include <errno.h>
32  #include "wptTypes.h"  #include <sys/types.h>
33  #include "wptNLS.h"  #include <sys/stat.h>
34    #include <windows.h>
35    
36  /* Missing W32 functions. */  #include "wptTypes.h"
37  static char *  #include "wptNLS.h"
38  stpcpy( char *a,const char *b )  
39  {  /* Missing W32 functions. */
40      while( *b )  static char *
41          *a++ = *b++;  w32_stpcpy (char *a,const char *b)
42      *a = 0;  {
43      return (char*)a;      while (*b)
44  }          *a++ = *b++;
45        *a = 0;
46  /* The magic number of the GNU message catalog format.  */      return (char*)a;
47  #define MAGIC         0x950412de  }
48  #define MAGIC_SWAPPED 0xde120495  
49    
50  /* Revision number of the currently used .mo (binary) file format.  */  /* The magic number of the GNU message catalog format.  */
51  #define MO_REVISION_NUMBER 0  #define MAGIC         0x950412de
52    #define MAGIC_SWAPPED 0xde120495
53    
54  /* Header for binary .mo file format.  */  /* Revision number of the currently used .mo (binary) file format.  */
55  struct mo_file_header {  #define MO_REVISION_NUMBER 0
56    u32 magic; /* The magic number.       */    
57    u32 revision; /* The revision number of the file format.  */  
58    u32 nstrings; /* The number of strings pairs.  */    /* Header for binary .mo file format.  */
59    u32 orig_tab_offset; /* Offset of table with start offsets of original  struct mo_file_header {
60                            strings.  */    u32 magic; /* The magic number.       */  
61    u32 trans_tab_offset; /* Offset of table with start offsets of translation    u32 revision; /* The revision number of the file format.  */
62                             strings.  */      u32 nstrings; /* The number of strings pairs.  */  
63    u32 hash_tab_size; /* Size of hashing table.  */      u32 orig_tab_offset; /* Offset of table with start offsets of original
64    u32 hash_tab_offset; /* Offset of first hashing entry.  */                            strings.  */
65  };    u32 trans_tab_offset; /* Offset of table with start offsets of translation
66                               strings.  */  
67  struct string_desc {    u32 hash_tab_size; /* Size of hashing table.  */  
68    u32 length; /* Length of addressed string.  */      u32 hash_tab_offset; /* Offset of first hashing entry.  */
69    u32 offset; /* Offset of string in file.      */  };
70  };  
71    struct string_desc {
72  struct loaded_domain {    u32 length; /* Length of addressed string.  */  
73    char *data;    u32 offset; /* Offset of string in file.      */
74    int must_swap;  };
75    u32 nstrings;  
76    char *mapped;  struct loaded_domain {
77    struct string_desc *orig_tab;    char *data;
78    struct string_desc *trans_tab;    int must_swap;
79    u32 hash_size;    u32 nstrings;
80    u32 *hash_tab;    char *mapped;
81  };    struct string_desc *orig_tab;
82      struct string_desc *trans_tab;
83  static struct loaded_domain *the_domain;    u32 hash_size;
84      u32 *hash_tab;
85  static u32  };
86  do_swap_u32( u32 i )  
87  {  static struct loaded_domain *the_domain;
88    return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);  
89  }  static u32
90    do_swap_u32( u32 i )
91  #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )  {
92      return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
93    }
94  /* We assume to have `unsigned long int' value with at least 32 bits.  */  
95  #define HASHWORDBITS 32  #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )
96    
97  /* The so called `hashpjw' function by P.J. Weinberger  
98     [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,  /* We assume to have `unsigned long int' value with at least 32 bits.  */
99     1986, 1987 Bell Telephone Laboratories, Inc.]  */  #define HASHWORDBITS 32
100    
101  static u32  /* The so called `hashpjw' function by P.J. Weinberger
102  hash_string( const char *str_param )     [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
103  {     1986, 1987 Bell Telephone Laboratories, Inc.]  */
104      unsigned long int hval, g;  
105      const char *str = str_param;  static u32
106    hash_string( const char *str_param )
107      hval = 0;  {
108      while (*str != '\0') {      unsigned long int hval, g;
109          hval <<= 4;      const char *str = str_param;
110          hval += (unsigned long int) *str++;      
111          g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));      hval = 0;
112          if (g != 0) {      while (*str != '\0') {
113              hval ^= g >> (HASHWORDBITS - 8);          hval <<= 4;
114              hval ^= g;            hval += (unsigned long int) *str++;    
115          }          g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
116      }          if (g != 0) {
117      return hval;              hval ^= g >> (HASHWORDBITS - 8);
118  } /* hash_string */              hval ^= g;  
119            }
120        }
121  static struct loaded_domain *      return hval;
122  load_domain( const char *filename )  } /* hash_string */
123  {  
124      FILE *fp;  
125      size_t size;  static struct loaded_domain *
126      struct stat st;  load_domain( const char *filename )
127      struct mo_file_header *data = NULL;  {
128      struct loaded_domain *domain = NULL;      FILE *fp;
129      size_t to_read;      size_t size;
130      char *read_ptr;      struct stat st;
131        struct mo_file_header *data = NULL;
132      fp = fopen( filename, "rb" );      struct loaded_domain *domain = NULL;
133      if( !fp )      size_t to_read;
134         return NULL; /* can't open the file */      char *read_ptr;
135      /* we must know about the size of the file */  
136      if( fstat( fileno(fp ), &st )      fp = fopen( filename, "rb" );
137          || (size = (size_t)st.st_size) != st.st_size      if( !fp )
138          || size < sizeof (struct mo_file_header) ) {         return NULL; /* can't open the file */
139          fclose( fp );        /* we must know about the size of the file */
140          return NULL;      if( fstat( fileno(fp ), &st )
141      }          || (size = (size_t)st.st_size) != st.st_size
142            || size < sizeof (struct mo_file_header) ) {
143      data = (struct mo_file_header *) malloc( size );          fclose( fp );  
144      if( !data ) {          return NULL;
145          fclose( fp );      }
146          return NULL; /* out of memory */  
147      }      data = (struct mo_file_header *) malloc( size );
148        if( !data ) {
149      to_read = size;          fclose( fp );
150      read_ptr = (char *) data;          return NULL; /* out of memory */
151      do {      }
152          long int nb = fread( read_ptr, 1, to_read, fp );  
153          if( nb < to_read ) {      to_read = size;
154              fclose (fp);      read_ptr = (char *) data;
155              free(data);      do {
156              return NULL; /* read error */          long int nb = fread( read_ptr, 1, to_read, fp );
157                            if( nb < to_read ) {
158          }              fclose (fp);
159          read_ptr += nb;              free(data);
160          to_read -= nb;              return NULL; /* read error */
161      } while( to_read > 0 );                  
162      fclose (fp);          }
163            read_ptr += nb;
164      /* Using the magic number we can test whether it really is a message          to_read -= nb;
165       * catalog file.  */      } while( to_read > 0 );
166      if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {      fclose (fp);
167          /* The magic number is wrong: not a message catalog file.  */  
168          free( data );      /* Using the magic number we can test whether it really is a message
169          return NULL;       * catalog file.  */
170      }      if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
171            /* The magic number is wrong: not a message catalog file.  */
172      domain = (struct loaded_domain *)calloc( 1, sizeof *domain );          free( data );
173      if( !domain )  {          return NULL;
174          free( data );        }
175          return NULL;  
176      }      domain = (struct loaded_domain *)calloc( 1, sizeof *domain );
177      domain->data = (char *) data;      if( !domain )  {
178      domain->must_swap = data->magic != MAGIC;          free( data );  
179            return NULL;
180      /* Fill in the information about the available tables.  */      }
181      switch( SWAPIT(domain->must_swap, data->revision) ) {      domain->data = (char *) data;
182        case 0:      domain->must_swap = data->magic != MAGIC;
183            domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);  
184            domain->orig_tab = (struct string_desc *)      /* Fill in the information about the available tables.  */
185                ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));      switch( SWAPIT(domain->must_swap, data->revision) ) {
186            domain->trans_tab = (struct string_desc *)        case 0:
187                ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));            domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
188            domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);              domain->orig_tab = (struct string_desc *)
189            domain->hash_tab = (u32 *)                    ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
190                ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));                  domain->trans_tab = (struct string_desc *)
191            break;                ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
192              domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);  
193        default: /* This is an invalid revision.  */            domain->hash_tab = (u32 *)    
194            free( data );                ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));      
195            free( domain );            break;
196            return NULL;  
197      }        default: /* This is an invalid revision.  */
198              free( data );
199      /* allocate an array to keep track of code page mappings */            free( domain );
200      domain->mapped = (char *)calloc( 1, domain->nstrings );            return NULL;
201      if( !domain->mapped ) {      }
202          free( data );  
203          free( domain );      /* allocate an array to keep track of code page mappings */
204          return NULL;      domain->mapped = (char *)calloc( 1, domain->nstrings );
205      }      if( !domain->mapped ) {
206            free( data );
207      return domain;          free( domain );
208  } /* load_domain */          return NULL;
209        }
210    
211  /****************      return domain;
212   * Set the file used for translations.  Pass a NULL to disable  } /* load_domain */
213   * translation.  A new filename may be set at anytime.  
214   * WARNING: After changing the filename you shoudl not access any data  
215   *          retrieved by gettext().  /****************
216   */   * Set the file used for translations.  Pass a NULL to disable
217  int   * translation.  A new filename may be set at anytime.
218  set_gettext_file( const char *filename, const char *nls_dir )   * WARNING: After changing the filename you shoudl not access any data
219  {   *          retrieved by gettext().
220      struct loaded_domain *domain = NULL;   */
221    int
222      if( filename && *filename ) {  set_gettext_file( const char *filename, const char *nls_dir )
223          if( filename[0] == '/'      {
224              || ( isalpha(filename[0])                  struct loaded_domain *domain = NULL;
225              && filename[1] == ':'        
226              && (filename[2] == '/' || filename[2] == '\\') )      if( filename && *filename ) {
227             ) {          if( filename[0] == '/'    
228              /* absolute path - use it as is */                    || ( isalpha(filename[0])            
229              domain = load_domain( filename );              && filename[1] == ':'      
230          }              && (filename[2] == '/' || filename[2] == '\\') )
231          else { /* relative path - append ".mo" and get dir from the environment */             ) {
232              char *buf = NULL;              /* absolute path - use it as is */      
233              char *dir;              domain = load_domain( filename );
234                            }
235              dir = strdup( nls_dir );          else { /* relative path - append ".mo" and get dir from the environment */
236              if( dir && (buf= (char *)malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {              char *buf = NULL;
237                  strcpy(stpcpy(stpcpy(stpcpy( buf, dir),"/"), filename),".mo");              char *dir;
238                  domain = load_domain( buf );                                      
239                  free(buf);              dir = strdup( nls_dir );
240              }              if( dir && (buf= (char *)malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {
241              free(dir);                  strcpy(w32_stpcpy(w32_stpcpy(w32_stpcpy( buf, dir),"/"), filename),".mo");
242          }                  domain = load_domain( buf );                    
243          if( !domain )                  free(buf);
244              return -1;              }
245      }              free(dir);
246            }
247      if( the_domain ) {          if( !domain )
248          free( the_domain->data );              return -1;
249          free( the_domain->mapped );      }
250          free( the_domain );      
251          the_domain = NULL;      if( the_domain ) {
252      }          free( the_domain->data );
253      the_domain = domain;          free( the_domain->mapped );
254      return 0;          free( the_domain );    
255  } /* set_gettext_file */          the_domain = NULL;
256        }
257        the_domain = domain;
258  static const char*      return 0;
259  get_string( struct loaded_domain *domain, u32 idx )  } /* set_gettext_file */
260  {  
261      char *p = domain->data + SWAPIT(domain->must_swap,  
262                                      domain->trans_tab[idx].offset);  static const char*
263      if( !domain->mapped[idx] ) {          get_string( struct loaded_domain *domain, u32 idx )
264          domain->mapped[idx] = 1;                  {
265      }      char *p = domain->data + SWAPIT(domain->must_swap,
266      return (const char*)p;                                      domain->trans_tab[idx].offset);
267  } /* get_string */      if( !domain->mapped[idx] ) {        
268            domain->mapped[idx] = 1;                
269  const char *      }
270  gettext( const char *msgid )      return (const char*)p;
271  {  } /* get_string */
272      struct loaded_domain *domain;  
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    not_found:
341        return msgid;
342    } /* gettext */
343    
344    
345    /* XXX: this has to be placed in a .c file but not here */
346    #include <shlobj.h>
347    
348    void _SHFree (void *p)
349    {
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.2  
changed lines
  Added in v.69

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26