capsimg/Codec/CTRawCodecDecompressor.cpp
2014-12-13 19:42:07 +01:00

378 lines
8.1 KiB
C++

#include "stdafx.h"
// decompress CT Raw dump format
int CCTRawCodec::DecompressDump(PUBYTE buf, int len)
{
CapsPack cpk;
PCAPSPACK pk;
// free all buffers
Free();
// check dump header
int hlen = sizeof(CapsRaw);
if (len < hlen)
return imgeShort;
wh.cr = *(PCAPSRAW)buf;
Swap((PUDWORD)&wh.cr, sizeof(CapsRaw));
// check dump size
int tlen = wh.cr.time;
int rlen = wh.cr.raw;
if (len < hlen + tlen + rlen)
return imgeShort;
// check density information
PUBYTE denbuf = buf + hlen;
pk = GetPackHeader(&cpk, denbuf, tlen);
if (!pk)
return imgeDensityHeader;
// check track information
PUBYTE trkbuf = denbuf + tlen;
pk = GetPackHeader(&cpk, trkbuf, rlen);
if (!pk)
return imgeTrackHeader;
int err;
// decompress density information
wh.cdbuf = denbuf;
wh.cdlen = tlen;
if (!(err = DecompressDensity(1)))
err = DecompressDensity();
wh.cdbuf = NULL;
if (err)
return err;
// decompress track data
wh.ctbuf = trkbuf;
wh.ctlen = rlen;
if (!(err = DecompressTrack(1)))
err = DecompressTrack();
wh.ctbuf = NULL;
return err;
}
// decompress or verify compressed CT Raw density information
int CCTRawCodec::DecompressDensity(int verify)
{
CapsPack cpk;
// in decompress mode free result buffer first
if (!verify)
FreeUncompressedDensity();
// get density header
PCAPSPACK pk = GetPackHeader(&cpk, wh.cdbuf, wh.cdlen);
if (!pk)
return imgeDensityHeader;
// check crc on compressed data in verify mode
if (verify)
if (pk->ccrc != CalcCRC(wh.cdbuf + sizeof(CapsPack), pk->csize))
return imgeDensityStream;
// decompress density data
PUDWORD dst = DecompressDensity(wh.cdbuf, wh.cdlen);
int res = imgeOk;
if (verify) {
// in verify mode get density data in target format
Swap(dst, pk->usize);
// check crc on uncompressed data
if (pk->ucrc != CalcCRC((PUBYTE)dst, pk->usize))
res = imgeDensityData;
// free density data
delete[] dst;
} else {
// in decompress mode save density data
wh.timbuf = dst;
wh.timlen = pk->usize >> 2;
}
return res;
}
// decompress CT Raw density information
PUDWORD CCTRawCodec::DecompressDensity(PUBYTE src, int slen, PUDWORD dst)
{
CapsPack cpk;
// get density header
PCAPSPACK pk = GetPackHeader(&cpk, src, slen);
if (!pk)
return NULL;
// use caller supplied buffer or allocate a new one
PUDWORD buf = dst;
if (!buf && pk->usize)
buf = new UDWORD[pk->usize >> 2];
// buffer pointer to end of destionation and source buffer
PUDWORD mem = buf + (pk->usize >> 2);
src += slen;
// decode the data, see compressor for encoding
while (mem > buf) {
int size, ofs;
UBYTE cb0 = *--src;
switch (cb0 & 0x03) {
// data block
case 0x0:
// 12 or 4 bit size
if (cb0 & 0x08)
size = ((cb0 << 4) & 0xf00) | (*--src);
else
size = (cb0 >> 4) + 1;
if (cb0 & 0x04) {
// 4 bytes per value
while (size--) {
UDWORD data;
data = (*--src);
data = (data << 8) | (*--src);
data = (data << 8) | (*--src);
data = (data << 8) | (*--src);
*--mem = data;
}
} else {
// 1 byte per value
while (size--)
*--mem = *--src;
}
continue;
// copy block, 8 bit offset, 6 bit size
case 0x1:
size = (cb0 >> 2) + 1;
ofs = (*--src) + 1;
break;
// copy block, 16 bit offset, 6 bit size
case 0x2:
size = (cb0 >> 2) + 1;
ofs = (*--src);
ofs = (ofs << 8) | (*--src);
break;
// copy block, 16 bit offset, 14 bit size
case 0x3:
size = ((cb0 << 6) & 0x3f00) | (*--src);
ofs = (*--src);
ofs = (ofs << 8) | (*--src);
break;
}
// copy decoded data
while (size--) {
mem--;
*mem = mem[ofs];
}
}
return buf;
}
// decompress or verify compressed CT Raw track information
int CCTRawCodec::DecompressTrack(int verify)
{
CapsPack cpk;
CapsWH cwh;
// in decompress mode free result buffer first
if (!verify)
FreeUncompressedTrack();
// get track header
PCAPSPACK pk = GetPackHeader(&cpk, wh.ctbuf, wh.ctlen);
if (!pk)
return imgeTrackHeader;
// check crc on compressed data in verify mode
if (verify)
if (pk->ccrc != CalcCRC(wh.ctbuf + sizeof(CapsPack), pk->csize))
return imgeTrackStream;
// decompress track data
PCAPSWH wb = DecompressTrack(&cwh, wh.ctbuf, wh.ctlen);
int res = imgeOk;
if (verify) {
// in verify mode check crc on uncompressed data
if (pk->ucrc != CalcCRC(wb->rawbuf, wb->rawlen))
res = imgeTrackData;
// free track data
FreeUncompressedTrack(wb);
} else {
// in decompress mode save track data
wh.rawbuf = wb->rawbuf;
wh.rawlen = wb->rawlen;
for (int trk = 0; trk < CAPS_MTRS; trk++) {
wh.trkbuf[trk] = wb->trkbuf[trk];
wh.trklen[trk] = wb->trklen[trk];
}
wh.trkcnt = wb->trkcnt;
}
return res;
}
// decompress CT Raw track information
PCAPSWH CCTRawCodec::DecompressTrack(PCAPSWH w, PUBYTE src, int slen, PUBYTE dst)
{
CapsPack cpk;
// get track header
PCAPSPACK pk = GetPackHeader(&cpk, src, slen);
if (!pk)
return NULL;
// use caller supplied buffer or allocate a new one
w->rawbuf = NULL;
FreeUncompressedTrack(w);
w->rawlen = pk->usize;
w->rawbuf = dst;
if (!w->rawbuf && w->rawlen)
w->rawbuf = new UBYTE[w->rawlen];
// read track number
w->ctmem = src + sizeof(CapsPack);
w->trkcnt = CTR(w, 1);
// read <track number> track sizes and calculate track buffer positions
dst = w->rawbuf;
for (int trk = 0; trk < w->trkcnt; trk++) {
w->trklen[trk] = CTR(w, 2);
w->trkbuf[trk] = dst;
dst += w->trklen[trk];
}
// first track is stored
if (w->trkcnt) {
w->txsrc = w->trkbuf[0];
w->txlen = w->trklen[0];
memmove(w->txsrc, w->ctmem, w->txlen);
w->ctmem += w->txlen;
}
// other tracks are compressed as deltas against the stored track
for (w->txact = 1; w->txact < w->trkcnt; w->txact++)
DecompressTrackData(w);
return w;
}
// decompress CT Raw track data
void CCTRawCodec::DecompressTrackData(PCAPSWH w)
{
// source stream
PUBYTE src = w->ctmem;
// destination buffer
PUBYTE dst = w->trkbuf[w->txact];
// end of destination buffer
PUBYTE max = dst + w->trklen[w->txact];
// first, stored track
PUBYTE mem = w->txsrc;
// decode the data, see compressor for encoding
while (dst < max) {
UDWORD size = *src++;
if (size & 0x80) {
// copy block
// 3 bit shift
int shift = size >> 4 & 7;
// 12 bit size
size = ((size & 0xf) << 8) | (*src++);
// 16 bit offset
UDWORD ofs = *src++;
ofs = (ofs << 8) | (*src++);
PUBYTE buf = mem + ofs;
if (shift) {
// bitshift copy
ofs = *buf++;
while (size--) {
ofs = (ofs << 8) | (*buf++);
*dst++ = (UBYTE)(ofs >> shift);
}
} else {
// simple copy
while (size--)
*dst++ = *buf++;
}
} else {
// data block, 15 bit size
size = (size << 8) | (*src++);
while (size--)
*dst++ = *src++;
}
}
// update the source stream position
w->ctmem = src;
}
// get CT Raw pack format header in host format and test integrity
PCAPSPACK CCTRawCodec::GetPackHeader(PCAPSPACK cpk, PUBYTE src, int slen)
{
// check header size
if (!src || slen<sizeof(CapsPack))
return NULL;
// check signature
if (memcmp(src, CAPS_IDPACK, sizeof(cpk->sign)))
return NULL;
// copy header to result
memcpy(cpk, src, sizeof(CapsPack));
// change header crc to host format and check crc
Swap(&cpk->hcrc, sizeof(cpk->hcrc));
UDWORD hcrc = cpk->hcrc;
cpk->hcrc = 0;
if (hcrc != CalcCRC((PUBYTE)cpk, sizeof(CapsPack)))
return NULL;
// change header to host format
Swap(PUDWORD(PUBYTE(cpk) + sizeof(cpk->sign)), sizeof(CapsPack) - sizeof(cpk->sign));
// buffer length must match the size of header and compressed data size
if ((UDWORD)slen != sizeof(CapsPack) + cpk->csize)
return NULL;
return cpk;
}
// read up to a dword value from CT Raw stream, update stream position
UDWORD CCTRawCodec::CTR(PCAPSWH w, int size)
{
UDWORD res = 0;
for (; size; size--) {
res <<= 8;
res |= *w->ctmem++;
}
return res;
}