/* IRI related functions.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GNU Wget.
#include <stdio.h>
#include <stdlib.h>
-#include <assert.h>
#include <string.h>
#include <iconv.h>
#include <stringprep.h>
#include <errno.h>
#include "utils.h"
-#include "iri.h"
/* RFC3987 section 3.1 mandates STD3 ASCII RULES */
#define IDNA_FLAGS IDNA_USE_STD3_ASCII_RULES
/* Note: locale encoding is kept in options struct (opt.locale) */
-static iconv_t locale2utf8;
-
-static bool open_locale_to_utf8 (void);
static bool do_conversion (iconv_t cd, char *in, size_t inlen, char **out);
{
if (!c_isascii (*s) || c_isspace (*s))
{
- logprintf (LOG_VERBOSE, "Encoding %s isn't valid\n", quote (encoding));
+ logprintf (LOG_VERBOSE, _("Encoding %s isn't valid\n"), quote (encoding));
return false;
}
return true;
}
-/* Try opening an iconv_t descriptor for conversion from locale to UTF-8 */
-static bool
-open_locale_to_utf8 (void)
-{
- if (locale2utf8)
- return true;
-
- /* sXXXav : That shouldn't happen, just in case */
- if (!opt.locale)
- {
- logprintf (LOG_VERBOSE, "open_locale_to_utf8: locale is unset\n");
- opt.locale = find_locale ();
- }
-
- if (!opt.locale)
- return false;
-
- locale2utf8 = iconv_open ("UTF-8", opt.locale);
- if (locale2utf8 != (iconv_t)(-1))
- return true;
-
- logprintf (LOG_VERBOSE, "Conversion from %s to %s isn't supported\n",
- quote (opt.locale), quote ("UTF-8"));
- locale2utf8 = NULL;
- return false;
-}
-
/* Try converting string str from locale to UTF-8. Return a new string
on success, or str on error or if conversion isn't needed. */
const char *
locale_to_utf8 (const char *str)
{
+ iconv_t l2u;
char *new;
- if (!strcasecmp (opt.locale, "utf-8"))
- return str;
+ /* That shouldn't happen, just in case */
+ if (!opt.locale)
+ {
+ logprintf (LOG_VERBOSE, _("locale_to_utf8: locale is unset\n"));
+ opt.locale = find_locale ();
+ }
- if (!open_locale_to_utf8 ())
+ if (!opt.locale || !strcasecmp (opt.locale, "utf-8"))
return str;
- if (do_conversion (locale2utf8, (char *) str, strlen ((char *) str), &new))
+ l2u = iconv_open ("UTF-8", opt.locale);
+ if (l2u != (iconv_t)(-1))
+ {
+ logprintf (LOG_VERBOSE, _("Conversion from %s to %s isn't supported\n"),
+ quote (opt.locale), quote ("UTF-8"));
+ return str;
+ }
+
+ if (do_conversion (l2u, (char *) str, strlen ((char *) str), &new))
return (const char *) new;
return str;
}
/* Do the conversion according to the passed conversion descriptor cd. *out
- will containes the transcoded string on success. *out content is
+ will contain the transcoded string on success. *out content is
unspecified otherwise. */
static bool
do_conversion (iconv_t cd, char *in, size_t inlen, char **out)
{
if (!invalid)
logprintf (LOG_VERBOSE,
- "Incomplete or invalide multibyte sequence encountered\n");
+ _("Incomplete or invalid multibyte sequence encountered\n"));
invalid++;
**out = *in;
}
else /* Weird, we got an unspecified error */
{
- logprintf (LOG_VERBOSE, "Unhandled errno %d\n", errno);
+ logprintf (LOG_VERBOSE, _("Unhandled errno %d\n"), errno);
break;
}
}
if (!i->utf8_encode)
{
if (!remote_to_utf8 (i, (const char *) host, (const char **) &new))
- {
- /* Nothing to encode or an error occured */
- return NULL;
- }
-
+ return NULL; /* Nothing to encode or an error occured */
host = new;
}
if (ret != IDNA_SUCCESS)
{
/* sXXXav : free new when needed ! */
- logprintf (LOG_VERBOSE, "idn_encode failed (%d): %s\n", ret,
+ logprintf (LOG_VERBOSE, _("idn_encode failed (%d): %s\n"), ret,
quote (idna_strerror (ret)));
return NULL;
}
ret = idna_to_unicode_8zlz (host, &new, IDNA_FLAGS);
if (ret != IDNA_SUCCESS)
{
- logprintf (LOG_VERBOSE, "idn_decode failed (%d): %s\n", ret,
+ logprintf (LOG_VERBOSE, _("idn_decode failed (%d): %s\n"), ret,
quote (idna_strerror (ret)));
return NULL;
}
bool
remote_to_utf8 (struct iri *i, const char *str, const char **new)
{
- char *r;
iconv_t cd;
bool ret = false;
- if (opt.encoding_remote)
- r = opt.encoding_remote;
- else if (i->uri_encoding)
- r = i->uri_encoding;
- else
+ if (!i->uri_encoding)
return false;
- cd = iconv_open ("UTF-8", r);
+ /* When `i->uri_encoding' == "UTF-8" there is nothing to convert. But we must
+ test for non-ASCII symbols for correct hostname processing in `idn_encode'
+ function. */
+ if (!strcmp (i->uri_encoding, "UTF-8"))
+ {
+ int i, len = strlen (str);
+ for (i = 0; i < len; i++)
+ if ((unsigned char) str[i] >= (unsigned char) '\200')
+ {
+ *new = strdup (str);
+ return true;
+ }
+ return false;
+ }
+
+ cd = iconv_open ("UTF-8", i->uri_encoding);
if (cd == (iconv_t)(-1))
return false;
return ret;
}
+/* Allocate a new iri structure and return a pointer to it. */
struct iri *
iri_new (void)
{
- struct iri *i = xmalloc (sizeof (struct iri));
+ struct iri *i = xmalloc (sizeof *i);
i->uri_encoding = opt.encoding_remote ? xstrdup (opt.encoding_remote) : NULL;
i->content_encoding = NULL;
+ i->orig_url = NULL;
i->utf8_encode = opt.enable_iri;
+ return i;
}
+struct iri *iri_dup (const struct iri *src)
+{
+ struct iri *i = xmalloc (sizeof *i);
+ i->uri_encoding = src->uri_encoding ? xstrdup (src->uri_encoding) : NULL;
+ i->content_encoding = (src->content_encoding ?
+ xstrdup (src->content_encoding) : NULL);
+ i->orig_url = src->orig_url ? xstrdup (src->orig_url) : NULL;
+ i->utf8_encode = src->utf8_encode;
+ return i;
+}
+
+/* Completely free an iri structure. */
void
iri_free (struct iri *i)
{
xfree_null (i->uri_encoding);
xfree_null (i->content_encoding);
+ xfree_null (i->orig_url);
xfree (i);
}
+/* Set uri_encoding of struct iri i. If a remote encoding was specified, use
+ it unless force is true. */
void
-set_uri_encoding (struct iri *i, char *charset)
+set_uri_encoding (struct iri *i, char *charset, bool force)
{
- logprintf (LOG_VERBOSE, "[ uri = `%s'\n", charset);
- if (opt.encoding_remote)
+ DEBUGP (("URI encoding = %s\n", charset ? quote (charset) : "None"));
+ if (!force && opt.encoding_remote)
return;
if (i->uri_encoding)
{
- if (!strcasecmp (i->uri_encoding, charset))
+ if (charset && !strcasecmp (i->uri_encoding, charset))
return;
xfree (i->uri_encoding);
}
i->uri_encoding = charset ? xstrdup (charset) : NULL;
}
+/* Set content_encoding of struct iri i. */
void
set_content_encoding (struct iri *i, char *charset)
{
- logprintf (LOG_VERBOSE, "[ content = `%s'\n", charset);
+ DEBUGP (("URI content encoding = %s\n", charset ? quote (charset) : "None"));
if (opt.encoding_remote)
return;
if (i->content_encoding)
{
- if (!strcasecmp (i->content_encoding, charset))
+ if (charset && !strcasecmp (i->content_encoding, charset))
return;
xfree (i->content_encoding);
}