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