~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to jnlib/utf8conv.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* utf8conf.c -  UTF8 character set conversion
2
2
 * Copyright (C) 1994, 1998, 1999, 2000, 2001,
3
 
 *               2003  Free Software Foundation, Inc.
4
 
 *
5
 
 * This file is part of GnuPG.
6
 
 *
7
 
 * GnuPG is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation; either version 2 of the License, or
10
 
 * (at your option) any later version.
11
 
 *
12
 
 * GnuPG is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
3
 *               2003, 2006  Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of JNLIB.
 
6
 *
 
7
 * JNLIB is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU Lesser General Public License as
 
9
 * published by the Free Software Foundation; either version 3 of
 
10
 * the License, or (at your option) any later version.
 
11
 *
 
12
 * JNLIB is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20
19
 */
21
20
 
22
21
#include <config.h>
27
26
#ifdef HAVE_LANGINFO_CODESET
28
27
#include <langinfo.h>
29
28
#endif
 
29
#include <errno.h>
 
30
#ifndef HAVE_W32_SYSTEM
 
31
# include <iconv.h>
 
32
#endif
30
33
 
31
34
#include "libjnlib-config.h"
32
35
#include "stringhelp.h"
 
36
#include "dynload.h"
33
37
#include "utf8conv.h"
34
38
 
35
 
 
36
 
static ushort koi8_unicode[128] = {
37
 
  0x2500, 0x2502, 0x250c, 0x2510, 0x2514, 0x2518, 0x251c, 0x2524,
38
 
  0x252c, 0x2534, 0x253c, 0x2580, 0x2584, 0x2588, 0x258c, 0x2590,
39
 
  0x2591, 0x2592, 0x2593, 0x2320, 0x25a0, 0x2219, 0x221a, 0x2248,
40
 
  0x2264, 0x2265, 0x00a0, 0x2321, 0x00b0, 0x00b2, 0x00b7, 0x00f7,
41
 
  0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556,
42
 
  0x2557, 0x2558, 0x2559, 0x255a, 0x255b, 0x255c, 0x255d, 0x255e,
43
 
  0x255f, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565,
44
 
  0x2566, 0x2567, 0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x00a9,
45
 
  0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
46
 
  0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
47
 
  0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
48
 
  0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
49
 
  0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
50
 
  0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
51
 
  0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
52
 
  0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a
53
 
};
54
 
 
55
 
static ushort latin2_unicode[128] = {
56
 
  0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
57
 
  0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
58
 
  0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
59
 
  0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
60
 
  0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
61
 
  0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
62
 
  0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
63
 
  0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
64
 
  0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
65
 
  0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
66
 
  0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
67
 
  0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
68
 
  0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
69
 
  0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
70
 
  0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
71
 
  0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
72
 
};
73
 
 
 
39
#ifndef MB_LEN_MAX
 
40
#define MB_LEN_MAX 16
 
41
#endif
74
42
 
75
43
static const char *active_charset_name = "iso-8859-1";
76
 
static ushort *active_charset = NULL;
77
 
static int no_translation = 0;
 
44
static unsigned short *active_charset;
 
45
static int no_translation;     /* Set to true if we let simply pass through. */
 
46
static int use_iconv;          /* iconv comversion fucntions required. */
 
47
 
 
48
 
 
49
/* Under W32 we dlopen the iconv dll and don't require any iconv
 
50
   related headers at all.  However we need to define some stuff.  */
 
51
#ifdef HAVE_W32_SYSTEM
 
52
typedef void *iconv_t;
 
53
#ifndef ICONV_CONST
 
54
#define ICONV_CONST const 
 
55
#endif
 
56
static iconv_t (* __stdcall iconv_open) (const char *tocode,
 
57
                                         const char *fromcode);
 
58
static size_t  (* __stdcall iconv) (iconv_t cd,
 
59
                                    const char **inbuf, size_t *inbytesleft,
 
60
                                    char **outbuf, size_t *outbytesleft);
 
61
static int     (* __stdcall iconv_close) (iconv_t cd);
 
62
 
 
63
static int 
 
64
load_libiconv (void)
 
