Blame src/libmpg123/readers.c

Packit c32a2d
/* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	readers.c: reading input data
Packit c32a2d
Packit c32a2d
	copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Michael Hipp
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
#include <sys/stat.h>
Packit c32a2d
#include <fcntl.h>
Packit c32a2d
#include <errno.h>
Packit c32a2d
/* For select(), I need select.h according to POSIX 2001, else: sys/time.h sys/types.h unistd.h (the latter two included in compat.h already). */
Packit c32a2d
#ifdef HAVE_SYS_SELECT_H
Packit c32a2d
#include <sys/select.h>
Packit c32a2d
#endif
Packit c32a2d
#ifdef HAVE_SYS_TIME_H
Packit c32a2d
#include <sys/time.h>
Packit c32a2d
#endif
Packit c32a2d
#ifdef _MSC_VER
Packit c32a2d
#include <io.h>
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#include "compat.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
static int default_init(mpg123_handle *fr);
Packit c32a2d
static off_t get_fileinfo(mpg123_handle *);
Packit c32a2d
static ssize_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); }
Packit c32a2d
static off_t   posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); }
Packit c32a2d
static off_t     nix_lseek(int fd, off_t offset, int whence){ return -1; }
Packit c32a2d
Packit c32a2d
static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count);
Packit c32a2d
Packit c32a2d
/* Wrapper to decide between descriptor-based and external handle-based I/O. */
Packit c32a2d
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence);
Packit c32a2d
static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count);
Packit c32a2d
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
/* Bufferchain methods. */
Packit c32a2d
static void bc_init(struct bufferchain *bc);
Packit c32a2d
static void bc_reset(struct bufferchain *bc);
Packit c32a2d
static int bc_append(struct bufferchain *bc, ssize_t size);
Packit c32a2d
#if 0
Packit c32a2d
static void bc_drop(struct bufferchain *bc);
Packit c32a2d
#endif
Packit c32a2d
static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size);
Packit c32a2d
static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size);
Packit c32a2d
static ssize_t bc_skip(struct bufferchain *bc, ssize_t count);
Packit c32a2d
static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count);
Packit c32a2d
static void bc_forget(struct bufferchain *bc);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
/* A normal read and a read with timeout. */
Packit c32a2d
static ssize_t plain_read(mpg123_handle *fr, void *buf, size_t count)
Packit c32a2d
{
Packit c32a2d
	ssize_t ret = io_read(&fr->rdat, buf, count);
Packit c32a2d
	if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count);
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifdef TIMEOUT_READ
Packit c32a2d
Packit c32a2d
/* Wait for data becoming available, allowing soft-broken network connection to die
Packit c32a2d
   This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */
Packit c32a2d
static ssize_t timeout_read(mpg123_handle *fr, void *buf, size_t count)
Packit c32a2d
{
Packit c32a2d
	struct timeval tv;
Packit c32a2d
	ssize_t ret = 0;
Packit c32a2d
	fd_set fds;
Packit c32a2d
	tv.tv_sec = fr->rdat.timeout_sec;
Packit c32a2d
	tv.tv_usec = 0;
Packit c32a2d
	FD_ZERO(&fds);
Packit c32a2d
	FD_SET(fr->rdat.filept, &fds);
Packit c32a2d
	ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv;;
Packit c32a2d
	/* This works only with "my" read function. Not user-replaced. */
Packit c32a2d
	if(ret > 0) ret = read(fr->rdat.filept, buf, count);
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		ret=-1; /* no activity is the error */
Packit c32a2d
		if(NOQUIET) error("stream timed out");
Packit c32a2d
	}
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
/* stream based operation  with icy meta data*/
Packit c32a2d
static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	ssize_t ret,cnt;
Packit c32a2d
	cnt = 0;
Packit c32a2d
	if(fr->rdat.flags & READER_SEEKABLE)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams.");
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	/*
Packit c32a2d
		There used to be a check for expected file end here (length value or ID3 flag).
Packit c32a2d
		This is not needed:
Packit c32a2d
		1. EOF is indicated by fdread returning zero bytes anyway.
Packit c32a2d
		2. We get false positives of EOF for either files that grew or
Packit c32a2d
		3. ... files that have ID3v1 tags in between (stream with intro).
Packit c32a2d
	*/
Packit c32a2d
Packit c32a2d
	while(cnt < count)
Packit c32a2d
	{
Packit c32a2d
		/* all icy code is inside this if block, everything else is the plain fullread we know */
Packit c32a2d
		/* debug1("read: %li left", (long) count-cnt); */
Packit c32a2d
		if(fr->icy.next < count-cnt)
Packit c32a2d
		{
Packit c32a2d
			unsigned char temp_buff;
Packit c32a2d
			size_t meta_size;
Packit c32a2d
			ssize_t cut_pos;
Packit c32a2d
Packit c32a2d
			/* we are near icy-metaint boundary, read up to the boundary */
Packit c32a2d
			if(fr->icy.next > 0)
Packit c32a2d
			{
Packit c32a2d
				cut_pos = fr->icy.next;
Packit c32a2d
				ret = fr->rdat.fdread(fr,buf+cnt,cut_pos);
Packit c32a2d
				if(ret < 1)
Packit c32a2d
				{
Packit c32a2d
					if(ret == 0) break; /* Just EOF. */
Packit c32a2d
					if(NOQUIET) error("icy boundary read");
Packit c32a2d
Packit c32a2d
					return READER_ERROR;
Packit c32a2d
				}
Packit c32a2d
Packit c32a2d
				if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
Packit c32a2d
				cnt += ret;
Packit c32a2d
				fr->icy.next -= ret;
Packit c32a2d
				if(fr->icy.next > 0)
Packit c32a2d
				{
Packit c32a2d
					debug1("another try... still %li left", (long)fr->icy.next);
Packit c32a2d
					continue;
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
			/* now off to read icy data */
Packit c32a2d
Packit c32a2d
			/* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */
Packit c32a2d
			
Packit c32a2d
			ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */
Packit c32a2d
			if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; }
Packit c32a2d
			if(ret == 0) break;
Packit c32a2d
Packit c32a2d
			debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );
Packit c32a2d
			if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */
Packit c32a2d
Packit c32a2d
			if((meta_size = ((size_t) temp_buff) * 16))
Packit c32a2d
			{
Packit c32a2d
				/* we have got some metadata */
Packit c32a2d
				char *meta_buff;
Packit c32a2d
				/* TODO: Get rid of this malloc ... perhaps hooking into the reader buffer pool? */
Packit c32a2d
				meta_buff = malloc(meta_size+1);
Packit c32a2d
				if(meta_buff != NULL)
Packit c32a2d
				{
Packit c32a2d
					ssize_t left = meta_size;
Packit c32a2d
					while(left > 0)
Packit c32a2d
					{
Packit c32a2d
						ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left);
Packit c32a2d
						/* 0 is error here, too... there _must_ be the ICY data, the server promised! */
Packit c32a2d
						if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; }
Packit c32a2d
						left -= ret;
Packit c32a2d
					}
Packit c32a2d
					meta_buff[meta_size] = 0; /* string paranoia */
Packit c32a2d
					if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
Packit c32a2d
Packit c32a2d
					if(fr->icy.data) free(fr->icy.data);
Packit c32a2d
					fr->icy.data = meta_buff;
Packit c32a2d
					fr->metaflags |= MPG123_NEW_ICY;
Packit c32a2d
					debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size);
Packit c32a2d
				}
