134 lines
2.5 KiB
C
134 lines
2.5 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <venti.h>
|
|
#include "cvt.h"
|
|
|
|
static int
|
|
checksize(int n)
|
|
{
|
|
if(n < 256) {
|
|
werrstr("bad block size %#ux", n);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// _VtEntryBig integer format is floating-point:
|
|
// (n>>5) << (n&31).
|
|
// Convert this number; must be exact or return -1.
|
|
int
|
|
vttobig(ulong n)
|
|
{
|
|
int shift;
|
|
ulong n0;
|
|
|
|
n0 = n;
|
|
shift = 0;
|
|
while(n >= (1<<(16 - 5))) {
|
|
if(n & 1)
|
|
return -1;
|
|
shift++;
|
|
n >>= 1;
|
|
}
|
|
|
|
n = (n<<5) | shift;
|
|
if(((n>>5)<<(n&31)) != n0)
|
|
sysfatal("vttobig %#lux => %#lux failed", n0, n);
|
|
return n;
|
|
}
|
|
|
|
void
|
|
vtentrypack(VtEntry *e, uchar *p, int index)
|
|
{
|
|
ulong t32;
|
|
int flags;
|
|
uchar *op;
|
|
int depth;
|
|
int psize, dsize;
|
|
|
|
p += index * VtEntrySize;
|
|
op = p;
|
|
|
|
depth = e->type&VtTypeDepthMask;
|
|
flags = (e->flags&~(_VtEntryDir|_VtEntryDepthMask));
|
|
flags |= depth << _VtEntryDepthShift;
|
|
if(e->type - depth == VtDirType)
|
|
flags |= _VtEntryDir;
|
|
U32PUT(p, e->gen);
|
|
p += 4;
|
|
psize = e->psize;
|
|
dsize = e->dsize;
|
|
if(psize >= (1<<16) || dsize >= (1<<16)) {
|
|
flags |= _VtEntryBig;
|
|
psize = vttobig(psize);
|
|
dsize = vttobig(dsize);
|
|
if(psize < 0 || dsize < 0)
|
|
sysfatal("invalid entry psize/dsize: %ld/%ld", e->psize, e->dsize);
|
|
}
|
|
U16PUT(p, psize);
|
|
p += 2;
|
|
U16PUT(p, dsize);
|
|
p += 2;
|
|
U8PUT(p, flags);
|
|
p++;
|
|
memset(p, 0, 5);
|
|
p += 5;
|
|
U48PUT(p, e->size, t32);
|
|
p += 6;
|
|
memmove(p, e->score, VtScoreSize);
|
|
p += VtScoreSize;
|
|
|
|
assert(p-op == VtEntrySize);
|
|
}
|
|
|
|
int
|
|
vtentryunpack(VtEntry *e, uchar *p, int index)
|
|
{
|
|
uchar *op;
|
|
|
|
p += index * VtEntrySize;
|
|
op = p;
|
|
|
|
e->gen = U32GET(p);
|
|
p += 4;
|
|
e->psize = U16GET(p);
|
|
p += 2;
|
|
e->dsize = U16GET(p);
|
|
p += 2;
|
|
e->flags = U8GET(p);
|
|
p++;
|
|
if(e->flags & _VtEntryBig) {
|
|
e->psize = (e->psize>>5)<<(e->psize & 31);
|
|
e->dsize = (e->dsize>>5)<<(e->dsize & 31);
|
|
}
|
|
e->type = (e->flags&_VtEntryDir) ? VtDirType : VtDataType;
|
|
e->type += (e->flags & _VtEntryDepthMask) >> _VtEntryDepthShift;
|
|
e->flags &= ~(_VtEntryDir|_VtEntryDepthMask|_VtEntryBig);
|
|
p += 5;
|
|
e->size = U48GET(p);
|
|
p += 6;
|
|
memmove(e->score, p, VtScoreSize);
|
|
p += VtScoreSize;
|
|
|
|
assert(p-op == VtEntrySize);
|
|
|
|
if(!(e->flags & VtEntryActive))
|
|
return 0;
|
|
|
|
/*
|
|
* Some old vac files use psize==0 and dsize==0 when the
|
|
* file itself has size 0 or is zeros. Just to make programs not
|
|
* have to figure out what block sizes of 0 means, rewrite them.
|
|
*/
|
|
if(e->psize == 0 && e->dsize == 0
|
|
&& memcmp(e->score, vtzeroscore, VtScoreSize) == 0){
|
|
e->psize = 4096;
|
|
e->dsize = 4096;
|
|
}
|
|
if(checksize(e->psize) < 0 || checksize(e->dsize) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|