Fix bug 326747, Alberto Ruiz:
[platform/upstream/glib.git] / glib / gconvert.c
1 /* GLIB - Library of useful routines for C programming
2  *
3  * gconvert.c: Convert between character sets using iconv
4  * Copyright Red Hat Inc., 2000
5  * Authors: Havoc Pennington <hp@redhat.com>, Owen Taylor <otaylor@redhat.com
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 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 library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24
25 #include <iconv.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include "glib.h"
32 #include "gprintfint.h"
33 #include "gthreadinit.h"
34
35 #ifdef G_PLATFORM_WIN32
36 #define STRICT
37 #include <windows.h>
38 #undef STRICT
39 #endif
40
41 #include "glibintl.h"
42
43 #if defined(USE_LIBICONV_GNU) && !defined (_LIBICONV_H)
44 #error GNU libiconv in use but included iconv.h not from libiconv
45 #endif
46 #if !defined(USE_LIBICONV_GNU) && defined (_LIBICONV_H)
47 #error GNU libiconv not in use but included iconv.h is from libiconv
48 #endif
49
50 #include "galias.h"
51
52 GQuark 
53 g_convert_error_quark (void)
54 {
55   static GQuark quark;
56   if (!quark)
57     quark = g_quark_from_static_string ("g_convert_error");
58
59   return quark;
60 }
61
62 static gboolean
63 try_conversion (const char *to_codeset,
64                 const char *from_codeset,
65                 iconv_t    *cd)
66 {
67   *cd = iconv_open (to_codeset, from_codeset);
68
69   if (*cd == (iconv_t)-1 && errno == EINVAL)
70     return FALSE;
71   else
72     return TRUE;
73 }
74
75 static gboolean
76 try_to_aliases (const char **to_aliases,
77                 const char  *from_codeset,
78                 iconv_t     *cd)
79 {
80   if (to_aliases)
81     {
82       const char **p = to_aliases;
83       while (*p)
84         {
85           if (try_conversion (*p, from_codeset, cd))
86             return TRUE;
87
88           p++;
89         }
90     }
91
92   return FALSE;
93 }
94
95 extern const char **_g_charset_get_aliases (const char *canonical_name) G_GNUC_INTERNAL;
96
97 /**
98  * g_iconv_open:
99  * @to_codeset: destination codeset
100  * @from_codeset: source codeset
101  * 
102  * Same as the standard UNIX routine iconv_open(), but
103  * may be implemented via libiconv on UNIX flavors that lack
104  * a native implementation.
105  * 
106  * GLib provides g_convert() and g_locale_to_utf8() which are likely
107  * more convenient than the raw iconv wrappers.
108  * 
109  * Return value: a "conversion descriptor", or (GIConv)-1 if
110  *  opening the converter failed.
111  **/
112 GIConv
113 g_iconv_open (const gchar  *to_codeset,
114               const gchar  *from_codeset)
115 {
116   iconv_t cd;
117   
118   if (!try_conversion (to_codeset, from_codeset, &cd))
119     {
120       const char **to_aliases = _g_charset_get_aliases (to_codeset);
121       const char **from_aliases = _g_charset_get_aliases (from_codeset);
122
123       if (from_aliases)
124         {
125           const char **p = from_aliases;
126           while (*p)
127             {
128               if (try_conversion (to_codeset, *p, &cd))
129                 goto out;
130
131               if (try_to_aliases (to_aliases, *p, &cd))
132                 goto out;
133
134               p++;
135             }
136         }
137
138       if (try_to_aliases (to_aliases, from_codeset, &cd))
139         goto out;
140     }
141
142  out:
143   return (cd == (iconv_t)-1) ? (GIConv)-1 : (GIConv)cd;
144 }
145
146 /**
147  * g_iconv:
148  * @converter: conversion descriptor from g_iconv_open()
149  * @inbuf: bytes to convert
150  * @inbytes_left: inout parameter, bytes remaining to convert in @inbuf
151  * @outbuf: converted output bytes
152  * @outbytes_left: inout parameter, bytes available to fill in @outbuf
153  * 
154  * Same as the standard UNIX routine iconv(), but
155  * may be implemented via libiconv on UNIX flavors that lack
156  * a native implementation.
157  *
158  * GLib provides g_convert() and g_locale_to_utf8() which are likely
159  * more convenient than the raw iconv wrappers.
160  * 
161  * Return value: count of non-reversible conversions, or -1 on error
162  **/
163 size_t 
164 g_iconv (GIConv   converter,
165          gchar  **inbuf,
166          gsize   *inbytes_left,
167          gchar  **outbuf,
168          gsize   *outbytes_left)
169 {
170   iconv_t cd = (iconv_t)converter;
171
172   return iconv (cd, inbuf, inbytes_left, outbuf, outbytes_left);
173 }
174
175 /**
176  * g_iconv_close:
177  * @converter: a conversion descriptor from g_iconv_open()
178  *
179  * Same as the standard UNIX routine iconv_close(), but
180  * may be implemented via libiconv on UNIX flavors that lack
181  * a native implementation. Should be called to clean up
182  * the conversion descriptor from g_iconv_open() when
183  * you are done converting things.
184  *
185  * GLib provides g_convert() and g_locale_to_utf8() which are likely
186  * more convenient than the raw iconv wrappers.
187  * 
188  * Return value: -1 on error, 0 on success
189  **/
190 gint
191 g_iconv_close (GIConv converter)
192 {
193   iconv_t cd = (iconv_t)converter;
194
195   return iconv_close (cd);
196 }
197
198
199 #ifdef NEED_ICONV_CACHE
200
201 #define ICONV_CACHE_SIZE   (16)
202
203 struct _iconv_cache_bucket {
204   gchar *key;
205   guint32 refcount;
206   gboolean used;
207   GIConv cd;
208 };
209
210 static GList *iconv_cache_list;
211 static GHashTable *iconv_cache;
212 static GHashTable *iconv_open_hash;
213 static guint iconv_cache_size = 0;
214 G_LOCK_DEFINE_STATIC (iconv_cache_lock);
215
216 /* caller *must* hold the iconv_cache_lock */
217 static void
218 iconv_cache_init (void)
219 {
220   static gboolean initialized = FALSE;
221   
222   if (initialized)
223     return;
224   
225   iconv_cache_list = NULL;
226   iconv_cache = g_hash_table_new (g_str_hash, g_str_equal);
227   iconv_open_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
228   
229   initialized = TRUE;
230 }
231
232
233 /**
234  * iconv_cache_bucket_new:
235  * @key: cache key
236  * @cd: iconv descriptor
237  *
238  * Creates a new cache bucket, inserts it into the cache and
239  * increments the cache size.
240  *
241  * Returns a pointer to the newly allocated cache bucket.
242  **/
243 static struct _iconv_cache_bucket *
244 iconv_cache_bucket_new (const gchar *key, GIConv cd)
245 {
246   struct _iconv_cache_bucket *bucket;
247   
248   bucket = g_new (struct _iconv_cache_bucket, 1);
249   bucket->key = g_strdup (key);
250   bucket->refcount = 1;
251   bucket->used = TRUE;
252   bucket->cd = cd;
253   
254   g_hash_table_insert (iconv_cache, bucket->key, bucket);
255   
256   /* FIXME: if we sorted the list so items with few refcounts were
257      first, then we could expire them faster in iconv_cache_expire_unused () */
258   iconv_cache_list = g_list_prepend (iconv_cache_list, bucket);
259   
260   iconv_cache_size++;
261   
262   return bucket;
263 }
264
265
266 /**
267  * iconv_cache_bucket_expire:
268  * @node: cache bucket's node
269  * @bucket: cache bucket
270  *
271  * Expires a single cache bucket @bucket. This should only ever be
272  * called on a bucket that currently has no used iconv descriptors
273  * open.
274  *
275  * @node is not a required argument. If @node is not supplied, we
276  * search for it ourselves.
277  **/
278 static void
279 iconv_cache_bucket_expire (GList *node, struct _iconv_cache_bucket *bucket)
280 {
281   g_hash_table_remove (iconv_cache, bucket->key);
282   
283   if (node == NULL)
284     node = g_list_find (iconv_cache_list, bucket);
285   
286   g_assert (node != NULL);
287   
288   if (node->prev)
289     {
290       node->prev->next = node->next;
291       if (node->next)
292         node->next->prev = node->prev;
293     }
294   else
295     {
296       iconv_cache_list = node->next;
297       if (node->next)
298         node->next->prev = NULL;
299     }
300   
301   g_list_free_1 (node);
302   
303   g_free (bucket->key);
304   g_iconv_close (bucket->cd);
305   g_free (bucket);
306   
307   iconv_cache_size--;
308 }
309
310
311 /**
312  * iconv_cache_expire_unused:
313  *
314  * Expires as many unused cache buckets as it needs to in order to get
315  * the total number of buckets < ICONV_CACHE_SIZE.
316  **/
317 static void
318 iconv_cache_expire_unused (void)
319 {
320   struct _iconv_cache_bucket *bucket;
321   GList *node, *next;
322   
323   node = iconv_cache_list;
324   while (node && iconv_cache_size >= ICONV_CACHE_SIZE)
325     {
326       next = node->next;
327       
328       bucket = node->data;
329       if (bucket->refcount == 0)
330         iconv_cache_bucket_expire (node, bucket);
331       
332       node = next;
333     }
334 }
335
336 static GIConv
337 open_converter (const gchar *to_codeset,
338                 const gchar *from_codeset,
339                 GError     **error)
340 {
341   struct _iconv_cache_bucket *bucket;
342   gchar *key;
343   GIConv cd;
344   
345   /* create our key */
346   key = g_alloca (strlen (from_codeset) + strlen (to_codeset) + 2);
347   _g_sprintf (key, "%s:%s", from_codeset, to_codeset);
348   
349   G_LOCK (iconv_cache_lock);
350   
351   /* make sure the cache has been initialized */
352   iconv_cache_init ();
353   
354   bucket = g_hash_table_lookup (iconv_cache, key);
355   if (bucket)
356     {
357       if (bucket->used)
358         {
359           cd = g_iconv_open (to_codeset, from_codeset);
360           if (cd == (GIConv) -1)
361             goto error;
362         }
363       else
364         {
365           /* Apparently iconv on Solaris <= 7 segfaults if you pass in
366            * NULL for anything but inbuf; work around that. (NULL outbuf
367            * or NULL *outbuf is allowed by Unix98.)
368            */
369           gsize inbytes_left = 0;
370           gchar *outbuf = NULL;
371           gsize outbytes_left = 0;
372                 
373           cd = bucket->cd;
374           bucket->used = TRUE;
375           
376           /* reset the descriptor */
377           g_iconv (cd, NULL, &inbytes_left, &outbuf, &outbytes_left);
378         }
379       
380       bucket->refcount++;
381     }
382   else
383     {
384       cd = g_iconv_open (to_codeset, from_codeset);
385       if (cd == (GIConv) -1)
386         goto error;
387       
388       iconv_cache_expire_unused ();
389       
390       bucket = iconv_cache_bucket_new (key, cd);
391     }
392   
393   g_hash_table_insert (iconv_open_hash, cd, bucket->key);
394   
395   G_UNLOCK (iconv_cache_lock);
396   
397   return cd;
398   
399  error:
400   
401   G_UNLOCK (iconv_cache_lock);
402   
403   /* Something went wrong.  */
404   if (error)
405     {
406       if (errno == EINVAL)
407         g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION,
408                      _("Conversion from character set '%s' to '%s' is not supported"),
409                      from_codeset, to_codeset);
410       else
411         g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
412                      _("Could not open converter from '%s' to '%s'"),
413                      from_codeset, to_codeset);
414     }
415   
416   return cd;
417 }
418
419 static int
420 close_converter (GIConv converter)
421 {
422   struct _iconv_cache_bucket *bucket;
423   const gchar *key;
424   GIConv cd;
425   
426   cd = converter;
427   
428   if (cd == (GIConv) -1)
429     return 0;
430   
431   G_LOCK (iconv_cache_lock);
432   
433   key = g_hash_table_lookup (iconv_open_hash, cd);
434   if (key)
435     {
436       g_hash_table_remove (iconv_open_hash, cd);
437       
438       bucket = g_hash_table_lookup (iconv_cache, key);
439       g_assert (bucket);
440       
441       bucket->refcount--;
442       
443       if (cd == bucket->cd)
444         bucket->used = FALSE;
445       else
446         g_iconv_close (cd);
447       
448       if (!bucket->refcount && iconv_cache_size > ICONV_CACHE_SIZE)
449         {
450           /* expire this cache bucket */
451           iconv_cache_bucket_expire (NULL, bucket);
452         }
453     }
454   else
455     {
456       G_UNLOCK (iconv_cache_lock);
457       
458       g_warning ("This iconv context wasn't opened using open_converter");
459       
460       return g_iconv_close (converter);
461     }
462   
463   G_UNLOCK (iconv_cache_lock);
464   
465   return 0;
466 }
467
468 #else  /* !NEED_ICONV_CACHE */
469
470 static GIConv
471 open_converter (const gchar *to_codeset,
472                 const gchar *from_codeset,
473                 GError     **error)
474 {
475   GIConv cd;
476
477   cd = g_iconv_open (to_codeset, from_codeset);
478
479   if (cd == (GIConv) -1)
480     {
481       /* Something went wrong.  */
482       if (error)
483         {
484           if (errno == EINVAL)
485             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION,
486                          _("Conversion from character set '%s' to '%s' is not supported"),
487                          from_codeset, to_codeset);
488           else
489             g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
490                          _("Could not open converter from '%s' to '%s'"),
491                          from_codeset, to_codeset);
492         }
493     }
494   
495   return cd;
496 }
497
498 static int
499 close_converter (GIConv cd)
500 {
501   if (cd == (GIConv) -1)
502     return 0;
503   
504   return g_iconv_close (cd);  
505 }
506
507 #endif /* NEED_ICONV_CACHE */
508
509 /**
510  * g_convert_with_iconv:
511  * @str:           the string to convert
512  * @len:           the length of the string, or -1 if the string is 
513  *                 nul-terminated<footnoteref linkend="nul-unsafe"/>. 
514  * @converter:     conversion descriptor from g_iconv_open()
515  * @bytes_read:    location to store the number of bytes in the
516  *                 input string that were successfully converted, or %NULL.
517  *                 Even if the conversion was successful, this may be 
518  *                 less than @len if there were partial characters
519  *                 at the end of the input. If the error
520  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
521  *                 stored will the byte offset after the last valid
522  *                 input sequence.
523  * @bytes_written: the number of bytes stored in the output buffer (not 
524  *                 including the terminating nul).
525  * @error:         location to store the error occuring, or %NULL to ignore
526  *                 errors. Any of the errors in #GConvertError may occur.
527  *
528  * Converts a string from one character set to another. 
529  * 
530  * Note that you should use g_iconv() for streaming 
531  * conversions<footnote id="streaming-state">
532  *  <para>
533  * Despite the fact that @byes_read can return information about partial 
534  * characters, the <literal>g_convert_...</literal> functions
535  * are not generally suitable for streaming. If the underlying converter 
536  * being used maintains internal state, then this won't be preserved 
537  * across successive calls to g_convert(), g_convert_with_iconv() or 
538  * g_convert_with_fallback(). (An example of this is the GNU C converter 
539  * for CP1255 which does not emit a base character until it knows that 
540  * the next character is not a mark that could combine with the base 
541  * character.)
542  *  </para>
543  * </footnote>. 
544  *
545  * Return value: If the conversion was successful, a newly allocated
546  *               nul-terminated string, which must be freed with
547  *               g_free(). Otherwise %NULL and @error will be set.
548  **/
549 gchar*
550 g_convert_with_iconv (const gchar *str,
551                       gssize       len,
552                       GIConv       converter,
553                       gsize       *bytes_read, 
554                       gsize       *bytes_written, 
555                       GError     **error)
556 {
557   gchar *dest;
558   gchar *outp;
559   const gchar *p;
560   const gchar *shift_p = NULL;
561   gsize inbytes_remaining;
562   gsize outbytes_remaining;
563   gsize err;
564   gsize outbuf_size;
565   gboolean have_error = FALSE;
566   gboolean done = FALSE;
567   
568   g_return_val_if_fail (converter != (GIConv) -1, NULL);
569      
570   if (len < 0)
571     len = strlen (str);
572
573   p = str;
574   inbytes_remaining = len;
575   outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
576   
577   outbytes_remaining = outbuf_size - 1; /* -1 for nul */
578   outp = dest = g_malloc (outbuf_size);
579
580   while (!done && !have_error)
581     {
582       err = g_iconv (converter, (char **)&p, &inbytes_remaining, &outp, &outbytes_remaining);
583
584       if (err == (size_t) -1)
585         {
586           switch (errno)
587             {
588             case EINVAL:
589               /* Incomplete text, do not report an error */
590               done = TRUE;
591               break;
592             case E2BIG:
593               {
594                 size_t used = outp - dest;
595                 
596                 outbuf_size *= 2;
597                 dest = g_realloc (dest, outbuf_size);
598                 
599                 outp = dest + used;
600                 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
601               }
602               break;
603             case EILSEQ:
604               if (error)
605                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
606                              _("Invalid byte sequence in conversion input"));
607               have_error = TRUE;
608               break;
609             default:
610               if (error)
611                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
612                              _("Error during conversion: %s"),
613                              g_strerror (errno));
614               have_error = TRUE;
615               break;
616             }
617         }
618       else 
619         {
620           if (!shift_p)
621             {
622               /* call g_iconv with NULL inbuf to cleanup shift state */
623               shift_p = p;
624               p = NULL;
625               inbytes_remaining = 0;
626             }
627           else
628             done = TRUE;
629         }
630     }
631
632   if (shift_p)
633     p = shift_p;
634
635   *outp = '\0';
636   
637   if (bytes_read)
638     *bytes_read = p - str;
639   else
640     {
641       if ((p - str) != len) 
642         {
643           if (!have_error)
644             {
645               if (error)
646                 g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
647                              _("Partial character sequence at end of input"));
648               have_error = TRUE;
649             }
650         }
651     }
652
653   if (bytes_written)
654     *bytes_written = outp - dest;       /* Doesn't include '\0' */
655
656   if (have_error)
657     {
658       g_free (dest);
659       return NULL;
660     }
661   else
662     return dest;
663 }
664
665 /**
666  * g_convert:
667  * @str:           the string to convert
668  * @len:           the length of the string, or -1 if the string is 
669  *                 nul-terminated<footnote id="nul-unsafe">
670                      <para>
671                        Note that some encodings may allow nul bytes to 
672                        occur inside strings. In that case, using -1 for 
673                        the @len parameter is unsafe.
674                      </para>
675                    </footnote>. 
676  * @to_codeset:    name of character set into which to convert @str
677  * @from_codeset:  character set of @str.
678  * @bytes_read:    location to store the number of bytes in the
679  *                 input string that were successfully converted, or %NULL.
680  *                 Even if the conversion was successful, this may be 
681  *                 less than @len if there were partial characters
682  *                 at the end of the input. If the error
683  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
684  *                 stored will the byte offset after the last valid
685  *                 input sequence.
686  * @bytes_written: the number of bytes stored in the output buffer (not 
687  *                 including the terminating nul).
688  * @error:         location to store the error occuring, or %NULL to ignore
689  *                 errors. Any of the errors in #GConvertError may occur.
690  *
691  * Converts a string from one character set to another.
692  *
693  * Note that you should use g_iconv() for streaming 
694  * conversions<footnoteref linkend="streaming-state"/>.
695  *
696  * Return value: If the conversion was successful, a newly allocated
697  *               nul-terminated string, which must be freed with
698  *               g_free(). Otherwise %NULL and @error will be set.
699  **/
700 gchar*
701 g_convert (const gchar *str,
702            gssize       len,  
703            const gchar *to_codeset,
704            const gchar *from_codeset,
705            gsize       *bytes_read, 
706            gsize       *bytes_written, 
707            GError     **error)
708 {
709   gchar *res;
710   GIConv cd;
711
712   g_return_val_if_fail (str != NULL, NULL);
713   g_return_val_if_fail (to_codeset != NULL, NULL);
714   g_return_val_if_fail (from_codeset != NULL, NULL);
715   
716   cd = open_converter (to_codeset, from_codeset, error);
717
718   if (cd == (GIConv) -1)
719     {
720       if (bytes_read)
721         *bytes_read = 0;
722       
723       if (bytes_written)
724         *bytes_written = 0;
725       
726       return NULL;
727     }
728
729   res = g_convert_with_iconv (str, len, cd,
730                               bytes_read, bytes_written,
731                               error);
732
733   close_converter (cd);
734
735   return res;
736 }
737
738 /**
739  * g_convert_with_fallback:
740  * @str:          the string to convert
741  * @len:          the length of the string, or -1 if the string is 
742  *                nul-terminated<footnoteref linkend="nul-unsafe"/>. 
743  * @to_codeset:   name of character set into which to convert @str
744  * @from_codeset: character set of @str.
745  * @fallback:     UTF-8 string to use in place of character not
746  *                present in the target encoding. (The string must be
747  *                representable in the target encoding). 
748                   If %NULL, characters not in the target encoding will 
749                   be represented as Unicode escapes \uxxxx or \Uxxxxyyyy.
750  * @bytes_read:   location to store the number of bytes in the
751  *                input string that were successfully converted, or %NULL.
752  *                Even if the conversion was successful, this may be 
753  *                less than @len if there were partial characters
754  *                at the end of the input.
755  * @bytes_written: the number of bytes stored in the output buffer (not 
756  *                including the terminating nul).
757  * @error:        location to store the error occuring, or %NULL to ignore
758  *                errors. Any of the errors in #GConvertError may occur.
759  *
760  * Converts a string from one character set to another, possibly
761  * including fallback sequences for characters not representable
762  * in the output. Note that it is not guaranteed that the specification
763  * for the fallback sequences in @fallback will be honored. Some
764  * systems may do a approximate conversion from @from_codeset
765  * to @to_codeset in their iconv() functions, 
766  * in which case GLib will simply return that approximate conversion.
767  *
768  * Note that you should use g_iconv() for streaming 
769  * conversions<footnoteref linkend="streaming-state"/>.
770  *
771  * Return value: If the conversion was successful, a newly allocated
772  *               nul-terminated string, which must be freed with
773  *               g_free(). Otherwise %NULL and @error will be set.
774  **/
775 gchar*
776 g_convert_with_fallback (const gchar *str,
777                          gssize       len,    
778                          const gchar *to_codeset,
779                          const gchar *from_codeset,
780                          gchar       *fallback,
781                          gsize       *bytes_read,
782                          gsize       *bytes_written,
783                          GError     **error)
784 {
785   gchar *utf8;
786   gchar *dest;
787   gchar *outp;
788   const gchar *insert_str = NULL;
789   const gchar *p;
790   gsize inbytes_remaining;   
791   const gchar *save_p = NULL;
792   gsize save_inbytes = 0;
793   gsize outbytes_remaining; 
794   gsize err;
795   GIConv cd;
796   gsize outbuf_size;
797   gboolean have_error = FALSE;
798   gboolean done = FALSE;
799
800   GError *local_error = NULL;
801   
802   g_return_val_if_fail (str != NULL, NULL);
803   g_return_val_if_fail (to_codeset != NULL, NULL);
804   g_return_val_if_fail (from_codeset != NULL, NULL);
805      
806   if (len < 0)
807     len = strlen (str);
808   
809   /* Try an exact conversion; we only proceed if this fails
810    * due to an illegal sequence in the input string.
811    */
812   dest = g_convert (str, len, to_codeset, from_codeset, 
813                     bytes_read, bytes_written, &local_error);
814   if (!local_error)
815     return dest;
816
817   if (!g_error_matches (local_error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
818     {
819       g_propagate_error (error, local_error);
820       return NULL;
821     }
822   else
823     g_error_free (local_error);
824
825   local_error = NULL;
826   
827   /* No go; to proceed, we need a converter from "UTF-8" to
828    * to_codeset, and the string as UTF-8.
829    */
830   cd = open_converter (to_codeset, "UTF-8", error);
831   if (cd == (GIConv) -1)
832     {
833       if (bytes_read)
834         *bytes_read = 0;
835       
836       if (bytes_written)
837         *bytes_written = 0;
838       
839       return NULL;
840     }
841
842   utf8 = g_convert (str, len, "UTF-8", from_codeset, 
843                     bytes_read, &inbytes_remaining, error);
844   if (!utf8)
845     {
846       close_converter (cd);
847       if (bytes_written)
848         *bytes_written = 0;
849       return NULL;
850     }
851
852   /* Now the heart of the code. We loop through the UTF-8 string, and
853    * whenever we hit an offending character, we form fallback, convert
854    * the fallback to the target codeset, and then go back to
855    * converting the original string after finishing with the fallback.
856    *
857    * The variables save_p and save_inbytes store the input state
858    * for the original string while we are converting the fallback
859    */
860   p = utf8;
861
862   outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
863   outbytes_remaining = outbuf_size - 1; /* -1 for nul */
864   outp = dest = g_malloc (outbuf_size);
865
866   while (!done && !have_error)
867     {
868       size_t inbytes_tmp = inbytes_remaining;
869       err = g_iconv (cd, (char **)&p, &inbytes_tmp, &outp, &outbytes_remaining);
870       inbytes_remaining = inbytes_tmp;
871
872       if (err == (size_t) -1)
873         {
874           switch (errno)
875             {
876             case EINVAL:
877               g_assert_not_reached();
878               break;
879             case E2BIG:
880               {
881                 size_t used = outp - dest;
882
883                 outbuf_size *= 2;
884                 dest = g_realloc (dest, outbuf_size);
885                 
886                 outp = dest + used;
887                 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
888                 
889                 break;
890               }
891             case EILSEQ:
892               if (save_p)
893                 {
894                   /* Error converting fallback string - fatal
895                    */
896                   g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
897                                _("Cannot convert fallback '%s' to codeset '%s'"),
898                                insert_str, to_codeset);
899                   have_error = TRUE;
900                   break;
901                 }
902               else if (p)
903                 {
904                   if (!fallback)
905                     { 
906                       gunichar ch = g_utf8_get_char (p);
907                       insert_str = g_strdup_printf (ch < 0x10000 ? "\\u%04x" : "\\U%08x",
908                                                     ch);
909                     }
910                   else
911                     insert_str = fallback;
912                   
913                   save_p = g_utf8_next_char (p);
914                   save_inbytes = inbytes_remaining - (save_p - p);
915                   p = insert_str;
916                   inbytes_remaining = strlen (p);
917                   break;
918                 }
919               /* fall thru if p is NULL */
920             default:
921               g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
922                            _("Error during conversion: %s"),
923                            g_strerror (errno));
924               have_error = TRUE;
925               break;
926             }
927         }
928       else
929         {
930           if (save_p)
931             {
932               if (!fallback)
933                 g_free ((gchar *)insert_str);
934               p = save_p;
935               inbytes_remaining = save_inbytes;
936               save_p = NULL;
937             }
938           else if (p)
939             {
940               /* call g_iconv with NULL inbuf to cleanup shift state */
941               p = NULL;
942               inbytes_remaining = 0;
943             }
944           else
945             done = TRUE;
946         }
947     }
948
949   /* Cleanup
950    */
951   *outp = '\0';
952   
953   close_converter (cd);
954
955   if (bytes_written)
956     *bytes_written = outp - dest;       /* Doesn't include '\0' */
957
958   g_free (utf8);
959
960   if (have_error)
961     {
962       if (save_p && !fallback)
963         g_free ((gchar *)insert_str);
964       g_free (dest);
965       return NULL;
966     }
967   else
968     return dest;
969 }
970
971 /*
972  * g_locale_to_utf8
973  *
974  * 
975  */
976
977 static gchar *
978 strdup_len (const gchar *string,
979             gssize       len,
980             gsize       *bytes_written,
981             gsize       *bytes_read,
982             GError      **error)
983          
984 {
985   gsize real_len;
986
987   if (!g_utf8_validate (string, len, NULL))
988     {
989       if (bytes_read)
990         *bytes_read = 0;
991       if (bytes_written)
992         *bytes_written = 0;
993
994       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
995                    _("Invalid byte sequence in conversion input"));
996       return NULL;
997     }
998   
999   if (len < 0)
1000     real_len = strlen (string);
1001   else
1002     {
1003       real_len = 0;
1004       
1005       while (real_len < len && string[real_len])
1006         real_len++;
1007     }
1008   
1009   if (bytes_read)
1010     *bytes_read = real_len;
1011   if (bytes_written)
1012     *bytes_written = real_len;
1013
1014   return g_strndup (string, real_len);
1015 }
1016
1017 /**
1018  * g_locale_to_utf8:
1019  * @opsysstring:   a string in the encoding of the current locale. On Windows
1020  *                 this means the system codepage.
1021  * @len:           the length of the string, or -1 if the string is
1022  *                 nul-terminated<footnoteref linkend="nul-unsafe"/>. 
1023  * @bytes_read:    location to store the number of bytes in the
1024  *                 input string that were successfully converted, or %NULL.
1025  *                 Even if the conversion was successful, this may be 
1026  *                 less than @len if there were partial characters
1027  *                 at the end of the input. If the error
1028  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1029  *                 stored will the byte offset after the last valid
1030  *                 input sequence.
1031  * @bytes_written: the number of bytes stored in the output buffer (not 
1032  *                 including the terminating nul).
1033  * @error:         location to store the error occuring, or %NULL to ignore
1034  *                 errors. Any of the errors in #GConvertError may occur.
1035  * 
1036  * Converts a string which is in the encoding used for strings by
1037  * the C runtime (usually the same as that used by the operating
1038  * system) in the current locale into a UTF-8 string.
1039  * 
1040  * Return value: The converted string, or %NULL on an error.
1041  **/
1042 gchar *
1043 g_locale_to_utf8 (const gchar  *opsysstring,
1044                   gssize        len,            
1045                   gsize        *bytes_read,    
1046                   gsize        *bytes_written,
1047                   GError      **error)
1048 {
1049   const char *charset;
1050
1051   if (g_get_charset (&charset))
1052     return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
1053   else
1054     return g_convert (opsysstring, len, 
1055                       "UTF-8", charset, bytes_read, bytes_written, error);
1056 }
1057
1058 /**
1059  * g_locale_from_utf8:
1060  * @utf8string:    a UTF-8 encoded string 
1061  * @len:           the length of the string, or -1 if the string is
1062  *                 nul-terminated<footnoteref linkend="nul-unsafe"/>. 
1063  * @bytes_read:    location to store the number of bytes in the
1064  *                 input string that were successfully converted, or %NULL.
1065  *                 Even if the conversion was successful, this may be 
1066  *                 less than @len if there were partial characters
1067  *                 at the end of the input. If the error
1068  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1069  *                 stored will the byte offset after the last valid
1070  *                 input sequence.
1071  * @bytes_written: the number of bytes stored in the output buffer (not 
1072  *                 including the terminating nul).
1073  * @error:         location to store the error occuring, or %NULL to ignore
1074  *                 errors. Any of the errors in #GConvertError may occur.
1075  * 
1076  * Converts a string from UTF-8 to the encoding used for strings by
1077  * the C runtime (usually the same as that used by the operating
1078  * system) in the current locale.
1079  * 
1080  * Return value: The converted string, or %NULL on an error.
1081  **/
1082 gchar *
1083 g_locale_from_utf8 (const gchar *utf8string,
1084                     gssize       len,            
1085                     gsize       *bytes_read,    
1086                     gsize       *bytes_written,
1087                     GError     **error)
1088 {
1089   const gchar *charset;
1090
1091   if (g_get_charset (&charset))
1092     return strdup_len (utf8string, len, bytes_read, bytes_written, error);
1093   else
1094     return g_convert (utf8string, len,
1095                       charset, "UTF-8", bytes_read, bytes_written, error);
1096 }
1097
1098 #ifndef G_PLATFORM_WIN32
1099
1100 typedef struct _GFilenameCharsetCache GFilenameCharsetCache;
1101
1102 struct _GFilenameCharsetCache {
1103   gboolean is_utf8;
1104   gchar *charset;
1105   gchar **filename_charsets;
1106 };
1107
1108 static void
1109 filename_charset_cache_free (gpointer data)
1110 {
1111   GFilenameCharsetCache *cache = data;
1112   g_free (cache->charset);
1113   g_strfreev (cache->filename_charsets);
1114   g_free (cache);
1115 }
1116
1117 /**
1118  * g_get_filename_charsets:
1119  * @charsets: return location for the %NULL-terminated list of encoding names
1120  *
1121  * Determines the preferred character sets used for filenames.
1122  * The first character set from the @charsets is the filename encoding, the
1123  * subsequent character sets are used when trying to generate a displayable
1124  * representation of a filename, see g_filename_display_name().
1125  *
1126  * On Unix, the character sets are determined by consulting the
1127  * environment variables <envar>G_FILENAME_ENCODING</envar> and
1128  * <envar>G_BROKEN_FILENAMES</envar>. On Windows, the character set
1129  * used in the GLib API is always UTF-8 and said environment variables
1130  * have no effect.
1131  *
1132  * <envar>G_FILENAME_ENCODING</envar> may be set to a comma-separated list 
1133  * of character set names. The special token "@locale" is taken to mean the 
1134  * character set for the current locale. If <envar>G_FILENAME_ENCODING</envar> 
1135  * is not set, but <envar>G_BROKEN_FILENAMES</envar> is, the character set of 
1136  * the current locale is taken as the filename encoding. If neither environment
1137  * variable is set, UTF-8 is taken as the filename encoding, but the character
1138  * set of the current locale is also put in the list of encodings.
1139  *
1140  * The returned @charsets belong to GLib and must not be freed.
1141  *
1142  * Note that on Unix, regardless of the locale character set or
1143  * <envar>G_FILENAME_ENCODING</envar> value, the actual file names present on a
1144  * system might be in any random encoding or just gibberish.
1145  *
1146  * Return value: %TRUE if the filename encoding is UTF-8.
1147  * 
1148  * Since: 2.6
1149  */
1150 gboolean
1151 g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets)
1152 {
1153   static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
1154   GFilenameCharsetCache *cache = g_static_private_get (&cache_private);
1155   const gchar *charset;
1156
1157   if (!cache)
1158     {
1159       cache = g_new0 (GFilenameCharsetCache, 1);
1160       g_static_private_set (&cache_private, cache, filename_charset_cache_free);
1161     }
1162
1163   g_get_charset (&charset);
1164
1165   if (!(cache->charset && strcmp (cache->charset, charset) == 0))
1166     {
1167       const gchar *new_charset;
1168       gchar *p;
1169       gint i;
1170
1171       g_free (cache->charset);
1172       g_strfreev (cache->filename_charsets);
1173       cache->charset = g_strdup (charset);
1174       
1175       p = getenv ("G_FILENAME_ENCODING");
1176       if (p != NULL && p[0] != '\0') 
1177         {
1178           cache->filename_charsets = g_strsplit (p, ",", 0);
1179           cache->is_utf8 = (strcmp (cache->filename_charsets[0], "UTF-8") == 0);
1180
1181           for (i = 0; cache->filename_charsets[i]; i++)
1182             {
1183               if (strcmp ("@locale", cache->filename_charsets[i]) == 0)
1184                 {
1185                   g_get_charset (&new_charset);
1186                   g_free (cache->filename_charsets[i]);
1187                   cache->filename_charsets[i] = g_strdup (new_charset);
1188                 }
1189             }
1190         }
1191       else if (getenv ("G_BROKEN_FILENAMES") != NULL)
1192         {
1193           cache->filename_charsets = g_new0 (gchar *, 2);
1194           cache->is_utf8 = g_get_charset (&new_charset);
1195           cache->filename_charsets[0] = g_strdup (new_charset);
1196         }
1197       else 
1198         {
1199           cache->filename_charsets = g_new0 (gchar *, 3);
1200           cache->is_utf8 = TRUE;
1201           cache->filename_charsets[0] = g_strdup ("UTF-8");
1202           if (!g_get_charset (&new_charset))
1203             cache->filename_charsets[1] = g_strdup (new_charset);
1204         }
1205     }
1206
1207   if (filename_charsets)
1208     *filename_charsets = (const gchar **)cache->filename_charsets;
1209
1210   return cache->is_utf8;
1211 }
1212
1213 #else /* G_PLATFORM_WIN32 */
1214
1215 gboolean
1216 g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets) 
1217 {
1218   static const gchar *charsets[] = {
1219     "UTF-8",
1220     NULL
1221   };
1222
1223 #ifdef G_OS_WIN32
1224   /* On Windows GLib pretends that the filename charset is UTF-8 */
1225   if (filename_charsets)
1226     *filename_charsets = charsets;
1227
1228   return TRUE;
1229 #else
1230   gboolean result;
1231
1232   /* Cygwin works like before */
1233   result = g_get_charset (&(charsets[0]));
1234
1235   if (filename_charsets)
1236     *filename_charsets = charsets;
1237
1238   return result;
1239 #endif
1240 }
1241
1242 #endif /* G_PLATFORM_WIN32 */
1243
1244 static gboolean
1245 get_filename_charset (const gchar **filename_charset)
1246 {
1247   const gchar **charsets;
1248   gboolean is_utf8;
1249   
1250   is_utf8 = g_get_filename_charsets (&charsets);
1251
1252   if (filename_charset)
1253     *filename_charset = charsets[0];
1254   
1255   return is_utf8;
1256 }
1257
1258 /* This is called from g_thread_init(). It's used to
1259  * initialize some static data in a threadsafe way.
1260  */
1261 void 
1262 _g_convert_thread_init (void)
1263 {
1264   const gchar **dummy;
1265   (void) g_get_filename_charsets (&dummy);
1266 }
1267
1268 /**
1269  * g_filename_to_utf8:
1270  * @opsysstring:   a string in the encoding for filenames
1271  * @len:           the length of the string, or -1 if the string is
1272  *                 nul-terminated<footnoteref linkend="nul-unsafe"/>. 
1273  * @bytes_read:    location to store the number of bytes in the
1274  *                 input string that were successfully converted, or %NULL.
1275  *                 Even if the conversion was successful, this may be 
1276  *                 less than @len if there were partial characters
1277  *                 at the end of the input. If the error
1278  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1279  *                 stored will the byte offset after the last valid
1280  *                 input sequence.
1281  * @bytes_written: the number of bytes stored in the output buffer (not 
1282  *                 including the terminating nul).
1283  * @error:         location to store the error occuring, or %NULL to ignore
1284  *                 errors. Any of the errors in #GConvertError may occur.
1285  * 
1286  * Converts a string which is in the encoding used by GLib for
1287  * filenames into a UTF-8 string. Note that on Windows GLib uses UTF-8
1288  * for filenames.
1289  * 
1290  * Return value: The converted string, or %NULL on an error.
1291  **/
1292 gchar*
1293 g_filename_to_utf8 (const gchar *opsysstring, 
1294                     gssize       len,           
1295                     gsize       *bytes_read,   
1296                     gsize       *bytes_written,
1297                     GError     **error)
1298 {
1299   const gchar *charset;
1300
1301   if (get_filename_charset (&charset))
1302     return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
1303   else
1304     return g_convert (opsysstring, len, 
1305                       "UTF-8", charset, bytes_read, bytes_written, error);
1306 }
1307
1308 #ifdef G_OS_WIN32
1309
1310 #undef g_filename_to_utf8
1311
1312 /* Binary compatibility version. Not for newly compiled code. */
1313
1314 gchar*
1315 g_filename_to_utf8 (const gchar *opsysstring, 
1316                     gssize       len,           
1317                     gsize       *bytes_read,   
1318                     gsize       *bytes_written,
1319                     GError     **error)
1320 {
1321   const gchar *charset;
1322
1323   if (g_get_charset (&charset))
1324     return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
1325   else
1326     return g_convert (opsysstring, len, 
1327                       "UTF-8", charset, bytes_read, bytes_written, error);
1328 }
1329
1330 #endif
1331
1332 /**
1333  * g_filename_from_utf8:
1334  * @utf8string:    a UTF-8 encoded string.
1335  * @len:           the length of the string, or -1 if the string is
1336  *                 nul-terminated.
1337  * @bytes_read:    location to store the number of bytes in the
1338  *                 input string that were successfully converted, or %NULL.
1339  *                 Even if the conversion was successful, this may be 
1340  *                 less than @len if there were partial characters
1341  *                 at the end of the input. If the error
1342  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1343  *                 stored will the byte offset after the last valid
1344  *                 input sequence.
1345  * @bytes_written: the number of bytes stored in the output buffer (not 
1346  *                 including the terminating nul).
1347  * @error:         location to store the error occuring, or %NULL to ignore
1348  *                 errors. Any of the errors in #GConvertError may occur.
1349  * 
1350  * Converts a string from UTF-8 to the encoding GLib uses for
1351  * filenames. Note that on Windows GLib uses UTF-8 for filenames.
1352  * 
1353  * Return value: The converted string, or %NULL on an error.
1354  **/
1355 gchar*
1356 g_filename_from_utf8 (const gchar *utf8string,
1357                       gssize       len,            
1358                       gsize       *bytes_read,    
1359                       gsize       *bytes_written,
1360                       GError     **error)
1361 {
1362   const gchar *charset;
1363
1364   if (get_filename_charset (&charset))
1365     return strdup_len (utf8string, len, bytes_read, bytes_written, error);
1366   else
1367     return g_convert (utf8string, len,
1368                       charset, "UTF-8", bytes_read, bytes_written, error);
1369 }
1370
1371 #ifdef G_OS_WIN32
1372
1373 #undef g_filename_from_utf8
1374
1375 /* Binary compatibility version. Not for newly compiled code. */
1376
1377 gchar*
1378 g_filename_from_utf8 (const gchar *utf8string,
1379                       gssize       len,            
1380                       gsize       *bytes_read,    
1381                       gsize       *bytes_written,
1382                       GError     **error)
1383 {
1384   const gchar *charset;
1385
1386   if (g_get_charset (&charset))
1387     return strdup_len (utf8string, len, bytes_read, bytes_written, error);
1388   else
1389     return g_convert (utf8string, len,
1390                       charset, "UTF-8", bytes_read, bytes_written, error);
1391 }
1392
1393 #endif
1394
1395 /* Test of haystack has the needle prefix, comparing case
1396  * insensitive. haystack may be UTF-8, but needle must
1397  * contain only ascii. */
1398 static gboolean
1399 has_case_prefix (const gchar *haystack, const gchar *needle)
1400 {
1401   const gchar *h, *n;
1402   
1403   /* Eat one character at a time. */
1404   h = haystack;
1405   n = needle;
1406
1407   while (*n && *h &&
1408          g_ascii_tolower (*n) == g_ascii_tolower (*h))
1409     {
1410       n++;
1411       h++;
1412     }
1413   
1414   return *n == '\0';
1415 }
1416
1417 typedef enum {
1418   UNSAFE_ALL        = 0x1,  /* Escape all unsafe characters   */
1419   UNSAFE_ALLOW_PLUS = 0x2,  /* Allows '+'  */
1420   UNSAFE_PATH       = 0x8,  /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
1421   UNSAFE_HOST       = 0x10, /* Allows '/' and ':' and '@' */
1422   UNSAFE_SLASHES    = 0x20  /* Allows all characters except for '/' and '%' */
1423 } UnsafeCharacterSet;
1424
1425 static const guchar acceptable[96] = {
1426   /* A table of the ASCII chars from space (32) to DEL (127) */
1427   /*      !    "    #    $    %    &    '    (    )    *    +    ,    -    .    / */ 
1428   0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
1429   /* 0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ? */
1430   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
1431   /* @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O */
1432   0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
1433   /* P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _ */
1434   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
1435   /* `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o */
1436   0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
1437   /* p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~  DEL */
1438   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
1439 };
1440
1441 static const gchar hex[16] = "0123456789ABCDEF";
1442
1443 /* Note: This escape function works on file: URIs, but if you want to
1444  * escape something else, please read RFC-2396 */
1445 static gchar *
1446 g_escape_uri_string (const gchar *string, 
1447                      UnsafeCharacterSet mask)
1448 {
1449 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
1450
1451   const gchar *p;
1452   gchar *q;
1453   gchar *result;
1454   int c;
1455   gint unacceptable;
1456   UnsafeCharacterSet use_mask;
1457   
1458   g_return_val_if_fail (mask == UNSAFE_ALL
1459                         || mask == UNSAFE_ALLOW_PLUS
1460                         || mask == UNSAFE_PATH
1461                         || mask == UNSAFE_HOST
1462                         || mask == UNSAFE_SLASHES, NULL);
1463   
1464   unacceptable = 0;
1465   use_mask = mask;
1466   for (p = string; *p != '\0'; p++)
1467     {
1468       c = (guchar) *p;
1469       if (!ACCEPTABLE (c)) 
1470         unacceptable++;
1471     }
1472   
1473   result = g_malloc (p - string + unacceptable * 2 + 1);
1474   
1475   use_mask = mask;
1476   for (q = result, p = string; *p != '\0'; p++)
1477     {
1478       c = (guchar) *p;
1479       
1480       if (!ACCEPTABLE (c))
1481         {
1482           *q++ = '%'; /* means hex coming */
1483           *q++ = hex[c >> 4];
1484           *q++ = hex[c & 15];
1485         }
1486       else
1487         *q++ = *p;
1488     }
1489   
1490   *q = '\0';
1491   
1492   return result;
1493 }
1494
1495
1496 static gchar *
1497 g_escape_file_uri (const gchar *hostname,
1498                    const gchar *pathname)
1499 {
1500   char *escaped_hostname = NULL;
1501   char *escaped_path;
1502   char *res;
1503
1504 #ifdef G_OS_WIN32
1505   char *p, *backslash;
1506
1507   /* Turn backslashes into forward slashes. That's what Netscape
1508    * does, and they are actually more or less equivalent in Windows.
1509    */
1510   
1511   pathname = g_strdup (pathname);
1512   p = (char *) pathname;
1513   
1514   while ((backslash = strchr (p, '\\')) != NULL)
1515     {
1516       *backslash = '/';
1517       p = backslash + 1;
1518     }
1519 #endif
1520
1521   if (hostname && *hostname != '\0')
1522     {
1523       escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST);
1524     }
1525
1526   escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH);
1527
1528   res = g_strconcat ("file://",
1529                      (escaped_hostname) ? escaped_hostname : "",
1530                      (*escaped_path != '/') ? "/" : "",
1531                      escaped_path,
1532                      NULL);
1533
1534 #ifdef G_OS_WIN32
1535   g_free ((char *) pathname);
1536 #endif
1537
1538   g_free (escaped_hostname);
1539   g_free (escaped_path);
1540   
1541   return res;
1542 }
1543
1544 static int
1545 unescape_character (const char *scanner)
1546 {
1547   int first_digit;
1548   int second_digit;
1549
1550   first_digit = g_ascii_xdigit_value (scanner[0]);
1551   if (first_digit < 0) 
1552     return -1;
1553   
1554   second_digit = g_ascii_xdigit_value (scanner[1]);
1555   if (second_digit < 0) 
1556     return -1;
1557   
1558   return (first_digit << 4) | second_digit;
1559 }
1560
1561 static gchar *
1562 g_unescape_uri_string (const char *escaped,
1563                        int         len,
1564                        const char *illegal_escaped_characters,
1565                        gboolean    ascii_must_not_be_escaped)
1566 {
1567   const gchar *in, *in_end;
1568   gchar *out, *result;
1569   int c;
1570   
1571   if (escaped == NULL)
1572     return NULL;
1573
1574   if (len < 0)
1575     len = strlen (escaped);
1576
1577   result = g_malloc (len + 1);
1578   
1579   out = result;
1580   for (in = escaped, in_end = escaped + len; in < in_end; in++)
1581     {
1582       c = *in;
1583
1584       if (c == '%')
1585         {
1586           /* catch partial escape sequences past the end of the substring */
1587           if (in + 3 > in_end)
1588             break;
1589
1590           c = unescape_character (in + 1);
1591
1592           /* catch bad escape sequences and NUL characters */
1593           if (c <= 0)
1594             break;
1595
1596           /* catch escaped ASCII */
1597           if (ascii_must_not_be_escaped && c <= 0x7F)
1598             break;
1599
1600           /* catch other illegal escaped characters */
1601           if (strchr (illegal_escaped_characters, c) != NULL)
1602             break;
1603
1604           in += 2;
1605         }
1606
1607       *out++ = c;
1608     }
1609   
1610   g_assert (out - result <= len);
1611   *out = '\0';
1612
1613   if (in != in_end)
1614     {
1615       g_free (result);
1616       return NULL;
1617     }
1618
1619   return result;
1620 }
1621
1622 static gboolean
1623 is_asciialphanum (gunichar c)
1624 {
1625   return c <= 0x7F && g_ascii_isalnum (c);
1626 }
1627
1628 static gboolean
1629 is_asciialpha (gunichar c)
1630 {
1631   return c <= 0x7F && g_ascii_isalpha (c);
1632 }
1633
1634 /* allows an empty string */
1635 static gboolean
1636 hostname_validate (const char *hostname)
1637 {
1638   const char *p;
1639   gunichar c, first_char, last_char;
1640
1641   p = hostname;
1642   if (*p == '\0')
1643     return TRUE;
1644   do
1645     {
1646       /* read in a label */
1647       c = g_utf8_get_char (p);
1648       p = g_utf8_next_char (p);
1649       if (!is_asciialphanum (c))
1650         return FALSE;
1651       first_char = c;
1652       do
1653         {
1654           last_char = c;
1655           c = g_utf8_get_char (p);
1656           p = g_utf8_next_char (p);
1657         }
1658       while (is_asciialphanum (c) || c == '-');
1659       if (last_char == '-')
1660         return FALSE;
1661       
1662       /* if that was the last label, check that it was a toplabel */
1663       if (c == '\0' || (c == '.' && *p == '\0'))
1664         return is_asciialpha (first_char);
1665     }
1666   while (c == '.');
1667   return FALSE;
1668 }
1669
1670 /**
1671  * g_filename_from_uri:
1672  * @uri: a uri describing a filename (escaped, encoded in ASCII).
1673  * @hostname: Location to store hostname for the URI, or %NULL.
1674  *            If there is no hostname in the URI, %NULL will be
1675  *            stored in this location.
1676  * @error: location to store the error occuring, or %NULL to ignore
1677  *         errors. Any of the errors in #GConvertError may occur.
1678  * 
1679  * Converts an escaped ASCII-encoded URI to a local filename in the
1680  * encoding used for filenames. 
1681  * 
1682  * Return value: a newly-allocated string holding the resulting
1683  *               filename, or %NULL on an error.
1684  **/
1685 gchar *
1686 g_filename_from_uri (const gchar *uri,
1687                      gchar      **hostname,
1688                      GError     **error)
1689 {
1690   const char *path_part;
1691   const char *host_part;
1692   char *unescaped_hostname;
1693   char *result;
1694   char *filename;
1695   int offs;
1696 #ifdef G_OS_WIN32
1697   char *p, *slash;
1698 #endif
1699
1700   if (hostname)
1701     *hostname = NULL;
1702
1703   if (!has_case_prefix (uri, "file:/"))
1704     {
1705       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1706                    _("The URI '%s' is not an absolute URI using the \"file\" scheme"),
1707                    uri);
1708       return NULL;
1709     }
1710   
1711   path_part = uri + strlen ("file:");
1712   
1713   if (strchr (path_part, '#') != NULL)
1714     {
1715       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1716                    _("The local file URI '%s' may not include a '#'"),
1717                    uri);
1718       return NULL;
1719     }
1720         
1721   if (has_case_prefix (path_part, "///")) 
1722     path_part += 2;
1723   else if (has_case_prefix (path_part, "//"))
1724     {
1725       path_part += 2;
1726       host_part = path_part;
1727
1728       path_part = strchr (path_part, '/');
1729
1730       if (path_part == NULL)
1731         {
1732           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1733                        _("The URI '%s' is invalid"),
1734                        uri);
1735           return NULL;
1736         }
1737
1738       unescaped_hostname = g_unescape_uri_string (host_part, path_part - host_part, "", TRUE);
1739
1740       if (unescaped_hostname == NULL ||
1741           !hostname_validate (unescaped_hostname))
1742         {
1743           g_free (unescaped_hostname);
1744           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1745                        _("The hostname of the URI '%s' is invalid"),
1746                        uri);
1747           return NULL;
1748         }
1749       
1750       if (hostname)
1751         *hostname = unescaped_hostname;
1752       else
1753         g_free (unescaped_hostname);
1754     }
1755
1756   filename = g_unescape_uri_string (path_part, -1, "/", FALSE);
1757
1758   if (filename == NULL)
1759     {
1760       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1761                    _("The URI '%s' contains invalidly escaped characters"),
1762                    uri);
1763       return NULL;
1764     }
1765
1766   offs = 0;
1767 #ifdef G_OS_WIN32
1768   /* Drop localhost */
1769   if (hostname && *hostname != NULL &&
1770       g_ascii_strcasecmp (*hostname, "localhost") == 0)
1771     {
1772       g_free (*hostname);
1773       *hostname = NULL;
1774     }
1775
1776   /* Turn slashes into backslashes, because that's the canonical spelling */
1777   p = filename;
1778   while ((slash = strchr (p, '/')) != NULL)
1779     {
1780       *slash = '\\';
1781       p = slash + 1;
1782     }
1783
1784   /* Windows URIs with a drive letter can be like "file://host/c:/foo"
1785    * or "file://host/c|/foo" (some Netscape versions). In those cases, start
1786    * the filename from the drive letter.
1787    */
1788   if (g_ascii_isalpha (filename[1]))
1789     {
1790       if (filename[2] == ':')
1791         offs = 1;
1792       else if (filename[2] == '|')
1793         {
1794           filename[2] = ':';
1795           offs = 1;
1796         }
1797     }
1798 #endif
1799
1800   result = g_strdup (filename + offs);
1801   g_free (filename);
1802
1803   return result;
1804 }
1805
1806 #ifdef G_OS_WIN32
1807
1808 #undef g_filename_from_uri
1809
1810 gchar *
1811 g_filename_from_uri (const gchar *uri,
1812                      gchar      **hostname,
1813                      GError     **error)
1814 {
1815   gchar *utf8_filename;
1816   gchar *retval = NULL;
1817
1818   utf8_filename = g_filename_from_uri_utf8 (uri, hostname, error);
1819   if (utf8_filename)
1820     {
1821       retval = g_locale_from_utf8 (utf8_filename, -1, NULL, NULL, error);
1822       g_free (utf8_filename);
1823     }
1824   return retval;
1825 }
1826
1827 #endif
1828
1829 /**
1830  * g_filename_to_uri:
1831  * @filename: an absolute filename specified in the GLib file name encoding,
1832  *            which is the on-disk file name bytes on Unix, and UTF-8 on 
1833  *            Windows
1834  * @hostname: A UTF-8 encoded hostname, or %NULL for none.
1835  * @error: location to store the error occuring, or %NULL to ignore
1836  *         errors. Any of the errors in #GConvertError may occur.
1837  * 
1838  * Converts an absolute filename to an escaped ASCII-encoded URI.
1839  * 
1840  * Return value: a newly-allocated string holding the resulting
1841  *               URI, or %NULL on an error.
1842  **/
1843 gchar *
1844 g_filename_to_uri (const gchar *filename,
1845                    const gchar *hostname,
1846                    GError     **error)
1847 {
1848   char *escaped_uri;
1849
1850   g_return_val_if_fail (filename != NULL, NULL);
1851
1852   if (!g_path_is_absolute (filename))
1853     {
1854       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH,
1855                    _("The pathname '%s' is not an absolute path"),
1856                    filename);
1857       return NULL;
1858     }
1859
1860   if (hostname &&
1861       !(g_utf8_validate (hostname, -1, NULL)
1862         && hostname_validate (hostname)))
1863     {
1864       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1865                    _("Invalid hostname"));
1866       return NULL;
1867     }
1868   
1869 #ifdef G_OS_WIN32
1870   /* Don't use localhost unnecessarily */
1871   if (hostname && g_ascii_strcasecmp (hostname, "localhost") == 0)
1872     hostname = NULL;
1873 #endif
1874
1875   escaped_uri = g_escape_file_uri (hostname, filename);
1876
1877   return escaped_uri;
1878 }
1879
1880 #ifdef G_OS_WIN32
1881
1882 #undef g_filename_to_uri
1883
1884 gchar *
1885 g_filename_to_uri (const gchar *filename,
1886                    const gchar *hostname,
1887                    GError     **error)
1888 {
1889   gchar *utf8_filename;
1890   gchar *retval = NULL;
1891
1892   utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
1893
1894   if (utf8_filename)
1895     {
1896       retval = g_filename_to_uri_utf8 (utf8_filename, hostname, error);
1897       g_free (utf8_filename);
1898     }
1899
1900   return retval;
1901 }
1902
1903 #endif
1904
1905 /**
1906  * g_uri_list_extract_uris:
1907  * @uri_list: an URI list 
1908  *
1909  * Splits an URI list conforming to the text/uri-list
1910  * mime type defined in RFC 2483 into individual URIs,
1911  * discarding any comments. The URIs are not validated.
1912  *
1913  * Returns: a newly allocated %NULL-terminated list of
1914  *   strings holding the individual URIs. The array should
1915  *   be freed with g_strfreev().
1916  *
1917  * Since: 2.6
1918  */
1919 gchar **
1920 g_uri_list_extract_uris (const gchar *uri_list)
1921 {
1922   GSList *uris, *u;
1923   const gchar *p, *q;
1924   gchar **result;
1925   gint n_uris = 0;
1926
1927   uris = NULL;
1928
1929   p = uri_list;
1930
1931   /* We don't actually try to validate the URI according to RFC
1932    * 2396, or even check for allowed characters - we just ignore
1933    * comments and trim whitespace off the ends.  We also
1934    * allow LF delimination as well as the specified CRLF.
1935    *
1936    * We do allow comments like specified in RFC 2483.
1937    */
1938   while (p)
1939     {
1940       if (*p != '#')
1941         {
1942           while (g_ascii_isspace (*p))
1943             p++;
1944
1945           q = p;
1946           while (*q && (*q != '\n') && (*q != '\r'))
1947             q++;
1948
1949           if (q > p)
1950             {
1951               q--;
1952               while (q > p && g_ascii_isspace (*q))
1953                 q--;
1954
1955               if (q > p)
1956                 {
1957                   uris = g_slist_prepend (uris, g_strndup (p, q - p + 1));
1958                   n_uris++;
1959                 }
1960             }
1961         }
1962       p = strchr (p, '\n');
1963       if (p)
1964         p++;
1965     }
1966
1967   result = g_new (gchar *, n_uris + 1);
1968
1969   result[n_uris--] = NULL;
1970   for (u = uris; u; u = u->next)
1971     result[n_uris--] = u->data;
1972
1973   g_slist_free (uris);
1974
1975   return result;
1976 }
1977
1978 static gchar *
1979 make_valid_utf8 (const gchar *name)
1980 {
1981   GString *string;
1982   const gchar *remainder, *invalid;
1983   gint remaining_bytes, valid_bytes;
1984   
1985   string = NULL;
1986   remainder = name;
1987   remaining_bytes = strlen (name);
1988   
1989   while (remaining_bytes != 0) 
1990     {
1991       if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
1992         break;
1993       valid_bytes = invalid - remainder;
1994     
1995       if (string == NULL) 
1996         string = g_string_sized_new (remaining_bytes);
1997
1998       g_string_append_len (string, remainder, valid_bytes);
1999       /* append U+FFFD REPLACEMENT CHARACTER */
2000       g_string_append (string, "\357\277\275");
2001       
2002       remaining_bytes -= valid_bytes + 1;
2003       remainder = invalid + 1;
2004     }
2005   
2006   if (string == NULL)
2007     return g_strdup (name);
2008   
2009   g_string_append (string, remainder);
2010
2011   g_assert (g_utf8_validate (string->str, -1, NULL));
2012   
2013   return g_string_free (string, FALSE);
2014 }
2015
2016 /**
2017  * g_filename_display_basename:
2018  * @filename: an absolute pathname in the GLib file name encoding
2019  *
2020  * Returns the display basename for the particular filename, guaranteed
2021  * to be valid UTF-8. The display name might not be identical to the filename,
2022  * for instance there might be problems converting it to UTF-8, and some files
2023  * can be translated in the display.
2024  *
2025  * If GLib can not make sense of the encoding of @filename, as a last resort it 
2026  * replaces unknown characters with U+FFFD, the Unicode replacement character.
2027  * You can search the result for the UTF-8 encoding of this character (which is
2028  * "\357\277\275" in octal notation) to find out if @filename was in an invalid
2029  * encoding.
2030  *
2031  * You must pass the whole absolute pathname to this functions so that
2032  * translation of well known locations can be done.
2033  *
2034  * This function is preferred over g_filename_display_name() if you know the
2035  * whole path, as it allows translation.
2036  *
2037  * Return value: a newly allocated string containing
2038  *   a rendition of the basename of the filename in valid UTF-8
2039  *
2040  * Since: 2.6
2041  **/
2042 gchar *
2043 g_filename_display_basename (const gchar *filename)
2044 {
2045   char *basename;
2046   char *display_name;
2047
2048   g_return_val_if_fail (filename != NULL, NULL);
2049   
2050   basename = g_path_get_basename (filename);
2051   display_name = g_filename_display_name (basename);
2052   g_free (basename);
2053   return display_name;
2054 }
2055
2056 /**
2057  * g_filename_display_name:
2058  * @filename: a pathname hopefully in the GLib file name encoding
2059  * 
2060  * Converts a filename into a valid UTF-8 string. The conversion is 
2061  * not necessarily reversible, so you should keep the original around 
2062  * and use the return value of this function only for display purposes.
2063  * Unlike g_filename_to_utf8(), the result is guaranteed to be non-%NULL 
2064  * even if the filename actually isn't in the GLib file name encoding.
2065  *
2066  * If GLib can not make sense of the encoding of @filename, as a last resort it 
2067  * replaces unknown characters with U+FFFD, the Unicode replacement character.
2068  * You can search the result for the UTF-8 encoding of this character (which is
2069  * "\357\277\275" in octal notation) to find out if @filename was in an invalid
2070  * encoding.
2071  *
2072  * If you know the whole pathname of the file you should use
2073  * g_filename_display_basename(), since that allows location-based
2074  * translation of filenames.
2075  *
2076  * Return value: a newly allocated string containing
2077  *   a rendition of the filename in valid UTF-8
2078  *
2079  * Since: 2.6
2080  **/
2081 gchar *
2082 g_filename_display_name (const gchar *filename)
2083 {
2084   gint i;
2085   const gchar **charsets;
2086   gchar *display_name = NULL;
2087   gboolean is_utf8;
2088  
2089   is_utf8 = g_get_filename_charsets (&charsets);
2090
2091   if (is_utf8)
2092     {
2093       if (g_utf8_validate (filename, -1, NULL))
2094         display_name = g_strdup (filename);
2095     }
2096   
2097   if (!display_name)
2098     {
2099       /* Try to convert from the filename charsets to UTF-8.
2100        * Skip the first charset if it is UTF-8.
2101        */
2102       for (i = is_utf8 ? 1 : 0; charsets[i]; i++)
2103         {
2104           display_name = g_convert (filename, -1, "UTF-8", charsets[i], 
2105                                     NULL, NULL, NULL);
2106
2107           if (display_name)
2108             break;
2109         }
2110     }
2111   
2112   /* if all conversions failed, we replace invalid UTF-8
2113    * by a question mark
2114    */
2115   if (!display_name) 
2116     display_name = make_valid_utf8 (filename);
2117
2118   return display_name;
2119 }
2120
2121 #define __G_CONVERT_C__
2122 #include "galiasdef.c"