65
{
 
66
  static int done;
 
67
  
 
68
  if (!done)
 
69
    {
 
70
      void *handle;
 
71
 
 
72
      done = 1; /* Do it right now because we might get called recursivly
 
73
                   through gettext.  */
 
74
    
 
75
      handle = dlopen ("iconv.dll", RTLD_LAZY);
 
76
      if (handle)
 
77
        {
 
78
          iconv_open  = dlsym (handle, "libiconv_open");
 
79
          if (iconv_open)
 
80
            iconv = dlsym (handle, "libiconv");
 
81
          if (iconv)    
 
82
            iconv_close = dlsym (handle, "libiconv_close");
 
83
        }
 
84
      if (!handle || !iconv_close)
 
85
        {
 
86
          log_info (_("error loading `%s': %s\n"),
 
87
                     "iconv.dll",  dlerror ());
 
88
          log_info (_("please see %s for more information\n"),
 
89
                    "http://www.gnupg.org/download/iconv.html");
 
90
          iconv_open = NULL;
 
91
          iconv = NULL;
 
92
          iconv_close = NULL;
 
93
          if (handle)
 
94
            dlclose (handle);
 
95
        }
 
96
    }
 
97
  return iconv_open? 0: -1;
 
98
}    
 
99
#endif /*HAVE_W32_SYSTEM*/
 
100
 
 
101
 
 
102
/* Error handler for iconv failures. This is needed to not clutter the
 
103
   output with repeated diagnostics about a missing conversion. */
 
104
static void
 
105
handle_iconv_error (const char *to, const char *from, int use_fallback)
 
106
{
 
107
  if (errno == EINVAL)
 
108
    {
 
109
      static int shown1, shown2;
 
110
      int x;
 
111
 
 
112
      if (to && !strcmp (to, "utf-8"))
 
113
        {
 
114
          x = shown1;
 
115
          shown1 = 1;
 
116
        }
 
117
      else
 
118
        {
 
119
          x = shown2;
 
120
          shown2 = 1;
 
121
        }
 
122
 
 
123
      if (!x)
 
124
        log_info (_("conversion from `%s' to `%s' not available\n"),
 
125
                  from, to);
 
126
    }
 
127
  else
 
128
    {
 
129
      static int shown;
 
130
 
 
131
      if (!shown)
 
132
        log_info (_("iconv_open failed: %s\n"), strerror (errno));
 
133
      shown = 1;
 
134
    }
 
135
 
 
136
  if (use_fallback)
 
137
    {
 
138
      /* To avoid further error messages we fallback to Latin-1 for the
 
139
         native encoding.  This is justified as one can expect that on a
 
140
         utf-8 enabled system nl_langinfo() will work and thus we won't
 
141
         never get to here.  Thus Latin-1 seems to be a reasonable
 
142
         default.  */
 
143
      active_charset_name = "iso-8859-1";
 
144
      no_translation = 0;
 
145
      active_charset = NULL;
 
146
      use_iconv = 0;
 
147
    }
 
148
}
 
149
 
 
150
 
78
151
 
79
152
int
80
153
set_native_charset (const char *newset)
81
154
{
82
 
  if (!newset)
 
155
  const char *full_newset;
 
156
 
 
157
  if (!newset) 
 
158
    {
 
159
#ifdef HAVE_W32_SYSTEM
 
160
      static char codepage[30];
 
161
      unsigned int cpno;
 
162
      const char *aliases;
 
163
      
 
164
      /* We are a console program thus we need to use the
 
165
         GetConsoleOutputCP function and not the the GetACP which
 
166
         would give the codepage for a GUI program.  Note this is not
 
167
         a bulletproof detection because GetConsoleCP might return a
 
168
         different one for console input.  Not sure how to cope with
 
169
         that.  If the console Code page is not known we fall back to
 
170
         the system code page.  */
 
171
      cpno = GetConsoleOutputCP ();
 
172
      if (!cpno)
 
173
        cpno = GetACP ();
 
174
      sprintf (codepage, "CP%u", cpno );
 
175
      /* Resolve alias.  We use a long string string and not the usual
 
176
         array to optimize if the code is taken to a DSO.  Taken from
 
177
         libiconv 1.9.2. */
 
178
      newset = codepage;
 
179
      for (aliases = ("CP936"   "\0" "GBK" "\0"
 
180
                      "CP1361"  "\0" "JOHAB" "\0"
 
181
                      "CP20127" "\0" "ASCII" "\0"
 
182
                      "CP20866" "\0" "KOI8-R" "\0"
 
183
                      "CP21866" "\0" "KOI8-RU" "\0"
 
184
                      "CP28591" "\0" "ISO-8859-1" "\0"
 
185
                      "CP28592" "\0" "ISO-8859-2" "\0"
 
186
                      "CP28593" "\0" "ISO-8859-3" "\0"
 
187
                      "CP28594" "\0" "ISO-8859-4" "\0"
 
188
                      "CP28595" "\0" "ISO-8859-5" "\0"
 
189
                      "CP28596" "\0" "ISO-8859-6" "\0"
 
190
                      "CP28597" "\0" "ISO-8859-7" "\0"
 
191
                      "CP28598" "\0" "ISO-8859-8" "\0"
 
192
                      "CP28599" "\0" "ISO-8859-9" "\0"
 
193
                      "CP28605" "\0" "ISO-8859-15" "\0"
 
194
                      "CP65001" "\0" "UTF-8" "\0");
 
195
           *aliases;
 
196
           aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
 
197
        {
 
198
          if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1]))
 
199
            {
 
200
              newset = aliases + strlen (aliases) + 1;
 
201
              break;
 
202
            }
 
203
        }
 
