g10: Fix card-edit/fetch to use keyserver_fetch.
[gnupg.git] / jnlib / utf8conv.c
1 /* utf8conf.c -  UTF8 character set conversion
2  * Copyright (C) 1994, 1998, 1999, 2000, 2001,
3  *               2003, 2006, 2008  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/>.
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26 #ifdef HAVE_LANGINFO_CODESET
27 #include <langinfo.h>
28 #endif
29 #include <errno.h>
30 #include <iconv.h>
31
32 #include "libjnlib-config.h"
33 #include "stringhelp.h"
34 #include "dynload.h"
35 #include "utf8conv.h"
36
37 #ifndef MB_LEN_MAX
38 #define MB_LEN_MAX 16
39 #endif
40
41 static const char *active_charset_name = "iso-8859-1";
42 static int no_translation;     /* Set to true if we let simply pass through. */
43 static int use_iconv;          /* iconv comversion fucntions required. */
44
45
46 /* Error handler for iconv failures. This is needed to not clutter the
47    output with repeated diagnostics about a missing conversion. */
48 static void
49 handle_iconv_error (const char *to, const char *from, int use_fallback)
50 {
51   if (errno == EINVAL)
52     {
53       static int shown1, shown2;
54       int x;
55
56       if (to && !strcmp (to, "utf-8"))
57         {
58           x = shown1;
59           shown1 = 1;
60         }
61       else
62         {
63           x = shown2;
64           shown2 = 1;
65         }
66
67       if (!x)
68         log_info (_("conversion from `%s' to `%s' not available\n"),
69                   from, to);
70     }
71   else
72     {
73       static int shown;
74
75       if (!shown)
76         log_info (_("iconv_open failed: %s\n"), strerror (errno));
77       shown = 1;
78     }
79
80   if (use_fallback)
81     {
82       /* To avoid further error messages we fallback to Latin-1 for the
83          native encoding.  This is justified as one can expect that on a
84          utf-8 enabled system nl_langinfo() will work and thus we won't
85          never get to here.  Thus Latin-1 seems to be a reasonable
86          default.  */
87       active_charset_name = "iso-8859-1";
88       no_translation = 0;
89       use_iconv = 0;
90     }
91 }
92
93
94
95 int
96 set_native_charset (const char *newset)
97 {
98   const char *full_newset;
99
100   if (!newset)
101     {
102 #ifdef HAVE_W32_SYSTEM
103       static char codepage[30];
104       unsigned int cpno;
105       const char *aliases;
106
107       /* We are a console program thus we need to use the
108          GetConsoleOutputCP function and not the the GetACP which
109          would give the codepage for a GUI program.  Note this is not
110          a bulletproof detection because GetConsoleCP might return a
111          different one for console input.  Not sure how to cope with
112          that.  If the console Code page is not known we fall back to
113          the system code page.  */
114       cpno = GetConsoleOutputCP ();
115       if (!cpno)
116         cpno = GetACP ();
117       sprintf (codepage, "CP%u", cpno );
118       /* Resolve alias.  We use a long string string and not the usual
119          array to optimize if the code is taken to a DSO.  Taken from
120          libiconv 1.9.2. */
121       newset = codepage;
122       for (aliases = ("CP936"   "\0" "GBK" "\0"
123                       "CP1361"  "\0" "JOHAB" "\0"
124                       "CP20127" "\0" "ASCII" "\0"
125                       "CP20866" "\0" "KOI8-R" "\0"
126                       "CP21866" "\0" "KOI8-RU" "\0"
127                       "CP28591" "\0" "ISO-8859-1" "\0"
128                       "CP28592" "\0" "ISO-8859-2" "\0"
129                       "CP28593" "\0" "ISO-8859-3" "\0"
130                       "CP28594" "\0" "ISO-8859-4" "\0"
131                       "CP28595" "\0" "ISO-8859-5" "\0"
132                       "CP28596" "\0" "ISO-8859-6" "\0"
133                       "CP28597" "\0" "ISO-8859-7" "\0"
134                       "CP28598" "\0" "ISO-8859-8" "\0"
135                       "CP28599" "\0" "ISO-8859-9" "\0"
136                       "CP28605" "\0" "ISO-8859-15" "\0"
137                       "CP65001" "\0" "UTF-8" "\0");
138            *aliases;
139            aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
140         {
141           if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1]))
142             {
143               newset = aliases + strlen (aliases) + 1;
144               break;
145             }
146         }
147
148 #else /*!HAVE_W32_SYSTEM*/
149
150 #ifdef HAVE_LANGINFO_CODESET
151       newset = nl_langinfo (CODESET);
152 #else /*!HAVE_LANGINFO_CODESET*/
153       /* Try to get the used charset from environment variables.  */
154       static char codepage[30];
155       const char *lc, *dot, *mod;
156
157       strcpy (codepage, "iso-8859-1");
158       lc = getenv ("LC_ALL");
159       if (!lc || !*lc)
160         {
161           lc = getenv ("LC_CTYPE");
162           if (!lc || !*lc)
163             lc = getenv ("LANG");
164         }
165       if (lc && *lc)
166         {
167           dot = strchr (lc, '.');
168           if (dot)
169             {
170               mod = strchr (++dot, '@');
171               if (!mod)
172                 mod = dot + strlen (dot);
173               if (mod - dot < sizeof codepage && dot != mod)
174                 {
175                   memcpy (codepage, dot, mod - dot);
176                   codepage [mod - dot] = 0;
177                 }
178             }
179         }
180       newset = codepage;
181 #endif /*!HAVE_LANGINFO_CODESET*/
182 #endif /*!HAVE_W32_SYSTEM*/
183     }
184
185   full_newset = newset;
186   if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
187     {
188       newset += 3;
189       if (*newset == '-' || *newset == '_')
190         newset++;
191     }
192
193   /* Note that we silently assume that plain ASCII is actually meant
194      as Latin-1.  This makes sense because many Unix system don't have
195      their locale set up properly and thus would get annoying error
196      messages and we have to handle all the "bug" reports. Latin-1 has
197      always been the character set used for 8 bit characters on Unix
198      systems. */
199   if ( !*newset
200        || !ascii_strcasecmp (newset, "8859-1" )
201        || !ascii_strcasecmp (newset, "646" )
202        || !ascii_strcasecmp (newset, "ASCII" )
203        || !ascii_strcasecmp (newset, "ANSI_X3.4-1968" )
204        )
205     {
206       active_charset_name = "iso-8859-1";
207       no_translation = 0;
208       use_iconv = 0;
209     }
210   else if ( !ascii_strcasecmp (newset, "utf8" )
211             || !ascii_strcasecmp(newset, "utf-8") )
212     {
213       active_charset_name = "utf-8";
214       no_translation = 1;
215       use_iconv = 0;
216     }
217   else
218     {
219       iconv_t cd;
220
221       cd = iconv_open (full_newset, "utf-8");
222       if (cd == (iconv_t)-1)
223         {
224           handle_iconv_error (full_newset, "utf-8", 0);
225           return -1;
226         }
227       iconv_close (cd);
228       cd = iconv_open ("utf-8", full_newset);
229       if (cd == (iconv_t)-1)
230         {
231           handle_iconv_error ("utf-8", full_newset, 0);
232           return -1;
233         }
234       iconv_close (cd);
235       active_charset_name = full_newset;
236       no_translation = 0;
237       use_iconv = 1;
238     }
239   return 0;
240 }
241
242 const char *
243 get_native_charset ()
244 {
245   return active_charset_name;
246 }
247
248 /* Return true if the native charset is utf-8.  */
249 int
250 is_native_utf8 (void)
251 {
252   return no_translation;
253 }
254
255
256 /* Convert string, which is in native encoding to UTF8 and return a
257    new allocated UTF-8 string.  This function terminates the process
258    on memory shortage.  */
259 char *
260 native_to_utf8 (const char *orig_string)
261 {
262   const unsigned char *string = (const unsigned char *)orig_string;
263   const unsigned char *s;
264   char *buffer;
265   unsigned char *p;
266   size_t length = 0;
267
268   if (no_translation)
269     {
270       /* Already utf-8 encoded. */
271       buffer = jnlib_xstrdup (orig_string);
272     }
273   else if (!use_iconv)
274     {
275       /* For Latin-1 we can avoid the iconv overhead. */
276       for (s = string; *s; s++)
277         {
278           length++;
279           if (*s & 0x80)
280             length++;
281         }
282       buffer = jnlib_xmalloc (length + 1);
283       for (p = (unsigned char *)buffer, s = string; *s; s++)
284         {
285           if ( (*s & 0x80 ))
286             {
287               *p++ = 0xc0 | ((*s >> 6) & 3);
288               *p++ = 0x80 | (*s & 0x3f);
289             }
290           else
291             *p++ = *s;
292         }
293       *p = 0;
294     }
295   else
296     {
297       /* Need to use iconv.  */
298       iconv_t cd;
299       const char *inptr;
300       char *outptr;
301       size_t inbytes, outbytes;
302
303       cd = iconv_open ("utf-8", active_charset_name);
304       if (cd == (iconv_t)-1)
305         {
306           handle_iconv_error ("utf-8", active_charset_name, 1);
307           return native_to_utf8 (string);
308         }
309
310       for (s=string; *s; s++ )
311         {
312           length++;
313           if ((*s & 0x80))
314             length += 5; /* We may need up to 6 bytes for the utf8 output. */
315         }
316       buffer = jnlib_xmalloc (length + 1);
317
318       inptr = string;
319       inbytes = strlen (string);
320       outptr = buffer;
321       outbytes = length;
322       if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
323                   &outptr, &outbytes) == (size_t)-1)
324         {
325           static int shown;
326
327           if (!shown)
328             log_info (_("conversion from `%s' to `%s' failed: %s\n"),
329                       active_charset_name, "utf-8", strerror (errno));
330           shown = 1;
331           /* We don't do any conversion at all but use the strings as is. */
332           strcpy (buffer, string);
333         }
334       else /* Success.  */
335         {
336           *outptr = 0;
337           /* We could realloc the buffer now but I doubt that it makes
338              much sense given that it will get freed anyway soon
339              after.  */
340         }
341       iconv_close (cd);
342     }
343   return buffer;
344 }
345
346
347
348 static char *
349 do_utf8_to_native (const char *string, size_t length, int delim,
350                    int with_iconv)
351 {
352   int nleft;
353   int i;
354   unsigned char encbuf[8];
355   int encidx;
356   const unsigned char *s;
357   size_t n;
358   char *buffer = NULL;
359   char *p = NULL;
360   unsigned long val = 0;
361   size_t slen;
362   int resync = 0;
363
364   /* First pass (p==NULL): count the extended utf-8 characters.  */
365   /* Second pass (p!=NULL): create string.  */
366   for (;;)
367     {
368       for (slen = length, nleft = encidx = 0, n = 0,
369              s = (const unsigned char *)string;
370            slen;
371            s++, slen--)
372         {
373           if (resync)
374             {
375               if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
376                 {
377                   /* Still invalid. */
378                   if (p)
379                     {
380                       sprintf (p, "\\x%02x", *s);
381                       p += 4;
382                     }
383                   n += 4;
384                   continue;
385                 }
386               resync = 0;
387             }
388           if (!nleft)
389             {
390               if (!(*s & 0x80))
391                 {
392                   /* Plain ascii. */
393                   if ( delim != -1
394                        && (*s < 0x20 || *s == 0x7f || *s == delim
395                            || (delim && *s == '\\')))
396                     {
397                       n++;
398                       if (p)
399                         *p++ = '\\';
400                       switch (*s)
401                         {
402                         case '\n': n++; if ( p ) *p++ = 'n'; break;
403                         case '\r': n++; if ( p ) *p++ = 'r'; break;
404                         case '\f': n++; if ( p ) *p++ = 'f'; break;
405                         case '\v': n++; if ( p ) *p++ = 'v'; break;
406                         case '\b': n++; if ( p ) *p++ = 'b'; break;
407                         case    0: n++; if ( p ) *p++ = '0'; break;
408                         default:
409                           n += 3;
410                           if (p)
411                             {
412                               sprintf (p, "x%02x", *s);
413                               p += 3;
414                             }
415                           break;
416                         }
417                     }
418                   else
419                     {
420                       if (p)
421                         *p++ = *s;
422                       n++;
423                     }
424                 }
425               else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
426                 {
427                   val = *s & 0x1f;
428                   nleft = 1;
429                   encidx = 0;
430                   encbuf[encidx++] = *s;
431                 }
432               else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
433                 {
434                   val = *s & 0x0f;
435                   nleft = 2;
436                   encidx = 0;
437                   encbuf[encidx++] = *s;
438                 }
439               else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
440                 {
441                   val = *s & 0x07;
442                   nleft = 3;
443                   encidx = 0;
444                   encbuf[encidx++] = *s;
445                 }
446               else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
447                 {
448                   val = *s & 0x03;
449                   nleft = 4;
450                   encidx = 0;
451                   encbuf[encidx++] = *s;
452                 }
453               else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
454                 {
455                   val = *s & 0x01;
456                   nleft = 5;
457                   encidx = 0;
458                   encbuf[encidx++] = *s;
459                 }
460               else /* Invalid encoding: print as \xNN. */
461                 {
462                   if (p)
463                     {
464                       sprintf (p, "\\x%02x", *s);
465                       p += 4;
466                     }
467                   n += 4;
468                   resync = 1;
469                 }
470             }
471           else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
472             {
473               if (p)
474                 {
475                   for (i = 0; i < encidx; i++)
476                     {
477                       sprintf (p, "\\x%02x", encbuf[i]);
478                       p += 4;
479                     }
480                   sprintf (p, "\\x%02x", *s);
481                   p += 4;
482                 }
483               n += 4 + 4 * encidx;
484               nleft = 0;
485               encidx = 0;
486               resync = 1;
487             }
488           else
489             {
490               encbuf[encidx++] = *s;
491               val <<= 6;
492               val |= *s & 0x3f;
493               if (!--nleft)  /* Ready. */
494                 {
495                   if (no_translation)
496                     {
497                       if (p)
498                         {
499                           for (i = 0; i < encidx; i++)
500                             *p++ = encbuf[i];
501                         }
502                       n += encidx;
503                       encidx = 0;
504                     }
505                   else if (with_iconv)
506                     {
507                       /* Our strategy for using iconv is a bit strange
508                          but it better keeps compatibility with
509                          previous versions in regard to how invalid
510                          encodings are displayed.  What we do is to
511                          keep the utf-8 as is and have the real
512                          translation step then at the end.  Yes, I
513                          know that this is ugly.  However we are short
514                          of the 1.4 release and for this branch we
515                          should not mess too much around with iconv
516                          things.  One reason for this is that we don't
517                          know enough about non-GNU iconv
518                          implementation and want to minimize the risk
519                          of breaking the code on too many platforms.  */
520                         if ( p )
521                           {
522                             for (i=0; i < encidx; i++ )
523                               *p++ = encbuf[i];
524                           }
525                         n += encidx;
526                         encidx = 0;
527                     }
528                   else  /* Latin-1 case. */
529                     {
530                       if (val >= 0x80 && val < 256)
531                         {
532                           /* We can simply print this character */
533                           n++;
534                           if (p)
535                             *p++ = val;
536                         }
537                       else
538                         {
539                           /* We do not have a translation: print utf8. */
540                           if (p)
541                             {
542                               for (i = 0; i < encidx; i++)
543                                 {
544                                   sprintf (p, "\\x%02x", encbuf[i]);
545                                   p += 4;
546                                 }
547                             }
548                           n += encidx * 4;
549                           encidx = 0;
550                         }
551                     }
552                 }
553
554             }
555         }
556       if (!buffer)
557         {
558           /* Allocate the buffer after the first pass. */
559           buffer = p = jnlib_xmalloc (n + 1);
560         }
561       else if (with_iconv)
562         {
563           /* Note: See above for comments.  */
564           iconv_t cd;
565           const char *inptr;
566           char *outbuf, *outptr;
567           size_t inbytes, outbytes;
568
569           *p = 0;  /* Terminate the buffer. */
570
571           cd = iconv_open (active_charset_name, "utf-8");
572           if (cd == (iconv_t)-1)
573             {
574               handle_iconv_error (active_charset_name, "utf-8", 1);
575               jnlib_free (buffer);
576               return utf8_to_native (string, length, delim);
577             }
578
579           /* Allocate a new buffer large enough to hold all possible
580              encodings. */
581           n = p - buffer + 1;
582           inbytes = n - 1;;
583           inptr = buffer;
584           outbytes = n * MB_LEN_MAX;
585           if (outbytes / MB_LEN_MAX != n)
586             BUG (); /* Actually an overflow. */
587           outbuf = outptr = jnlib_xmalloc (outbytes);
588           if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
589                       &outptr, &outbytes) == (size_t)-1)
590             {
591               static int shown;
592
593               if (!shown)
594                 log_info (_("conversion from `%s' to `%s' failed: %s\n"),
595                           "utf-8", active_charset_name, strerror (errno));
596               shown = 1;
597               /* Didn't worked out.  Try again but without iconv.  */
598               jnlib_free (buffer);
599               buffer = NULL;
600               jnlib_free (outbuf);
601               outbuf = do_utf8_to_native (string, length, delim, 0);
602             }
603             else /* Success.  */
604               {
605                 *outptr = 0; /* Make sure it is a string. */
606                 /* We could realloc the buffer now but I doubt that it
607                    makes much sense given that it will get freed
608                    anyway soon after.  */
609                 jnlib_free (buffer);
610               }
611           iconv_close (cd);
612           return outbuf;
613         }
614       else /* Not using iconv. */
615         {
616           *p = 0; /* Make sure it is a string. */
617           return buffer;
618         }
619     }
620 }
621
622 /* Convert string, which is in UTF-8 to native encoding.  Replace
623    illegal encodings by some "\xnn" and quote all control
624    characters. A character with value DELIM will always be quoted, it
625    must be a vanilla ASCII character.  A DELIM value of -1 is special:
626    it disables all quoting of control characters.  This function
627    terminates the process on memory shortage.  */
628 char *
629 utf8_to_native (const char *string, size_t length, int delim)
630 {
631   return do_utf8_to_native (string, length, delim, use_iconv);
632 }
633
634
635
636
637 /* Wrapper function for iconv_open, formerly required for W32 as we
638    used to dlopen that library on that system.  */
639 jnlib_iconv_t
640 jnlib_iconv_open (const char *tocode, const char *fromcode)
641 {
642   return (jnlib_iconv_t)iconv_open (tocode, fromcode);
643 }
644
645
646 /* Wrapper function for iconv, formerly required for W32 as we used to
647    dlopen that library on that system.  */
648 size_t
649 jnlib_iconv (jnlib_iconv_t cd,
650              const char **inbuf, size_t *inbytesleft,
651              char **outbuf, size_t *outbytesleft)
652 {
653   return iconv ((iconv_t)cd, (char**)inbuf, inbytesleft, outbuf, outbytesleft);
654 }
655
656 /* Wrapper function for iconv_close, formerly required for W32 as we
657    used to dlopen that library on that system.  */
658 int
659 jnlib_iconv_close (jnlib_iconv_t cd)
660 {
661   return iconv_close ((iconv_t)cd);
662 }