diff --git a/NEWS b/NEWS index a2e35ba..ccf927c 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,11 @@ Changes in 0.5.0 (SVN): files come from a broken encoder/tagging program. Disabled by default, this feature can be enabled with the new `-n' command line parameter. + - [NEW] Enable Unicode support in TagLib and convert metadata strings + to the current locale (LC_CTYPE) before displaying them on the + console. Unsupported characters are displayed as '?', which + does not affect the actual metadata. This feature requires + iconv() via libc, if available, or libiconv. - [MISC] Add new --enable-debug configuration option to the configure script, which enables (also new) memory debugging features. (Not interesting for non-developers.) diff --git a/configure.in b/configure.in index 5042df1..2954282 100644 --- a/configure.in +++ b/configure.in @@ -39,7 +39,7 @@ if test -z "$GCC"; then ;; esac else - XIPH_CPPFLAGS="-fstrict-aliasing -Wall -W -Wno-unused-parameter -Wwrite-strings -Wpointer-arith -Wsign-compare -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations" + XIPH_CPPFLAGS="-fstrict-aliasing -Wall -Wno-unused-parameter -Wwrite-strings -Wpointer-arith -Wsign-compare -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations" fi ez_enable_debug=no @@ -89,7 +89,7 @@ AC_CHECK_TYPES(ssize_t, , dnl USEFUL HEADERS -AC_CHECK_HEADERS(sys/time.h paths.h signal.h libgen.h) +AC_CHECK_HEADERS(sys/time.h paths.h signal.h langinfo.h libgen.h locale.h) COMPAT_INCLUDES="" if test x"$ez_enable_debug" = "xyes"; then @@ -119,13 +119,14 @@ AC_SUBST(COMPAT_INCLUDES) dnl LIBRARY FUNCTIONS AC_CHECK_LIB(gen, basename) -AC_CHECK_FUNCS(arc4random gettimeofday random srandomdev stat) +AC_CHECK_FUNCS(arc4random gettimeofday nl_langinfo random setlocale srandomdev stat) AC_REPLACE_FUNCS(getopt strlcat strlcpy strtonum) if test x"$ac_cv_header_signal_h" = "xyes"; then AC_CHECK_FUNCS([sigaction], [ AC_DEFINE(HAVE_SIGNALS, 1, [Define whether we have BSD signals]) ], [], [#include ]) fi +AM_ICONV dnl CONFIGURE OPTIONS @@ -208,10 +209,6 @@ if test x"$use_taglib" != "xno"; then CFLAGS="$ac_taglib_save_CFLAGS" CPPFLAGS="$ac_taglib_save_CPPFLAGS" LIBS="$ac_taglib_save_LIBS" - - AM_ICONV - AC_CHECK_HEADERS(langinfo.h locale.h) - AC_CHECK_FUNCS(setlocale nl_langinfo) else AC_MSG_RESULT([disabled]) fi diff --git a/doc/ezstream.1.in b/doc/ezstream.1.in index 9b4a6ab..6f96876 100644 --- a/doc/ezstream.1.in +++ b/doc/ezstream.1.in @@ -461,6 +461,8 @@ When called with the command line parameter .Qq Li title , the program should return only the title information of the metadata. .Pq Optional. +.It +The supplied metadata should be encoded in UTF-8. .El .Sh METADATA The main tool for handling metadata with diff --git a/src/ezstream.c b/src/ezstream.c index b707d91..f47089a 100644 --- a/src/ezstream.c +++ b/src/ezstream.c @@ -851,8 +851,11 @@ streamFile(shout_t *shout, const char *fileName) } if (mdata != NULL) { - char *metaData = metadata_assemble_string(mdata); + char *tmp, *metaData; + tmp = metadata_assemble_string(mdata); + metaData = utf82char(tmp); + xfree(tmp); printf("%s: Streaming ``%s''", __progname, metaData); if (vFlag) printf(" (file: %s)\n", fileName); diff --git a/src/metadata.c b/src/metadata.c index 4c9af5b..18ab36f 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -37,10 +37,12 @@ # include #endif #include +#include #include "compat.h" #include "metadata.h" #include "strfctns.h" +#include "util.h" #include "xalloc.h" extern char *__progname; @@ -109,7 +111,11 @@ metadata_use_taglib(metadata_t *md, FILE **filep) metadata_clean_md(md); taglib_set_string_management_enabled(0); +#ifdef HAVE_ICONV + taglib_set_strings_unicode(1); +#else taglib_set_strings_unicode(0); +#endif /* HAVE_ICONV */ if (md->string != NULL) { xfree(md->string); @@ -179,9 +185,9 @@ metadata_use_self(metadata_t *md, FILE **filep) fread(&id3tag, 1, sizeof(struct ID3Tag), *filep); if (memcmp(id3tag.tag, "TAG", 3) == 0) { if (strlen(id3tag.artistName) > 0) - md->artist = xstrdup(id3tag.artistName); + md->artist = char2utf8(id3tag.artistName); if (strlen(id3tag.trackName) > 0) - md->title = xstrdup(id3tag.trackName); + md->title = char2utf8(id3tag.trackName); } } else if (strcmp(extension, ".ogg") == 0) { OggVorbis_File vf; diff --git a/src/util.c b/src/util.c index 00d3816..9b861a1 100644 --- a/src/util.c +++ b/src/util.c @@ -46,6 +46,7 @@ #endif #include +#include "compat.h" #include "util.h" #include "configfile.h" #include "xalloc.h" @@ -230,21 +231,28 @@ char2utf8(const char *in_str) size_t input_len; char *output; size_t output_size; - char buf[4], *bp; + char buf[BUFSIZ], *bp; size_t bufavail; size_t out_pos; + +# ifndef WIN32 char *codeset; - if (in_str == NULL || strlen(in_str) == 0) - return (NULL); - -# if defined(HAVE_NL_LANGINFO) && defined(HAVE_SETLOCALE) +# if defined(HAVE_NL_LANGINFO) && defined(HAVE_SETLOCALE) && defined(CODESET) setlocale(LC_CTYPE, ""); codeset = nl_langinfo(CODESET); setlocale(LC_CTYPE, "C"); -# else +# else codeset = (char *)""; -# endif /* HAVE_NL_LANGINFO && HAVE_SETLOCALE */ +# endif /* HAVE_NL_LANGINFO && HAVE_SETLOCALE */ +# else + char codeset[24]; + + snprintf(codeset, sizeof(codeset), "CP%u", GetACP()); +# endif /* !WIN32 */ + + if (in_str == NULL || strlen(in_str) == 0) + return (NULL); if ((cd = iconv_open("UTF-8", codeset)) == (iconv_t)-1 && (cd = iconv_open("UTF-8", "")) == (iconv_t)-1) { @@ -264,7 +272,7 @@ char2utf8(const char *in_str) buf[0] = '\0'; bp = buf; - bufavail = sizeof(buf); + bufavail = sizeof(buf) - 1; if (iconv(cd, &ip, &input_len, &bp, &bufavail) == (size_t)-1 && errno != E2BIG) { @@ -275,7 +283,7 @@ char2utf8(const char *in_str) } *bp = '\0'; - count = sizeof(buf) - bufavail; + count = sizeof(buf) - bufavail - 1; output_size += count; op = output = xrealloc(output, output_size, sizeof(char)); @@ -308,21 +316,28 @@ utf82char(const char *in_str) size_t input_len; char *output; size_t output_size; - char buf[4], *bp; + char buf[BUFSIZ], *bp; size_t bufavail; size_t out_pos; + +# ifndef WIN32 char *codeset; - if (in_str == NULL || strlen(in_str) == 0) - return (NULL); - -# if defined(HAVE_NL_LANGINFO) && defined(HAVE_SETLOCALE) +# if defined(HAVE_NL_LANGINFO) && defined(HAVE_SETLOCALE) && defined(CODESET) setlocale(LC_CTYPE, ""); codeset = nl_langinfo(CODESET); setlocale(LC_CTYPE, "C"); -# else +# else codeset = (char *)""; -# endif /* HAVE_NL_LANGINFO && HAVE_SETLOCALE */ +# endif /* HAVE_NL_LANGINFO && HAVE_SETLOCALE */ +# else + char codeset[24]; + + snprintf(codeset, sizeof(codeset), "CP%u", GetACP()); +# endif /* !WIN32 */ + + if (in_str == NULL || strlen(in_str) == 0) + return (NULL); if ((cd = iconv_open(codeset, "UTF-8")) == (iconv_t)-1 && (cd = iconv_open("", "UTF-8")) == (iconv_t)-1) { @@ -342,7 +357,7 @@ utf82char(const char *in_str) buf[0] = '\0'; bp = buf; - bufavail = sizeof(buf); + bufavail = sizeof(buf) - 1; if (iconv(cd, &ip, &input_len, &bp, &bufavail) == (size_t)-1 && errno != E2BIG) { @@ -353,7 +368,7 @@ utf82char(const char *in_str) } *bp = '\0'; - count = sizeof(buf) - bufavail; + count = sizeof(buf) - bufavail - 1; output_size += count; op = output = xrealloc(output, output_size, sizeof(char)); diff --git a/win32/config.h b/win32/config.h index 073b2de..bafea14 100644 --- a/win32/config.h +++ b/win32/config.h @@ -2,10 +2,13 @@ #include #include -#define HAVE_INTTYPES_H 1 -#define HAVE_STAT 1 -#define HAVE_STDINT_H 1 -#define HAVE_SYS_STAT_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LOCALE_H 1 +#define HAVE_STAT 1 +#define HAVE_STDINT_H 1 +#define HAVE_SYS_STAT_H 1 + +#define ICONV_CONST const /* Name of package */ #define PACKAGE "ezstream" diff --git a/win32/ezstream.vcproj b/win32/ezstream.vcproj index 23bf159..0fdb939 100644 --- a/win32/ezstream.vcproj +++ b/win32/ezstream.vcproj @@ -28,7 +28,7 @@ InlineFunctionExpansion="1" ImproveFloatingPointConsistency="TRUE" AdditionalIncludeDirectories="../../ogg/include;../../vorbis/include;../../shout/include;../src;../../libxml2/include;../../libiconv/include;.;../compat" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;HAVE_ICONV" StringPooling="TRUE" ExceptionHandling="FALSE" BasicRuntimeChecks="0" @@ -96,7 +96,7 @@ Optimization="0" ImproveFloatingPointConsistency="TRUE" AdditionalIncludeDirectories="../../ogg/include;../../vorbis/include;../../shout/include;../src;../../libxml2/include;../../libiconv/include;.;../compat" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;XALLOC_DEBUG" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;HAVE_ICONV;XALLOC_DEBUG" ExceptionHandling="FALSE" BasicRuntimeChecks="3" RuntimeLibrary="1"