Packit c32a2d
				else
Packit c32a2d
				{
Packit c32a2d
					if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size);
Packit c32a2d
					fr->rd->skip_bytes(fr, meta_size);
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
			fr->icy.next = fr->icy.interval;
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			ret = plain_fullread(fr, buf+cnt, count-cnt);
Packit c32a2d
			if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; }
Packit c32a2d
			if(ret == 0) break;
Packit c32a2d
Packit c32a2d
			cnt += ret;
Packit c32a2d
			fr->icy.next -= ret;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	/* debug1("done reading, got %li", (long)cnt); */
Packit c32a2d
	return cnt;
Packit c32a2d
}
Packit c32a2d
#else
Packit c32a2d
#define icy_fullread NULL
Packit c32a2d
#endif /* NO_ICY */
Packit c32a2d
Packit c32a2d
/* stream based operation */
Packit c32a2d
static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	ssize_t ret,cnt=0;
Packit c32a2d
Packit c32a2d
#ifdef EXTRA_DEBUG
Packit c32a2d
	debug1("plain fullread of %"SSIZE_P, (size_p)count);
Packit c32a2d
#endif
Packit c32a2d
	/*
Packit c32a2d
		There used to be a check for expected file end here (length value or ID3 flag).
Packit c32a2d
		This is not needed:
Packit c32a2d
		1. EOF is indicated by fdread returning zero bytes anyway.
Packit c32a2d
		2. We get false positives of EOF for either files that grew or
Packit c32a2d
		3. ... files that have ID3v1 tags in between (stream with intro).
Packit c32a2d
	*/
Packit c32a2d
	while(cnt < count)
Packit c32a2d
	{
Packit c32a2d
		ret = fr->rdat.fdread(fr,buf+cnt,count-cnt);
Packit c32a2d
		if(ret < 0) return READER_ERROR;
Packit c32a2d
		if(ret == 0) break;
Packit c32a2d
		if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
Packit c32a2d
		cnt += ret;
Packit c32a2d
	}
Packit c32a2d
	return cnt;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence)
Packit c32a2d
{
Packit c32a2d
	off_t ret;
Packit c32a2d
	ret = io_seek(&fr->rdat, pos, whence);
Packit c32a2d
	if (ret >= 0)	fr->rdat.filepos = ret;
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		fr->err = MPG123_LSEEK_FAILED;
Packit c32a2d
		ret = READER_ERROR; /* not the original value */
Packit c32a2d
	}
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void stream_close(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->rdat.flags & READER_FD_OPENED) compat_close(fr->rdat.filept);
Packit c32a2d
Packit c32a2d
	fr->rdat.filept = 0;
Packit c32a2d
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	if(fr->rdat.flags & READER_BUFFERED)  bc_reset(&fr->rdat.buffer);
Packit c32a2d
#endif
Packit c32a2d
	if(fr->rdat.flags & READER_HANDLEIO)
Packit c32a2d
	{
Packit c32a2d
		if(fr->rdat.cleanup_handle != NULL) fr->rdat.cleanup_handle(fr->rdat.iohandle);
Packit c32a2d
Packit c32a2d
		fr->rdat.iohandle = NULL;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int stream_seek_frame(mpg123_handle *fr, off_t newframe)
Packit c32a2d
{
Packit c32a2d
	debug2("seek_frame to %"OFF_P" (from %"OFF_P")", (off_p)newframe, (off_p)fr->num);
Packit c32a2d
	/* Seekable streams can go backwards and jump forwards.
Packit c32a2d
	   Non-seekable streams still can go forward, just not jump. */
Packit c32a2d
	if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num))
Packit c32a2d
	{
Packit c32a2d
		off_t preframe; /* a leading frame we jump to */
Packit c32a2d
		off_t seek_to;  /* the byte offset we want to reach */
Packit c32a2d
		off_t to_skip;  /* bytes to skip to get there (can be negative) */
Packit c32a2d
		/*
Packit c32a2d
			now seek to nearest leading index position and read from there until newframe is reached.
Packit c32a2d
			We use skip_bytes, which handles seekable and non-seekable streams
Packit c32a2d
			(the latter only for positive offset, which we ensured before entering here).
Packit c32a2d
		*/
Packit c32a2d
		seek_to = frame_index_find(fr, newframe, &preframe);
Packit c32a2d
		/* No need to seek to index position if we are closer already.
Packit c32a2d
		   But I am picky about fr->num == newframe, play safe by reading the frame again.
Packit c32a2d
		   If you think that's stupid, don't call a seek to the current frame. */
Packit c32a2d
		if(fr->num >= newframe || fr->num < preframe)
Packit c32a2d
		{
Packit c32a2d
			to_skip = seek_to - fr->rd->tell(fr);
Packit c32a2d
			if(fr->rd->skip_bytes(fr, to_skip) != seek_to)
Packit c32a2d
			return READER_ERROR;
Packit c32a2d
Packit c32a2d
			debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe);
Packit c32a2d
			fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */
Packit c32a2d
		}
Packit c32a2d
		while(fr->num < newframe)
Packit c32a2d
		{
Packit c32a2d
			/* try to be non-fatal now... frameNum only gets advanced on success anyway */
Packit c32a2d
			if(!read_frame(fr)) break;
Packit c32a2d
		}
Packit c32a2d
		/* Now the wanted frame should be ready for decoding. */
Packit c32a2d
		debug1("arrived at %lu", (long unsigned)fr->num);
Packit c32a2d
Packit c32a2d
		return MPG123_OK;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		fr->err = MPG123_NO_SEEK;
