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