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