204
 
 
205
#else /*!HAVE_W32_SYSTEM*/
 
206
      
83
207
#ifdef HAVE_LANGINFO_CODESET
84
 
    newset = nl_langinfo (CODESET);
85
 
#else
86
 
    newset = "8859-1";
87
 
#endif
88
 
 
 
208
      newset = nl_langinfo (CODESET);
 
209
#else /*!HAVE_LANGINFO_CODESET*/
 
210
      /* Try to get the used charset from environment variables.  */
 
211
      static char codepage[30];
 
212
      const char *lc, *dot, *mod;
 
213
 
 
214
      strcpy (codepage, "iso-8859-1");
 
215
      lc = getenv ("LC_ALL");
 
216
      if (!lc || !*lc)
 
217
        {
 
218
          lc = getenv ("LC_CTYPE");
 
219
          if (!lc || !*lc)
 
220
            lc = getenv ("LANG");
 
221
        }
 
222
      if (lc && *lc)
 
223
        {
 
224
          dot = strchr (lc, '.');
 
225
          if (dot)
 
226
            {
 
227
              mod = strchr (++dot, '@');
 
228
              if (!mod)
 
229
                mod = dot + strlen (dot);
 
230
              if (mod - dot < sizeof codepage && dot != mod) 
 
231
                {
 
232
                  memcpy (codepage, dot, mod - dot);
 
233
                  codepage [mod - dot] = 0;
 
234
                }
 
235
            }
 
236
        }
 
237
      newset = codepage;
 
238
#endif /*!HAVE_LANGINFO_CODESET*/
 
239
#endif /*!HAVE_W32_SYSTEM*/
 
240
    }
 
241
 
 
242
  full_newset = newset;
89
243
  if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
90
244
    {
91
245
      newset += 3;
92
246
      if (*newset == '-' || *newset == '_')
93
 
        newset++;
 
247
        newset++;
94
248
    }
95
249
 
96
 
  if (!*newset
97
 
      || !ascii_strcasecmp (newset, "8859-1")
98
 
      || !ascii_strcasecmp (newset, "8859-15"))
 
250
  /* Note that we silently assume that plain ASCII is actually meant
 
251
     as Latin-1.  This makes sense because many Unix system don't have
 
252
     their locale set up properly and thus would get annoying error
 
253
     messages and we have to handle all the "bug" reports. Latin-1 has
 
254
     always been the character set used for 8 bit characters on Unix
 
255
     systems. */
 
256
  if ( !*newset
 
257
       || !ascii_strcasecmp (newset, "8859-1" )
 
258
       || !ascii_strcasecmp (newset, "646" )
 
259
       || !ascii_strcasecmp (newset, "ASCII" )
 
260
       || !ascii_strcasecmp (newset, "ANSI_X3.4-1968" )
 
261
       )
99
262
    {
100
263
      active_charset_name = "iso-8859-1";
101
264
      no_translation = 0;
102
265
      active_charset = NULL;
103
 
    }
