From 47def3207487c6c6c6fec81da6058dd853ea77f5 Mon Sep 17 00:00:00 2001 From: Karl Heyes Date: Thu, 30 Aug 2007 23:36:19 +0000 Subject: [PATCH] missed some NULL checks from previous character set commit. Add optional charset setting on metadata update request and conversion code for it. svn path=/icecast/trunk/icecast/; revision=13663 --- admin/updatemetadata.xsl | 1 + src/admin.c | 11 +++++----- src/format.h | 2 +- src/format_mp3.c | 43 +++++++++++++++++++------------------- src/format_vorbis.c | 45 ++++++++++++++++++---------------------- src/source.c | 18 ++++++++++------ src/util.c | 40 +++++++++++++++++++++++++++++++++++ src/util.h | 1 + 8 files changed, 103 insertions(+), 58 deletions(-) diff --git a/admin/updatemetadata.xsl b/admin/updatemetadata.xsl index 34ba0334..5f212568 100644 --- a/admin/updatemetadata.xsl +++ b/admin/updatemetadata.xsl @@ -48,6 +48,7 @@ +
diff --git a/src/admin.c b/src/admin.c index 0ff52d62..d8b4a750 100644 --- a/src/admin.c +++ b/src/admin.c @@ -854,7 +854,7 @@ static void command_metadata(client_t *client, source_t *source, int response) { const char *action; - const char *song, *title, *artist; + const char *song, *title, *artist, *charset; format_plugin_t *plugin; xmlDocPtr doc; xmlNodePtr node; @@ -869,6 +869,7 @@ static void command_metadata(client_t *client, source_t *source, COMMAND_OPTIONAL(client, "song", song); COMMAND_OPTIONAL(client, "title", title); COMMAND_OPTIONAL(client, "artist", artist); + COMMAND_OPTIONAL(client, "charset", charset); if (strcmp (action, "updinfo") != 0) { @@ -886,15 +887,15 @@ static void command_metadata(client_t *client, source_t *source, { if (song) { - plugin->set_tag (plugin, "song", song); + plugin->set_tag (plugin, "song", song, charset); INFO2 ("Metadata on mountpoint %s changed to \"%s\"", source->mount, song); } else { if (artist && title) { - plugin->set_tag (plugin, "title", title); - plugin->set_tag (plugin, "artist", artist); + plugin->set_tag (plugin, "title", title, charset); + plugin->set_tag (plugin, "artist", artist, charset); INFO3("Metadata on mountpoint %s changed to \"%s - %s\"", source->mount, artist, title); } @@ -936,7 +937,7 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) if (source->format && source->format->set_tag) { - source->format->set_tag (source->format, "title", value); + source->format->set_tag (source->format, "title", value, NULL); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); diff --git a/src/format.h b/src/format.h index f06c9b0c..d52b9e93 100644 --- a/src/format.h +++ b/src/format.h @@ -48,7 +48,7 @@ typedef struct _format_plugin_tag int (*write_buf_to_client)(client_t *client); void (*write_buf_to_file)(struct source_tag *source, refbuf_t *refbuf); int (*create_client_data)(struct source_tag *source, client_t *client); - void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value); + void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value, const char *charset); void (*free_plugin)(struct _format_plugin_tag *self); void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount); diff --git a/src/format_mp3.c b/src/format_mp3.c index 151ff15e..fd7311ab 100644 --- a/src/format_mp3.c +++ b/src/format_mp3.c @@ -61,7 +61,7 @@ static int format_mp3_create_client_data (source_t *source, client_t *client); static void free_mp3_client_data (client_t *client); static int format_mp3_write_buf_to_client(client_t *client); static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf); -static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *value); +static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset); static void format_mp3_apply_settings(client_t *client, format_plugin_t *format, mount_proxy *mount); @@ -124,42 +124,43 @@ int format_mp3_get_plugin (source_t *source) } -static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *value) +static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset) { mp3_state *source_mp3 = plugin->_state; unsigned int len; const char meta[] = "StreamTitle='"; int size = sizeof (meta) + 1; + char *value; - if (tag==NULL || value == NULL) + if (tag==NULL || in_value == NULL) return; + /* protect against multiple updaters */ + thread_mutex_lock (&source_mp3->url_lock); + + value = util_conv_string (in_value, charset, plugin->charset); + if (value == NULL) + value = strdup (in_value); + len = strlen (value)+1; size += len; - /* protect against multiple updaters */ - thread_mutex_lock (&source_mp3->url_lock); + if (strcmp (tag, "title") == 0 || strcmp (tag, "song") == 0) { - char *p = strdup (value); - if (p) - { - free (source_mp3->url_title); - free (source_mp3->url_artist); - source_mp3->url_artist = NULL; - source_mp3->url_title = p; - source_mp3->update_metadata = 1; - } + free (source_mp3->url_title); + free (source_mp3->url_artist); + source_mp3->url_artist = NULL; + source_mp3->url_title = value; + source_mp3->update_metadata = 1; } else if (strcmp (tag, "artist") == 0) { - char *p = strdup (value); - if (p) - { - free (source_mp3->url_artist); - source_mp3->url_artist = p; - source_mp3->update_metadata = 1; - } + free (source_mp3->url_artist); + source_mp3->url_artist = value; + source_mp3->update_metadata = 1; } + else + free (value); thread_mutex_unlock (&source_mp3->url_lock); } diff --git a/src/format_vorbis.c b/src/format_vorbis.c index fc438e6a..e0c39beb 100644 --- a/src/format_vorbis.c +++ b/src/format_vorbis.c @@ -67,7 +67,7 @@ static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec); static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page); static refbuf_t *process_vorbis (ogg_state_t *ogg_info, ogg_codec_t *codec); -static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *value); +static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *value, const char *charset); static void free_ogg_packet (ogg_packet *packet) @@ -413,12 +413,13 @@ ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page) /* called from the admin interface, here we update the artist/title info * and schedule a new set of header pages */ -static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *value) +static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = ogg_info->codecs; vorbis_codec_t *source_vorbis; int change = 0; + char *value; /* avoid updating if multiple codecs in use */ if (codec && codec->next == NULL) @@ -426,43 +427,37 @@ static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char else return; + value = util_conv_string (value, charset, "UTF-8"); + if (value == NULL) + value = strdup (in_value); + if (strcmp (tag, "artist") == 0) { - char *p = strdup (value); - if (p) - { - free (ogg_info->artist); - ogg_info->artist = p; - change = 1; - } + free (ogg_info->artist); + ogg_info->artist = value; + change = 1; } if (strcmp (tag, "title") == 0) { - char *p = strdup (value); - if (p) - { - free (ogg_info->title); - ogg_info->title = p; - change = 1; - } + free (ogg_info->title); + ogg_info->title = value; + change = 1; } if (strcmp (tag, "song") == 0) { - char *p = strdup (value); - if (p) - { - free (ogg_info->artist); - free (ogg_info->title); - ogg_info->artist = NULL; - ogg_info->title = p; - change = 1; - } + free (ogg_info->artist); + free (ogg_info->title); + ogg_info->artist = NULL; + ogg_info->title = value; + change = 1; } if (change) { source_vorbis->stream_notify = 1; source_vorbis->rebuild_comment = 1; } + else + free (value); } diff --git a/src/source.c b/src/source.c index a15d44ec..442ee0ab 100644 --- a/src/source.c +++ b/src/source.c @@ -949,6 +949,10 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) if (source->client) parser = source->client->parser; + /* to be done before possible non-utf8 stats */ + if (source->format && source->format->apply_settings) + source->format->apply_settings (source->client, source->format, mountinfo); + /* public */ if (mountinfo && mountinfo->yp_public >= 0) val = mountinfo->yp_public; @@ -994,7 +998,8 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) str = "Unspecified name"; } while (0); } - stats_event_conv (source->mount, "server_name", str, source->format->charset); + if (str && source->format) + stats_event_conv (source->mount, "server_name", str, source->format->charset); /* stream description */ if (mountinfo && mountinfo->stream_description) @@ -1011,7 +1016,8 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) str = "Unspecified description"; } while (0); } - stats_event_conv (source->mount, "server_description", str, source->format->charset); + if (str && source->format) + stats_event_conv (source->mount, "server_description", str, source->format->charset); /* stream URL */ if (mountinfo && mountinfo->stream_url) @@ -1027,7 +1033,8 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) if (str) break; } while (0); } - stats_event (source->mount, "server_url", str); + if (str && source->format) + stats_event_conv (source->mount, "server_url", str, source->format->charset); /* stream genre */ if (mountinfo && mountinfo->stream_genre) @@ -1044,7 +1051,8 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) str = "various"; } while (0); } - stats_event_conv (source->mount, "genre", str, source->format->charset); + if (str && source->format) + stats_event_conv (source->mount, "genre", str, source->format->charset); /* stream bitrate */ if (mountinfo && mountinfo->bitrate) @@ -1132,8 +1140,6 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) if (mountinfo && mountinfo->fallback_when_full) source->fallback_when_full = mountinfo->fallback_when_full; - if (source->format && source->format->apply_settings) - source->format->apply_settings (source->client, source->format, mountinfo); avl_tree_unlock (source->client_tree); } diff --git a/src/util.c b/src/util.c index 5cd991e1..dba88da8 100644 --- a/src/util.c +++ b/src/util.c @@ -633,3 +633,43 @@ struct tm *localtime_r (const time_t *timep, struct tm *result) return result; } #endif + + +/* helper function for converting a passed string in one character set to another + * we use libxml2 for this + */ +char *util_conv_string (const char *string, const char *in_charset, const char *out_charset) +{ + xmlCharEncodingHandlerPtr in, out; + char *ret = NULL; + + if (string == NULL || in_charset == NULL || out_charset == NULL) + return NULL; + + in = xmlFindCharEncodingHandler (in_charset); + out = xmlFindCharEncodingHandler (out_charset); + + if (in && out) + { + xmlBufferPtr orig = xmlBufferCreate (); + xmlBufferPtr utf8 = xmlBufferCreate (); + xmlBufferPtr conv = xmlBufferCreate (); + + INFO2 ("converting metadata from %s to %s", in_charset, out_charset); + xmlBufferCCat (orig, string); + if (xmlCharEncInFunc (in, utf8, orig) > 0) + { + xmlCharEncOutFunc (out, conv, NULL); + if (xmlCharEncOutFunc (out, conv, utf8) >= 0) + ret = strdup ((const char *)xmlBufferContent (conv)); + } + xmlBufferFree (orig); + xmlBufferFree (utf8); + xmlBufferFree (conv); + } + xmlCharEncCloseFunc (in); + xmlCharEncCloseFunc (out); + + return ret; +} + diff --git a/src/util.h b/src/util.h index b117788c..855f7264 100644 --- a/src/util.h +++ b/src/util.h @@ -51,5 +51,6 @@ char *util_dict_urlencode(util_dict *dict, char delim); #ifndef HAVE_LOCALTIME_R struct tm *localtime_r (const time_t *timep, struct tm *result); #endif +char *util_conv_string (const char *string, const char *in_charset, const char *out_charset); #endif /* __UTIL_H__ */