Fix spelling Add g_return_val_if_fail.
[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_display_name().
1021  *
1022  * On Unix, the character sets are determined by consulting the
1023  * environment variables <envar>G_FILENAME_ENCODING</envar> and
1024  * <envar>G_BROKEN_FILENAMES</envar>. On Windows, the character set
1025  * used in the GLib API is always UTF-8 and said environment variables
1026  * have no effect.
1027  *
1028  * <envar>G_FILENAME_ENCODING</envar> may be set to a comma-separated list 
1029  * of character set names. The special token "@locale" is taken to mean the 
1030  * character set for the current locale. If <envar>G_FILENAME_ENCODING</envar> 
1031  * is not set, but <envar>G_BROKEN_FILENAMES</envar> is, the character set of 
1032  * the current locale is taken as the filename encoding. If neither environment
1033  * variable is set, UTF-8 is taken as the filename encoding, but the character
1034  * set of the current locale is also put in the list of encodings.
1035  *
1036  * The returned @charsets belong to GLib and must not be freed.
1037  *
1038  * Note that on Unix, regardless of the locale character set or
1039  * <envar>G_FILENAME_ENCODING</envar> value, the actual file names present on a
1040  * system might be in any random encoding or just gibberish.
1041  *
1042  * Return value: %TRUE if the filename encoding is UTF-8.
1043  * 
1044  * Since: 2.6
1045  */
1046 gboolean
1047 g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets)
1048 {
1049   static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
1050   GFilenameCharsetCache *cache = g_static_private_get (&cache_private);
1051   const gchar *charset;
1052
1053   if (!cache)
1054     {
1055       cache = g_new0 (GFilenameCharsetCache, 1);
1056       g_static_private_set (&cache_private, cache, filename_charset_cache_free);
1057     }
1058
1059   g_get_charset (&charset);
1060
1061   if (!(cache->charset && strcmp (cache->charset, charset) == 0))
1062     {
1063       const gchar *new_charset;
1064       gchar *p;
1065       gint i;
1066
1067       g_free (cache->charset);
1068       g_strfreev (cache->filename_charsets);
1069       cache->charset = g_strdup (charset);
1070       
1071       p = getenv ("G_FILENAME_ENCODING");
1072       if (p != NULL) 
1073         {
1074           cache->filename_charsets = g_strsplit (p, ",", 0);
1075           cache->is_utf8 = (strcmp (cache->filename_charsets[0], "UTF-8") == 0);
1076
1077           for (i = 0; cache->filename_charsets[i]; i++)
1078             {
1079               if (strcmp ("@locale", cache->filename_charsets[i]) == 0)
1080                 {
1081                   g_get_charset (&new_charset);
1082                   g_free (cache->filename_charsets[i]);
1083                   cache->filename_charsets[i] = g_strdup (new_charset);
1084                 }
1085             }
1086         }
1087       else if (getenv ("G_BROKEN_FILENAMES") != NULL)
1088         {
1089           cache->filename_charsets = g_new0 (gchar *, 2);
1090           cache->is_utf8 = g_get_charset (&new_charset);
1091           cache->filename_charsets[0] = g_strdup (new_charset);
1092         }
1093       else 
1094         {
1095           cache->filename_charsets = g_new0 (gchar *, 3);
1096           cache->is_utf8 = TRUE;
1097           cache->filename_charsets[0] = g_strdup ("UTF-8");
1098           if (!g_get_charset (&new_charset))
1099             cache->filename_charsets[1] = g_strdup (new_charset);
1100         }
1101     }
1102
1103   if (filename_charsets)
1104     *filename_charsets = (const gchar **)cache->filename_charsets;
1105
1106   return cache->is_utf8;
1107 }
1108
1109 #else /* G_PLATFORM_WIN32 */
1110
1111 gboolean
1112 g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets) 
1113 {
1114   static gchar *charsets[] = {
1115     "UTF-8",
1116     NULL
1117   };
1118
1119 #ifdef G_OS_WIN32
1120   /* On Windows GLib pretends that the filename charset is UTF-8 */
1121   if (filename_charsets)
1122     *filename_charsets = charsets;
1123
1124   return TRUE;
1125 #else
1126   gboolean result;
1127
1128   /* Cygwin works like before */
1129   result = g_get_charset (&(charsets[0]));
1130
1131   if (filename_charsets)
1132     *filename_charsets = charsets;
1133
1134   return result;
1135 #endif
1136 }
1137
1138 #endif /* G_PLATFORM_WIN32 */
1139
1140 static gboolean
1141 get_filename_charset (const gchar **filename_charset)
1142 {
1143   const gchar **charsets;
1144   gboolean is_utf8;
1145   
1146   is_utf8 = g_get_filename_charsets (&charsets);
1147
1148   if (filename_charset)
1149     *filename_charset = charsets[0];
1150   
1151   return is_utf8;
1152 }
1153
1154 /* This is called from g_thread_init(). It's used to
1155  * initialize some static data in a threadsafe way.
1156  */
1157 void 
1158 _g_convert_thread_init (void)
1159 {
1160   const gchar **dummy;
1161   (void) g_get_filename_charsets (&dummy);
1162 }
1163
1164 /**
1165  * g_filename_to_utf8:
1166  * @opsysstring:   a string in the encoding for filenames
1167  * @len:           the length of the string, or -1 if the string is
1168  *                 nul-terminated.
1169  * @bytes_read:    location to store the number of bytes in the
1170  *                 input string that were successfully converted, or %NULL.
1171  *                 Even if the conversion was successful, this may be 
1172  *                 less than @len if there were partial characters
1173  *                 at the end of the input. If the error
1174  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1175  *                 stored will the byte offset after the last valid
1176  *                 input sequence.
1177  * @bytes_written: the number of bytes stored in the output buffer (not 
1178  *                 including the terminating nul).
1179  * @error:         location to store the error occuring, or %NULL to ignore
1180  *                 errors. Any of the errors in #GConvertError may occur.
1181  * 
1182  * Converts a string which is in the encoding used by GLib for filenames
1183  * into a UTF-8 string.
1184  * 
1185  * Return value: The converted string, or %NULL on an error.
1186  **/
1187 gchar*
1188 g_filename_to_utf8 (const gchar *opsysstring, 
1189                     gssize       len,           
1190                     gsize       *bytes_read,   
1191                     gsize       *bytes_written,
1192                     GError     **error)
1193 {
1194   const gchar *charset;
1195
1196   if (get_filename_charset (&charset))
1197     return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
1198   else
1199     return g_convert (opsysstring, len, 
1200                       "UTF-8", charset, bytes_read, bytes_written, error);
1201 }
1202
1203 #ifdef G_OS_WIN32
1204
1205 #undef g_filename_to_utf8
1206
1207 /* Binary compatibility version. Not for newly compiled code. */
1208
1209 gchar*
1210 g_filename_to_utf8 (const gchar *opsysstring, 
1211                     gssize       len,           
1212                     gsize       *bytes_read,   
1213                     gsize       *bytes_written,
1214                     GError     **error)
1215 {
1216   const gchar *charset;
1217
1218   if (g_get_charset (&charset))
1219     return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
1220   else
1221     return g_convert (opsysstring, len, 
1222                       "UTF-8", charset, bytes_read, bytes_written, error);
1223 }
1224
1225 #endif
1226
1227 /**
1228  * g_filename_from_utf8:
1229  * @utf8string:    a UTF-8 encoded string.
1230  * @len:           the length of the string, or -1 if the string is
1231  *                 nul-terminated.
1232  * @bytes_read:    location to store the number of bytes in the
1233  *                 input string that were successfully converted, or %NULL.
1234  *                 Even if the conversion was successful, this may be 
1235  *                 less than @len if there were partial characters
1236  *                 at the end of the input. If the error
1237  *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
1238  *                 stored will the byte offset after the last valid
1239  *                 input sequence.
1240  * @bytes_written: the number of bytes stored in the output buffer (not 
1241  *                 including the terminating nul).
1242  * @error:         location to store the error occuring, or %NULL to ignore
1243  *                 errors. Any of the errors in #GConvertError may occur.
1244  * 
1245  * Converts a string from UTF-8 to the encoding used for filenames.
1246  * 
1247  * Return value: The converted string, or %NULL on an error.
1248  **/
1249 gchar*
1250 g_filename_from_utf8 (const gchar *utf8string,
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 (utf8string, len, bytes_read, bytes_written, error);
1260   else
1261     return g_convert (utf8string, len,
1262                       charset, "UTF-8", bytes_read, bytes_written, error);
1263 }
1264
1265 #ifdef G_OS_WIN32
1266
1267 #undef g_filename_from_utf8
1268
1269 /* Binary compatibility version. Not for newly compiled code. */
1270
1271 gchar*
1272 g_filename_from_utf8 (const gchar *utf8string,
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 (utf8string, len, bytes_read, bytes_written, error);
1282   else
1283     return g_convert (utf8string, len,
1284                       charset, "UTF-8", bytes_read, bytes_written, error);
1285 }
1286
1287 #endif
1288
1289 /* Test of haystack has the needle prefix, comparing case
1290  * insensitive. haystack may be UTF-8, but needle must
1291  * contain only ascii. */
1292 static gboolean
1293 has_case_prefix (const gchar *haystack, const gchar *needle)
1294 {
1295   const gchar *h, *n;
1296   
1297   /* Eat one character at a time. */
1298   h = haystack;
1299   n = needle;
1300
1301   while (*n && *h &&
1302          g_ascii_tolower (*n) == g_ascii_tolower (*h))
1303     {
1304       n++;
1305       h++;
1306     }
1307   
1308   return *n == '\0';
1309 }
1310
1311 typedef enum {
1312   UNSAFE_ALL        = 0x1,  /* Escape all unsafe characters   */
1313   UNSAFE_ALLOW_PLUS = 0x2,  /* Allows '+'  */
1314   UNSAFE_PATH       = 0x8,  /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
1315   UNSAFE_HOST       = 0x10, /* Allows '/' and ':' and '@' */
1316   UNSAFE_SLASHES    = 0x20  /* Allows all characters except for '/' and '%' */
1317 } UnsafeCharacterSet;
1318
1319 static const guchar acceptable[96] = {
1320   /* A table of the ASCII chars from space (32) to DEL (127) */
1321   /*      !    "    #    $    %    &    '    (    )    *    +    ,    -    .    / */ 
1322   0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
1323   /* 0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ? */
1324   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
1325   /* @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O */
1326   0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
1327   /* P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _ */
1328   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
1329   /* `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o */
1330   0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
1331   /* p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~  DEL */
1332   0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
1333 };
1334
1335 static const gchar hex[16] = "0123456789ABCDEF";
1336
1337 /* Note: This escape function works on file: URIs, but if you want to
1338  * escape something else, please read RFC-2396 */
1339 static gchar *
1340 g_escape_uri_string (const gchar *string, 
1341                      UnsafeCharacterSet mask)
1342 {
1343 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
1344
1345   const gchar *p;
1346   gchar *q;
1347   gchar *result;
1348   int c;
1349   gint unacceptable;
1350   UnsafeCharacterSet use_mask;
1351   
1352   g_return_val_if_fail (mask == UNSAFE_ALL
1353                         || mask == UNSAFE_ALLOW_PLUS
1354                         || mask == UNSAFE_PATH
1355                         || mask == UNSAFE_HOST
1356                         || mask == UNSAFE_SLASHES, NULL);
1357   
1358   unacceptable = 0;
1359   use_mask = mask;
1360   for (p = string; *p != '\0'; p++)
1361     {
1362       c = (guchar) *p;
1363       if (!ACCEPTABLE (c)) 
1364         unacceptable++;
1365     }
1366   
1367   result = g_malloc (p - string + unacceptable * 2 + 1);
1368   
1369   use_mask = mask;
1370   for (q = result, p = string; *p != '\0'; p++)
1371     {
1372       c = (guchar) *p;
1373       
1374       if (!ACCEPTABLE (c))
1375         {
1376           *q++ = '%'; /* means hex coming */
1377           *q++ = hex[c >> 4];
1378           *q++ = hex[c & 15];
1379         }
1380       else
1381         *q++ = *p;
1382     }
1383   
1384   *q = '\0';
1385   
1386   return result;
1387 }
1388
1389
1390 static gchar *
1391 g_escape_file_uri (const gchar *hostname,
1392                    const gchar *pathname)
1393 {
1394   char *escaped_hostname = NULL;
1395   char *escaped_path;
1396   char *res;
1397
1398 #ifdef G_OS_WIN32
1399   char *p, *backslash;
1400
1401   /* Turn backslashes into forward slashes. That's what Netscape
1402    * does, and they are actually more or less equivalent in Windows.
1403    */
1404   
1405   pathname = g_strdup (pathname);
1406   p = (char *) pathname;
1407   
1408   while ((backslash = strchr (p, '\\')) != NULL)
1409     {
1410       *backslash = '/';
1411       p = backslash + 1;
1412     }
1413 #endif
1414
1415   if (hostname && *hostname != '\0')
1416     {
1417       escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST);
1418     }
1419
1420   escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH);
1421
1422   res = g_strconcat ("file://",
1423                      (escaped_hostname) ? escaped_hostname : "",
1424                      (*escaped_path != '/') ? "/" : "",
1425                      escaped_path,
1426                      NULL);
1427
1428 #ifdef G_OS_WIN32
1429   g_free ((char *) pathname);
1430 #endif
1431
1432   g_free (escaped_hostname);
1433   g_free (escaped_path);
1434   
1435   return res;
1436 }
1437
1438 static int
1439 unescape_character (const char *scanner)
1440 {
1441   int first_digit;
1442   int second_digit;
1443
1444   first_digit = g_ascii_xdigit_value (scanner[0]);
1445   if (first_digit < 0) 
1446     return -1;
1447   
1448   second_digit = g_ascii_xdigit_value (scanner[1]);
1449   if (second_digit < 0) 
1450     return -1;
1451   
1452   return (first_digit << 4) | second_digit;
1453 }
1454
1455 static gchar *
1456 g_unescape_uri_string (const char *escaped,
1457                        int         len,
1458                        const char *illegal_escaped_characters,
1459                        gboolean    ascii_must_not_be_escaped)
1460 {
1461   const gchar *in, *in_end;
1462   gchar *out, *result;
1463   int c;
1464   
1465   if (escaped == NULL)
1466     return NULL;
1467
1468   if (len < 0)
1469     len = strlen (escaped);
1470
1471   result = g_malloc (len + 1);
1472   
1473   out = result;
1474   for (in = escaped, in_end = escaped + len; in < in_end; in++)
1475     {
1476       c = *in;
1477
1478       if (c == '%')
1479         {
1480           /* catch partial escape sequences past the end of the substring */
1481           if (in + 3 > in_end)
1482             break;
1483
1484           c = unescape_character (in + 1);
1485
1486           /* catch bad escape sequences and NUL characters */
1487           if (c <= 0)
1488             break;
1489
1490           /* catch escaped ASCII */
1491           if (ascii_must_not_be_escaped && c <= 0x7F)
1492             break;
1493
1494           /* catch other illegal escaped characters */
1495           if (strchr (illegal_escaped_characters, c) != NULL)
1496             break;
1497
1498           in += 2;
1499         }
1500
1501       *out++ = c;
1502     }
1503   
1504   g_assert (out - result <= len);
1505   *out = '\0';
1506
1507   if (in != in_end)
1508     {
1509       g_free (result);
1510       return NULL;
1511     }
1512
1513   return result;
1514 }
1515
1516 static gboolean
1517 is_asciialphanum (gunichar c)
1518 {
1519   return c <= 0x7F && g_ascii_isalnum (c);
1520 }
1521
1522 static gboolean
1523 is_asciialpha (gunichar c)
1524 {
1525   return c <= 0x7F && g_ascii_isalpha (c);
1526 }
1527
1528 /* allows an empty string */
1529 static gboolean
1530 hostname_validate (const char *hostname)
1531 {
1532   const char *p;
1533   gunichar c, first_char, last_char;
1534
1535   p = hostname;
1536   if (*p == '\0')
1537     return TRUE;
1538   do
1539     {
1540       /* read in a label */
1541       c = g_utf8_get_char (p);
1542       p = g_utf8_next_char (p);
1543       if (!is_asciialphanum (c))
1544         return FALSE;
1545       first_char = c;
1546       do
1547         {
1548           last_char = c;
1549           c = g_utf8_get_char (p);
1550           p = g_utf8_next_char (p);
1551         }
1552       while (is_asciialphanum (c) || c == '-');
1553       if (last_char == '-')
1554         return FALSE;
1555       
1556       /* if that was the last label, check that it was a toplabel */
1557       if (c == '\0' || (c == '.' && *p == '\0'))
1558         return is_asciialpha (first_char);
1559     }
1560   while (c == '.');
1561   return FALSE;
1562 }
1563
1564 /**
1565  * g_filename_from_uri:
1566  * @uri: a uri describing a filename (escaped, encoded in ASCII).
1567  * @hostname: Location to store hostname for the URI, or %NULL.
1568  *            If there is no hostname in the URI, %NULL will be
1569  *            stored in this location.
1570  * @error: location to store the error occuring, or %NULL to ignore
1571  *         errors. Any of the errors in #GConvertError may occur.
1572  * 
1573  * Converts an escaped ASCII-encoded URI to a local filename in the
1574  * encoding used for filenames. 
1575  * 
1576  * Return value: a newly-allocated string holding the resulting
1577  *               filename, or %NULL on an error.
1578  **/
1579 gchar *
1580 g_filename_from_uri (const gchar *uri,
1581                      gchar      **hostname,
1582                      GError     **error)
1583 {
1584   const char *path_part;
1585   const char *host_part;
1586   char *unescaped_hostname;
1587   char *result;
1588   char *filename;
1589   int offs;
1590 #ifdef G_OS_WIN32
1591   char *p, *slash;
1592 #endif
1593
1594   if (hostname)
1595     *hostname = NULL;
1596
1597   if (!has_case_prefix (uri, "file:/"))
1598     {
1599       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1600                    _("The URI '%s' is not an absolute URI using the \"file\" scheme"),
1601                    uri);
1602       return NULL;
1603     }
1604   
1605   path_part = uri + strlen ("file:");
1606   
1607   if (strchr (path_part, '#') != NULL)
1608     {
1609       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1610                    _("The local file URI '%s' may not include a '#'"),
1611                    uri);
1612       return NULL;
1613     }
1614         
1615   if (has_case_prefix (path_part, "///")) 
1616     path_part += 2;
1617   else if (has_case_prefix (path_part, "//"))
1618     {
1619       path_part += 2;
1620       host_part = path_part;
1621
1622       path_part = strchr (path_part, '/');
1623
1624       if (path_part == NULL)
1625         {
1626           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1627                        _("The URI '%s' is invalid"),
1628                        uri);
1629           return NULL;
1630         }
1631
1632       unescaped_hostname = g_unescape_uri_string (host_part, path_part - host_part, "", TRUE);
1633
1634       if (unescaped_hostname == NULL ||
1635           !hostname_validate (unescaped_hostname))
1636         {
1637           g_free (unescaped_hostname);
1638           g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1639                        _("The hostname of the URI '%s' is invalid"),
1640                        uri);
1641           return NULL;
1642         }
1643       
1644       if (hostname)
1645         *hostname = unescaped_hostname;
1646       else
1647         g_free (unescaped_hostname);
1648     }
1649
1650   filename = g_unescape_uri_string (path_part, -1, "/", FALSE);
1651
1652   if (filename == NULL)
1653     {
1654       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
1655                    _("The URI '%s' contains invalidly escaped characters"),
1656                    uri);
1657       return NULL;
1658     }
1659
1660   offs = 0;
1661 #ifdef G_OS_WIN32
1662   /* Drop localhost */
1663   if (hostname && *hostname != NULL &&
1664       g_ascii_strcasecmp (*hostname, "localhost") == 0)
1665     {
1666       g_free (*hostname);
1667       *hostname = NULL;
1668     }
1669
1670   /* Turn slashes into backslashes, because that's the canonical spelling */
1671   p = filename;
1672   while ((slash = strchr (p, '/')) != NULL)
1673     {
1674       *slash = '\\';
1675       p = slash + 1;
1676     }
1677
1678   /* Windows URIs with a drive letter can be like "file://host/c:/foo"
1679    * or "file://host/c|/foo" (some Netscape versions). In those cases, start
1680    * the filename from the drive letter.
1681    */
1682   if (g_ascii_isalpha (filename[1]))
1683     {
1684       if (filename[2] == ':')
1685         offs = 1;
1686       else if (filename[2] == '|')
1687         {
1688           filename[2] = ':';
1689           offs = 1;
1690         }
1691     }
1692 #endif
1693
1694   result = g_strdup (filename + offs);
1695   g_free (filename);
1696
1697   return result;
1698 }
1699
1700 #ifdef G_OS_WIN32
1701
1702 #undef g_filename_from_uri
1703
1704 gchar *
1705 g_filename_from_uri (const gchar *uri,
1706                      gchar      **hostname,
1707                      GError     **error)
1708 {
1709   gchar *utf8_filename;
1710   gchar *retval = NULL;
1711
1712   utf8_filename = g_filename_from_uri_utf8 (uri, hostname, error);
1713   if (utf8_filename)
1714     {
1715       retval = g_locale_from_utf8 (utf8_filename, -1, NULL, NULL, error);
1716       g_free (utf8_filename);
1717     }
1718   return retval;
1719 }
1720
1721 #endif
1722
1723 /**
1724  * g_filename_to_uri:
1725  * @filename: an absolute filename specified in the encoding
1726  *            used for filenames by the operating system.
1727  * @hostname: A UTF-8 encoded hostname, or %NULL for none.
1728  * @error: location to store the error occuring, or %NULL to ignore
1729  *         errors. Any of the errors in #GConvertError may occur.
1730  * 
1731  * Converts an absolute filename to an escaped ASCII-encoded URI.
1732  * 
1733  * Return value: a newly-allocated string holding the resulting
1734  *               URI, or %NULL on an error.
1735  **/
1736 gchar *
1737 g_filename_to_uri (const gchar *filename,
1738                    const gchar *hostname,
1739                    GError     **error)
1740 {
1741   char *escaped_uri;
1742
1743   g_return_val_if_fail (filename != NULL, NULL);
1744
1745   if (!g_path_is_absolute (filename))
1746     {
1747       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH,
1748                    _("The pathname '%s' is not an absolute path"),
1749                    filename);
1750       return NULL;
1751     }
1752
1753   if (hostname &&
1754       !(g_utf8_validate (hostname, -1, NULL)
1755         && hostname_validate (hostname)))
1756     {
1757       g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1758                    _("Invalid hostname"));
1759       return NULL;
1760     }
1761   
1762 #ifdef G_OS_WIN32
1763   /* Don't use localhost unnecessarily */
1764   if (hostname && g_ascii_strcasecmp (hostname, "localhost") == 0)
1765     hostname = NULL;
1766 #endif
1767
1768   escaped_uri = g_escape_file_uri (hostname, filename);
1769
1770   return escaped_uri;
1771 }
1772
1773 #ifdef G_OS_WIN32
1774
1775 #undef g_filename_to_uri
1776
1777 gchar *
1778 g_filename_to_uri (const gchar *filename,
1779                    const gchar *hostname,
1780                    GError     **error)
1781 {
1782   gchar *utf8_filename;
1783   gchar *retval = NULL;
1784
1785   utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
1786
1787   if (utf8_filename)
1788     {
1789       retval = g_filename_to_uri_utf8 (utf8_filename, hostname, error);
1790       g_free (utf8_filename);
1791     }
1792
1793   return retval;
1794 }
1795
1796 #endif
1797
1798 /**
1799  * g_uri_list_extract_uris:
1800  * @uri_list: an URI list 
1801  *
1802  * Splits an URI list conforming to the text/uri-list
1803  * mime type defined in RFC 2483 into individual URIs,
1804  * discarding any comments. The URIs are not validated.
1805  *
1806  * Returns: a newly allocated %NULL-terminated list of
1807  *   strings holding the individual URIs. The array should
1808  *   be freed with g_strfreev().
1809  *
1810  * Since: 2.6
1811  */
1812 gchar **
1813 g_uri_list_extract_uris (const gchar *uri_list)
1814 {
1815   GSList *uris, *u;
1816   const gchar *p, *q;
1817   gchar **result;
1818   gint n_uris = 0;
1819
1820   uris = NULL;
1821
1822   p = uri_list;
1823
1824   /* We don't actually try to validate the URI according to RFC
1825    * 2396, or even check for allowed characters - we just ignore
1826    * comments and trim whitespace off the ends.  We also
1827    * allow LF delimination as well as the specified CRLF.
1828    *
1829    * We do allow comments like specified in RFC 2483.
1830    */
1831   while (p)
1832     {
1833       if (*p != '#')
1834         {
1835           while (g_ascii_isspace (*p))
1836             p++;
1837
1838           q = p;
1839           while (*q && (*q != '\n') && (*q != '\r'))
1840             q++;
1841
1842           if (q > p)
1843             {
1844               q--;
1845               while (q > p && g_ascii_isspace (*q))
1846                 q--;
1847
1848               if (q > p)
1849                 {
1850                   uris = g_slist_prepend (uris, g_strndup (p, q - p + 1));
1851                   n_uris++;
1852                 }
1853             }
1854         }
1855       p = strchr (p, '\n');
1856       if (p)
1857         p++;
1858     }
1859
1860   result = g_new (gchar *, n_uris + 1);
1861
1862   result[n_uris--] = NULL;
1863   for (u = uris; u; u = u->next)
1864     result[n_uris--] = u->data;
1865
1866   g_slist_free (uris);
1867
1868   return result;
1869 }
1870
1871 static gchar *
1872 make_valid_utf8 (const gchar *name)
1873 {
1874   GString *string;
1875   const gchar *remainder, *invalid;
1876   gint remaining_bytes, valid_bytes;
1877   
1878   string = NULL;
1879   remainder = name;
1880   remaining_bytes = strlen (name);
1881   
1882   while (remaining_bytes != 0) 
1883     {
1884       if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
1885         break;
1886       valid_bytes = invalid - remainder;
1887     
1888       if (string == NULL) 
1889         string = g_string_sized_new (remaining_bytes);
1890
1891       g_string_append_len (string, remainder, valid_bytes);
1892       g_string_append_c (string, '?');
1893       
1894       remaining_bytes -= valid_bytes + 1;
1895       remainder = invalid + 1;
1896     }
1897   
1898   if (string == NULL)
1899     return g_strdup (name);
1900   
1901   g_string_append (string, remainder);
1902   g_string_append (string, " (invalid encoding)");
1903
1904   g_assert (g_utf8_validate (string->str, -1, NULL));
1905   
1906   return g_string_free (string, FALSE);
1907 }
1908
1909 /**
1910  * g_filename_display_basename:
1911  * @filename: an absolute pathname in the GLib file name encoding
1912  *
1913  * Returns the display basename for the particular filename, guaranteed
1914  * to be valid UTF-8. The display name might not be identical to the filename,
1915  * for instance there might be problems converting it to UTF-8, and some files
1916  * can be translated in the display
1917  *
1918  * You must pass the whole absolute pathname to this functions so that
1919  * translation of well known locations can be done.
1920  *
1921  * This function is preferred over g_filename_display_name() if you know the
1922  * whole path, as it allows translation.
1923  *
1924  * Return value: a newly allocated string containing
1925  *   a rendition of the basename of the filename in valid UTF-8
1926  *
1927  * Since: 2.6
1928  **/
1929 gchar *
1930 g_filename_display_basename (const gchar *filename)
1931 {
1932   char *basename;
1933   char *display_name;
1934
1935   g_return_val_if_fail (filename != NULL, NULL);
1936   
1937   basename = g_path_get_basename (filename);
1938   display_name = g_filename_display_name (basename);
1939   g_free (basename);
1940   return display_name;
1941 }
1942
1943 /**
1944  * g_filename_display_name:
1945  * @filename: a pathname hopefully in the GLib file name encoding
1946  * 
1947  * Converts a filename into a valid UTF-8 string. The 
1948  * conversion is not necessarily reversible, so you 
1949  * should keep the original around and use the return
1950  * value of this function only for display purposes.
1951  * Unlike g_filename_to_utf8(), the result is guaranteed 
1952  * to be non-NULL even if the filename actually isn't in the GLib
1953  * file name encoding.
1954  *
1955  * If you know the whole pathname of the file you should use
1956  * g_filename_display_basename(), since that allows location-based
1957  * translation of filenames.
1958  *
1959  * Return value: a newly allocated string containing
1960  *   a rendition of the filename in valid UTF-8
1961  *
1962  * Since: 2.6
1963  **/
1964 gchar *
1965 g_filename_display_name (const gchar *filename)
1966 {
1967   gint i;
1968   const gchar **charsets;
1969   gchar *display_name = NULL;
1970   gboolean is_utf8;
1971  
1972   is_utf8 = g_get_filename_charsets (&charsets);
1973
1974   if (is_utf8)
1975     {
1976       if (g_utf8_validate (filename, -1, NULL))
1977         display_name = g_strdup (filename);
1978     }
1979   
1980   if (!display_name)
1981     {
1982       /* Try to convert from the filename charsets to UTF-8.
1983        * Skip the first charset if it is UTF-8.
1984        */
1985       for (i = is_utf8 ? 1 : 0; charsets[i]; i++)
1986         {
1987           display_name = g_convert (filename, -1, "UTF-8", charsets[i], 
1988                                     NULL, NULL, NULL);
1989
1990           if (display_name)
1991             break;
1992         }
1993     }
1994   
1995   /* if all conversions failed, we replace invalid UTF-8
1996    * by a question mark
1997    */
1998   if (!display_name) 
1999     display_name = make_valid_utf8 (filename);
2000
2001   return display_name;
2002 }
2003