104
 
  else if (!ascii_strcasecmp (newset, "8859-2"))
105
 
    {
106
 
      active_charset_name = "iso-8859-2";
107
 
      no_translation = 0;
108
 
      active_charset = latin2_unicode;
109
 
    }
110
 
  else if (!ascii_strcasecmp (newset, "koi8-r"))
111
 
    {
112
 
      active_charset_name = "koi8-r";
113
 
      no_translation = 0;
114
 
      active_charset = koi8_unicode;
115
 
    }
116
 
  else if (!ascii_strcasecmp (newset, "utf8")
117
 
           || !ascii_strcasecmp (newset, "utf-8"))
 
266
      use_iconv = 0;
 
267
    }
 
268
  else if ( !ascii_strcasecmp (newset, "utf8" )
 
269
            || !ascii_strcasecmp(newset, "utf-8") )
118
270
    {
119
271
      active_charset_name = "utf-8";
120
272
      no_translation = 1;
121
273
      active_charset = NULL;
 
274
      use_iconv = 0;
122
275
    }
123
276
  else
124
 
    return -1;
 
277
    {
 
278
      iconv_t cd;
 
279
      
 
280
#ifdef HAVE_W32_SYSTEM
 
281
      if (load_libiconv ())
 
282
        return -1;
 
283
#endif /*HAVE_W32_SYSTEM*/      
 
284
 
 
285
      cd = iconv_open (full_newset, "utf-8");
 
286
      if (cd == (iconv_t)-1) 
 
287
        {
 
288
          handle_iconv_error (full_newset, "utf-8", 0);
 
289
          return -1;
 
290
        }
 
291
      iconv_close (cd);
 
292
      cd = iconv_open ("utf-8", full_newset);
 
293
      if (cd == (iconv_t)-1) 
 
294
        {
 
295
          handle_iconv_error ("utf-8", full_newset, 0);
 
296
          return -1;
 
297
        }
 
298
      iconv_close (cd);
 
299
      active_charset_name = full_newset;
 
300
      no_translation = 0;
 
301
      active_charset = NULL; 
 
302
      use_iconv = 1;
 
303
    }
125
304
  return 0;
126
305
}
127
306
 
131
310
  return active_charset_name;
132
311
}
133
312
 
134
 
/****************
135
 
 * Convert string, which is in native encoding to UTF8 and return the
136
 
 * new allocated UTF8 string.
137
 
 */
 
313
/* Return true if the native charset is utf-8.  */
 
314
int 
 
315
is_native_utf8 (void)
 
316
{
 
317
  return no_translation;
 
318
}
 
319
 
 
320
 
 
321
/* Convert string, which is in native encoding to UTF8 and return a
 
322
   new allocated UTF-8 string.  */
