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).
This commit is contained in:
@@ -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 = {
|
||||
|
@@ -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 = {
|
||||
|
@@ -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
|
||||
|
@@ -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");
|
||||
|
||||
is->plugin = &input_plugin_mms;
|
||||
is->data = m;
|
||||
is->ready = true;
|
||||
return true;
|
||||
m->base.ready = 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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user