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