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