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