Packit c32a2d
		return READER_ERROR; /* invalid, no seek happened */
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* return FALSE on error, TRUE on success, READER_MORE on occasion */
Packit c32a2d
static int generic_head_read(mpg123_handle *fr,unsigned long *newhead)
Packit c32a2d
{
Packit c32a2d
	unsigned char hbuf[4];
Packit c32a2d
	int ret = fr->rd->fullread(fr,hbuf,4);
Packit c32a2d
	if(ret == READER_MORE) return ret;
Packit c32a2d
	if(ret != 4) return FALSE;
Packit c32a2d
Packit c32a2d
	*newhead = ((unsigned long) hbuf[0] << 24) |
Packit c32a2d
	           ((unsigned long) hbuf[1] << 16) |
Packit c32a2d
	           ((unsigned long) hbuf[2] << 8)  |
Packit c32a2d
	            (unsigned long) hbuf[3];
Packit c32a2d
Packit c32a2d
	return TRUE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* return FALSE on error, TRUE on success, READER_MORE on occasion */
Packit c32a2d
static int generic_head_shift(mpg123_handle *fr,unsigned long *head)
Packit c32a2d
{
Packit c32a2d
	unsigned char hbuf;
Packit c32a2d
	int ret = fr->rd->fullread(fr,&hbuf,1);
Packit c32a2d
	if(ret == READER_MORE) return ret;
Packit c32a2d
	if(ret != 1) return FALSE;
Packit c32a2d
Packit c32a2d
	*head <<= 8;
Packit c32a2d
	*head |= hbuf;
Packit c32a2d
	*head &= 0xffffffff;
Packit c32a2d
	return TRUE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* returns reached position... negative ones are bad... */
Packit c32a2d
static off_t stream_skip_bytes(mpg123_handle *fr,off_t len)
Packit c32a2d
{
Packit c32a2d
	if(fr->rdat.flags & READER_SEEKABLE)
Packit c32a2d
	{
Packit c32a2d
		off_t ret = stream_lseek(fr, len, SEEK_CUR);
Packit c32a2d
		return (ret < 0) ? READER_ERROR : ret;
Packit c32a2d
	}
Packit c32a2d
	else if(len >= 0)
Packit c32a2d
	{
Packit c32a2d
		unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */
Packit c32a2d
		ssize_t ret;
Packit c32a2d
		while (len > 0)
Packit c32a2d
		{
Packit c32a2d
			ssize_t num = len < (off_t)sizeof(buf) ? (ssize_t)len : (ssize_t)sizeof(buf);
Packit c32a2d
			ret = fr->rd->fullread(fr, buf, num);
Packit c32a2d
			if (ret < 0) return ret;
Packit c32a2d
			else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */
Packit c32a2d
			len -= ret;
Packit c32a2d
		}
Packit c32a2d
		return fr->rd->tell(fr);
Packit c32a2d
	}
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	else if(fr->rdat.flags & READER_BUFFERED)
Packit c32a2d
	{ /* Perhaps we _can_ go a bit back. */
Packit c32a2d
		if(fr->rdat.buffer.pos >= -len)
Packit c32a2d
		{
Packit c32a2d
			fr->rdat.buffer.pos += len;
Packit c32a2d
			return fr->rd->tell(fr);
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			fr->err = MPG123_NO_SEEK;
Packit c32a2d
			return READER_ERROR;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		fr->err = MPG123_NO_SEEK;
Packit c32a2d
		return READER_ERROR;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Return 0 on success... */
Packit c32a2d
static int stream_back_bytes(mpg123_handle *fr, off_t bytes)
Packit c32a2d
{
Packit c32a2d
	off_t want = fr->rd->tell(fr)-bytes;
Packit c32a2d
	if(want < 0) return READER_ERROR;
Packit c32a2d
	if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR;
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* returns size on success... */
Packit c32a2d
static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size)
Packit c32a2d
{
Packit c32a2d
	long l;
Packit c32a2d
Packit c32a2d
	if((l=fr->rd->fullread(fr,buf,size)) != size)
Packit c32a2d
	{
Packit c32a2d
		long ll = l;
Packit c32a2d
		if(ll <= 0) ll = 0;
Packit c32a2d
		return READER_MORE;
Packit c32a2d
	}
Packit c32a2d
	return l;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static off_t generic_tell(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	if(fr->rdat.flags & READER_BUFFERED)
Packit c32a2d
	fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos;
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	return fr->rdat.filepos;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */
Packit c32a2d
static void stream_rewind(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->rdat.flags & READER_SEEKABLE)
Packit c32a2d
	{
Packit c32a2d
		fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET);
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
		fr->rdat.buffer.fileoff = fr->rdat.filepos;
Packit c32a2d
#endif
Packit c32a2d
	}
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	if(fr->rdat.flags & READER_BUFFERED)
Packit c32a2d
	{
Packit c32a2d
		fr->rdat.buffer.pos      = 0;
Packit c32a2d
		fr->rdat.buffer.firstpos = 0;
Packit c32a2d
		fr->rdat.filepos = fr->rdat.buffer.fileoff;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * returns length of a file (if filept points to a file)
Packit c32a2d
 * reads the last 128 bytes information into buffer
Packit c32a2d
 * ... that is not totally safe...
Packit c32a2d
 */
Packit c32a2d
static off_t get_fileinfo(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	off_t len;
Packit c32a2d
Packit c32a2d
	if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0)	return -1;
Packit c32a2d
Packit c32a2d
	if(io_seek(&fr->rdat,-128,SEEK_END) < 0) return -1;
Packit c32a2d
Packit c32a2d
	if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128)	return -1;
Packit c32a2d
Packit c32a2d
	if(!strncmp((char*)fr->id3buf,"TAG",3))	len -= 128;
Packit c32a2d
Packit c32a2d
	if(io_seek(&fr->rdat,0,SEEK_SET) < 0)	return -1;
Packit c32a2d
Packit c32a2d
	if(len <= 0)	return -1;
Packit c32a2d
Packit c32a2d
	return len;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
/* Methods for the buffer chain, mainly used for feed reader, but not just that. */
Packit c32a2d
Packit c32a2d
Packit c32a2d
static struct buffy* buffy_new(size_t size, size_t minsize)
Packit c32a2d
{
Packit c32a2d
	struct buffy *newbuf;
Packit c32a2d
	newbuf = malloc(sizeof(struct buffy));
Packit c32a2d
	if(newbuf == NULL) return NULL;
Packit c32a2d
Packit c32a2d
	newbuf->realsize = size > minsize ? size : minsize;
Packit c32a2d
	newbuf->data = malloc(newbuf->realsize);
Packit c32a2d
	if(newbuf->data == NULL)
Packit c32a2d
	{
Packit c32a2d
		free(newbuf);
Packit c32a2d
		return NULL;
Packit c32a2d
	}
Packit c32a2d
	newbuf->size = 0;
Packit c32a2d
	newbuf->next = NULL;
Packit c32a2d
	return newbuf;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void buffy_del(struct buffy* buf)
Packit c32a2d
{
Packit c32a2d
	if(buf)
Packit c32a2d
	{
Packit c32a2d
		free(buf->data);
Packit c32a2d
		free(buf);
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Delete this buffy and all following buffies. */
Packit c32a2d
static void buffy_del_chain(struct buffy* buf)
Packit c32a2d
{
Packit c32a2d
	while(buf)
Packit c32a2d
	{
Packit c32a2d
		struct buffy* next = buf->next;
Packit c32a2d
		buffy_del(buf);
Packit c32a2d
		buf = next;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void bc_prepare(struct bufferchain *bc, size_t pool_size, size_t bufblock)
Packit c32a2d
{
Packit c32a2d
	bc_poolsize(bc, pool_size, bufblock);
Packit c32a2d
	bc->pool = NULL;
Packit c32a2d
	bc->pool_fill = 0;
Packit c32a2d
	bc_init(bc); /* Ensure that members are zeroed for read-only use. */
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
size_t bc_fill(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	return (size_t)(bc->size - bc->pos);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void bc_poolsize(struct bufferchain *bc, size_t pool_size, size_t bufblock)
Packit c32a2d
{
Packit c32a2d
	bc->pool_size = pool_size;
Packit c32a2d
	bc->bufblock = bufblock;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void bc_cleanup(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	buffy_del_chain(bc->pool);
Packit c32a2d
	bc->pool = NULL;
Packit c32a2d
	bc->pool_fill = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Fetch a buffer from the pool (if possible) or create one. */
Packit c32a2d
static struct buffy* bc_alloc(struct bufferchain *bc, size_t size)
Packit c32a2d
{
Packit c32a2d
	/* Easy route: Just try the first available buffer.
Packit c32a2d
	   Size does not matter, it's only a hint for creation of new buffers. */
Packit c32a2d
	if(bc->pool)
Packit c32a2d
	{
Packit c32a2d
		struct buffy *buf = bc->pool;
Packit c32a2d
		bc->pool = buf->next;
Packit c32a2d
		buf->next = NULL; /* That shall be set to a sensible value later. */
Packit c32a2d
		buf->size = 0;
Packit c32a2d
		--bc->pool_fill;
Packit c32a2d
		debug2("bc_alloc: picked %p from pool (fill now %"SIZE_P")", (void*)buf, (size_p)bc->pool_fill);
Packit c32a2d
		return buf;
Packit c32a2d
	}
Packit c32a2d
	else return buffy_new(size, bc->bufblock);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Either stuff the buffer back into the pool or free it for good. */
Packit c32a2d
static void bc_free(struct bufferchain *bc, struct buffy* buf)
Packit c32a2d
{
Packit c32a2d
	if(!buf) return;
Packit c32a2d
Packit c32a2d
	if(bc->pool_fill < bc->pool_size)
Packit c32a2d
	{
Packit c32a2d
		buf->next = bc->pool;
Packit c32a2d
		bc->pool = buf;
Packit c32a2d
		++bc->pool_fill;
Packit c32a2d
	}
Packit c32a2d
	else buffy_del(buf);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Make the buffer count in the pool match the pool size. */
Packit c32a2d
static int bc_fill_pool(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	/* Remove superfluous ones. */
Packit c32a2d
	while(bc->pool_fill > bc->pool_size)
Packit c32a2d
	{
Packit c32a2d
		/* Lazyness: Just work on the front. */
Packit c32a2d
		struct buffy* buf = bc->pool;
Packit c32a2d
		bc->pool = buf->next;
Packit c32a2d
		buffy_del(buf);
Packit c32a2d
		--bc->pool_fill;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Add missing ones. */
Packit c32a2d
	while(bc->pool_fill < bc->pool_size)
Packit c32a2d
	{
Packit c32a2d
		/* Again, just work on the front. */
Packit c32a2d
		struct buffy* buf;
Packit c32a2d
		buf = buffy_new(0, bc->bufblock); /* Use default block size. */
Packit c32a2d
		if(!buf) return -1;
Packit c32a2d
Packit c32a2d
		buf->next = bc->pool;
Packit c32a2d
		bc->pool = buf;
Packit c32a2d
		++bc->pool_fill;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static void bc_init(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	bc->first = NULL;
Packit c32a2d
	bc->last  = bc->first;
Packit c32a2d
	bc->size  = 0;
Packit c32a2d
	bc->pos   = 0;
Packit c32a2d
	bc->firstpos = 0;
Packit c32a2d
	bc->fileoff  = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void bc_reset(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	/* Free current chain, possibly stuffing back into the pool. */
Packit c32a2d
	while(bc->first)
Packit c32a2d
	{
Packit c32a2d
		struct buffy* buf = bc->first;
Packit c32a2d
		bc->first = buf->next;
Packit c32a2d
		bc_free(bc, buf);
Packit c32a2d
	}
Packit c32a2d
	bc_fill_pool(bc); /* Ignoring an error here... */
Packit c32a2d
	bc_init(bc);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Create a new buffy at the end to be filled. */
Packit c32a2d
static int bc_append(struct bufferchain *bc, ssize_t size)
Packit c32a2d
{
Packit c32a2d
	struct buffy *newbuf;
Packit c32a2d
	if(size < 1) return -1;
Packit c32a2d
Packit c32a2d
	newbuf = bc_alloc(bc, size);
Packit c32a2d
	if(newbuf == NULL) return -2;
Packit c32a2d
Packit c32a2d
	if(bc->last != NULL)  bc->last->next = newbuf;
Packit c32a2d
	else if(bc->first == NULL) bc->first = newbuf;
Packit c32a2d
Packit c32a2d
	bc->last  = newbuf;
Packit c32a2d
	debug3("bc_append: new last buffer %p with %"SSIZE_P" B (really %"SSIZE_P")", (void*)bc->last, (ssize_p)bc->last->size, (ssize_p)bc->last->realsize);
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Append a new buffer and copy content to it. */
Packit c32a2d
static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size)
Packit c32a2d
{
Packit c32a2d
	int ret = 0;
Packit c32a2d
	ssize_t part = 0;
Packit c32a2d
	debug2("bc_add: adding %"SSIZE_P" bytes at %"OFF_P, (ssize_p)size, (off_p)(bc->fileoff+bc->size));
Packit c32a2d
	if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
Packit c32a2d
Packit c32a2d
	while(size > 0)
Packit c32a2d
	{
Packit c32a2d
		/* Try to fill up the last buffer block. */
Packit c32a2d
		if(bc->last != NULL && bc->last->size < bc->last->realsize)
Packit c32a2d
		{
Packit c32a2d
			part = bc->last->realsize - bc->last->size;
Packit c32a2d
			if(part > size) part = size;
Packit c32a2d
Packit c32a2d
			debug2("bc_add: adding %"SSIZE_P" B to existing block %p", (ssize_p)part, (void*)bc->last);
Packit c32a2d
			memcpy(bc->last->data+bc->last->size, data, part);
Packit c32a2d
			bc->last->size += part;
Packit c32a2d
			size -= part;
Packit c32a2d
			bc->size += part;
Packit c32a2d
			data += part;
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		/* If there is still data left, put it into a new buffer block. */
Packit c32a2d
		if(size > 0 && (ret = bc_append(bc, size)) != 0)
Packit c32a2d
		break;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Common handler for "You want more than I can give." situation. */
Packit c32a2d
static ssize_t bc_need_more(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)bc->size);
Packit c32a2d
	/* go back to firstpos, undo the previous reads */
Packit c32a2d
	bc->pos = bc->firstpos;
Packit c32a2d
	return READER_MORE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Give some data, advancing position but not forgetting yet. */
Packit c32a2d
static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size)
Packit c32a2d
{
Packit c32a2d
	struct buffy *b = bc->first;
Packit c32a2d
	ssize_t gotcount = 0;
Packit c32a2d
	ssize_t offset = 0;
Packit c32a2d
	if(bc->size - bc->pos < size) return bc_need_more(bc);
Packit c32a2d
Packit c32a2d
	/* find the current buffer */
Packit c32a2d
	while(b != NULL && (offset + b->size) <= bc->pos)
Packit c32a2d
	{
Packit c32a2d
		offset += b->size;
Packit c32a2d
		b = b->next;
Packit c32a2d
	}
Packit c32a2d
	/* now start copying from there */
Packit c32a2d
	while(gotcount < size && (b != NULL))
Packit c32a2d
	{
Packit c32a2d
		ssize_t loff = bc->pos - offset;
Packit c32a2d
		ssize_t chunk = size - gotcount; /* amount of bytes to get from here... */
Packit c32a2d
		if(chunk > b->size - loff) chunk = b->size - loff;
Packit c32a2d
Packit c32a2d
#ifdef EXTRA_DEBUG
Packit c32a2d
		debug3("copying %liB from %p+%li",(long)chunk, b->data, (long)loff);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
		memcpy(out+gotcount, b->data+loff, chunk);
Packit c32a2d
		gotcount += chunk;
Packit c32a2d
		bc->pos  += chunk;
Packit c32a2d
		offset += b->size;
Packit c32a2d
		b = b->next;
Packit c32a2d
	}
Packit c32a2d
#ifdef EXTRA_DEBUG
Packit c32a2d
	debug2("got %li bytes, pos advanced to %li", (long)gotcount, (long)bc->pos);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	return gotcount;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Skip some bytes and return the new position.
Packit c32a2d
   The buffers are still there, just the read pointer is moved! */
Packit c32a2d
static ssize_t bc_skip(struct bufferchain *bc, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	if(count >= 0)
Packit c32a2d
	{
Packit c32a2d
		if(bc->size - bc->pos < count) return bc_need_more(bc);
Packit c32a2d
		else return bc->pos += count;
Packit c32a2d
	}
Packit c32a2d
	else return READER_ERROR;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	if(count >= 0 && count <= bc->pos) return bc->pos -= count;
Packit c32a2d
	else return READER_ERROR;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Throw away buffies that we passed. */
Packit c32a2d
static void bc_forget(struct bufferchain *bc)
Packit c32a2d
{
Packit c32a2d
	struct buffy *b = bc->first;
Packit c32a2d
	/* free all buffers that are def'n'tly outdated */
Packit c32a2d
	/* we have buffers until filepos... delete all buffers fully below it */
Packit c32a2d
	if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos);
Packit c32a2d
	else debug("forget with nothing there!");
Packit c32a2d
Packit c32a2d
	while(b != NULL && bc->pos >= b->size)
Packit c32a2d
	{
Packit c32a2d
		struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */
Packit c32a2d
		if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */
Packit c32a2d
		bc->fileoff += b->size;
Packit c32a2d
		bc->pos  -= b->size;
Packit c32a2d
		bc->size -= b->size;
Packit c32a2d
Packit c32a2d
		debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos,  (long)bc->size, (long)bc->fileoff);
Packit c32a2d
Packit c32a2d
		bc_free(bc, b);
Packit c32a2d
		b = n;
Packit c32a2d
	}
Packit c32a2d
	bc->first = b;
Packit c32a2d
	bc->firstpos = bc->pos;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* reader for input via manually provided buffers */
Packit c32a2d
Packit c32a2d
static int feed_init(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	bc_init(&fr->rdat.buffer);
Packit c32a2d
	bc_fill_pool(&fr->rdat.buffer);
Packit c32a2d
	fr->rdat.filelen = 0;
Packit c32a2d
	fr->rdat.filepos = 0;
Packit c32a2d
	fr->rdat.flags |= READER_BUFFERED;
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* externally called function, returns 0 on success, -1 on error */
Packit c32a2d
int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
Packit c32a2d
{
Packit c32a2d
	int ret = 0;
Packit c32a2d
	if(VERBOSE3) debug("feed_more");
Packit c32a2d
	if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0)
Packit c32a2d
	{
Packit c32a2d
		ret = READER_ERROR;
Packit c32a2d
		if(NOQUIET) error1("Failed to add buffer, return: %i", ret);
Packit c32a2d
	}
Packit c32a2d
	else /* Not talking about filelen... that stays at 0. */
Packit c32a2d
Packit c32a2d
	if(VERBOSE3) debug3("feed_more: %p %luB bufsize=%lu", fr->rdat.buffer.last->data,
Packit c32a2d
		(unsigned long)fr->rdat.buffer.last->size, (unsigned long)fr->rdat.buffer.size);
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static ssize_t feed_read(mpg123_handle *fr, unsigned char *out, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	ssize_t gotcount = bc_give(&fr->rdat.buffer, out, count);
Packit c32a2d
	if(gotcount >= 0 && gotcount != count) return READER_ERROR;
Packit c32a2d
	else return gotcount;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* returns reached position... negative ones are bad... */
Packit c32a2d
static off_t feed_skip_bytes(mpg123_handle *fr,off_t len)
Packit c32a2d
{
Packit c32a2d
	/* This is either the new buffer offset or some negative error value. */
Packit c32a2d
	off_t res = bc_skip(&fr->rdat.buffer, (ssize_t)len);
Packit c32a2d
	if(res < 0) return res;
Packit c32a2d
Packit c32a2d
	return fr->rdat.buffer.fileoff+res;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int feed_back_bytes(mpg123_handle *fr, off_t bytes)
Packit c32a2d
{
Packit c32a2d
	if(bytes >=0)
Packit c32a2d
	return bc_seekback(&fr->rdat.buffer, (ssize_t)bytes) >= 0 ? 0 : READER_ERROR;
Packit c32a2d
	else
Packit c32a2d
	return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; }
Packit c32a2d
Packit c32a2d
/* Not just for feed reader, also for self-feeding buffered reader. */
Packit c32a2d
static void buffered_forget(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	bc_forget(&fr->rdat.buffer);
Packit c32a2d
	fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t feed_set_pos(mpg123_handle *fr, off_t pos)
Packit c32a2d
{
Packit c32a2d
	struct bufferchain *bc = &fr->rdat.buffer;
Packit c32a2d
	if(pos >= bc->fileoff && pos-bc->fileoff < bc->size)
Packit c32a2d
	{ /* We have the position! */
Packit c32a2d
		bc->pos = (ssize_t)(pos - bc->fileoff);
Packit c32a2d
		debug1("feed_set_pos inside, next feed from %"OFF_P, (off_p)(bc->fileoff+bc->size));
Packit c32a2d
		return bc->fileoff+bc->size; /* Next input after end of buffer... */
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{ /* I expect to get the specific position on next feed. Forget what I have now. */
Packit c32a2d
		bc_reset(bc);
Packit c32a2d
		bc->fileoff = pos;
Packit c32a2d
		debug1("feed_set_pos outside, buffer reset, next feed from %"OFF_P, (off_p)pos);
Packit c32a2d
		return pos; /* Next input from exactly that position. */
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* The specific stuff for buffered stream reader. */
Packit c32a2d
Packit c32a2d
static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t count)
Packit c32a2d
{
Packit c32a2d
	struct bufferchain *bc = &fr->rdat.buffer;
Packit c32a2d
	ssize_t gotcount;
Packit c32a2d
	if(bc->size - bc->pos < count)
Packit c32a2d
	{ /* Add more stuff to buffer. If hitting end of file, adjust count. */
Packit c32a2d
		unsigned char readbuf[4096];
Packit c32a2d
		ssize_t need = count - (bc->size-bc->pos);
Packit c32a2d
		while(need>0)
Packit c32a2d
		{
Packit c32a2d
			int ret;
Packit c32a2d
			ssize_t got = fr->rdat.fullread(fr, readbuf, sizeof(readbuf));
Packit c32a2d
			if(got < 0)
Packit c32a2d
			{
Packit c32a2d
				if(NOQUIET) error("buffer reading");
Packit c32a2d
				return READER_ERROR;
Packit c32a2d
			}
Packit c32a2d
Packit c32a2d
			if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got);
Packit c32a2d
			if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0)
Packit c32a2d
			{
Packit c32a2d
				if(NOQUIET) error1("unable to add to chain, return: %i", ret);
Packit c32a2d
				return READER_ERROR;
Packit c32a2d
			}
Packit c32a2d
Packit c32a2d
			need -= got; /* May underflow here... */
Packit c32a2d
			if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */
Packit c32a2d
			{
Packit c32a2d
				if(VERBOSE3) fprintf(stderr, "Note: Input data end.\n");
Packit c32a2d
				break; /* End. */
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
		if(bc->size - bc->pos < count)
Packit c32a2d
		count = bc->size - bc->pos; /* We want only what we got. */
Packit c32a2d
	}
Packit c32a2d
	gotcount = bc_give(bc, out, count);
Packit c32a2d
Packit c32a2d
	if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount);
Packit c32a2d
Packit c32a2d
	if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; }
Packit c32a2d
	else return gotcount;
Packit c32a2d
}
Packit c32a2d
#else
Packit c32a2d
int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
Packit c32a2d
{
Packit c32a2d
	fr->err = MPG123_MISSING_FEATURE;
Packit c32a2d
	return -1;
Packit c32a2d
}
Packit c32a2d
off_t feed_set_pos(mpg123_handle *fr, off_t pos)
Packit c32a2d
{
Packit c32a2d
	fr->err = MPG123_MISSING_FEATURE;
Packit c32a2d
	return -1;
Packit c32a2d
}
Packit c32a2d
#endif /* NO_FEEDER */
Packit c32a2d
Packit c32a2d
/*****************************************************************
Packit c32a2d
 * read frame helper
Packit c32a2d
 */
Packit c32a2d
Packit c32a2d
#define bugger_off { mh->err = MPG123_NO_READER; return MPG123_ERR; }
Packit c32a2d
static int bad_init(mpg123_handle *mh) bugger_off
Packit c32a2d
static void bad_close(mpg123_handle *mh){}
Packit c32a2d
static ssize_t bad_fullread(mpg123_handle *mh, unsigned char *data, ssize_t count) bugger_off
Packit c32a2d
static int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off
Packit c32a2d
static int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off
Packit c32a2d
static off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off
Packit c32a2d
static int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off
Packit c32a2d
static int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off
Packit c32a2d
static int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off
Packit c32a2d
static off_t bad_tell(mpg123_handle *mh) bugger_off
Packit c32a2d
static void bad_rewind(mpg123_handle *mh){}
Packit c32a2d
#undef bugger_off
Packit c32a2d
Packit c32a2d
#define READER_STREAM 0
Packit c32a2d
#define READER_ICY_STREAM 1
Packit c32a2d
#define READER_FEED       2
Packit c32a2d
#define READER_BUF_STREAM 3
Packit c32a2d
#define READER_BUF_ICY_STREAM 4
Packit c32a2d
static struct reader readers[] =
Packit c32a2d
{
Packit c32a2d
	{ /* READER_STREAM */
Packit c32a2d
		default_init,
Packit c32a2d
		stream_close,
Packit c32a2d
		plain_fullread,
Packit c32a2d
		generic_head_read,
Packit c32a2d
		generic_head_shift,
Packit c32a2d
		stream_skip_bytes,
Packit c32a2d
		generic_read_frame_body,
Packit c32a2d
		stream_back_bytes,
Packit c32a2d
		stream_seek_frame,
Packit c32a2d
		generic_tell,
Packit c32a2d
		stream_rewind,
Packit c32a2d
		NULL
Packit c32a2d
	} ,
Packit c32a2d
	{ /* READER_ICY_STREAM */
Packit c32a2d
		default_init,
Packit c32a2d
		stream_close,
Packit c32a2d
		icy_fullread,
Packit c32a2d
		generic_head_read,
Packit c32a2d
		generic_head_shift,
Packit c32a2d
		stream_skip_bytes,
Packit c32a2d
		generic_read_frame_body,
Packit c32a2d
		stream_back_bytes,
Packit c32a2d
		stream_seek_frame,
Packit c32a2d
		generic_tell,
Packit c32a2d
		stream_rewind,
Packit c32a2d
		NULL
Packit c32a2d
	},
Packit c32a2d
#ifdef NO_FEEDER
Packit c32a2d
#define feed_init NULL
Packit c32a2d
#define feed_read NULL
Packit c32a2d
#define buffered_fullread NULL
Packit c32a2d
#define feed_seek_frame NULL
Packit c32a2d
#define feed_back_bytes NULL
Packit c32a2d
#define feed_skip_bytes NULL
Packit c32a2d
#define buffered_forget NULL
Packit c32a2d
#endif
Packit c32a2d
	{ /* READER_FEED */
Packit c32a2d
		feed_init,
Packit c32a2d
		stream_close,
Packit c32a2d
		feed_read,
Packit c32a2d
		generic_head_read,
Packit c32a2d
		generic_head_shift,
Packit c32a2d
		feed_skip_bytes,
Packit c32a2d
		generic_read_frame_body,
Packit c32a2d
		feed_back_bytes,
Packit c32a2d
		feed_seek_frame,
Packit c32a2d
		generic_tell,
Packit c32a2d
		stream_rewind,
Packit c32a2d
		buffered_forget
Packit c32a2d
	},
Packit c32a2d
	{ /* READER_BUF_STREAM */
Packit c32a2d
		default_init,
Packit c32a2d
		stream_close,
Packit c32a2d
		buffered_fullread,
Packit c32a2d
		generic_head_read,
Packit c32a2d
		generic_head_shift,
Packit c32a2d
		stream_skip_bytes,
Packit c32a2d
		generic_read_frame_body,
Packit c32a2d
		stream_back_bytes,
Packit c32a2d
		stream_seek_frame,
Packit c32a2d
		generic_tell,
Packit c32a2d
		stream_rewind,
Packit c32a2d
		buffered_forget
Packit c32a2d
	} ,
Packit c32a2d
	{ /* READER_BUF_ICY_STREAM */
Packit c32a2d
		default_init,
Packit c32a2d
		stream_close,
Packit c32a2d
		buffered_fullread,
Packit c32a2d
		generic_head_read,
Packit c32a2d
		generic_head_shift,
Packit c32a2d
		stream_skip_bytes,
Packit c32a2d
		generic_read_frame_body,
Packit c32a2d
		stream_back_bytes,
Packit c32a2d
		stream_seek_frame,
Packit c32a2d
		generic_tell,
Packit c32a2d
		stream_rewind,
Packit c32a2d
		buffered_forget
Packit c32a2d
	},
Packit c32a2d
#ifdef READ_SYSTEM
Packit c32a2d
	,{
Packit c32a2d
		system_init,
Packit c32a2d
		NULL,	/* filled in by system_init() */
Packit c32a2d
		fullread,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
		NULL,
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
static struct reader bad_reader =
Packit c32a2d
{
Packit c32a2d
	bad_init,
Packit c32a2d
	bad_close,
Packit c32a2d
	bad_fullread,
Packit c32a2d
	bad_head_read,
Packit c32a2d
	bad_head_shift,
Packit c32a2d
	bad_skip_bytes,
Packit c32a2d
	bad_read_frame_body,
Packit c32a2d
	bad_back_bytes,
Packit c32a2d
	bad_seek_frame,
Packit c32a2d
	bad_tell,
Packit c32a2d
	bad_rewind,
Packit c32a2d
	NULL
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
static int default_init(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
#ifdef TIMEOUT_READ
Packit c32a2d
	if(fr->p.timeout > 0)
Packit c32a2d
	{
Packit c32a2d
		int flags;
Packit c32a2d
		if(fr->rdat.r_read != NULL)
Packit c32a2d
		{
Packit c32a2d
			error("Timeout reading does not work with user-provided read function. Implement it yourself!");
Packit c32a2d
			return -1;
Packit c32a2d
		}
Packit c32a2d
		flags = fcntl(fr->rdat.filept, F_GETFL);
Packit c32a2d
		flags |= O_NONBLOCK;
Packit c32a2d
		fcntl(fr->rdat.filept, F_SETFL, flags);
Packit c32a2d
		fr->rdat.fdread = timeout_read;
Packit c32a2d
		fr->rdat.timeout_sec = fr->p.timeout;
Packit c32a2d
		fr->rdat.flags |= READER_NONBLOCK;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
#endif
Packit c32a2d
	fr->rdat.fdread = plain_read;
Packit c32a2d
Packit c32a2d
	fr->rdat.read  = fr->rdat.r_read  != NULL ? fr->rdat.r_read  : posix_read;
Packit c32a2d
	fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek;
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	/* ICY streams of any sort shall not be seekable. */
Packit c32a2d
	if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek;
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr);
Packit c32a2d
	fr->rdat.filepos = 0;
Packit c32a2d
	if(fr->p.flags & MPG123_FORCE_SEEKABLE)
Packit c32a2d
		fr->rdat.flags |= READER_SEEKABLE;
Packit c32a2d
	/*
Packit c32a2d
		Don't enable seeking on ICY streams, just plain normal files.
Packit c32a2d
		This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable.
Packit c32a2d
		It is a task for the future to make the ICY parsing safe with seeks ... or not.
Packit c32a2d
	*/
Packit c32a2d
	if(fr->rdat.filelen >= 0)
Packit c32a2d
	{
Packit c32a2d
		fr->rdat.flags |= READER_SEEKABLE;
Packit c32a2d
		if(!strncmp((char*)fr->id3buf,"TAG",3))
Packit c32a2d
		{
Packit c32a2d
			fr->rdat.flags |= READER_ID3TAG;
Packit c32a2d
			fr->metaflags  |= MPG123_NEW_ID3;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	/* Switch reader to a buffered one, if allowed. */
Packit c32a2d
	else if(fr->p.flags & MPG123_SEEKBUFFER)
Packit c32a2d
	{
Packit c32a2d
#ifdef NO_FEEDER
Packit c32a2d
		error("Buffered readers not supported in this build.");
Packit c32a2d
		fr->err = MPG123_MISSING_FEATURE;
Packit c32a2d
		return -1;
Packit c32a2d
#else
Packit c32a2d
		if     (fr->rd == &readers[READER_STREAM])
Packit c32a2d
		{
Packit c32a2d
			fr->rd = &readers[READER_BUF_STREAM];
Packit c32a2d
			fr->rdat.fullread = plain_fullread;
Packit c32a2d
		}
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
		else if(fr->rd == &readers[READER_ICY_STREAM])
Packit c32a2d
		{
Packit c32a2d
			fr->rd = &readers[READER_BUF_ICY_STREAM];
Packit c32a2d
			fr->rdat.fullread = icy_fullread;
Packit c32a2d
		}
Packit c32a2d
#endif
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			if(NOQUIET) error("mpg123 Programmer's fault: invalid reader");
Packit c32a2d
			return -1;
Packit c32a2d
		}
Packit c32a2d
		bc_init(&fr->rdat.buffer);
Packit c32a2d
		fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */
Packit c32a2d
		fr->rdat.flags |= READER_BUFFERED;
Packit c32a2d
#endif /* NO_FEEDER */
Packit c32a2d
	}
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
void open_bad(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	debug("open_bad");
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	clear_icy(&mh->icy);
Packit c32a2d
#endif
Packit c32a2d
	mh->rd = &bad_reader;
Packit c32a2d
	mh->rdat.flags = 0;
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	bc_init(&mh->rdat.buffer);
Packit c32a2d
#endif
Packit c32a2d
	mh->rdat.filelen = -1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int open_feed(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	debug("feed reader");
Packit c32a2d
#ifdef NO_FEEDER
Packit c32a2d
	error("Buffered readers not supported in this build.");
Packit c32a2d
	fr->err = MPG123_MISSING_FEATURE;
Packit c32a2d
	return -1;
Packit c32a2d
#else
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	if(fr->p.icy_interval > 0)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("Feed reader cannot do ICY parsing!");
Packit c32a2d
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	clear_icy(&fr->icy);
Packit c32a2d
#endif
Packit c32a2d
	fr->rd = &readers[READER_FEED];
Packit c32a2d
	fr->rdat.flags = 0;
Packit c32a2d
	if(fr->rd->init(fr) < 0) return -1;
Packit c32a2d
Packit c32a2d
	debug("feed reader init successful");
Packit c32a2d
	return 0;
Packit c32a2d
#endif /* NO_FEEDER */
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Final code common to open_stream and open_stream_handle. */
Packit c32a2d
static int open_finish(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	if(fr->p.icy_interval > 0)
Packit c32a2d
	{
Packit c32a2d
		debug("ICY reader");
Packit c32a2d
		fr->icy.interval = fr->p.icy_interval;
Packit c32a2d
		fr->icy.next = fr->icy.interval;
Packit c32a2d
		fr->rd = &readers[READER_ICY_STREAM];
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
#endif
Packit c32a2d
	{
Packit c32a2d
		fr->rd = &readers[READER_STREAM];
Packit c32a2d
		debug("stream reader");
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(fr->rd->init(fr) < 0) return -1;
Packit c32a2d
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd)
Packit c32a2d
{
Packit c32a2d
	int filept_opened = 1;
Packit c32a2d
	int filept; /* descriptor of opened file/stream */
Packit c32a2d
Packit c32a2d
	clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
Packit c32a2d
Packit c32a2d
	if(!bs_filenam) /* no file to open, got a descriptor (stdin) */
Packit c32a2d
	{
Packit c32a2d
		filept = fd;
Packit c32a2d
		filept_opened = 0; /* and don't try to close it... */
Packit c32a2d
	}
Packit c32a2d
	#ifndef O_BINARY
Packit c32a2d
	#define O_BINARY (0)
Packit c32a2d
	#endif
Packit c32a2d
	else if((filept = compat_open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno));
Packit c32a2d
		fr->err = MPG123_BAD_FILE;
Packit c32a2d
		return MPG123_ERR; /* error... */
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* now we have something behind filept and can init the reader */
Packit c32a2d
	fr->rdat.filelen = -1;
Packit c32a2d
	fr->rdat.filept  = filept;
Packit c32a2d
	fr->rdat.flags = 0;
Packit c32a2d
	if(filept_opened)	fr->rdat.flags |= READER_FD_OPENED;
Packit c32a2d
Packit c32a2d
	return open_finish(fr);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int open_stream_handle(mpg123_handle *fr, void *iohandle)
Packit c32a2d
{
Packit c32a2d
	clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
Packit c32a2d
	fr->rdat.filelen = -1;
Packit c32a2d
	fr->rdat.filept  = -1;
Packit c32a2d
	fr->rdat.iohandle = iohandle;
Packit c32a2d
	fr->rdat.flags = 0;
Packit c32a2d
	fr->rdat.flags |= READER_HANDLEIO;
Packit c32a2d
Packit c32a2d
	return open_finish(fr);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Wrappers for actual reading/seeking... I'm full of wrappers here. */
Packit c32a2d
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence)
Packit c32a2d
{
Packit c32a2d
	if(rdat->flags & READER_HANDLEIO)
Packit c32a2d
	{
Packit c32a2d
		if(rdat->r_lseek_handle != NULL)
Packit c32a2d
		{
Packit c32a2d
			return rdat->r_lseek_handle(rdat->iohandle, offset, whence);
Packit c32a2d
		}
Packit c32a2d
		else return -1;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	return rdat->lseek(rdat->filept, offset, whence);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count)
Packit c32a2d
{
Packit c32a2d
	if(rdat->flags & READER_HANDLEIO)
Packit c32a2d
	{
Packit c32a2d
		if(rdat->r_read_handle != NULL)
Packit c32a2d
		{
Packit c32a2d
			return rdat->r_read_handle(rdat->iohandle, buf, count);
Packit c32a2d
		}
Packit c32a2d
		else return -1;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	return rdat->read(rdat->filept, buf, count);
Packit c32a2d
}