138
323
char *
139
324
native_to_utf8 (const char *orig_string)
140
325
{
146
331
 
147
332
  if (no_translation)
148
333
    {
 
334
      /* Already utf-8 encoded. */
149
335
      buffer = jnlib_xstrdup (orig_string);
150
336
    }
151
 
  else if (active_charset)
152
 
    {
153
 
      for (s = string; *s; s++)
154
 
        {
155
 
          length++;
156
 
          if (*s & 0x80)
157
 
            length += 2;        /* we may need 3 bytes */
158
 
        }
159
 
      buffer = jnlib_xmalloc (length + 1);
160
 
      for (p = (unsigned char *)buffer, s = string; *s; s++)
161
 
        {
162
 
          if ((*s & 0x80))
163
 
            {
164
 
              ushort val = active_charset[*s & 0x7f];
165
 
              if (val < 0x0800)
166
 
                {
167
 
                  *p++ = 0xc0 | ((val >> 6) & 0x1f);
168
 
                  *p++ = 0x80 | (val & 0x3f);
169
 
                }
170
 
              else
171
 
                {
172
 
                  *p++ = 0xe0 | ((val >> 12) & 0x0f);
173
 
                  *p++ = 0x80 | ((val >> 6) & 0x3f);
174
 
                  *p++ = 0x80 | (val & 0x3f);
175
 
                }
176
 
            }
177
 
          else
178
 
            *p++ = *s;
179
 
        }
180
 
      *p = 0;
181
 
    }
182
 
  else
183
 
    {
 
337
  else if (!active_charset && !use_iconv)
 
338
    {
 
339
      /* For Latin-1 we can avoid the iconv overhead. */
184
340
      for (s = string; *s; s++)
185
341
        {
186
342
          length++;
190
346
      buffer = jnlib_xmalloc (length + 1);
191
347
      for (p = (unsigned char *)buffer, s = string; *s; s++)
192
348
        {
193
 
          if (*s & 0x80)
 
349
          if ( (*s & 0x80 ))
194
350
            {
195
351
              *p++ = 0xc0 | ((*s >> 6) & 3);
196
352
              *p++ = 0x80 | (*s & 0x3f);
200
356
        }
201
357
      *p = 0;
202
358
    }
 
359
  else
 
360
    { 
 
361
      /* Need to use iconv.  */
 
362
      iconv_t cd;
 
363
      const char *inptr;
 
364
      char *outptr;
 
365
      size_t inbytes, outbytes;
 
366
     
 
367
      cd = iconv_open ("utf-8", active_charset_name);
 
368
      if (cd == (iconv_t)-1)
 
369
        {
 
370
          handle_iconv_error ("utf-8", active_charset_name, 1);
 
371
          return native_to_utf8 (string);
 
372
        }
 
373
 
 
374
      for (s=string; *s; s++ ) 
 
375
        {
 
376
          length++;
 
377
          if ((*s & 0x80))
 
378
            length += 5; /* We may need up to 6 bytes for the utf8 output. */
 
379
        }
 
380
      buffer = jnlib_xmalloc (length + 1);
 
381
      
 
382
      inptr = string;
 
383
      inbytes = strlen (string);
 
384
      outptr = buffer;
 
385
      outbytes = length;
 
386
      if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
 
387
                  &outptr, &outbytes) == (size_t)-1)
 
388
        {
 
389
          static int shown;
 
390
 
 
391
          if (!shown)
 
392
            log_info (_("conversion from `%s' to `%s' failed: %s\n"),
 
393
                      active_charset_name, "utf-8", strerror (errno));
 
394
          shown = 1;
 
395
          /* We don't do any conversion at all but use the strings as is. */
 
396
          strcpy (buffer, string);
 
397
        }
 
398
      else /* Success.  */
 
399
        {
 
400
          *outptr = 0;
 
401
          /* We could realloc the buffer now but I doubt that it makes
 
402
             much sense given that it will get freed anyway soon
 
403
             after.  */
 
404
        }
 
405
      iconv_close (cd);
 
406
    }
203
407
  return buffer;
204
408
}
205
409
 
206
410
 
207
 
/* Convert string, which is in UTF8 to native encoding.  Replace
208
 
 * illegal encodings by some "\xnn" and quote all control
209
 
 * characters. A character with value DELIM will always be quoted, it
210
 
 * must be a vanilla ASCII character.  */
211
 
char *
212
 
utf8_to_native (const char *string, size_t length, int delim)
 
411
 
 
412
static char *
 
413
do_utf8_to_native (const char *string, size_t length, int delim,
 
414
                   int with_iconv)
213
415
{
214
416
  int nleft;
215
417
  int i;
216
418
  unsigned char encbuf[8];
217
419
  int encidx;
218
 
  const byte *s;
 
420
  const unsigned char *s;
219
421
  size_t n;
220
422
  char *buffer = NULL;
221
423
  char *p = NULL;
223
425
  size_t slen;
224
426
  int resync = 0;
225
427
 
226
 
  /* 1. pass (p==NULL): count the extended utf-8 characters */
227
 
  /* 2. pass (p!=NULL): create string */
 
428
  /* First pass (p==NULL): count the extended utf-8 characters.  */
 
429
  /* Second pass (p!=NULL): create string.  */
228
430
  for (;;)
229
431
    {
230
432
      for (slen = length, nleft = encidx = 0, n = 0,
231
 
             s = (const unsigned char *)string; slen;
 
433
             s = (const unsigned char *)string;
 
434
           slen;
232
435
           s++, slen--)
233
436
        {
234
437
          if (resync)
235
438
            {
236
439
              if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
237
440
                {
238
 
                  /* still invalid */
 
441
                  /* Still invalid. */
239
442
                  if (p)
240
443
                    {
241
444
                      sprintf (p, "\\x%02x", *s);
249
452
          if (!nleft)
250
453
            {
251
454
              if (!(*s & 0x80))
252
 
                {               /* plain ascii */
253
 
                  if (*s < 0x20 || *s == 0x7f || *s == delim ||
254
 
                      (delim && *s == '\\'))
 
455
                {       
 
456
                  /* Plain ascii. */
 
457
                  if ( delim != -1
 
458
                       && (*s < 0x20 || *s == 0x7f || *s == delim 
 
459
                           || (delim && *s == '\\')))
255
460
                    {
256
461
                      n++;
257
462
                      if (p)
258
463
                        *p++ = '\\';
259
464
                      switch (*s)
260
465
                        {
261
 
                        case '\n':
262
 
                          n++;
263
 
                          if (p)
264
 
                            *p++ = 'n';
265
 
                          break;
266
 
                        case '\r':
267
 
                          n++;
268
 
                          if (p)
269
 
                            *p++ = 'r';
270
 
                          break;
271
 
                        case '\f':
272
 
                          n++;
273
 
                          if (p)
274
 
                            *p++ = 'f';
275
 
                          break;
276
 
                        case '\v':
277
 
                          n++;
278
 
                          if (p)
279
 
                            *p++ = 'v';
280
 
                          break;
281
 
                        case '\b':
282
 
                          n++;
283
 
                          if (p)
284
 
                            *p++ = 'b';
285
 
                          break;
286
 
                        case 0:
287
 
                          n++;
288
 
                          if (p)
289
 
                            *p++ = '0';
290
 
                          break;
 
466
                        case '\n': n++; if ( p ) *p++ = 'n'; break;
 
467
                        case '\r': n++; if ( p ) *p++ = 'r'; break;
 
468
                        case '\f': n++; if ( p ) *p++ = 'f'; break;
 
469
                        case '\v': n++; if ( p ) *p++ = 'v'; break;
 
470
                        case '\b': n++; if ( p ) *p++ = 'b'; break;
 
471
                        case    0: n++; if ( p ) *p++ = '0'; break;
291
472
                        default:
292
473
                          n += 3;
293
474
                          if (p)
305
486
                      n++;
306
487
                    }
307
488
                }
308
 
              else if ((*s & 0xe0) == 0xc0)
309
 
                {               /* 110x xxxx */
 
489
              else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
 
490
                {
310
491
                  val = *s & 0x1f;
311
492
                  nleft = 1;
312
493
                  encidx = 0;
313
494
                  encbuf[encidx++] = *s;
314
495
                }
315
 
              else if ((*s & 0xf0) == 0xe0)
316
 
                {               /* 1110 xxxx */
 
496
              else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
 
497
                {       
317
498
                  val = *s & 0x0f;
318
499
                  nleft = 2;
319
500
                  encidx = 0;
320
501
                  encbuf[encidx++] = *s;
321
502
                }
322
 
              else if ((*s & 0xf8) == 0xf0)
323
 
                {               /* 1111 0xxx */
 
503
              else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
 
504
                {       
324
505
                  val = *s & 0x07;
325
506
                  nleft = 3;
326
507
                  encidx = 0;
327
508
                  encbuf[encidx++] = *s;
328
509
                }
329
 
              else if ((*s & 0xfc) == 0xf8)
330
 
                {               /* 1111 10xx */
 
510
              else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
 
511
                {       
331
512
                  val = *s & 0x03;
332
513
                  nleft = 4;
333
514
                  encidx = 0;
334
515
                  encbuf[encidx++] = *s;
335
516
                }
336
 
              else if ((*s & 0xfe) == 0xfc)
337
 
                {               /* 1111 110x */
 
517
              else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
 
518
                {               
338
519
                  val = *s & 0x01;
339
520
                  nleft = 5;
340
521
                  encidx = 0;
341
522
                  encbuf[encidx++] = *s;
342
523
                }
343
 
              else
344
 
                {               /* invalid encoding: print as \xnn */
 
524
              else /* Invalid encoding: print as \xNN. */
 
525
                {               
345
526
                  if (p)
346
527
                    {
347
528
                      sprintf (p, "\\x%02x", *s);
351
532
                  resync = 1;
352
533
                }
353
534
            }
354
 
          else if (*s < 0x80 || *s >= 0xc0)
355
 
            {                   /* invalid */
 
535
          else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
 
536
            {
356
537
              if (p)
357
538
                {
358
539
                  for (i = 0; i < encidx; i++)
373
554
              encbuf[encidx++] = *s;
374
555
              val <<= 6;
375
556
              val |= *s & 0x3f;
376
 
              if (!--nleft)
377
 
                {               /* ready */
 
557
              if (!--nleft)  /* Ready. */
 
558
                { 
378
559
                  if (no_translation)
379
560
                    {
380
561
                      if (p)
385
566
                      n += encidx;
386
567
                      encidx = 0;
387
568
                    }
388
 
                  else if (active_charset)
389
 
                    {           /* table lookup */
390
 
                      for (i = 0; i < 128; i++)
391
 
                        {
392
 
                          if (active_charset[i] == val)
393
 
                            break;
394
 
                        }
395
 
                      if (i < 128)
396
 
                        {       /* we can print this one */
397
 
                          if (p)
398
 
                            *p++ = i + 128;
399
 
                          n++;
400
 
                        }
401
 
                      else
402
 
                        {       /* we do not have a translation: print utf8 */
403
 
                          if (p)
404
 
                            {
405
 
                              for (i = 0; i < encidx; i++)
406
 
                                {
407
 
                                  sprintf (p, "\\x%02x", encbuf[i]);
408
 
                                  p += 4;
409
 
                                }
410
 
                            }
411
 
                          n += encidx * 4;
412
 
                          encidx = 0;
413
 
                        }
414
 
                    }
415
 
                  else
416
 
                    {           /* native set */
 
569
                  else if (with_iconv)
 
570
                    {
 
571
                      /* Our strategy for using iconv is a bit strange
 
572
                         but it better keeps compatibility with
 
573
                         previous versions in regard to how invalid
 
574
                         encodings are displayed.  What we do is to
 
575
                         keep the utf-8 as is and have the real
 
576
                         translation step then at the end.  Yes, I
 
577
                         know that this is ugly.  However we are short
 
578
                         of the 1.4 release and for this branch we
 
579
                         should not mess too much around with iconv
 
580
                         things.  One reason for this is that we don't
 
581
                         know enough about non-GNU iconv
 
582
                         implementation and want to minimize the risk
 
583
                         of breaking the code on too many platforms.  */
 
584
                        if ( p )
 
585
                          {
 
586
                            for (i=0; i < encidx; i++ )
 
587
                              *p++ = encbuf[i];
 
588
                          }
 
589
                        n += encidx;
 
590
                        encidx = 0;
 
591
                    }
 
592
                  else  /* Latin-1 case. */
 
593
                    {
417
594
                      if (val >= 0x80 && val < 256)
418
595
                        {
419
 
                          n++;  /* we can simply print this character */
 
596
                          /* We can simply print this character */
 
597
                          n++;  
420
598
                          if (p)
421
599
                            *p++ = val;
422
600
                        }
423
601
                      else
424
 
                        {       /* we do not have a translation: print utf8 */
 
602
                        {       
 
603
                          /* We do not have a translation: print utf8. */
425
604
                          if (p)
426
605
                            {
427
606
                              for (i = 0; i < encidx; i++)
439
618
            }
440
619
        }
441
620
      if (!buffer)
442
 
        {                       /* allocate the buffer after the first pass */
 
621
        {
 
622
          /* Allocate the buffer after the first pass. */
443
623
          buffer = p = jnlib_xmalloc (n + 1);
444
624
        }
445
 
      else
 
625
      else if (with_iconv)
 
626
        {
 
627
          /* Note: See above for comments.  */
 
628
          iconv_t cd;
 
629
          const char *inptr;
 
630
          char *outbuf, *outptr;
 
631
          size_t inbytes, outbytes;
 
632
          
 
633
          *p = 0;  /* Terminate the buffer. */
 
634
 
 
635
          cd = iconv_open (active_charset_name, "utf-8");
 
636
          if (cd == (iconv_t)-1)
 
637
            {
 
638
              handle_iconv_error (active_charset_name, "utf-8", 1);
 
639
              jnlib_free (buffer);
 
640
              return utf8_to_native (string, length, delim);
 
641
            }
 
642
 
 
643
          /* Allocate a new buffer large enough to hold all possible
 
644
             encodings. */
 
645
          n = p - buffer + 1;
 
646
          inbytes = n - 1;;
 
647
          inptr = buffer;
 
648
          outbytes = n * MB_LEN_MAX;
 
649
          if (outbytes / MB_LEN_MAX != n) 
 
650
            BUG (); /* Actually an overflow. */
 
651
          outbuf = outptr = jnlib_xmalloc (outbytes);
 
652
          if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
 
653
                      &outptr, &outbytes) == (size_t)-1) 
 
654
            {
 
655
              static int shown;
 
656
              
 
657
              if (!shown)
 
658
                log_info (_("conversion from `%s' to `%s' failed: %s\n"),
 
659
                          "utf-8", active_charset_name, strerror (errno));
 
660
              shown = 1;
 
661
              /* Didn't worked out.  Try again but without iconv.  */
 
662
              jnlib_free (buffer);
 
663
              buffer = NULL;
 
664
              jnlib_free (outbuf);
 
665
              outbuf = do_utf8_to_native (string, length, delim, 0);
 
666
            }
 
667
            else /* Success.  */
 
668
              { 
 
669
                *outptr = 0; /* Make sure it is a string. */
 
670
                /* We could realloc the buffer now but I doubt that it
 
671
                   makes much sense given that it will get freed
 
672
                   anyway soon after.  */
 
673
                jnlib_free (buffer);
 
674
              }
 
675
          iconv_close (cd);
 
676
          return outbuf;
 
677
        }
 
678
      else /* Not using iconv. */
446
679
        {
447
 
          *p = 0;               /* make a string */
 
680
          *p = 0; /* Make sure it is a string. */
448
681
          return buffer;
449
682
        }
450
683
    }
451
684
}
 
685
 
 
686
/* Convert string, which is in UTF-8 to native encoding.  Replace
 
687
   illegal encodings by some "\xnn" and quote all control
 
688
   characters. A character with value DELIM will always be quoted, it
 
689
   must be a vanilla ASCII character.  A DELIM value of -1 is special:
 
690
   it disables all quoting of control characters. */
 
691
char *
 
692
utf8_to_native (const char *string, size_t length, int delim)
 
693
{
 
694
  return do_utf8_to_native (string, length, delim, use_iconv);
 
695
}
 
696
 
 
697
 
 
698
 
 
699
 
 
700
/* Wrapper function for iconv_open, required for W32 as we dlopen that
 
701
   library on that system.  */
 
702
jnlib_iconv_t 
 
703
jnlib_iconv_open (const char *tocode, const char *fromcode)
 
704
{
 
705
#ifdef HAVE_W32_SYSTEM
 
706
  if (load_libiconv ())
 
707
    return (jnlib_iconv_t)(-1);
 
708
#endif /*HAVE_W32_SYSTEM*/      
 
709
 
 
710
  return (jnlib_iconv_t)iconv_open (tocode, fromcode);
 
711
}
 
712
 
 
713
 
 
714
/* Wrapper function for iconv, required for W32 as we dlopen that
 
715
   library on that system.  */
 
716
size_t
 
717
jnlib_iconv (jnlib_iconv_t cd,
 
718
             const char **inbuf, size_t *inbytesleft,
 
719
             char **outbuf, size_t *outbytesleft)
 
720
{
 
721
 
 
722
#ifdef HAVE_W32_SYSTEM
 
723
  if (load_libiconv ())
 
724
    return 0;
 
725
#endif /*HAVE_W32_SYSTEM*/      
 
726
 
 
727
  return iconv ((iconv_t)cd, (char**)inbuf, inbytesleft, outbuf, outbytesleft);
 
728
}
 
729
 
 
730
/* Wrapper function for iconv_close, required for W32 as we dlopen that
 
731
   library on that system.  */
 
732
int
 
733
jnlib_iconv_close (jnlib_iconv_t cd)
 
734
{
 
735
#ifdef HAVE_W32_SYSTEM
 
736
  if (load_libiconv ())
 
737
    return 0;
 
738
#endif /*HAVE_W32_SYSTEM*/      
 
739
 
 
740
  return iconv_close ((iconv_t)cd);
 
741
}