From d3b763a48c09a60a0c0b5ccb6cccd9376875c470 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Dec 2009 23:27:37 +0100 Subject: input_stream: return allocated input_stream objects Major API redesign: don't let the caller allocate the input_stream object. Let each input plugin allocate its own (derived/extended) input_stream pointer. The "data" attribute can now be removed, and all input plugins simply cast the input_stream pointer to their own structure (with an "struct input_stream base" as the first attribute). --- src/input/archive_input_plugin.c | 19 ++++---- src/input/curl_input_plugin.c | 97 +++++++++++++++++++--------------------- src/input/file_input_plugin.c | 44 ++++++++++-------- src/input/mms_input_plugin.c | 27 ++++++----- src/input/rewind_input_plugin.c | 77 +++++++++++++++---------------- src/input/rewind_input_plugin.h | 6 +-- 6 files changed, 136 insertions(+), 134 deletions(-) (limited to 'src/input') diff --git a/src/input/archive_input_plugin.c b/src/input/archive_input_plugin.c index 9e3e79692..97e4836ff 100644 --- a/src/input/archive_input_plugin.c +++ b/src/input/archive_input_plugin.c @@ -33,24 +33,23 @@ * parent_stream so tar plugin fetches file data from gzip * plugin and gzip fetches file from disk */ -static bool -input_archive_open(struct input_stream *is, const char *pathname, - GError **error_r) +static struct input_stream * +input_archive_open(const char *pathname, GError **error_r) { const struct archive_plugin *arplug; struct archive_file *file; char *archive, *filename, *suffix, *pname; - bool opened; + struct input_stream *is; if (!g_path_is_absolute(pathname)) - return false; + return NULL; pname = g_strdup(pathname); // archive_lookup will modify pname when true is returned if (!archive_lookup(pname, &archive, &filename, &suffix)) { g_debug("not an archive, lookup %s failed\n", pname); g_free(pname); - return false; + return NULL; } //check which archive plugin to use (by ext) @@ -58,19 +57,19 @@ input_archive_open(struct input_stream *is, const char *pathname, if (!arplug) { g_warning("can't handle archive %s\n",archive); g_free(pname); - return false; + return NULL; } file = archive_file_open(arplug, archive, error_r); if (file == NULL) - return false; + return NULL; //setup fileops - opened = archive_file_open_stream(file, is, filename, error_r); + is = archive_file_open_stream(file, filename, error_r); archive_file_close(file); g_free(pname); - return opened; + return is; } const struct input_plugin input_plugin_archive = { diff --git a/src/input/curl_input_plugin.c b/src/input/curl_input_plugin.c index 53f2e0404..c54d994e8 100644 --- a/src/input/curl_input_plugin.c +++ b/src/input/curl_input_plugin.c @@ -57,6 +57,8 @@ struct buffer { }; struct input_curl { + struct input_stream base; + /* some buffers which were passed to libcurl, which we have too free */ char *url, *range; @@ -179,10 +181,8 @@ input_curl_easy_free(struct input_curl *c) * Frees this stream (but not the input_stream struct itself). */ static void -input_curl_free(struct input_stream *is) +input_curl_free(struct input_curl *c) { - struct input_curl *c = is->data; - if (c->tag != NULL) tag_free(c->tag); g_free(c->meta_name); @@ -201,7 +201,7 @@ input_curl_free(struct input_stream *is) static struct tag * input_curl_tag(struct input_stream *is) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; struct tag *tag = c->tag; c->tag = NULL; @@ -209,9 +209,8 @@ input_curl_tag(struct input_stream *is) } static bool -input_curl_multi_info_read(struct input_stream *is, GError **error_r) +input_curl_multi_info_read(struct input_curl *c, GError **error_r) { - struct input_curl *c = is->data; CURLMsg *msg; int msgs_in_queue; @@ -219,7 +218,7 @@ input_curl_multi_info_read(struct input_stream *is, GError **error_r) &msgs_in_queue)) != NULL) { if (msg->msg == CURLMSG_DONE) { c->eof = true; - is->ready = true; + c->base.ready = true; if (msg->data.result != CURLE_OK) { g_set_error(error_r, curl_quark(), @@ -279,7 +278,7 @@ input_curl_select(struct input_curl *c, GError **error_r) static bool fill_buffer(struct input_stream *is, GError **error_r) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; CURLMcode mcode = CURLM_CALL_MULTI_PERFORM; while (!c->eof && g_queue_is_empty(c->buffers)) { @@ -305,7 +304,7 @@ fill_buffer(struct input_stream *is, GError **error_r) return false; } - bret = input_curl_multi_info_read(is, error_r); + bret = input_curl_multi_info_read(c, error_r); if (!bret) return false; } @@ -407,7 +406,7 @@ static size_t input_curl_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; bool success; size_t nbytes = 0; char *dest = ptr; @@ -441,13 +440,15 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size, static void input_curl_close(struct input_stream *is) { - input_curl_free(is); + struct input_curl *c = (struct input_curl *)is; + + input_curl_free(c); } static bool input_curl_eof(G_GNUC_UNUSED struct input_stream *is) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; return c->eof && g_queue_is_empty(c->buffers); } @@ -455,7 +456,7 @@ input_curl_eof(G_GNUC_UNUSED struct input_stream *is) static int input_curl_buffer(struct input_stream *is, GError **error_r) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; CURLMcode mcode; int running_handles; bool ret; @@ -483,7 +484,7 @@ input_curl_buffer(struct input_stream *is, GError **error_r) return -1; } - ret = input_curl_multi_info_read(is, error_r); + ret = input_curl_multi_info_read(c, error_r); if (!ret) return -1; @@ -494,8 +495,7 @@ input_curl_buffer(struct input_stream *is, GError **error_r) static size_t input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) { - struct input_stream *is = stream; - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)stream; const char *header = ptr, *end, *value; char name[64]; @@ -524,7 +524,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)) - is->seekable = true; + c->base.seekable = true; } else if (g_ascii_strcasecmp(name, "content-length") == 0) { char buffer[64]; @@ -534,10 +534,10 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) memcpy(buffer, value, end - value); buffer[end - value] = 0; - is->size = is->offset + g_ascii_strtoull(buffer, NULL, 10); + c->base.size = c->base.offset + g_ascii_strtoull(buffer, NULL, 10); } else if (g_ascii_strcasecmp(name, "content-type") == 0) { - g_free(is->mime); - is->mime = g_strndup(value, end - value); + g_free(c->base.mime); + c->base.mime = g_strndup(value, end - value); } else if (g_ascii_strcasecmp(name, "icy-name") == 0 || g_ascii_strcasecmp(name, "ice-name") == 0 || g_ascii_strcasecmp(name, "x-audiocast-name") == 0) { @@ -568,7 +568,7 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) /* a stream with icy-metadata is not seekable */ - is->seekable = false; + c->base.seekable = false; } } @@ -579,8 +579,7 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) static size_t input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) { - struct input_stream *is = stream; - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)stream; struct buffer *buffer; size *= nmemb; @@ -594,15 +593,14 @@ input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) g_queue_push_tail(c->buffers, buffer); c->buffered = true; - is->ready = true; + c->base.ready = true; return size; } static bool -input_curl_easy_init(struct input_stream *is, GError **error_r) +input_curl_easy_init(struct input_curl *c, GError **error_r) { - struct input_curl *c = is->data; CURLcode code; CURLMcode mcode; @@ -627,10 +625,10 @@ input_curl_easy_init(struct input_stream *is, GError **error_r) "Music Player Daemon " VERSION); curl_easy_setopt(c->easy, CURLOPT_HEADERFUNCTION, input_curl_headerfunction); - curl_easy_setopt(c->easy, CURLOPT_WRITEHEADER, is); + curl_easy_setopt(c->easy, CURLOPT_WRITEHEADER, c); curl_easy_setopt(c->easy, CURLOPT_WRITEFUNCTION, input_curl_writefunction); - curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, is); + curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c); curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases); curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5); @@ -669,9 +667,9 @@ input_curl_easy_init(struct input_stream *is, GError **error_r) void input_curl_reinit(struct input_stream *is) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; - assert(is->plugin == &input_plugin_curl); + assert(c->base.plugin == &input_plugin_curl); assert(c->easy != NULL); curl_easy_setopt(c->easy, CURLOPT_WRITEHEADER, is); @@ -702,7 +700,7 @@ static bool input_curl_seek(struct input_stream *is, goffset offset, int whence, GError **error_r) { - struct input_curl *c = is->data; + struct input_curl *c = (struct input_curl *)is; bool ret; assert(is->ready); @@ -774,7 +772,7 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence, return true; } - ret = input_curl_easy_init(is, error_r); + ret = input_curl_easy_init(c, error_r); if (!ret) return false; @@ -789,55 +787,54 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence, if (!ret) return false; - return input_curl_multi_info_read(is, error_r); + return input_curl_multi_info_read(c, error_r); } -static bool -input_curl_open(struct input_stream *is, const char *url, GError **error_r) +static struct input_stream * +input_curl_open(const char *url, GError **error_r) { struct input_curl *c; bool ret; if (strncmp(url, "http://", 7) != 0) - return false; + return NULL; c = g_new0(struct input_curl, 1); + input_stream_init(&c->base, &input_plugin_curl); + c->url = g_strdup(url); c->buffers = g_queue_new(); - is->plugin = &input_plugin_curl; - is->data = c; - c->multi = curl_multi_init(); if (c->multi == NULL) { g_set_error(error_r, curl_quark(), 0, "curl_multi_init() failed"); - input_curl_free(is); - return false; + input_curl_free(c); + return NULL; } icy_clear(&c->icy_metadata); c->tag = NULL; - ret = input_curl_easy_init(is, error_r); + ret = input_curl_easy_init(c, error_r); if (!ret) { - input_curl_free(is); - return false; + input_curl_free(c); + return NULL; } ret = input_curl_send_request(c, error_r); if (!ret) { - input_curl_free(is); - return false; + input_curl_free(c); + return NULL; } - ret = input_curl_multi_info_read(is, error_r); + ret = input_curl_multi_info_read(c, error_r); if (!ret) { - input_curl_free(is); - return false; + input_curl_free(c); + return NULL; } - return true; + return &c->base; } const struct input_plugin input_plugin_curl = { diff --git a/src/input/file_input_plugin.c b/src/input/file_input_plugin.c index 92da42290..1c5813f88 100644 --- a/src/input/file_input_plugin.c +++ b/src/input/file_input_plugin.c @@ -32,18 +32,24 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "input_file" +struct file_input_stream { + struct input_stream base; + + int fd; +}; + static inline GQuark file_quark(void) { return g_quark_from_static_string("file"); } -static bool -input_file_open(struct input_stream *is, const char *filename, - GError **error_r) +static struct input_stream * +input_file_open(const char *filename, GError **error_r) { int fd, ret; struct stat st; + struct file_input_stream *fis; if (!g_path_is_absolute(filename)) return false; @@ -57,8 +63,6 @@ input_file_open(struct input_stream *is, const char *filename, return false; } - is->seekable = true; - ret = fstat(fd, &st); if (ret < 0) { g_set_error(error_r, file_quark(), errno, @@ -75,26 +79,29 @@ input_file_open(struct input_stream *is, const char *filename, return false; } - is->size = st.st_size; - #ifdef POSIX_FADV_SEQUENTIAL - posix_fadvise(fd, (off_t)0, is->size, POSIX_FADV_SEQUENTIAL); + posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL); #endif - is->plugin = &input_plugin_file; - is->data = GINT_TO_POINTER(fd); - is->ready = true; + fis = g_new(struct file_input_stream, 1); + input_stream_init(&fis->base, &input_plugin_file); - return true; + fis->base.size = st.st_size; + fis->base.seekable = true; + fis->base.ready = true; + + fis->fd = fd; + + return &fis->base; } static bool input_file_seek(struct input_stream *is, goffset offset, int whence, GError **error_r) { - int fd = GPOINTER_TO_INT(is->data); + struct file_input_stream *fis = (struct file_input_stream *)is; - offset = (goffset)lseek(fd, (off_t)offset, whence); + offset = (goffset)lseek(fis->fd, (off_t)offset, whence); if (offset < 0) { g_set_error(error_r, file_quark(), errno, "Failed to seek: %s", g_strerror(errno)); @@ -109,10 +116,10 @@ static size_t input_file_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) { - int fd = GPOINTER_TO_INT(is->data); + struct file_input_stream *fis = (struct file_input_stream *)is; ssize_t nbytes; - nbytes = read(fd, ptr, size); + nbytes = read(fis->fd, ptr, size); if (nbytes < 0) { g_set_error(error_r, file_quark(), errno, "Failed to read: %s", g_strerror(errno)); @@ -126,9 +133,10 @@ input_file_read(struct input_stream *is, void *ptr, size_t size, static void input_file_close(struct input_stream *is) { - int fd = GPOINTER_TO_INT(is->data); + struct file_input_stream *fis = (struct file_input_stream *)is; - close(fd); + close(fis->fd); + g_free(fis); } static bool diff --git a/src/input/mms_input_plugin.c b/src/input/mms_input_plugin.c index e7dc56bc8..5055eb05e 100644 --- a/src/input/mms_input_plugin.c +++ b/src/input/mms_input_plugin.c @@ -31,6 +31,8 @@ #define G_LOG_DOMAIN "input_mms" struct input_mms { + struct input_stream base; + mmsx_t *mms; bool eof; @@ -42,8 +44,8 @@ mms_quark(void) return g_quark_from_static_string("mms"); } -static bool -input_mms_open(struct input_stream *is, const char *url, GError **error_r) +static struct input_stream * +input_mms_open(const char *url, GError **error_r) { struct input_mms *m; @@ -51,30 +53,31 @@ input_mms_open(struct input_stream *is, const char *url, GError **error_r) !g_str_has_prefix(url, "mmsh://") && !g_str_has_prefix(url, "mmst://") && !g_str_has_prefix(url, "mmsu://")) - return false; + return NULL; m = g_new(struct input_mms, 1); + input_stream_init(&m->base, &input_plugin_mms); + m->mms = mmsx_connect(NULL, NULL, url, 128 * 1024); if (m->mms == NULL) { g_set_error(error_r, mms_quark(), 0, "mmsx_connect() failed"); - return false; + return NULL; } /* XX is this correct? at least this selects the ffmpeg decoder, which seems to work fine*/ - is->mime = g_strdup("audio/x-ms-wma"); + m->base.mime = g_strdup("audio/x-ms-wma"); + + m->base.ready = true; - is->plugin = &input_plugin_mms; - is->data = m; - is->ready = true; - return true; + return &m->base; } static size_t input_mms_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) { - struct input_mms *m = is->data; + struct input_mms *m = (struct input_mms *)is; int ret; ret = mmsx_read(NULL, m->mms, ptr, size); @@ -97,7 +100,7 @@ input_mms_read(struct input_stream *is, void *ptr, size_t size, static void input_mms_close(struct input_stream *is) { - struct input_mms *m = is->data; + struct input_mms *m = (struct input_mms *)is; mmsx_close(m->mms); g_free(m); @@ -106,7 +109,7 @@ input_mms_close(struct input_stream *is) static bool input_mms_eof(struct input_stream *is) { - struct input_mms *m = is->data; + struct input_mms *m = (struct input_mms *)is; return m->eof; } diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c index 54efa75fb..68b3e8036 100644 --- a/src/input/rewind_input_plugin.c +++ b/src/input/rewind_input_plugin.c @@ -32,7 +32,9 @@ #define G_LOG_DOMAIN "input_rewind" struct input_rewind { - struct input_stream input; + struct input_stream base; + + struct input_stream *input; /** * The read position within the buffer. Undefined as long as @@ -61,11 +63,9 @@ struct input_rewind { * contain more data for the next read operation? */ static bool -reading_from_buffer(const struct input_stream *is) +reading_from_buffer(const struct input_rewind *r) { - const struct input_rewind *r = is->data; - - return r->tail > 0 && is->offset < r->input.offset; + return r->tail > 0 && r->base.offset < r->input->offset; } /** @@ -75,10 +75,10 @@ reading_from_buffer(const struct input_stream *is) * attributes. */ static void -copy_attributes(struct input_stream *dest) +copy_attributes(struct input_rewind *r) { - const struct input_rewind *r = dest->data; - const struct input_stream *src = &r->input; + struct input_stream *dest = &r->base; + const struct input_stream *src = r->input; dest->ready = src->ready; dest->seekable = src->seekable; @@ -94,9 +94,9 @@ copy_attributes(struct input_stream *dest) static void input_rewind_close(struct input_stream *is) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; - input_stream_close(&r->input); + input_stream_close(r->input); g_free(r); } @@ -104,19 +104,19 @@ input_rewind_close(struct input_stream *is) static struct tag * input_rewind_tag(struct input_stream *is) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; - return input_stream_tag(&r->input); + return input_stream_tag(r->input); } static int input_rewind_buffer(struct input_stream *is, GError **error_r) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; - int ret = input_stream_buffer(&r->input, error_r); - if (ret < 0 || !reading_from_buffer(is)) - copy_attributes(is); + int ret = input_stream_buffer(r->input, error_r); + if (ret < 0 || !reading_from_buffer(r)) + copy_attributes(r); return ret; } @@ -125,13 +125,13 @@ static size_t input_rewind_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; - if (reading_from_buffer(is)) { + if (reading_from_buffer(r)) { /* buffered read */ assert(r->head == (size_t)is->offset); - assert(r->tail == (size_t)r->input.offset); + assert(r->tail == (size_t)r->input->offset); if (size > r->tail - r->head) size = r->tail - r->head; @@ -144,9 +144,9 @@ input_rewind_read(struct input_stream *is, void *ptr, size_t size, } else { /* pass method call to underlying stream */ - size_t nbytes = input_stream_read(&r->input, ptr, size, error_r); + size_t nbytes = input_stream_read(r->input, ptr, size, error_r); - if (r->input.offset > (goffset)sizeof(r->buffer)) + if (r->input->offset > (goffset)sizeof(r->buffer)) /* disable buffering */ r->tail = 0; else if (r->tail == (size_t)is->offset) { @@ -155,46 +155,46 @@ input_rewind_read(struct input_stream *is, void *ptr, size_t size, memcpy(r->buffer + r->tail, ptr, nbytes); r->tail += nbytes; - assert(r->tail == (size_t)r->input.offset); + assert(r->tail == (size_t)r->input->offset); } - copy_attributes(is); + copy_attributes(r); return nbytes; } } static bool -input_rewind_eof(G_GNUC_UNUSED struct input_stream *is) +input_rewind_eof(struct input_stream *is) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; - return !reading_from_buffer(is) && input_stream_eof(&r->input); + return !reading_from_buffer(r) && input_stream_eof(r->input); } static bool input_rewind_seek(struct input_stream *is, goffset offset, int whence, GError **error_r) { - struct input_rewind *r = is->data; + struct input_rewind *r = (struct input_rewind *)is; assert(is->ready); if (whence == SEEK_SET && r->tail > 0 && offset <= (goffset)r->tail) { /* buffered seek */ - assert(!reading_from_buffer(is) || + assert(!reading_from_buffer(r) || r->head == (size_t)is->offset); - assert(r->tail == (size_t)r->input.offset); + assert(r->tail == (size_t)r->input->offset); r->head = (size_t)offset; is->offset = offset; return true; } else { - bool success = input_stream_seek(&r->input, offset, whence, + bool success = input_stream_seek(r->input, offset, whence, error_r); - copy_attributes(is); + copy_attributes(r); /* disable the buffer, because r->input has left the buffered range now */ @@ -213,7 +213,7 @@ static const struct input_plugin rewind_input_plugin = { .seek = input_rewind_seek, }; -void +struct input_stream * input_rewind_open(struct input_stream *is) { struct input_rewind *c; @@ -224,17 +224,12 @@ input_rewind_open(struct input_stream *is) if (is->plugin != &input_plugin_curl) /* due to limitations in the input_plugin API, we only (explicitly) support the CURL input plugin */ - return; + return is; c = g_new(struct input_rewind, 1); + input_stream_init(&c->base, &rewind_input_plugin); c->tail = 0; + c->input = is; - /* move the CURL input stream to c->input */ - c->input = *is; - input_curl_reinit(&c->input); - - /* convert the existing input_stream pointer to a "rewind" - input stream */ - is->plugin = &rewind_input_plugin; - is->data = c; + return &c->base; } diff --git a/src/input/rewind_input_plugin.h b/src/input/rewind_input_plugin.h index 83152e588..27ad169b6 100644 --- a/src/input/rewind_input_plugin.h +++ b/src/input/rewind_input_plugin.h @@ -33,15 +33,15 @@ struct input_stream; #ifdef ENABLE_CURL -void +struct input_stream * input_rewind_open(struct input_stream *is); #else -static inline void +static inline struct input_stream * input_rewind_open(struct input_stream *is) { - (void)is; + return is; } #endif -- cgit v1.2.3