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