From 85074f5ac6c1b912e1ac21d552e6fd524d29b39d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 10 Jan 2013 22:33:16 +0100 Subject: icy_metadata: convert to C++ --- src/IcyMetaDataParser.cxx | 173 +++++++++++++++++++++++++++++++++++++++ src/IcyMetaDataParser.hxx | 83 +++++++++++++++++++ src/icy_metadata.c | 182 ------------------------------------------ src/icy_metadata.h | 99 ----------------------- src/input/CurlInputPlugin.cxx | 24 +++--- 5 files changed, 267 insertions(+), 294 deletions(-) create mode 100644 src/IcyMetaDataParser.cxx create mode 100644 src/IcyMetaDataParser.hxx delete mode 100644 src/icy_metadata.c delete mode 100644 src/icy_metadata.h (limited to 'src') diff --git a/src/IcyMetaDataParser.cxx b/src/IcyMetaDataParser.cxx new file mode 100644 index 000000000..cda63da44 --- /dev/null +++ b/src/IcyMetaDataParser.cxx @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "IcyMetaDataParser.hxx" +#include "tag.h" + +#include + +#include +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "icy_metadata" + +void +IcyMetaDataParser::Reset() +{ + if (!IsDefined()) + return; + + if (data_rest == 0 && meta_size > 0) + g_free(meta_data); + + if (tag != nullptr) + tag_free(tag); + + data_rest = data_size; + meta_size = 0; +} + +size_t +IcyMetaDataParser::Data(size_t length) +{ + assert(length > 0); + + if (!IsDefined()) + return length; + + if (data_rest == 0) + return 0; + + if (length >= data_rest) { + length = data_rest; + data_rest = 0; + } else + data_rest -= length; + + return length; +} + +static void +icy_add_item(struct tag *tag, enum tag_type type, const char *value) +{ + size_t length = strlen(value); + + if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') { + /* strip the single quotes */ + ++value; + length -= 2; + } + + if (length > 0) + tag_add_item_n(tag, type, value, length); +} + +static void +icy_parse_tag_item(struct tag *tag, const char *item) +{ + gchar **p = g_strsplit(item, "=", 0); + + if (p[0] != nullptr && p[1] != nullptr) { + if (strcmp(p[0], "StreamTitle") == 0) + icy_add_item(tag, TAG_TITLE, p[1]); + else + g_debug("unknown icy-tag: '%s'", p[0]); + } + + g_strfreev(p); +} + +static struct tag * +icy_parse_tag(const char *p) +{ + struct tag *tag = tag_new(); + gchar **items = g_strsplit(p, ";", 0); + + for (unsigned i = 0; items[i] != nullptr; ++i) + icy_parse_tag_item(tag, items[i]); + + g_strfreev(items); + + return tag; +} + +size_t +IcyMetaDataParser::Meta(const void *data, size_t length) +{ + const unsigned char *p = (const unsigned char *)data; + + assert(IsDefined()); + assert(data_rest == 0); + assert(length > 0); + + if (meta_size == 0) { + /* read meta_size from the first byte of a meta + block */ + meta_size = *p++ * 16; + if (meta_size == 0) { + /* special case: no metadata */ + data_rest = data_size; + return 1; + } + + /* 1 byte was consumed (must be re-added later for the + return value */ + --length; + + /* initialize metadata reader, allocate enough + memory (+1 for the null terminator) */ + meta_position = 0; + meta_data = (char *)g_malloc(meta_size + 1); + } + + assert(meta_position < meta_size); + + if (length > meta_size - meta_position) + length = meta_size - meta_position; + + memcpy(meta_data + meta_position, p, length); + meta_position += length; + + if (p != data) + /* re-add the first byte (which contained meta_size) */ + ++length; + + if (meta_position == meta_size) { + /* null-terminate the string */ + + meta_data[meta_size] = 0; + + /* parse */ + + if (tag != nullptr) + tag_free(tag); + + tag = icy_parse_tag(meta_data); + g_free(meta_data); + + /* change back to normal data mode */ + + meta_size = 0; + data_rest = data_size; + } + + return length; +} diff --git a/src/IcyMetaDataParser.hxx b/src/IcyMetaDataParser.hxx new file mode 100644 index 000000000..6ccc73f52 --- /dev/null +++ b/src/IcyMetaDataParser.hxx @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_ICY_META_DATA_PARSER_HXX +#define MPD_ICY_META_DATA_PARSER_HXX + +#include + +class IcyMetaDataParser { + size_t data_size, data_rest; + + size_t meta_size, meta_position; + char *meta_data; + + struct tag *tag; + +public: + IcyMetaDataParser():data_size(0) {} + ~IcyMetaDataParser() { + Reset(); + } + + /** + * Initialize an enabled icy_metadata object with the specified + * data_size (from the icy-metaint HTTP response header). + */ + void Start(size_t _data_size) { + data_size = data_rest = _data_size; + meta_size = 0; + tag = nullptr; + } + + /** + * Resets the icy_metadata. Call this after rewinding the stream. + */ + void Reset(); + + /** + * Checks whether the icy_metadata object is enabled. + */ + bool IsDefined() const { + return data_size > 0; + } + + /** + * Evaluates data. Returns the number of bytes of normal data which + * can be read by the caller, but not more than "length". If the + * return value is smaller than "length", the caller should invoke + * icy_meta(). + */ + size_t Data(size_t length); + + /** + * Reads metadata from the stream. Returns the number of bytes + * consumed. If the return value is smaller than "length", the caller + * should invoke icy_data(). + */ + size_t Meta(const void *data, size_t length); + + struct tag *ReadTag() { + struct tag *result = tag; + tag = nullptr; + return result; + } +}; + +#endif diff --git a/src/icy_metadata.c b/src/icy_metadata.c deleted file mode 100644 index 32953e69f..000000000 --- a/src/icy_metadata.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "icy_metadata.h" -#include "tag.h" - -#include - -#include -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "icy_metadata" - -void -icy_deinit(struct icy_metadata *im) -{ - if (!icy_defined(im)) - return; - - if (im->data_rest == 0 && im->meta_size > 0) - g_free(im->meta_data); - - if (im->tag != NULL) - tag_free(im->tag); -} - -void -icy_reset(struct icy_metadata *im) -{ - if (!icy_defined(im)) - return; - - icy_deinit(im); - - im->data_rest = im->data_size; - im->meta_size = 0; -} - -size_t -icy_data(struct icy_metadata *im, size_t length) -{ - assert(length > 0); - - if (!icy_defined(im)) - return length; - - if (im->data_rest == 0) - return 0; - - if (length >= im->data_rest) { - length = im->data_rest; - im->data_rest = 0; - } else - im->data_rest -= length; - - return length; -} - -static void -icy_add_item(struct tag *tag, enum tag_type type, const char *value) -{ - size_t length = strlen(value); - - if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') { - /* strip the single quotes */ - ++value; - length -= 2; - } - - if (length > 0) - tag_add_item_n(tag, type, value, length); -} - -static void -icy_parse_tag_item(struct tag *tag, const char *item) -{ - gchar **p = g_strsplit(item, "=", 0); - - if (p[0] != NULL && p[1] != NULL) { - if (strcmp(p[0], "StreamTitle") == 0) - icy_add_item(tag, TAG_TITLE, p[1]); - else - g_debug("unknown icy-tag: '%s'", p[0]); - } - - g_strfreev(p); -} - -static struct tag * -icy_parse_tag(const char *p) -{ - struct tag *tag = tag_new(); - gchar **items = g_strsplit(p, ";", 0); - - for (unsigned i = 0; items[i] != NULL; ++i) - icy_parse_tag_item(tag, items[i]); - - g_strfreev(items); - - return tag; -} - -size_t -icy_meta(struct icy_metadata *im, const void *data, size_t length) -{ - const unsigned char *p = data; - - assert(icy_defined(im)); - assert(im->data_rest == 0); - assert(length > 0); - - if (im->meta_size == 0) { - /* read meta_size from the first byte of a meta - block */ - im->meta_size = *p++ * 16; - if (im->meta_size == 0) { - /* special case: no metadata */ - im->data_rest = im->data_size; - return 1; - } - - /* 1 byte was consumed (must be re-added later for the - return value */ - --length; - - /* initialize metadata reader, allocate enough - memory (+1 for the null terminator) */ - im->meta_position = 0; - im->meta_data = g_malloc(im->meta_size + 1); - } - - assert(im->meta_position < im->meta_size); - - if (length > im->meta_size - im->meta_position) - length = im->meta_size - im->meta_position; - - memcpy(im->meta_data + im->meta_position, p, length); - im->meta_position += length; - - if (p != data) - /* re-add the first byte (which contained meta_size) */ - ++length; - - if (im->meta_position == im->meta_size) { - /* null-terminate the string */ - - im->meta_data[im->meta_size] = 0; - - /* parse */ - - if (im->tag != NULL) - tag_free(im->tag); - - im->tag = icy_parse_tag(im->meta_data); - g_free(im->meta_data); - - /* change back to normal data mode */ - - im->meta_size = 0; - im->data_rest = im->data_size; - } - - return length; -} diff --git a/src/icy_metadata.h b/src/icy_metadata.h deleted file mode 100644 index 9797122ca..000000000 --- a/src/icy_metadata.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef ICY_METADATA_H -#define ICY_METADATA_H - -#include -#include - -struct icy_metadata { - size_t data_size, data_rest; - - size_t meta_size, meta_position; - char *meta_data; - - struct tag *tag; -}; - -/** - * Initialize a disabled icy_metadata object. - */ -static inline void -icy_clear(struct icy_metadata *im) -{ - im->data_size = 0; -} - -/** - * Initialize an enabled icy_metadata object with the specified - * data_size (from the icy-metaint HTTP response header). - */ -static inline void -icy_start(struct icy_metadata *im, size_t data_size) -{ - im->data_size = im->data_rest = data_size; - im->meta_size = 0; - im->tag = NULL; -} - -/** - * Resets the icy_metadata. Call this after rewinding the stream. - */ -void -icy_reset(struct icy_metadata *im); - -void -icy_deinit(struct icy_metadata *im); - -/** - * Checks whether the icy_metadata object is enabled. - */ -static inline bool -icy_defined(const struct icy_metadata *im) -{ - return im->data_size > 0; -} - -/** - * Evaluates data. Returns the number of bytes of normal data which - * can be read by the caller, but not more than "length". If the - * return value is smaller than "length", the caller should invoke - * icy_meta(). - */ -size_t -icy_data(struct icy_metadata *im, size_t length); - -/** - * Reads metadata from the stream. Returns the number of bytes - * consumed. If the return value is smaller than "length", the caller - * should invoke icy_data(). - */ -size_t -icy_meta(struct icy_metadata *im, const void *data, size_t length); - -static inline struct tag * -icy_tag(struct icy_metadata *im) -{ - struct tag *tag = im->tag; - im->tag = NULL; - return tag; -} - -#endif diff --git a/src/input/CurlInputPlugin.cxx b/src/input/CurlInputPlugin.cxx index b329d626f..08df6cbd9 100644 --- a/src/input/CurlInputPlugin.cxx +++ b/src/input/CurlInputPlugin.cxx @@ -22,10 +22,10 @@ #include "input_plugin.h" #include "conf.h" #include "tag.h" +#include "IcyMetaDataParser.hxx" extern "C" { #include "input_internal.h" -#include "icy_metadata.h" } #include "IOThread.hxx" @@ -106,7 +106,7 @@ struct input_curl { char error[CURL_ERROR_SIZE]; /** parser for icy-metadata */ - struct icy_metadata icy_metadata; + IcyMetaDataParser icy; /** the stream name from the icy-name response header */ char *meta_name; @@ -125,7 +125,6 @@ struct input_curl { tag(nullptr), postponed_error(nullptr) { input_stream_init(&base, &input_plugin_curl, url, mutex, cond); - icy_clear(&icy_metadata); } ~input_curl(); @@ -811,7 +810,7 @@ consume_buffer(struct buffer *buffer, size_t length) } static size_t -read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers, +read_from_buffer(IcyMetaDataParser &icy, GQueue *buffers, void *dest0, size_t length) { struct buffer *buffer = (struct buffer *)g_queue_pop_head(buffers); @@ -827,7 +826,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers, while (true) { size_t chunk; - chunk = icy_data(icy_metadata, length); + chunk = icy.Data(length); if (chunk > 0) { memcpy(dest, buffer->data + buffer->consumed, chunk); @@ -843,8 +842,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers, assert(buffer != NULL); } - chunk = icy_meta(icy_metadata, buffer->data + buffer->consumed, - length); + chunk = icy.Meta(buffer->data + buffer->consumed, length); if (chunk > 0) { buffer = consume_buffer(buffer, chunk); @@ -866,7 +864,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers, static void copy_icy_tag(struct input_curl *c) { - struct tag *tag = icy_tag(&c->icy_metadata); + struct tag *tag = c->icy.ReadTag(); if (tag == NULL) return; @@ -908,7 +906,7 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size, /* send buffer contents */ while (size > 0 && !g_queue_is_empty(c->buffers)) { - size_t copy = read_from_buffer(&c->icy_metadata, c->buffers, + size_t copy = read_from_buffer(c->icy, c->buffers, dest + nbytes, size); nbytes += copy; @@ -916,7 +914,7 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size, } } while (nbytes == 0); - if (icy_defined(&c->icy_metadata)) + if (c->icy.IsDefined()) copy_icy_tag(c); is->offset += (goffset)nbytes; @@ -979,7 +977,7 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) if (g_ascii_strcasecmp(name, "accept-ranges") == 0) { /* a stream with icy-metadata is not seekable */ - if (!icy_defined(&c->icy_metadata)) + if (!c->icy.IsDefined()) c->base.seekable = true; } else if (g_ascii_strcasecmp(name, "content-length") == 0) { char buffer[64]; @@ -1010,7 +1008,7 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) size_t icy_metaint; if ((size_t)(end - header) >= sizeof(buffer) || - icy_defined(&c->icy_metadata)) + c->icy.IsDefined()) return size; memcpy(buffer, value, end - value); @@ -1020,7 +1018,7 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) g_debug("icy-metaint=%zu", icy_metaint); if (icy_metaint > 0) { - icy_start(&c->icy_metadata, icy_metaint); + c->icy.Start(icy_metaint); /* a stream with icy-metadata is not seekable */ -- cgit v1.2.3