Changed to GPLv3.
[gnupg.git] / jnlib / utf8conv.c
1 /* utf8conf.c -  UTF8 character set conversion
2  * Copyright (C) 1994, 1998, 1999, 2000, 2001,
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/>.
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 #ifndef HAVE_W32_SYSTEM
31 # include <iconv.h>
32 #endif
33
34 #include "libjnlib-config.h"
35 #include "stringhelp.h"
36 #include "dynload.h"
37 #include "utf8conv.h"
38
39 #ifndef MB_LEN_MAX
40 #define MB_LEN_MAX 16
41 #endif
42
43 static const char *active_charset_name = "iso-8859-1";
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
151
152 int
153 set_native_charset (const char *newset)
154 {
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       
207 #ifdef HAVE_LANGINFO_CODESET
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;
243   if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
244     {
245       newset += 3;
246       if (*newset == '-' || *newset == '_')
247         newset++;
248     }
249
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        )
262     {
263       active_charset_name = "iso-8859-1";
264       no_translation = 0;
265       active_charset = NULL;
266       use_iconv = 0;
267     }
268   else if ( !ascii_strcasecmp (newset, "utf8" )
269             || !ascii_strcasecmp(newset, "utf-8") )
270     {
271       active_charset_name = "utf-8";
272       no_translation = 1;
273       active_charset = NULL;
274       use_iconv = 0;
275     }
276   else
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     }
304   return 0;
305 }
306
307 const char *
308 get_native_charset ()
309 {
310   return active_charset_name;
311 }
312
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.  */
323 char *
324 native_to_utf8 (const char *orig_string)
325 {
326   const unsigned char *string = (const unsigned char *)orig_string;
327   const unsigned char *s;
328   char *buffer;
329   unsigned char *p;
330   size_t length = 0;
331
332   if (no_translation)
333     {
334       /* Already utf-8 encoded. */
335       buffer = jnlib_xstrdup (orig_string);
336     }
337   else if (!active_charset && !use_iconv)
338     {
339       /* For Latin-1 we can avoid the iconv overhead. */
340       for (s = string; *s; s++)
341         {
342           length++;
343           if (*s & 0x80)
344             length++;
345         }
346       buffer = jnlib_xmalloc (length + 1);
347       for (p = (unsigned char *)buffer, s = string; *s; s++)
348         {
349           if ( (*s & 0x80 ))
350             {
351               *p++ = 0xc0 | ((*s >> 6) & 3);
352               *p++ = 0x80 | (*s & 0x3f);
353             }
354           else
355             *p++ = *s;
356         }
357       *p = 0;
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     }
407   return buffer;
408 }
409
410
411
412 static char *
413 do_utf8_to_native (const char *string, size_t length, int delim,
414                    int with_iconv)
415 {
416   int nleft;
417   int i;
418   unsigned char encbuf[8];
419   int encidx;
420   const unsigned char *s;
421   size_t n;
422   char *buffer = NULL;
423   char *p = NULL;
424   unsigned long val = 0;
425   size_t slen;
426   int resync = 0;
427
428   /* First pass (p==NULL): count the extended utf-8 characters.  */
429   /* Second pass (p!=NULL): create string.  */
430   for (;;)
431     {
432       for (slen = length, nleft = encidx = 0, n = 0,
433              s = (const unsigned char *)string;
434            slen;
435            s++, slen--)
436         {
437           if (resync)
438             {
439               if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
440                 {
441                   /* Still invalid. */
442                   if (p)
443                     {
444                       sprintf (p, "\\x%02x", *s);
445                       p += 4;
446                     }
447                   n += 4;
448                   continue;
449                 }
450               resync = 0;
451             }
452           if (!nleft)
453             {
454               if (!(*s & 0x80))
455                 {       
456                   /* Plain ascii. */
457                   if ( delim != -1
458                        && (*s < 0x20 || *s == 0x7f || *s == delim 
459                            || (delim && *s == '\\')))
460                     {
461                       n++;
462                       if (p)
463                         *p++ = '\\';
464                       switch (*s)
465                         {
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;
472                         default:
473                           n += 3;
474                           if (p)
475                             {
476                               sprintf (p, "x%02x", *s);
477                               p += 3;
478                             }
479                           break;
480                         }
481                     }
482                   else
483                     {
484                       if (p)
485                         *p++ = *s;
486                       n++;
487                     }
488                 }
489               else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
490                 {
491                   val = *s & 0x1f;
492                   nleft = 1;
493                   encidx = 0;
494                   encbuf[encidx++] = *s;
495                 }
496               else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
497                 {       
498                   val = *s & 0x0f;
499                   nleft = 2;
500                   encidx = 0;
501                   encbuf[encidx++] = *s;
502                 }
503               else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
504                 {       
505                   val = *s & 0x07;
506                   nleft = 3;
507                   encidx = 0;
508                   encbuf[encidx++] = *s;
509                 }
510               else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
511                 {       
512                   val = *s & 0x03;
513                   nleft = 4;
514                   encidx = 0;
515                   encbuf[encidx++] = *s;
516                 }
517               else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
518                 {               
519                   val = *s & 0x01;
520                   nleft = 5;
521                   encidx = 0;
522                   encbuf[encidx++] = *s;
523                 }
524               else /* Invalid encoding: print as \xNN. */
525                 {               
526                   if (p)
527                     {
528                       sprintf (p, "\\x%02x", *s);
529                       p += 4;
530                     }
531                   n += 4;
532                   resync = 1;
533                 }
534             }
535           else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
536             {
537               if (p)
538                 {
539                   for (i = 0; i < encidx; i++)
540                     {
541                       sprintf (p, "\\x%02x", encbuf[i]);
542                       p += 4;
543                     }
544                   sprintf (p, "\\x%02x", *s);
545                   p += 4;
546                 }
547               n += 4 + 4 * encidx;
548               nleft = 0;
549               encidx = 0;
550               resync = 1;
551             }
552           else
553             {
554               encbuf[encidx++] = *s;
555               val <<= 6;
556               val |= *s & 0x3f;
557               if (!--nleft)  /* Ready. */
558                 { 
559                   if (no_translation)
560                     {
561                       if (p)
562                         {
563                           for (i = 0; i < encidx; i++)
564                             *p++ = encbuf[i];
565                         }
566                       n += encidx;
567                       encidx = 0;
568                     }
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                     {
594                       if (val >= 0x80 && val < 256)
595                         {
596                           /* We can simply print this character */
597                           n++;  
598                           if (p)
599                             *p++ = val;
600                         }
601                       else
602                         {       
603                           /* We do not have a translation: print utf8. */
604                           if (p)
605                             {
606                               for (i = 0; i < encidx; i++)
607                                 {
608                                   sprintf (p, "\\x%02x", encbuf[i]);
609                                   p += 4;
610                                 }
611                             }
612                           n += encidx * 4;
613                           encidx = 0;
614                         }
615                     }
616                 }
617
618             }
619         }
620       if (!buffer)
621         {
622           /* Allocate the buffer after the first pass. */
623           buffer = p = jnlib_xmalloc (n + 1);
624         }
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. */
679         {
680           *p = 0; /* Make sure it is a string. */
681           return buffer;
682         }
683     }
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 }