input_stream: return errors with GError
This commit is contained in:
		| @@ -51,11 +51,19 @@ typedef struct { | |||||||
|  |  | ||||||
| static const struct input_plugin bz2_inputplugin; | static const struct input_plugin bz2_inputplugin; | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | bz2_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("bz2"); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* single archive handling allocation helpers */ | /* single archive handling allocation helpers */ | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| bz2_alloc(bz2_context *data) | bz2_alloc(bz2_context *data, GError **error_r) | ||||||
| { | { | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
| 	data->bzstream.bzalloc = NULL; | 	data->bzstream.bzalloc = NULL; | ||||||
| 	data->bzstream.bzfree  = NULL; | 	data->bzstream.bzfree  = NULL; | ||||||
| 	data->bzstream.opaque  = NULL; | 	data->bzstream.opaque  = NULL; | ||||||
| @@ -64,9 +72,13 @@ bz2_alloc(bz2_context *data) | |||||||
| 	data->bzstream.next_in = (void *) data->buffer; | 	data->bzstream.next_in = (void *) data->buffer; | ||||||
| 	data->bzstream.avail_in = 0; | 	data->bzstream.avail_in = 0; | ||||||
|  |  | ||||||
| 	if (BZ2_bzDecompressInit(&data->bzstream, 0, 0) != BZ_OK) { | 	ret = BZ2_bzDecompressInit(&data->bzstream, 0, 0); | ||||||
|  | 	if (ret != BZ_OK) { | ||||||
| 		g_free(data->buffer); | 		g_free(data->buffer); | ||||||
| 		g_free(data); | 		g_free(data); | ||||||
|  |  | ||||||
|  | 		g_set_error(error_r, bz2_quark(), ret, | ||||||
|  | 			    "BZ2_bzDecompressInit() has failed"); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -92,7 +104,7 @@ bz2_open(char *pathname) | |||||||
| 	context = g_malloc(sizeof(*context)); | 	context = g_malloc(sizeof(*context)); | ||||||
|  |  | ||||||
| 	//open archive | 	//open archive | ||||||
| 	if (!input_stream_open(&context->istream, pathname)) { | 	if (!input_stream_open(&context->istream, pathname, NULL)) { | ||||||
| 		g_warning("failed to open an bzip2 archive %s\n",pathname); | 		g_warning("failed to open an bzip2 archive %s\n",pathname); | ||||||
| 		g_free(context); | 		g_free(context); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| @@ -153,7 +165,7 @@ bz2_close(struct archive_file *file) | |||||||
|  |  | ||||||
| static bool | static bool | ||||||
| bz2_open_stream(struct archive_file *file, struct input_stream *is, | bz2_open_stream(struct archive_file *file, struct input_stream *is, | ||||||
| 		G_GNUC_UNUSED const char *path) | 		G_GNUC_UNUSED const char *path, GError **error_r) | ||||||
| { | { | ||||||
| 	bz2_context *context = (bz2_context *) file; | 	bz2_context *context = (bz2_context *) file; | ||||||
|  |  | ||||||
| @@ -163,10 +175,8 @@ bz2_open_stream(struct archive_file *file, struct input_stream *is, | |||||||
| 	is->data = context; | 	is->data = context; | ||||||
| 	is->seekable = false; | 	is->seekable = false; | ||||||
|  |  | ||||||
| 	if (!bz2_alloc(context)) { | 	if (!bz2_alloc(context, error_r)) | ||||||
| 		g_warning("alloc bz2 failed\n"); |  | ||||||
| 		return false; | 		return false; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	context->eof = false; | 	context->eof = false; | ||||||
|  |  | ||||||
| @@ -184,7 +194,7 @@ bz2_is_close(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| bz2_fillbuffer(bz2_context *context) | bz2_fillbuffer(bz2_context *context, GError **error_r) | ||||||
| { | { | ||||||
| 	size_t count; | 	size_t count; | ||||||
| 	bz_stream *bzstream; | 	bz_stream *bzstream; | ||||||
| @@ -195,7 +205,8 @@ bz2_fillbuffer(bz2_context *context) | |||||||
| 		return true; | 		return true; | ||||||
|  |  | ||||||
| 	count = input_stream_read(&context->istream, | 	count = input_stream_read(&context->istream, | ||||||
| 				  context->buffer, BZ_BUFSIZE); | 				  context->buffer, BZ_BUFSIZE, | ||||||
|  | 				  error_r); | ||||||
| 	if (count == 0) | 	if (count == 0) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| @@ -205,7 +216,8 @@ bz2_fillbuffer(bz2_context *context) | |||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| bz2_is_read(struct input_stream *is, void *ptr, size_t length) | bz2_is_read(struct input_stream *is, void *ptr, size_t length, | ||||||
|  | 	    GError **error_r) | ||||||
| { | { | ||||||
| 	bz2_context *context = (bz2_context *) is->data; | 	bz2_context *context = (bz2_context *) is->data; | ||||||
| 	bz_stream *bzstream; | 	bz_stream *bzstream; | ||||||
| @@ -220,10 +232,8 @@ bz2_is_read(struct input_stream *is, void *ptr, size_t length) | |||||||
| 	bzstream->avail_out = length; | 	bzstream->avail_out = length; | ||||||
|  |  | ||||||
| 	do { | 	do { | ||||||
| 		if (!bz2_fillbuffer(context)) { | 		if (!bz2_fillbuffer(context, error_r)) | ||||||
| 			is->error = -1; |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		bz_result = BZ2_bzDecompress(bzstream); | 		bz_result = BZ2_bzDecompress(bzstream); | ||||||
|  |  | ||||||
| @@ -233,7 +243,8 @@ bz2_is_read(struct input_stream *is, void *ptr, size_t length) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (bz_result != BZ_OK) { | 		if (bz_result != BZ_OK) { | ||||||
| 			is->error = bz_result; | 			g_set_error(error_r, bz2_quark(), bz_result, | ||||||
|  | 				    "BZ2_bzDecompress() has failed"); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 	} while (bzstream->avail_out == length); | 	} while (bzstream->avail_out == length); | ||||||
|   | |||||||
| @@ -44,6 +44,12 @@ typedef struct { | |||||||
|  |  | ||||||
| static const struct input_plugin iso_inputplugin; | static const struct input_plugin iso_inputplugin; | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | iso9660_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("iso9660"); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* archive open && listing routine */ | /* archive open && listing routine */ | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -141,7 +147,7 @@ iso_close(struct archive_file *file) | |||||||
|  |  | ||||||
| static bool | static bool | ||||||
| iso_open_stream(struct archive_file *file, struct input_stream *is, | iso_open_stream(struct archive_file *file, struct input_stream *is, | ||||||
| 		const char *pathname) | 		const char *pathname, GError **error_r) | ||||||
| { | { | ||||||
| 	iso_context *context = (iso_context *) file; | 	iso_context *context = (iso_context *) file; | ||||||
| 	//setup file ops | 	//setup file ops | ||||||
| @@ -154,7 +160,8 @@ iso_open_stream(struct archive_file *file, struct input_stream *is, | |||||||
| 	context->statbuf = iso9660_ifs_stat_translate (context->iso, pathname); | 	context->statbuf = iso9660_ifs_stat_translate (context->iso, pathname); | ||||||
|  |  | ||||||
| 	if (context->statbuf == NULL) { | 	if (context->statbuf == NULL) { | ||||||
| 		g_warning("file %s not found in iso\n", pathname); | 		g_set_error(error_r, iso9660_quark(), 0, | ||||||
|  | 			    "not found in the ISO file: %s", pathname); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	context->cur_ofs = 0; | 	context->cur_ofs = 0; | ||||||
| @@ -173,7 +180,7 @@ iso_is_close(struct input_stream *is) | |||||||
|  |  | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| iso_is_read(struct input_stream *is, void *ptr, size_t size) | iso_is_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) | ||||||
| { | { | ||||||
| 	iso_context *context = (iso_context *) is->data; | 	iso_context *context = (iso_context *) is->data; | ||||||
| 	int toread, readed = 0; | 	int toread, readed = 0; | ||||||
| @@ -197,9 +204,10 @@ iso_is_read(struct input_stream *is, void *ptr, size_t size) | |||||||
| 			context->statbuf->lsn + cur_block, no_blocks); | 			context->statbuf->lsn + cur_block, no_blocks); | ||||||
|  |  | ||||||
| 		if (readed != no_blocks * ISO_BLOCKSIZE) { | 		if (readed != no_blocks * ISO_BLOCKSIZE) { | ||||||
| 			g_warning("error reading ISO file at lsn %lu\n", | 			g_set_error(error_r, iso9660_quark(), 0, | ||||||
| 				(long unsigned int) cur_block ); | 				    "error reading ISO file at lsn %lu", | ||||||
| 			return -1; | 				    (long unsigned int) cur_block); | ||||||
|  | 			return 0; | ||||||
| 		} | 		} | ||||||
| 		if (left_bytes < size) { | 		if (left_bytes < size) { | ||||||
| 			readed = left_bytes; | 			readed = left_bytes; | ||||||
|   | |||||||
| @@ -40,6 +40,12 @@ struct zzip_archive { | |||||||
|  |  | ||||||
| static const struct input_plugin zzip_input_plugin; | static const struct input_plugin zzip_input_plugin; | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | zzip_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("zzip"); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* archive open && listing routine */ | /* archive open && listing routine */ | ||||||
|  |  | ||||||
| static struct archive_file * | static struct archive_file * | ||||||
| @@ -108,7 +114,7 @@ zzip_archive_close(struct archive_file *file) | |||||||
|  |  | ||||||
| static bool | static bool | ||||||
| zzip_archive_open_stream(struct archive_file *file, struct input_stream *is, | zzip_archive_open_stream(struct archive_file *file, struct input_stream *is, | ||||||
| 			 const char *pathname) | 			 const char *pathname, GError **error_r) | ||||||
| { | { | ||||||
| 	struct zzip_archive *context = (struct zzip_archive *) file; | 	struct zzip_archive *context = (struct zzip_archive *) file; | ||||||
| 	ZZIP_STAT z_stat; | 	ZZIP_STAT z_stat; | ||||||
| @@ -122,7 +128,8 @@ zzip_archive_open_stream(struct archive_file *file, struct input_stream *is, | |||||||
|  |  | ||||||
| 	context->file = zzip_file_open(context->dir, pathname, 0); | 	context->file = zzip_file_open(context->dir, pathname, 0); | ||||||
| 	if (!context->file) { | 	if (!context->file) { | ||||||
| 		g_warning("file %s not found in the zipfile\n", pathname); | 		g_set_error(error_r, zzip_quark(), 0, | ||||||
|  | 			    "not found in the ZIP file: %s", pathname); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	zzip_file_stat(context->file, &z_stat); | 	zzip_file_stat(context->file, &z_stat); | ||||||
| @@ -140,13 +147,15 @@ zzip_input_close(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| zzip_input_read(struct input_stream *is, void *ptr, size_t size) | zzip_input_read(struct input_stream *is, void *ptr, size_t size, | ||||||
|  | 		GError **error_r) | ||||||
| { | { | ||||||
| 	struct zzip_archive *context = (struct zzip_archive *) is->data; | 	struct zzip_archive *context = (struct zzip_archive *) is->data; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	ret = zzip_file_read(context->file, ptr, size); | 	ret = zzip_file_read(context->file, ptr, size); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		g_warning("error %d reading zipfile\n", ret); | 		g_set_error(error_r, zzip_quark(), ret, | ||||||
|  | 			    "zzip_file_read() has failed"); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 	return ret; | 	return ret; | ||||||
| @@ -160,12 +169,14 @@ zzip_input_eof(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| zzip_input_seek(G_GNUC_UNUSED struct input_stream *is, | zzip_input_seek(struct input_stream *is, | ||||||
| 		G_GNUC_UNUSED goffset offset, G_GNUC_UNUSED int whence) | 		goffset offset, int whence, GError **error_r) | ||||||
| { | { | ||||||
| 	struct zzip_archive *context = (struct zzip_archive *) is->data; | 	struct zzip_archive *context = (struct zzip_archive *) is->data; | ||||||
| 	zzip_off_t ofs = zzip_seek(context->file, offset, whence); | 	zzip_off_t ofs = zzip_seek(context->file, offset, whence); | ||||||
| 	if (ofs != -1) { | 	if (ofs != -1) { | ||||||
|  | 		g_set_error(error_r, zzip_quark(), ofs, | ||||||
|  | 			    "zzip_seek() has failed"); | ||||||
| 		is->offset = ofs; | 		is->offset = ofs; | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ | |||||||
| #ifndef MPD_ARCHIVE_PLUGIN_H | #ifndef MPD_ARCHIVE_PLUGIN_H | ||||||
| #define MPD_ARCHIVE_PLUGIN_H | #define MPD_ARCHIVE_PLUGIN_H | ||||||
|  |  | ||||||
|  | #include <glib.h> | ||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| struct input_stream; | struct input_stream; | ||||||
| @@ -69,9 +71,11 @@ struct archive_plugin { | |||||||
| 	 * the archive file and will automatically close it. | 	 * the archive file and will automatically close it. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param path the path within the archive | 	 * @param path the path within the archive | ||||||
|  | 	 * @param error_r location to store the error occuring, or | ||||||
|  | 	 * NULL to ignore errors | ||||||
| 	 */ | 	 */ | ||||||
| 	bool (*open_stream)(struct archive_file *, struct input_stream *is, | 	bool (*open_stream)(struct archive_file *, struct input_stream *is, | ||||||
| 			    const char *path); | 			    const char *path, GError **error_r); | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * closes archive file. | 	 * closes archive file. | ||||||
|   | |||||||
| @@ -47,10 +47,20 @@ static int audiofile_get_duration(const char *file) | |||||||
| } | } | ||||||
|  |  | ||||||
| static ssize_t | static ssize_t | ||||||
| audiofile_file_read(AFvirtualfile *vfile, void *data, size_t nbytes) | audiofile_file_read(AFvirtualfile *vfile, void *data, size_t length) | ||||||
| { | { | ||||||
| 	struct input_stream *is = (struct input_stream *) vfile->closure; | 	struct input_stream *is = (struct input_stream *) vfile->closure; | ||||||
| 	return input_stream_read(is, data, nbytes); | 	GError *error = NULL; | ||||||
|  | 	size_t nbytes; | ||||||
|  |  | ||||||
|  | 	nbytes = input_stream_read(is, data, length, &error); | ||||||
|  | 	if (nbytes == 0 && error != NULL) { | ||||||
|  | 		g_warning("%s", error->message); | ||||||
|  | 		g_error_free(error); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nbytes; | ||||||
| } | } | ||||||
|  |  | ||||||
| static long | static long | ||||||
| @@ -80,7 +90,7 @@ audiofile_file_seek(AFvirtualfile *vfile, long offset, int is_relative) | |||||||
| { | { | ||||||
| 	struct input_stream *is = (struct input_stream *) vfile->closure; | 	struct input_stream *is = (struct input_stream *) vfile->closure; | ||||||
| 	int whence = (is_relative ? SEEK_CUR : SEEK_SET); | 	int whence = (is_relative ? SEEK_CUR : SEEK_SET); | ||||||
| 	if (input_stream_seek(is, offset, whence)) { | 	if (input_stream_seek(is, offset, whence, NULL)) { | ||||||
| 		return is->offset; | 		return is->offset; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -1; | 		return -1; | ||||||
|   | |||||||
| @@ -205,7 +205,7 @@ faad_song_duration(struct decoder_buffer *buffer, struct input_stream *is) | |||||||
| 		/* obtain the duration from the ADTS header */ | 		/* obtain the duration from the ADTS header */ | ||||||
| 		float song_length = adts_song_duration(buffer); | 		float song_length = adts_song_duration(buffer); | ||||||
|  |  | ||||||
| 		input_stream_seek(is, tagsize, SEEK_SET); | 		input_stream_seek(is, tagsize, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 		data = decoder_buffer_read(buffer, &length); | 		data = decoder_buffer_read(buffer, &length); | ||||||
| 		if (data != NULL) | 		if (data != NULL) | ||||||
| @@ -330,7 +330,7 @@ faad_get_file_time_float(const char *file) | |||||||
| 	faacDecConfigurationPtr config; | 	faacDecConfigurationPtr config; | ||||||
| 	struct input_stream is; | 	struct input_stream is; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&is, file)) | 	if (!input_stream_open(&is, file, NULL)) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| 	buffer = decoder_buffer_new(NULL, &is, | 	buffer = decoder_buffer_new(NULL, &is, | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ static int64_t mpd_ffmpeg_seek(URLContext *h, int64_t pos, int whence) | |||||||
| 	if (whence == AVSEEK_SIZE) | 	if (whence == AVSEEK_SIZE) | ||||||
| 		return stream->input->size; | 		return stream->input->size; | ||||||
|  |  | ||||||
| 	ret = input_stream_seek(stream->input, pos, whence); | 	ret = input_stream_seek(stream->input, pos, whence, NULL); | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| @@ -434,7 +434,7 @@ static struct tag *ffmpeg_tag(const char *file) | |||||||
| 	struct ffmpeg_context ctx; | 	struct ffmpeg_context ctx; | ||||||
| 	bool ret; | 	bool ret; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&input, file)) { | 	if (!input_stream_open(&input, file, NULL)) { | ||||||
| 		g_warning("failed to open %s\n", file); | 		g_warning("failed to open %s\n", file); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ flac_seek_cb(G_GNUC_UNUSED const FLAC__StreamDecoder *fd, | |||||||
| 	if (!data->input_stream->seekable) | 	if (!data->input_stream->seekable) | ||||||
| 		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; | 		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; | ||||||
|  |  | ||||||
| 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET)) | 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET, NULL)) | ||||||
| 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; | 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; | ||||||
|  |  | ||||||
| 	return FLAC__STREAM_DECODER_SEEK_STATUS_OK; | 	return FLAC__STREAM_DECODER_SEEK_STATUS_OK; | ||||||
| @@ -784,7 +784,7 @@ oggflac_decode(struct decoder *decoder, struct input_stream *input_stream) | |||||||
|  |  | ||||||
| 	/* rewind the stream, because ogg_stream_type_detect() has | 	/* rewind the stream, because ogg_stream_type_detect() has | ||||||
| 	   moved it */ | 	   moved it */ | ||||||
| 	input_stream_seek(input_stream, 0, SEEK_SET); | 	input_stream_seek(input_stream, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 	flac_decode_internal(decoder, input_stream, true); | 	flac_decode_internal(decoder, input_stream, true); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -165,7 +165,7 @@ mp3_data_init(struct mp3_data *data, struct decoder *decoder, | |||||||
|  |  | ||||||
| static bool mp3_seek(struct mp3_data *data, long offset) | static bool mp3_seek(struct mp3_data *data, long offset) | ||||||
| { | { | ||||||
| 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET)) | 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET, NULL)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	mad_stream_buffer(&data->stream, data->input_buffer, 0); | 	mad_stream_buffer(&data->stream, data->input_buffer, 0); | ||||||
| @@ -920,7 +920,7 @@ static int mp3_total_file_time(const char *file) | |||||||
| 	struct mp3_data data; | 	struct mp3_data data; | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&input_stream, file)) | 	if (!input_stream_open(&input_stream, file, NULL)) | ||||||
| 		return -1; | 		return -1; | ||||||
| 	mp3_data_init(&data, NULL, &input_stream); | 	mp3_data_init(&data, NULL, &input_stream); | ||||||
| 	if (!mp3_decode_first_frame(&data, NULL, NULL)) | 	if (!mp3_decode_first_frame(&data, NULL, NULL)) | ||||||
|   | |||||||
| @@ -163,7 +163,7 @@ static struct tag *mod_tagdup(const char *file) | |||||||
| 	char *title; | 	char *title; | ||||||
| 	struct input_stream is; | 	struct input_stream is; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&is, file)) { | 	if (!input_stream_open(&is, file, NULL)) { | ||||||
| 		g_warning("cant open file %s\n", file); | 		g_warning("cant open file %s\n", file); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -60,7 +60,7 @@ mpc_seek_cb(cb_first_arg, mpc_int32_t offset) | |||||||
| { | { | ||||||
| 	struct mpc_decoder_data *data = (struct mpc_decoder_data *) cb_data; | 	struct mpc_decoder_data *data = (struct mpc_decoder_data *) cb_data; | ||||||
|  |  | ||||||
| 	return input_stream_seek(data->is, offset, SEEK_SET); | 	return input_stream_seek(data->is, offset, SEEK_SET, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| static mpc_int32_t | static mpc_int32_t | ||||||
| @@ -295,7 +295,7 @@ mpcdec_get_file_duration(const char *file) | |||||||
| 	mpc_streaminfo info; | 	mpc_streaminfo info; | ||||||
| 	struct mpc_decoder_data data; | 	struct mpc_decoder_data data; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&is, file)) | 	if (!input_stream_open(&is, file, NULL)) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| 	data.is = &is; | 	data.is = &is; | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(G_GNUC_UNUSED const | |||||||
| { | { | ||||||
| 	struct flac_data *data = (struct flac_data *) fdata; | 	struct flac_data *data = (struct flac_data *) fdata; | ||||||
|  |  | ||||||
| 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET)) | 	if (!input_stream_seek(data->input_stream, offset, SEEK_SET, NULL)) | ||||||
| 		return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; | 		return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; | ||||||
|  |  | ||||||
| 	return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; | 	return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; | ||||||
| @@ -245,13 +245,21 @@ fail: | |||||||
| static struct tag * | static struct tag * | ||||||
| oggflac_tag_dup(const char *file) | oggflac_tag_dup(const char *file) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	struct input_stream input_stream; | 	struct input_stream input_stream; | ||||||
| 	OggFLAC__SeekableStreamDecoder *decoder; | 	OggFLAC__SeekableStreamDecoder *decoder; | ||||||
| 	struct flac_data data; | 	struct flac_data data; | ||||||
| 	struct tag *tag; | 	struct tag *tag; | ||||||
|  |  | ||||||
| 	if (!input_stream_open(&input_stream, file)) | 	if (!input_stream_open(&input_stream, file, &error)) { | ||||||
|  | 		if (error != NULL) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (ogg_stream_type_detect(&input_stream) != FLAC) { | 	if (ogg_stream_type_detect(&input_stream) != FLAC) { | ||||||
| 		input_stream_close(&input_stream); | 		input_stream_close(&input_stream); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| @@ -259,7 +267,7 @@ oggflac_tag_dup(const char *file) | |||||||
|  |  | ||||||
| 	/* rewind the stream, because ogg_stream_type_detect() has | 	/* rewind the stream, because ogg_stream_type_detect() has | ||||||
| 	   moved it */ | 	   moved it */ | ||||||
| 	input_stream_seek(&input_stream, 0, SEEK_SET); | 	input_stream_seek(&input_stream, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 	flac_data_init(&data, NULL, &input_stream); | 	flac_data_init(&data, NULL, &input_stream); | ||||||
|  |  | ||||||
| @@ -295,7 +303,7 @@ oggflac_decode(struct decoder * mpd_decoder, struct input_stream *input_stream) | |||||||
|  |  | ||||||
| 	/* rewind the stream, because ogg_stream_type_detect() has | 	/* rewind the stream, because ogg_stream_type_detect() has | ||||||
| 	   moved it */ | 	   moved it */ | ||||||
| 	input_stream_seek(input_stream, 0, SEEK_SET); | 	input_stream_seek(input_stream, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 	flac_data_init(&data, mpd_decoder, input_stream); | 	flac_data_init(&data, mpd_decoder, input_stream); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ sndfile_vio_seek(sf_count_t offset, int whence, void *user_data) | |||||||
| 	struct input_stream *is = user_data; | 	struct input_stream *is = user_data; | ||||||
| 	bool success; | 	bool success; | ||||||
|  |  | ||||||
| 	success = input_stream_seek(is, offset, whence); | 	success = input_stream_seek(is, offset, whence, NULL); | ||||||
| 	if (!success) | 	if (!success) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| @@ -51,11 +51,15 @@ static sf_count_t | |||||||
| sndfile_vio_read(void *ptr, sf_count_t count, void *user_data) | sndfile_vio_read(void *ptr, sf_count_t count, void *user_data) | ||||||
| { | { | ||||||
| 	struct input_stream *is = user_data; | 	struct input_stream *is = user_data; | ||||||
|  | 	GError *error = NULL; | ||||||
| 	size_t nbytes; | 	size_t nbytes; | ||||||
|  |  | ||||||
| 	nbytes = input_stream_read(is, ptr, count); | 	nbytes = input_stream_read(is, ptr, count, &error); | ||||||
| 	if (nbytes == 0 && is->error != 0) | 	if (nbytes == 0 && error != NULL) { | ||||||
|  | 		g_warning("%s", error->message); | ||||||
|  | 		g_error_free(error); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return nbytes; | 	return nbytes; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -80,7 +80,7 @@ static int ogg_seek_cb(void *vdata, ogg_int64_t offset, int whence) | |||||||
|  |  | ||||||
| 	return data->seekable && | 	return data->seekable && | ||||||
| 		decoder_get_command(data->decoder) != DECODE_COMMAND_STOP && | 		decoder_get_command(data->decoder) != DECODE_COMMAND_STOP && | ||||||
| 		input_stream_seek(data->input_stream, offset, whence) | 		input_stream_seek(data->input_stream, offset, whence, NULL) | ||||||
| 		? 0 : -1; | 		? 0 : -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -286,7 +286,7 @@ vorbis_stream_decode(struct decoder *decoder, | |||||||
|  |  | ||||||
| 	/* rewind the stream, because ogg_stream_type_detect() has | 	/* rewind the stream, because ogg_stream_type_detect() has | ||||||
| 	   moved it */ | 	   moved it */ | ||||||
| 	input_stream_seek(input_stream, 0, SEEK_SET); | 	input_stream_seek(input_stream, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 	data.decoder = decoder; | 	data.decoder = decoder; | ||||||
| 	data.input_stream = input_stream; | 	data.input_stream = input_stream; | ||||||
|   | |||||||
| @@ -417,13 +417,13 @@ wavpack_input_get_pos(void *id) | |||||||
| static int | static int | ||||||
| wavpack_input_set_pos_abs(void *id, uint32_t pos) | wavpack_input_set_pos_abs(void *id, uint32_t pos) | ||||||
| { | { | ||||||
| 	return input_stream_seek(wpin(id)->is, pos, SEEK_SET) ? 0 : -1; | 	return input_stream_seek(wpin(id)->is, pos, SEEK_SET, NULL) ? 0 : -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| wavpack_input_set_pos_rel(void *id, int32_t delta, int mode) | wavpack_input_set_pos_rel(void *id, int32_t delta, int mode) | ||||||
| { | { | ||||||
| 	return input_stream_seek(wpin(id)->is, delta, mode) ? 0 : -1; | 	return input_stream_seek(wpin(id)->is, delta, mode, NULL) ? 0 : -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| @@ -494,7 +494,7 @@ wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc, | |||||||
| 	wvc_url = g_strconcat(utf8url, "c", NULL); | 	wvc_url = g_strconcat(utf8url, "c", NULL); | ||||||
| 	g_free(utf8url); | 	g_free(utf8url); | ||||||
|  |  | ||||||
| 	ret = input_stream_open(is_wvc, wvc_url); | 	ret = input_stream_open(is_wvc, wvc_url, NULL); | ||||||
| 	g_free(wvc_url); | 	g_free(wvc_url); | ||||||
|  |  | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
|   | |||||||
| @@ -154,6 +154,7 @@ size_t decoder_read(struct decoder *decoder, | |||||||
| { | { | ||||||
| 	const struct decoder_control *dc = | 	const struct decoder_control *dc = | ||||||
| 		decoder != NULL ? decoder->dc : NULL; | 		decoder != NULL ? decoder->dc : NULL; | ||||||
|  | 	GError *error = NULL; | ||||||
| 	size_t nbytes; | 	size_t nbytes; | ||||||
|  |  | ||||||
| 	assert(decoder == NULL || | 	assert(decoder == NULL || | ||||||
| @@ -176,7 +177,14 @@ size_t decoder_read(struct decoder *decoder, | |||||||
| 		    dc->command != DECODE_COMMAND_NONE) | 		    dc->command != DECODE_COMMAND_NONE) | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| 		nbytes = input_stream_read(is, buffer, length); | 		nbytes = input_stream_read(is, buffer, length, &error); | ||||||
|  |  | ||||||
|  | 		if (G_UNLIKELY(nbytes == 0 && error != NULL)) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (nbytes > 0 || input_stream_eof(is)) | 		if (nbytes > 0 || input_stream_eof(is)) | ||||||
| 			return nbytes; | 			return nbytes; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,10 +37,16 @@ | |||||||
| static bool | static bool | ||||||
| decoder_input_buffer(struct decoder_control *dc, struct input_stream *is) | decoder_input_buffer(struct decoder_control *dc, struct input_stream *is) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	decoder_unlock(dc); | 	decoder_unlock(dc); | ||||||
| 	ret = input_stream_buffer(is); | 	ret = input_stream_buffer(is, &error); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		g_warning("%s", error->message); | ||||||
|  | 		g_error_free(error); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	decoder_lock(dc); | 	decoder_lock(dc); | ||||||
|  |  | ||||||
| 	return ret > 0; | 	return ret > 0; | ||||||
|   | |||||||
| @@ -63,8 +63,16 @@ static bool | |||||||
| decoder_input_stream_open(struct decoder_control *dc, | decoder_input_stream_open(struct decoder_control *dc, | ||||||
| 			  struct input_stream *is, const char *uri) | 			  struct input_stream *is, const char *uri) | ||||||
| { | { | ||||||
| 	if (!input_stream_open(is, uri)) | 	GError *error = NULL; | ||||||
|  |  | ||||||
|  | 	if (!input_stream_open(is, uri, &error)) { | ||||||
|  | 		if (error != NULL) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return false; | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/* wait for the input stream to become ready; its metadata | 	/* wait for the input stream to become ready; its metadata | ||||||
| 	   will be available then */ | 	   will be available then */ | ||||||
| @@ -73,9 +81,11 @@ decoder_input_stream_open(struct decoder_control *dc, | |||||||
| 	       decoder_lock_get_command(dc) != DECODE_COMMAND_STOP) { | 	       decoder_lock_get_command(dc) != DECODE_COMMAND_STOP) { | ||||||
| 		int ret; | 		int ret; | ||||||
|  |  | ||||||
| 		ret = input_stream_buffer(is); | 		ret = input_stream_buffer(is, &error); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			input_stream_close(is); | 			input_stream_close(is); | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -103,7 +113,7 @@ decoder_stream_decode(const struct decoder_plugin *plugin, | |||||||
| 	decoder_unlock(decoder->dc); | 	decoder_unlock(decoder->dc); | ||||||
|  |  | ||||||
| 	/* rewind the stream, so each plugin gets a fresh start */ | 	/* rewind the stream, so each plugin gets a fresh start */ | ||||||
| 	input_stream_seek(input_stream, 0, SEEK_SET); | 	input_stream_seek(input_stream, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 	decoder_plugin_stream_decode(plugin, decoder, input_stream); | 	decoder_plugin_stream_decode(plugin, decoder, input_stream); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,7 +34,8 @@ | |||||||
|  * plugin and gzip fetches file from disk |  * plugin and gzip fetches file from disk | ||||||
|  */ |  */ | ||||||
| static bool | static bool | ||||||
| input_archive_open(struct input_stream *is, const char *pathname) | input_archive_open(struct input_stream *is, const char *pathname, | ||||||
|  | 		   GError **error_r) | ||||||
| { | { | ||||||
| 	const struct archive_plugin *arplug; | 	const struct archive_plugin *arplug; | ||||||
| 	struct archive_file *file; | 	struct archive_file *file; | ||||||
| @@ -63,15 +64,15 @@ input_archive_open(struct input_stream *is, const char *pathname) | |||||||
| 	file = arplug->open(archive); | 	file = arplug->open(archive); | ||||||
|  |  | ||||||
| 	//setup fileops | 	//setup fileops | ||||||
| 	opened = arplug->open_stream(file, is, filename); | 	opened = arplug->open_stream(file, is, filename, error_r); | ||||||
|  | 	g_free(pname); | ||||||
|  |  | ||||||
| 	if (!opened) { | 	if (!opened) { | ||||||
| 		g_warning("open inarchive file %s failed\n\n",filename); |  | ||||||
| 		arplug->close(file); | 		arplug->close(file); | ||||||
| 	} else { | 	} else { | ||||||
| 		is->ready = true; | 		is->ready = true; | ||||||
| 	} | 	} | ||||||
| 	g_free(pname); |  | ||||||
| 	return opened; | 	return opened; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,6 +103,12 @@ static struct curl_slist *http_200_aliases; | |||||||
| static const char *proxy, *proxy_user, *proxy_password; | static const char *proxy, *proxy_user, *proxy_password; | ||||||
| static unsigned proxy_port; | static unsigned proxy_port; | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | curl_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("curl"); | ||||||
|  | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_init(const struct config_param *param, | input_curl_init(const struct config_param *param, | ||||||
| 		G_GNUC_UNUSED GError **error_r) | 		G_GNUC_UNUSED GError **error_r) | ||||||
| @@ -216,7 +222,7 @@ input_curl_tag(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_multi_info_read(struct input_stream *is) | input_curl_multi_info_read(struct input_stream *is, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c = is->data; | 	struct input_curl *c = is->data; | ||||||
| 	CURLMsg *msg; | 	CURLMsg *msg; | ||||||
| @@ -229,8 +235,9 @@ input_curl_multi_info_read(struct input_stream *is) | |||||||
| 			is->ready = true; | 			is->ready = true; | ||||||
|  |  | ||||||
| 			if (msg->data.result != CURLE_OK) { | 			if (msg->data.result != CURLE_OK) { | ||||||
| 				g_warning("curl failed: %s\n", c->error); | 				g_set_error(error_r, curl_quark(), | ||||||
| 				is->error = -1; | 					    msg->data.result, | ||||||
|  | 					    "curl failed: %s", c->error); | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -246,7 +253,7 @@ input_curl_multi_info_read(struct input_stream *is) | |||||||
|  * available |  * available | ||||||
|  */ |  */ | ||||||
| static int | static int | ||||||
| input_curl_select(struct input_curl *c) | input_curl_select(struct input_curl *c, GError **error_r) | ||||||
| { | { | ||||||
| 	fd_set rfds, wfds, efds; | 	fd_set rfds, wfds, efds; | ||||||
| 	int max_fd, ret; | 	int max_fd, ret; | ||||||
| @@ -265,8 +272,9 @@ input_curl_select(struct input_curl *c) | |||||||
|  |  | ||||||
| 	mcode = curl_multi_fdset(c->multi, &rfds, &wfds, &efds, &max_fd); | 	mcode = curl_multi_fdset(c->multi, &rfds, &wfds, &efds, &max_fd); | ||||||
| 	if (mcode != CURLM_OK) { | 	if (mcode != CURLM_OK) { | ||||||
| 		g_warning("curl_multi_fdset() failed: %s\n", | 		g_set_error(error_r, curl_quark(), mcode, | ||||||
| 			  curl_multi_strerror(mcode)); | 			    "curl_multi_fdset() failed: %s", | ||||||
|  | 			    curl_multi_strerror(mcode)); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -274,13 +282,15 @@ input_curl_select(struct input_curl *c) | |||||||
|  |  | ||||||
| 	ret = select(max_fd + 1, &rfds, &wfds, &efds, &timeout); | 	ret = select(max_fd + 1, &rfds, &wfds, &efds, &timeout); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		g_warning("select() failed: %s\n", strerror(errno)); | 		g_set_error(error_r, g_quark_from_static_string("errno"), | ||||||
|  | 			    errno, | ||||||
|  | 			    "select() failed: %s\n", g_strerror(errno)); | ||||||
|  |  | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| fill_buffer(struct input_stream *is) | fill_buffer(struct input_stream *is, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c = is->data; | 	struct input_curl *c = is->data; | ||||||
| 	CURLMcode mcode = CURLM_CALL_MULTI_PERFORM; | 	CURLMcode mcode = CURLM_CALL_MULTI_PERFORM; | ||||||
| @@ -292,7 +302,7 @@ fill_buffer(struct input_stream *is) | |||||||
| 		if (mcode != CURLM_CALL_MULTI_PERFORM) { | 		if (mcode != CURLM_CALL_MULTI_PERFORM) { | ||||||
| 			/* if we're still here, there is no input yet | 			/* if we're still here, there is no input yet | ||||||
| 			   - wait for input */ | 			   - wait for input */ | ||||||
| 			int ret = input_curl_select(c); | 			int ret = input_curl_select(c, error_r); | ||||||
| 			if (ret <= 0) | 			if (ret <= 0) | ||||||
| 				/* no data yet or error */ | 				/* no data yet or error */ | ||||||
| 				return false; | 				return false; | ||||||
| @@ -300,14 +310,15 @@ fill_buffer(struct input_stream *is) | |||||||
|  |  | ||||||
| 		mcode = curl_multi_perform(c->multi, &running_handles); | 		mcode = curl_multi_perform(c->multi, &running_handles); | ||||||
| 		if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) { | 		if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) { | ||||||
| 			g_warning("curl_multi_perform() failed: %s\n", | 			g_set_error(error_r, curl_quark(), mcode, | ||||||
| 				  curl_multi_strerror(mcode)); | 				    "curl_multi_perform() failed: %s", | ||||||
|  | 				    curl_multi_strerror(mcode)); | ||||||
| 			c->eof = true; | 			c->eof = true; | ||||||
| 			is->ready = true; | 			is->ready = true; | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		bret = input_curl_multi_info_read(is); | 		bret = input_curl_multi_info_read(is, error_r); | ||||||
| 		if (!bret) | 		if (!bret) | ||||||
| 			return false; | 			return false; | ||||||
| 	} | 	} | ||||||
| @@ -411,7 +422,8 @@ copy_icy_tag(struct input_curl *c) | |||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| input_curl_read(struct input_stream *is, void *ptr, size_t size) | 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 = is->data; | ||||||
| 	bool success; | 	bool success; | ||||||
| @@ -443,7 +455,7 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size) | |||||||
| 	do { | 	do { | ||||||
| 		/* fill the buffer */ | 		/* fill the buffer */ | ||||||
|  |  | ||||||
| 		success = fill_buffer(is); | 		success = fill_buffer(is, error_r); | ||||||
| 		if (!success) | 		if (!success) | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| @@ -518,7 +530,7 @@ input_curl_eof(G_GNUC_UNUSED struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| input_curl_buffer(struct input_stream *is) | input_curl_buffer(struct input_stream *is, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c = is->data; | 	struct input_curl *c = is->data; | ||||||
| 	CURLMcode mcode; | 	CURLMcode mcode; | ||||||
| @@ -531,7 +543,8 @@ input_curl_buffer(struct input_stream *is) | |||||||
| 		/* not ready yet means the caller is waiting in a busy | 		/* not ready yet means the caller is waiting in a busy | ||||||
| 		   loop; relax that by calling select() on the | 		   loop; relax that by calling select() on the | ||||||
| 		   socket */ | 		   socket */ | ||||||
| 		input_curl_select(c); | 		if (input_curl_select(c, error_r) < 0) | ||||||
|  | 			return -1; | ||||||
|  |  | ||||||
| 	do { | 	do { | ||||||
| 		mcode = curl_multi_perform(c->multi, &running_handles); | 		mcode = curl_multi_perform(c->multi, &running_handles); | ||||||
| @@ -539,14 +552,15 @@ input_curl_buffer(struct input_stream *is) | |||||||
| 		 g_queue_is_empty(c->buffers)); | 		 g_queue_is_empty(c->buffers)); | ||||||
|  |  | ||||||
| 	if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) { | 	if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) { | ||||||
| 		g_warning("curl_multi_perform() failed: %s\n", | 		g_set_error(error_r, curl_quark(), mcode, | ||||||
| 			  curl_multi_strerror(mcode)); | 			    "curl_multi_perform() failed: %s", | ||||||
|  | 			    curl_multi_strerror(mcode)); | ||||||
| 		c->eof = true; | 		c->eof = true; | ||||||
| 		is->ready = true; | 		is->ready = true; | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = input_curl_multi_info_read(is); | 	ret = input_curl_multi_info_read(is, error_r); | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
| @@ -672,7 +686,7 @@ input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_easy_init(struct input_stream *is) | input_curl_easy_init(struct input_stream *is, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c = is->data; | 	struct input_curl *c = is->data; | ||||||
| 	CURLcode code; | 	CURLcode code; | ||||||
| @@ -682,13 +696,18 @@ input_curl_easy_init(struct input_stream *is) | |||||||
|  |  | ||||||
| 	c->easy = curl_easy_init(); | 	c->easy = curl_easy_init(); | ||||||
| 	if (c->easy == NULL) { | 	if (c->easy == NULL) { | ||||||
| 		g_warning("curl_easy_init() failed\n"); | 		g_set_error(error_r, curl_quark(), 0, | ||||||
|  | 			    "curl_easy_init() failed"); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	mcode = curl_multi_add_handle(c->multi, c->easy); | 	mcode = curl_multi_add_handle(c->multi, c->easy); | ||||||
| 	if (mcode != CURLM_OK) | 	if (mcode != CURLM_OK) { | ||||||
|  | 		g_set_error(error_r, curl_quark(), mcode, | ||||||
|  | 			    "curl_multi_add_handle() failed: %s", | ||||||
|  | 			    curl_multi_strerror(mcode)); | ||||||
| 		return false; | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	curl_easy_setopt(c->easy, CURLOPT_USERAGENT, | 	curl_easy_setopt(c->easy, CURLOPT_USERAGENT, | ||||||
| 			 "Music Player Daemon " VERSION); | 			 "Music Player Daemon " VERSION); | ||||||
| @@ -718,8 +737,12 @@ input_curl_easy_init(struct input_stream *is) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	code = curl_easy_setopt(c->easy, CURLOPT_URL, c->url); | 	code = curl_easy_setopt(c->easy, CURLOPT_URL, c->url); | ||||||
| 	if (code != CURLE_OK) | 	if (code != CURLE_OK) { | ||||||
|  | 		g_set_error(error_r, curl_quark(), code, | ||||||
|  | 			    "curl_easy_setopt() failed: %s", | ||||||
|  | 			    curl_easy_strerror(code)); | ||||||
| 		return false; | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	c->request_headers = NULL; | 	c->request_headers = NULL; | ||||||
| 	c->request_headers = curl_slist_append(c->request_headers, | 	c->request_headers = curl_slist_append(c->request_headers, | ||||||
| @@ -730,7 +753,7 @@ input_curl_easy_init(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_send_request(struct input_curl *c) | input_curl_send_request(struct input_curl *c, GError **error_r) | ||||||
| { | { | ||||||
| 	CURLMcode mcode; | 	CURLMcode mcode; | ||||||
| 	int running_handles; | 	int running_handles; | ||||||
| @@ -740,8 +763,9 @@ input_curl_send_request(struct input_curl *c) | |||||||
| 	} while (mcode == CURLM_CALL_MULTI_PERFORM); | 	} while (mcode == CURLM_CALL_MULTI_PERFORM); | ||||||
|  |  | ||||||
| 	if (mcode != CURLM_OK) { | 	if (mcode != CURLM_OK) { | ||||||
| 		g_warning("curl_multi_perform() failed: %s\n", | 		g_set_error(error_r, curl_quark(), mcode, | ||||||
| 			  curl_multi_strerror(mcode)); | 			    "curl_multi_perform() failed: %s", | ||||||
|  | 			    curl_multi_strerror(mcode)); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -815,7 +839,8 @@ input_curl_rewind(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_seek(struct input_stream *is, goffset offset, int whence) | input_curl_seek(struct input_stream *is, goffset offset, int whence, | ||||||
|  | 		GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c = is->data; | 	struct input_curl *c = is->data; | ||||||
| 	bool ret; | 	bool ret; | ||||||
| @@ -907,7 +932,7 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence) | |||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = input_curl_easy_init(is); | 	ret = input_curl_easy_init(is, error_r); | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| @@ -918,15 +943,15 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence) | |||||||
| 		curl_easy_setopt(c->easy, CURLOPT_RANGE, c->range); | 		curl_easy_setopt(c->easy, CURLOPT_RANGE, c->range); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = input_curl_send_request(c); | 	ret = input_curl_send_request(c, error_r); | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	return input_curl_multi_info_read(is); | 	return input_curl_multi_info_read(is, error_r); | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_curl_open(struct input_stream *is, const char *url) | input_curl_open(struct input_stream *is, const char *url, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_curl *c; | 	struct input_curl *c; | ||||||
| 	bool ret; | 	bool ret; | ||||||
| @@ -944,8 +969,8 @@ input_curl_open(struct input_stream *is, const char *url) | |||||||
|  |  | ||||||
| 	c->multi = curl_multi_init(); | 	c->multi = curl_multi_init(); | ||||||
| 	if (c->multi == NULL) { | 	if (c->multi == NULL) { | ||||||
| 		g_warning("curl_multi_init() failed\n"); | 		g_set_error(error_r, curl_quark(), 0, | ||||||
|  | 			    "curl_multi_init() failed"); | ||||||
| 		input_curl_free(is); | 		input_curl_free(is); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -953,19 +978,19 @@ input_curl_open(struct input_stream *is, const char *url) | |||||||
| 	icy_clear(&c->icy_metadata); | 	icy_clear(&c->icy_metadata); | ||||||
| 	c->tag = NULL; | 	c->tag = NULL; | ||||||
|  |  | ||||||
| 	ret = input_curl_easy_init(is); | 	ret = input_curl_easy_init(is, error_r); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		input_curl_free(is); | 		input_curl_free(is); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = input_curl_send_request(c); | 	ret = input_curl_send_request(c, error_r); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		input_curl_free(is); | 		input_curl_free(is); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = input_curl_multi_info_read(is); | 	ret = input_curl_multi_info_read(is, error_r); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		input_curl_free(is); | 		input_curl_free(is); | ||||||
| 		return false; | 		return false; | ||||||
|   | |||||||
| @@ -32,8 +32,15 @@ | |||||||
| #undef G_LOG_DOMAIN | #undef G_LOG_DOMAIN | ||||||
| #define G_LOG_DOMAIN "input_file" | #define G_LOG_DOMAIN "input_file" | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | file_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("file"); | ||||||
|  | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_file_open(struct input_stream *is, const char *filename) | input_file_open(struct input_stream *is, const char *filename, | ||||||
|  | 		GError **error_r) | ||||||
| { | { | ||||||
| 	int fd, ret; | 	int fd, ret; | ||||||
| 	struct stat st; | 	struct stat st; | ||||||
| @@ -43,9 +50,10 @@ input_file_open(struct input_stream *is, const char *filename) | |||||||
|  |  | ||||||
| 	fd = open_cloexec(filename, O_RDONLY, 0); | 	fd = open_cloexec(filename, O_RDONLY, 0); | ||||||
| 	if (fd < 0) { | 	if (fd < 0) { | ||||||
| 		is->error = errno; | 		if (errno != ENOENT && errno != ENOTDIR) | ||||||
| 		g_debug("Failed to open \"%s\": %s", | 			g_set_error(error_r, file_quark(), errno, | ||||||
| 			filename, g_strerror(errno)); | 				    "Failed to open \"%s\": %s", | ||||||
|  | 				    filename, g_strerror(errno)); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -53,14 +61,16 @@ input_file_open(struct input_stream *is, const char *filename) | |||||||
|  |  | ||||||
| 	ret = fstat(fd, &st); | 	ret = fstat(fd, &st); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		is->error = errno; | 		g_set_error(error_r, file_quark(), errno, | ||||||
|  | 			    "Failed to stat \"%s\": %s", | ||||||
|  | 			    filename, g_strerror(errno)); | ||||||
| 		close(fd); | 		close(fd); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (!S_ISREG(st.st_mode)) { | 	if (!S_ISREG(st.st_mode)) { | ||||||
| 		g_debug("Not a regular file: %s", filename); | 		g_set_error(error_r, file_quark(), 0, | ||||||
| 		is->error = EINVAL; | 			    "Not a regular file: %s", filename); | ||||||
| 		close(fd); | 		close(fd); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -79,13 +89,15 @@ input_file_open(struct input_stream *is, const char *filename) | |||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_file_seek(struct input_stream *is, goffset offset, int whence) | input_file_seek(struct input_stream *is, goffset offset, int whence, | ||||||
|  | 		GError **error_r) | ||||||
| { | { | ||||||
| 	int fd = GPOINTER_TO_INT(is->data); | 	int fd = GPOINTER_TO_INT(is->data); | ||||||
|  |  | ||||||
| 	offset = (goffset)lseek(fd, (off_t)offset, whence); | 	offset = (goffset)lseek(fd, (off_t)offset, whence); | ||||||
| 	if (offset < 0) { | 	if (offset < 0) { | ||||||
| 		is->error = errno; | 		g_set_error(error_r, file_quark(), errno, | ||||||
|  | 			    "Failed to seek: %s", g_strerror(errno)); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -94,16 +106,16 @@ input_file_seek(struct input_stream *is, goffset offset, int whence) | |||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| input_file_read(struct input_stream *is, void *ptr, size_t size) | input_file_read(struct input_stream *is, void *ptr, size_t size, | ||||||
|  | 		GError **error_r) | ||||||
| { | { | ||||||
| 	int fd = GPOINTER_TO_INT(is->data); | 	int fd = GPOINTER_TO_INT(is->data); | ||||||
| 	ssize_t nbytes; | 	ssize_t nbytes; | ||||||
|  |  | ||||||
| 	nbytes = read(fd, ptr, size); | 	nbytes = read(fd, ptr, size); | ||||||
| 	if (nbytes < 0) { | 	if (nbytes < 0) { | ||||||
| 		is->error = errno; | 		g_set_error(error_r, file_quark(), errno, | ||||||
| 		g_debug("input_file_read: error reading: %s\n", | 			    "Failed to read: %s", g_strerror(errno)); | ||||||
| 			strerror(is->error)); |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,8 +36,14 @@ struct input_mms { | |||||||
| 	bool eof; | 	bool eof; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | static inline GQuark | ||||||
|  | mms_quark(void) | ||||||
|  | { | ||||||
|  | 	return g_quark_from_static_string("mms"); | ||||||
|  | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_mms_open(struct input_stream *is, const char *url) | input_mms_open(struct input_stream *is, const char *url, GError **error_r) | ||||||
| { | { | ||||||
| 	struct input_mms *m; | 	struct input_mms *m; | ||||||
|  |  | ||||||
| @@ -50,7 +56,7 @@ input_mms_open(struct input_stream *is, const char *url) | |||||||
| 	m = g_new(struct input_mms, 1); | 	m = g_new(struct input_mms, 1); | ||||||
| 	m->mms = mmsx_connect(NULL, NULL, url, 128 * 1024); | 	m->mms = mmsx_connect(NULL, NULL, url, 128 * 1024); | ||||||
| 	if (m->mms == NULL) { | 	if (m->mms == NULL) { | ||||||
| 		g_warning("mmsx_connect() failed"); | 		g_set_error(error_r, mms_quark(), 0, "mmsx_connect() failed"); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -65,7 +71,8 @@ input_mms_open(struct input_stream *is, const char *url) | |||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| input_mms_read(struct input_stream *is, void *ptr, size_t size) | 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 = is->data; | ||||||
| 	int ret; | 	int ret; | ||||||
| @@ -73,8 +80,9 @@ input_mms_read(struct input_stream *is, void *ptr, size_t size) | |||||||
| 	ret = mmsx_read(NULL, m->mms, ptr, size); | 	ret = mmsx_read(NULL, m->mms, ptr, size); | ||||||
| 	if (ret <= 0) { | 	if (ret <= 0) { | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			is->error = errno; | 			g_set_error(error_r, mms_quark(), errno, | ||||||
| 			g_warning("mmsx_read() failed: %s", g_strerror(errno)); | 				    "mmsx_read() failed: %s", | ||||||
|  | 				    g_strerror(errno)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m->eof = true; | 		m->eof = true; | ||||||
| @@ -104,14 +112,16 @@ input_mms_eof(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| input_mms_buffer(G_GNUC_UNUSED struct input_stream *is) | input_mms_buffer(G_GNUC_UNUSED struct input_stream *is, | ||||||
|  | 		 G_GNUC_UNUSED GError **error_r) | ||||||
| { | { | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| input_mms_seek(G_GNUC_UNUSED struct input_stream *is, | input_mms_seek(G_GNUC_UNUSED struct input_stream *is, | ||||||
| 	       G_GNUC_UNUSED goffset offset, G_GNUC_UNUSED int whence) | 	       G_GNUC_UNUSED goffset offset, G_GNUC_UNUSED int whence, | ||||||
|  | 	       G_GNUC_UNUSED GError **error_r) | ||||||
| { | { | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -48,14 +48,17 @@ struct input_plugin { | |||||||
| 	 */ | 	 */ | ||||||
| 	void (*finish)(void); | 	void (*finish)(void); | ||||||
|  |  | ||||||
| 	bool (*open)(struct input_stream *is, const char *url); | 	bool (*open)(struct input_stream *is, const char *url, | ||||||
|  | 		     GError **error_r); | ||||||
| 	void (*close)(struct input_stream *is); | 	void (*close)(struct input_stream *is); | ||||||
|  |  | ||||||
| 	struct tag *(*tag)(struct input_stream *is); | 	struct tag *(*tag)(struct input_stream *is); | ||||||
| 	int (*buffer)(struct input_stream *is); | 	int (*buffer)(struct input_stream *is, GError **error_r); | ||||||
| 	size_t (*read)(struct input_stream *is, void *ptr, size_t size); | 	size_t (*read)(struct input_stream *is, void *ptr, size_t size, | ||||||
|  | 		       GError **error_r); | ||||||
| 	bool (*eof)(struct input_stream *is); | 	bool (*eof)(struct input_stream *is); | ||||||
| 	bool (*seek)(struct input_stream *is, goffset offset, int whence); | 	bool (*seek)(struct input_stream *is, goffset offset, int whence, | ||||||
|  | 		     GError **error_r); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -25,20 +25,32 @@ | |||||||
| #include <glib.h> | #include <glib.h> | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
|  |  | ||||||
| bool | static inline GQuark | ||||||
| input_stream_open(struct input_stream *is, const char *url) | input_quark(void) | ||||||
| { | { | ||||||
|  | 	return g_quark_from_static_string("input"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | input_stream_open(struct input_stream *is, const char *url, GError **error_r) | ||||||
|  | { | ||||||
|  | 	GError *error = NULL; | ||||||
|  |  | ||||||
|  | 	assert(error_r == NULL || *error_r == NULL); | ||||||
|  |  | ||||||
| 	is->seekable = false; | 	is->seekable = false; | ||||||
| 	is->ready = false; | 	is->ready = false; | ||||||
| 	is->offset = 0; | 	is->offset = 0; | ||||||
| 	is->size = -1; | 	is->size = -1; | ||||||
| 	is->error = 0; |  | ||||||
| 	is->mime = NULL; | 	is->mime = NULL; | ||||||
|  |  | ||||||
| 	for (unsigned i = 0; input_plugins[i] != NULL; ++i) { | 	for (unsigned i = 0; input_plugins[i] != NULL; ++i) { | ||||||
| 		const struct input_plugin *plugin = input_plugins[i]; | 		const struct input_plugin *plugin = input_plugins[i]; | ||||||
|  |  | ||||||
| 		if (input_plugins_enabled[i] && plugin->open(is, url)) { | 		if (!input_plugins_enabled[i]) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		if (plugin->open(is, url, &error)) { | ||||||
| 			assert(is->plugin != NULL); | 			assert(is->plugin != NULL); | ||||||
| 			assert(is->plugin->close != NULL); | 			assert(is->plugin->close != NULL); | ||||||
| 			assert(is->plugin->read != NULL); | 			assert(is->plugin->read != NULL); | ||||||
| @@ -46,19 +58,24 @@ input_stream_open(struct input_stream *is, const char *url) | |||||||
| 			assert(!is->seekable || is->plugin->seek != NULL); | 			assert(!is->seekable || is->plugin->seek != NULL); | ||||||
|  |  | ||||||
| 			return true; | 			return true; | ||||||
|  | 		} else if (error != NULL) { | ||||||
|  | 			g_propagate_error(error_r, error); | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	g_set_error(error_r, input_quark(), 0, "Unrecognized URI"); | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool | bool | ||||||
| input_stream_seek(struct input_stream *is, goffset offset, int whence) | input_stream_seek(struct input_stream *is, goffset offset, int whence, | ||||||
|  | 		  GError **error_r) | ||||||
| { | { | ||||||
| 	if (is->plugin->seek == NULL) | 	if (is->plugin->seek == NULL) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	return is->plugin->seek(is, offset, whence); | 	return is->plugin->seek(is, offset, whence, error_r); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct tag * | struct tag * | ||||||
| @@ -72,12 +89,13 @@ input_stream_tag(struct input_stream *is) | |||||||
| } | } | ||||||
|  |  | ||||||
| size_t | size_t | ||||||
| input_stream_read(struct input_stream *is, void *ptr, size_t size) | input_stream_read(struct input_stream *is, void *ptr, size_t size, | ||||||
|  | 		  GError **error_r) | ||||||
| { | { | ||||||
| 	assert(ptr != NULL); | 	assert(ptr != NULL); | ||||||
| 	assert(size > 0); | 	assert(size > 0); | ||||||
|  |  | ||||||
| 	return is->plugin->read(is, ptr, size); | 	return is->plugin->read(is, ptr, size, error_r); | ||||||
| } | } | ||||||
|  |  | ||||||
| void input_stream_close(struct input_stream *is) | void input_stream_close(struct input_stream *is) | ||||||
| @@ -92,10 +110,11 @@ bool input_stream_eof(struct input_stream *is) | |||||||
| 	return is->plugin->eof(is); | 	return is->plugin->eof(is); | ||||||
| } | } | ||||||
|  |  | ||||||
| int input_stream_buffer(struct input_stream *is) | int | ||||||
|  | input_stream_buffer(struct input_stream *is, GError **error_r) | ||||||
| { | { | ||||||
| 	if (is->plugin->buffer == NULL) | 	if (is->plugin->buffer == NULL) | ||||||
| 		return 0; | 		return 0; | ||||||
|  |  | ||||||
| 	return is->plugin->buffer(is); | 	return is->plugin->buffer(is, error_r); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -54,11 +54,6 @@ struct input_stream { | |||||||
| 	 */ | 	 */ | ||||||
| 	bool seekable; | 	bool seekable; | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * an optional errno error code, set to non-zero after an error occured |  | ||||||
| 	 */ |  | ||||||
| 	int error; |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * the size of the resource, or -1 if unknown | 	 * the size of the resource, or -1 if unknown | ||||||
| 	 */ | 	 */ | ||||||
| @@ -83,7 +78,7 @@ struct input_stream { | |||||||
|  * @return true on success |  * @return true on success | ||||||
|  */ |  */ | ||||||
| bool | bool | ||||||
| input_stream_open(struct input_stream *is, const char *url); | input_stream_open(struct input_stream *is, const char *url, GError **error_r); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Closes the input stream and free resources.  This does not free the |  * Closes the input stream and free resources.  This does not free the | ||||||
| @@ -102,7 +97,8 @@ input_stream_close(struct input_stream *is); | |||||||
|  * @param whence the base of the seek, one of SEEK_SET, SEEK_CUR, SEEK_END |  * @param whence the base of the seek, one of SEEK_SET, SEEK_CUR, SEEK_END | ||||||
|  */ |  */ | ||||||
| bool | bool | ||||||
| input_stream_seek(struct input_stream *is, goffset offset, int whence); | input_stream_seek(struct input_stream *is, goffset offset, int whence, | ||||||
|  | 		  GError **error_r); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Returns true if the stream has reached end-of-file. |  * Returns true if the stream has reached end-of-file. | ||||||
| @@ -126,7 +122,7 @@ input_stream_tag(struct input_stream *is); | |||||||
|  * The semantics of this function are not well-defined, and it will |  * The semantics of this function are not well-defined, and it will | ||||||
|  * eventually be removed. |  * eventually be removed. | ||||||
|  */ |  */ | ||||||
| int input_stream_buffer(struct input_stream *is); | int input_stream_buffer(struct input_stream *is, GError **error_r); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Reads data from the stream into the caller-supplied buffer. |  * Reads data from the stream into the caller-supplied buffer. | ||||||
| @@ -138,6 +134,7 @@ int input_stream_buffer(struct input_stream *is); | |||||||
|  * @return the number of bytes read |  * @return the number of bytes read | ||||||
|  */ |  */ | ||||||
| size_t | size_t | ||||||
| input_stream_read(struct input_stream *is, void *ptr, size_t size); | input_stream_read(struct input_stream *is, void *ptr, size_t size, | ||||||
|  | 		  GError **error_r); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -233,9 +233,17 @@ asx_open_stream(struct input_stream *is) | |||||||
| 					     &parser, asx_parser_destroy); | 					     &parser, asx_parser_destroy); | ||||||
|  |  | ||||||
| 	while (true) { | 	while (true) { | ||||||
| 		nbytes = input_stream_read(is, buffer, sizeof(buffer)); | 		nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); | ||||||
| 		if (nbytes == 0) | 		if (nbytes == 0) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_markup_parse_context_free(context); | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			break; | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		success = g_markup_parse_context_parse(context, buffer, nbytes, | 		success = g_markup_parse_context_parse(context, buffer, nbytes, | ||||||
| 						       &error); | 						       &error); | ||||||
|   | |||||||
| @@ -86,27 +86,41 @@ static char * | |||||||
| lastfm_get(const char *url) | lastfm_get(const char *url) | ||||||
| { | { | ||||||
| 	struct input_stream input_stream; | 	struct input_stream input_stream; | ||||||
|  | 	GError *error = NULL; | ||||||
| 	bool success; | 	bool success; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	char buffer[4096]; | 	char buffer[4096]; | ||||||
| 	size_t length = 0, nbytes; | 	size_t length = 0, nbytes; | ||||||
|  |  | ||||||
| 	success = input_stream_open(&input_stream, url); | 	success = input_stream_open(&input_stream, url, &error); | ||||||
| 	if (!success) | 	if (!success) { | ||||||
|  | 		if (error != NULL) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	while (!input_stream.ready) { | 	while (!input_stream.ready) { | ||||||
| 		ret = input_stream_buffer(&input_stream); | 		ret = input_stream_buffer(&input_stream, &error); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			input_stream_close(&input_stream); | 			input_stream_close(&input_stream); | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	do { | 	do { | ||||||
| 		nbytes = input_stream_read(&input_stream, buffer + length, | 		nbytes = input_stream_read(&input_stream, buffer + length, | ||||||
| 					   sizeof(buffer) - length); | 					   sizeof(buffer) - length, &error); | ||||||
| 		if (nbytes == 0) { | 		if (nbytes == 0) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			if (input_stream_eof(&input_stream)) | 			if (input_stream_eof(&input_stream)) | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| @@ -152,6 +166,7 @@ static struct playlist_provider * | |||||||
| lastfm_open_uri(const char *uri) | lastfm_open_uri(const char *uri) | ||||||
| { | { | ||||||
| 	struct lastfm_playlist *playlist; | 	struct lastfm_playlist *playlist; | ||||||
|  | 	GError *error = NULL; | ||||||
| 	char *p, *q, *response, *session; | 	char *p, *q, *response, *session; | ||||||
| 	bool success; | 	bool success; | ||||||
|  |  | ||||||
| @@ -216,20 +231,27 @@ lastfm_open_uri(const char *uri) | |||||||
| 			NULL); | 			NULL); | ||||||
| 	g_free(session); | 	g_free(session); | ||||||
|  |  | ||||||
| 	success = input_stream_open(&playlist->is, p); | 	success = input_stream_open(&playlist->is, p, &error); | ||||||
| 	g_free(p); | 	g_free(p); | ||||||
|  |  | ||||||
| 	if (!success) { | 	if (!success) { | ||||||
| 		g_warning("Failed to load XSPF playlist"); | 		if (error != NULL) { | ||||||
|  | 			g_warning("Failed to load XSPF playlist: %s", | ||||||
|  | 				  error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} else | ||||||
|  | 			g_warning("Failed to load XSPF playlist"); | ||||||
| 		g_free(playlist); | 		g_free(playlist); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while (!playlist->is.ready) { | 	while (!playlist->is.ready) { | ||||||
| 		int ret = input_stream_buffer(&playlist->is); | 		int ret = input_stream_buffer(&playlist->is, &error); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			input_stream_close(&playlist->is); | 			input_stream_close(&playlist->is); | ||||||
| 			g_free(playlist); | 			g_free(playlist); | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,9 +115,18 @@ pls_open_stream(struct input_stream *is) | |||||||
| 	GString *kf_data = g_string_new(""); | 	GString *kf_data = g_string_new(""); | ||||||
|  |  | ||||||
| 	do { | 	do { | ||||||
| 		nbytes = input_stream_read(is, buffer, sizeof(buffer)); | 		nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); | ||||||
| 		if(nbytes ==0) | 		if (nbytes == 0) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_string_free(kf_data, TRUE); | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			break; | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		kf_data = g_string_append_len(kf_data, buffer,nbytes); | 		kf_data = g_string_append_len(kf_data, buffer,nbytes); | ||||||
| 		/* Limit to 64k */ | 		/* Limit to 64k */ | ||||||
| 	} while(kf_data->len < 65536); | 	} while(kf_data->len < 65536); | ||||||
|   | |||||||
| @@ -253,9 +253,17 @@ xspf_open_stream(struct input_stream *is) | |||||||
| 					     &parser, xspf_parser_destroy); | 					     &parser, xspf_parser_destroy); | ||||||
|  |  | ||||||
| 	while (true) { | 	while (true) { | ||||||
| 		nbytes = input_stream_read(is, buffer, sizeof(buffer)); | 		nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); | ||||||
| 		if (nbytes == 0) | 		if (nbytes == 0) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_markup_parse_context_free(context); | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			break; | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		success = g_markup_parse_context_parse(context, buffer, nbytes, | 		success = g_markup_parse_context_parse(context, buffer, nbytes, | ||||||
| 						       &error); | 						       &error); | ||||||
|   | |||||||
| @@ -159,7 +159,7 @@ playlist_list_open_stream_mime(struct input_stream *is) | |||||||
| 		    string_array_contains(plugin->mime_types, is->mime)) { | 		    string_array_contains(plugin->mime_types, is->mime)) { | ||||||
| 			/* rewind the stream, so each plugin gets a | 			/* rewind the stream, so each plugin gets a | ||||||
| 			   fresh start */ | 			   fresh start */ | ||||||
| 			input_stream_seek(is, 0, SEEK_SET); | 			input_stream_seek(is, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 			playlist = playlist_plugin_open_stream(plugin, is); | 			playlist = playlist_plugin_open_stream(plugin, is); | ||||||
| 			if (playlist != NULL) | 			if (playlist != NULL) | ||||||
| @@ -185,7 +185,7 @@ playlist_list_open_stream_suffix(struct input_stream *is, const char *suffix) | |||||||
| 		    string_array_contains(plugin->suffixes, suffix)) { | 		    string_array_contains(plugin->suffixes, suffix)) { | ||||||
| 			/* rewind the stream, so each plugin gets a | 			/* rewind the stream, so each plugin gets a | ||||||
| 			   fresh start */ | 			   fresh start */ | ||||||
| 			input_stream_seek(is, 0, SEEK_SET); | 			input_stream_seek(is, 0, SEEK_SET, NULL); | ||||||
|  |  | ||||||
| 			playlist = playlist_plugin_open_stream(plugin, is); | 			playlist = playlist_plugin_open_stream(plugin, is); | ||||||
| 			if (playlist != NULL) | 			if (playlist != NULL) | ||||||
| @@ -237,16 +237,25 @@ playlist_suffix_supported(const char *suffix) | |||||||
| struct playlist_provider * | struct playlist_provider * | ||||||
| playlist_list_open_path(struct input_stream *is, const char *path_fs) | playlist_list_open_path(struct input_stream *is, const char *path_fs) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	const char *suffix; | 	const char *suffix; | ||||||
| 	struct playlist_provider *playlist; | 	struct playlist_provider *playlist; | ||||||
|  |  | ||||||
| 	assert(path_fs != NULL); | 	assert(path_fs != NULL); | ||||||
|  |  | ||||||
| 	suffix = uri_get_suffix(path_fs); | 	suffix = uri_get_suffix(path_fs); | ||||||
| 	if (suffix == NULL || !playlist_suffix_supported(suffix) || | 	if (suffix == NULL || !playlist_suffix_supported(suffix)) | ||||||
| 	    !input_stream_open(is, path_fs)) |  | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
|  | 	if (!input_stream_open(is, path_fs, &error)) { | ||||||
|  | 		if (error != NULL) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	playlist = playlist_list_open_stream_suffix(is, suffix); | 	playlist = playlist_list_open_stream_suffix(is, suffix); | ||||||
| 	if (playlist == NULL) | 	if (playlist == NULL) | ||||||
| 		input_stream_close(is); | 		input_stream_close(is); | ||||||
|   | |||||||
| @@ -65,6 +65,7 @@ playlist_load_into_queue(struct playlist_provider *source, | |||||||
| static enum playlist_result | static enum playlist_result | ||||||
| playlist_open_remote_into_queue(const char *uri, struct playlist *dest) | playlist_open_remote_into_queue(const char *uri, struct playlist *dest) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	struct playlist_provider *playlist; | 	struct playlist_provider *playlist; | ||||||
| 	bool stream = false; | 	bool stream = false; | ||||||
| 	struct input_stream is; | 	struct input_stream is; | ||||||
| @@ -74,9 +75,16 @@ playlist_open_remote_into_queue(const char *uri, struct playlist *dest) | |||||||
|  |  | ||||||
| 	playlist = playlist_list_open_uri(uri); | 	playlist = playlist_list_open_uri(uri); | ||||||
| 	if (playlist == NULL) { | 	if (playlist == NULL) { | ||||||
| 		stream = input_stream_open(&is, uri); | 		stream = input_stream_open(&is, uri, &error); | ||||||
| 		if (!stream) | 		if (!stream) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_warning("Failed to open %s: %s", | ||||||
|  | 					  uri, error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			return PLAYLIST_RESULT_NO_SUCH_LIST; | 			return PLAYLIST_RESULT_NO_SUCH_LIST; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		playlist = playlist_list_open_stream(&is, uri); | 		playlist = playlist_list_open_stream(&is, uri); | ||||||
| 		if (playlist == NULL) { | 		if (playlist == NULL) { | ||||||
|   | |||||||
| @@ -57,6 +57,7 @@ text_input_stream_free(struct text_input_stream *tis) | |||||||
| const char * | const char * | ||||||
| text_input_stream_read(struct text_input_stream *tis) | text_input_stream_read(struct text_input_stream *tis) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	void *dest; | 	void *dest; | ||||||
| 	const char *src, *p; | 	const char *src, *p; | ||||||
| 	size_t length, nbytes; | 	size_t length, nbytes; | ||||||
| @@ -67,9 +68,15 @@ text_input_stream_read(struct text_input_stream *tis) | |||||||
| 	do { | 	do { | ||||||
| 		dest = fifo_buffer_write(tis->buffer, &length); | 		dest = fifo_buffer_write(tis->buffer, &length); | ||||||
| 		if (dest != NULL) { | 		if (dest != NULL) { | ||||||
| 			nbytes = input_stream_read(tis->is, dest, length); | 			nbytes = input_stream_read(tis->is, dest, length, | ||||||
|  | 						   &error); | ||||||
| 			if (nbytes > 0) | 			if (nbytes > 0) | ||||||
| 				fifo_buffer_append(tis->buffer, nbytes); | 				fifo_buffer_append(tis->buffer, nbytes); | ||||||
|  | 			else if (error != NULL) { | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		src = fifo_buffer_read(tis->buffer, &length); | 		src = fifo_buffer_read(tis->buffer, &length); | ||||||
|   | |||||||
| @@ -88,17 +88,24 @@ int main(int argc, char **argv) | |||||||
| 	if (playlist == NULL) { | 	if (playlist == NULL) { | ||||||
| 		/* open the stream and wait until it becomes ready */ | 		/* open the stream and wait until it becomes ready */ | ||||||
|  |  | ||||||
| 		success = input_stream_open(&is, uri); | 		success = input_stream_open(&is, uri, &error); | ||||||
| 		if (!success) { | 		if (!success) { | ||||||
| 			g_printerr("input_stream_open() failed\n"); | 			if (error != NULL) { | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 			} else | ||||||
|  | 				g_printerr("input_stream_open() failed\n"); | ||||||
| 			return 2; | 			return 2; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		while (!is.ready) { | 		while (!is.ready) { | ||||||
| 			int ret = input_stream_buffer(&is); | 			int ret = input_stream_buffer(&is, &error); | ||||||
| 			if (ret < 0) | 			if (ret < 0) { | ||||||
| 				/* error */ | 				/* error */ | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
| 				return 2; | 				return 2; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			if (ret == 0) | 			if (ret == 0) | ||||||
| 				/* nothing was buffered - wait */ | 				/* nothing was buffered - wait */ | ||||||
|   | |||||||
| @@ -93,7 +93,7 @@ decoder_read(G_GNUC_UNUSED struct decoder *decoder, | |||||||
| 	     struct input_stream *is, | 	     struct input_stream *is, | ||||||
| 	     void *buffer, size_t length) | 	     void *buffer, size_t length) | ||||||
| { | { | ||||||
| 	return input_stream_read(is, buffer, length); | 	return input_stream_read(is, buffer, length, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| enum decoder_command | enum decoder_command | ||||||
|   | |||||||
| @@ -114,7 +114,7 @@ decoder_read(G_GNUC_UNUSED struct decoder *decoder, | |||||||
| 	     struct input_stream *is, | 	     struct input_stream *is, | ||||||
| 	     void *buffer, size_t length) | 	     void *buffer, size_t length) | ||||||
| { | { | ||||||
| 	return input_stream_read(is, buffer, length); | 	return input_stream_read(is, buffer, length, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| enum decoder_command | enum decoder_command | ||||||
| @@ -175,9 +175,16 @@ int main(int argc, char **argv) | |||||||
| 	} else if (decoder.plugin->stream_decode != NULL) { | 	} else if (decoder.plugin->stream_decode != NULL) { | ||||||
| 		struct input_stream is; | 		struct input_stream is; | ||||||
|  |  | ||||||
| 		ret = input_stream_open(&is, decoder.uri); | 		ret = input_stream_open(&is, decoder.uri, &error); | ||||||
| 		if (!ret) | 		if (!ret) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 			} else | ||||||
|  | 				g_printerr("input_stream_open() failed\n"); | ||||||
|  |  | ||||||
| 			return 1; | 			return 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		decoder_plugin_stream_decode(decoder.plugin, &decoder, &is); | 		decoder_plugin_stream_decode(decoder.plugin, &decoder, &is); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, | |||||||
| static int | static int | ||||||
| dump_input_stream(struct input_stream *is) | dump_input_stream(struct input_stream *is) | ||||||
| { | { | ||||||
|  | 	GError *error = NULL; | ||||||
| 	char buffer[4096]; | 	char buffer[4096]; | ||||||
| 	size_t num_read; | 	size_t num_read; | ||||||
| 	ssize_t num_written; | 	ssize_t num_written; | ||||||
| @@ -52,10 +53,13 @@ dump_input_stream(struct input_stream *is) | |||||||
| 	/* wait until the stream becomes ready */ | 	/* wait until the stream becomes ready */ | ||||||
|  |  | ||||||
| 	while (!is->ready) { | 	while (!is->ready) { | ||||||
| 		int ret = input_stream_buffer(is); | 		int ret = input_stream_buffer(is, &error); | ||||||
| 		if (ret < 0) | 		if (ret < 0) { | ||||||
| 			/* error */ | 			/* error */ | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
| 			return 2; | 			return 2; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (ret == 0) | 		if (ret == 0) | ||||||
| 			/* nothing was buffered - wait */ | 			/* nothing was buffered - wait */ | ||||||
| @@ -77,9 +81,16 @@ dump_input_stream(struct input_stream *is) | |||||||
| 			tag_free(tag); | 			tag_free(tag); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		num_read = input_stream_read(is, buffer, sizeof(buffer)); | 		num_read = input_stream_read(is, buffer, sizeof(buffer), | ||||||
| 		if (num_read == 0) | 					     &error); | ||||||
|  | 		if (num_read == 0) { | ||||||
|  | 			if (error != NULL) { | ||||||
|  | 				g_warning("%s", error->message); | ||||||
|  | 				g_error_free(error); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			break; | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		num_written = write(1, buffer, num_read); | 		num_written = write(1, buffer, num_read); | ||||||
| 		if (num_written <= 0) | 		if (num_written <= 0) | ||||||
| @@ -122,11 +133,15 @@ int main(int argc, char **argv) | |||||||
|  |  | ||||||
| 	/* open the stream and dump it */ | 	/* open the stream and dump it */ | ||||||
|  |  | ||||||
| 	if (input_stream_open(&is, argv[1])) { | 	if (input_stream_open(&is, argv[1], &error)) { | ||||||
| 		ret = dump_input_stream(&is); | 		ret = dump_input_stream(&is); | ||||||
| 		input_stream_close(&is); | 		input_stream_close(&is); | ||||||
| 	} else { | 	} else { | ||||||
| 		g_printerr("input_stream_open() failed\n"); | 		if (error != NULL) { | ||||||
|  | 			g_warning("%s", error->message); | ||||||
|  | 			g_error_free(error); | ||||||
|  | 		} else | ||||||
|  | 			g_printerr("input_stream_open() failed\n"); | ||||||
| 		ret = 2; | 		ret = 2; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann