#include "sfdchdr.h"
typedef struct _skable_s
{ Sfdisc_t disc;
Sfio_t* shadow;
int eof;
} Seek_t;
#if __STD_C
static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
#else
static ssize_t skwrite(f, buf, n, disc)
Sfio_t* f;
Void_t* buf;
size_t n;
Sfdisc_t* disc;
#endif
{
return (ssize_t)(-1);
}
#if __STD_C
static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
#else
static ssize_t skread(f, buf, n, disc)
Sfio_t* f;
Void_t* buf;
size_t n;
Sfdisc_t* disc;
#endif
{
Seek_t* sk;
Sfio_t* sf;
Sfoff_t addr, extent;
ssize_t r, w;
sk = (Seek_t*)disc;
sf = sk->shadow;
if(sk->eof)
return sfread(sf,buf,n);
addr = sfseek(sf,(Sfoff_t)0,1);
extent = sfsize(sf);
if(addr+n <= extent)
return sfread(sf,buf,n);
if((r = (ssize_t)(extent-addr)) > 0)
{ if((w = sfread(sf,buf,r)) != r)
return w;
buf = (char*)buf + r;
n -= r;
}
if((w = sfrd(f,buf,n,disc)) <= 0)
{ sk->eof = 1;
w = 0;
}
else if(sfwrite(sf,buf,w) != w)
sk->eof = 1;
return r+w;
}
#if __STD_C
static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
#else
static Sfoff_t skseek(f, addr, type, disc)
Sfio_t* f;
Sfoff_t addr;
int type;
Sfdisc_t* disc;
#endif
{
Sfoff_t extent;
Seek_t* sk;
Sfio_t* sf;
char buf[SF_BUFSIZE];
ssize_t r, w;
if(type < 0 || type > 2)
return (Sfoff_t)(-1);
sk = (Seek_t*)disc;
sf = sk->shadow;
extent = sfseek(sf,(Sfoff_t)0,2);
if(type == 1)
addr += sftell(sf);
else if(type == 2)
addr += extent;
if(addr < 0)
return (Sfoff_t)(-1);
else if(addr > extent)
{ if(sk->eof)
return (Sfoff_t)(-1);
while(addr > extent)
{ if(addr > extent+sizeof(buf) )
w = sizeof(buf);
else w = (int)(addr-extent);
if((r = sfrd(f,buf,w,disc)) <= 0)
w = r-1;
else if((w = sfwrite(sf,buf,r)) > 0)
extent += r;
if(w != r)
{ sk->eof = 1;
break;
}
}
if(addr > extent)
return (Sfoff_t)(-1);
}
return sfseek(sf,addr,0);
}
#if __STD_C
static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
#else
static int skexcept(f,type,data,disc)
Sfio_t* f;
int type;
Void_t* data;
Sfdisc_t* disc;
#endif
{
if(type == SF_FINAL || type == SF_DPOP)
{ sfclose(((Seek_t*)disc)->shadow);
free(disc);
}
return 0;
}
#if __STD_C
int sfdcseekable(Sfio_t* f)
#else
int sfdcseekable(f)
Sfio_t* f;
#endif
{
reg Seek_t* sk;
if(sfseek(f,(Sfoff_t)0,1) >= 0)
return 0;
if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
return -1;
sk->disc.readf = skread;
sk->disc.writef = skwrite;
sk->disc.seekf = skseek;
sk->disc.exceptf = skexcept;
sk->shadow = sftmp(SF_BUFSIZE);
sk->eof = 0;
if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
{ sfclose(sk->shadow);
free(sk);
return -1;
}
return 0;
}