#include "vchdr.h"
#define N_CODERS 1024
typedef struct _store_s
{ Vcmethod_t* meth;
Vcchar_t* data;
ssize_t dtsz;
} Store_t;
#if __STD_C
ssize_t vcextract(Vcodex_t* vc, Void_t** datap)
#else
ssize_t vcextract(vc, datap)
Vcodex_t* vc;
Void_t** datap;
#endif
{
ssize_t n, k, dtsz;
Store_t store[N_CODERS];
Vcchar_t *data;
Vcodex_t *coder;
Vcmtcode_t mtcd;
int rv;
char *ident, buf[1024];
Vcio_t io;
if(!(vc->flags&VC_ENCODE) )
return -1;
dtsz = 0;
for(n = -1, coder = vc; coder; coder = coder->coder)
{ if((n += 1) >= N_CODERS)
return -1;
store[n].meth = coder->meth;
if(!(ident = vcgetident(coder->meth, buf, sizeof(buf))) || !ident[0] )
return -1;
dtsz += strlen(ident) + 1;
store[n].dtsz = 0;
if(coder->meth->eventf)
{ mtcd.data = NIL(Vcchar_t*);
mtcd.size = 0;
rv = (*coder->meth->eventf)(coder, VC_EXTRACT, (Void_t*)(&mtcd));
if(rv < 0)
return -1;
else if(rv > 0)
{ if((store[n].dtsz = mtcd.size) < 0 )
return -1;
store[n].data = mtcd.data;
}
}
dtsz += vcsizeu(store[n].dtsz) + store[n].dtsz;
}
if(!(data = vcbuffer(vc, NIL(Vcchar_t*), dtsz, 0)) )
return -1;
vcioinit(&io, data, dtsz);
for(k = 0; k <= n; ++k)
{ if(!(ident = vcgetident(store[k].meth, buf, sizeof(buf))) )
return -1;
vcioputs(&io, ident, strlen(ident)+1);
vcioputu(&io, store[k].dtsz);
vcioputs(&io, store[k].data, store[k].dtsz);
}
if(datap)
*datap = (Void_t*)data;
return dtsz;
}
#if __STD_C
Vcodex_t* vcrestore(Void_t* data, size_t dtsz)
#else
Vcodex_t* vcrestore(data, dtsz)
Void_t* data;
size_t dtsz;
#endif
{
Vcodex_t *vc, *coder, *cdr;
Vcmethod_t *meth;
ssize_t sz, k;
char *mt;
Void_t *dt;
Vcmtcode_t mtcd;
int rv;
Vcio_t io;
if(!data || dtsz <= 0 )
return NIL(Vcodex_t*);
vcioinit(&io, data, dtsz);
vc = coder = NIL(Vcodex_t*);
while(vciomore(&io) > 0)
{
mt = (char*)vcionext(&io);
for(sz = vciomore(&io), k = 0; k < sz; ++k)
if(mt[k] == 0)
break;
if(k >= sz)
goto error;
if(!(meth = vcgetmeth(mt, 1)) )
goto error;
vcioskip(&io, k+1);
if((sz = (ssize_t)vciogetu(&io)) < 0 || sz > vciomore(&io))
goto error;
dt = vcionext(&io);
vcioskip(&io, sz);
cdr = NIL(Vcodex_t*);
if(meth->eventf)
{ mtcd.data = dt;
mtcd.size = sz;
mtcd.coder = NIL(Vcodex_t*);
rv = (*meth->eventf)(0, VC_RESTORE, (Void_t*)(&mtcd));
if(rv < 0 )
goto error;
else if(rv > 0)
cdr = mtcd.coder;
}
if(!cdr && !(cdr = vcopen(0, meth, 0, 0, VC_DECODE)) )
{ error:
if(vc)
vcclose(vc);
return NIL(Vcodex_t*);
}
if(!coder)
vc = cdr;
else
{ coder->coder = cdr;
coder->flags |= VC_CLOSECODER;
}
coder = cdr;
}
return vc;
}