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

776 lines
18 KiB
C++

#include "stdafx.h"
// fm tables
uint32_t CDiskEncoding::fminit=0;
uint32_t *CDiskEncoding::fmcode=NULL;
uint32_t *CDiskEncoding::fmdecode=NULL;
// mfm tables
uint32_t CDiskEncoding::mfminit=0;
uint32_t CDiskEncoding::mfmcodebit=0;
uint32_t *CDiskEncoding::mfmcode=NULL;
uint32_t *CDiskEncoding::mfmdecode=NULL;
// primary and secondary gcr tables
int CDiskEncoding::gcrinit=gcridNone;
uint32_t *CDiskEncoding::gcrcode=NULL;
uint32_t *CDiskEncoding::gcrdecode=NULL;
int CDiskEncoding::gcrinit_s=gcridNone;
uint32_t *CDiskEncoding::gcrcode_s=NULL;
uint32_t *CDiskEncoding::gcrdecode_s=NULL;
// gcr apple header tables
int CDiskEncoding::gcrahinit=0;
uint32_t *CDiskEncoding::gcrahcode=NULL;
uint32_t *CDiskEncoding::gcrahdecode=NULL;
// gcr apple 5 bit tables
int CDiskEncoding::gcra5init=0;
uint32_t *CDiskEncoding::gcra5code=NULL;
uint32_t *CDiskEncoding::gcra5decode=NULL;
// gcr apple 6 bit tables
int CDiskEncoding::gcra6init=0;
uint32_t *CDiskEncoding::gcra6code=NULL;
uint32_t *CDiskEncoding::gcra6decode=NULL;
// gcr cbm vorpal 6 bit tables
int CDiskEncoding::gcrvorpalinit=0;
uint32_t *CDiskEncoding::gcrvorpalcode=NULL;
uint32_t *CDiskEncoding::gcrvorpaldecode=NULL;
// gcr cbm vorpal 2, 5 bit tables
int CDiskEncoding::gcrvorpal2init=0;
uint32_t *CDiskEncoding::gcrvorpal2code=NULL;
uint32_t *CDiskEncoding::gcrvorpal2decode=NULL;
// gcr cbm vmax 6 bit tables
int CDiskEncoding::gcrvmaxinit=vmaxidNone;
uint32_t *CDiskEncoding::gcrvmaxcode=NULL;
uint32_t *CDiskEncoding::gcrvmaxdecode=NULL;
// gcr cbm teque 4 bit tables
int CDiskEncoding::gcr4bitinit=0;
uint32_t *CDiskEncoding::gcr4bitcode=NULL;
uint32_t *CDiskEncoding::gcr4bitdecode=NULL;
// GCR table used by CBM DOS
uint32_t CDiskEncoding::gcr_cbm[]= {
0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15
};
// 4 bit GCR table used by CBM Big Five
uint32_t CDiskEncoding::gcr_bigfive[]= {
0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x12, 0x13,
0x15, 0x16, 0x17, 0x19, 0x1a, 0x1b, 0x1d, 0x1e
};
// 5 bit GCR table used by Apple DOS
uint32_t CDiskEncoding::gcr_apple5[]= {
0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba,
0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb,
0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef,
0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff
};
// 6 bit GCR table used by Apple DOS
uint32_t CDiskEncoding::gcr_apple6[]= {
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
// 6 bit GCR table used by CBM Vorpal
uint32_t CDiskEncoding::gcr_vorpal[]= {
0x49, 0x56, 0x4b, 0x5a, 0x99, 0xaa, 0x9b, 0xad,
0x4e, 0x5d, 0x53, 0x65, 0x9e, 0xb2, 0xa6, 0xb5,
0x69, 0x76, 0x6b, 0x7a, 0xb9, 0xce, 0xbb, 0xd3,
0x6e, 0x92, 0x73, 0x95, 0xc9, 0xd6, 0xcb, 0xda,
0x4a, 0x59, 0x4d, 0x5b, 0x9a, 0xab, 0x9d, 0xae,
0x52, 0x5e, 0x55, 0x66, 0xa5, 0xb3, 0xa9, 0xb6,
0x6a, 0x79, 0x6d, 0x7b, 0xba, 0xd2, 0xbd, 0xd5,
0x72, 0x93, 0x75, 0x96, 0xca, 0xd9, 0xcd, 0xdb
};
// 5 bit GCR tables used by CBM Vorpal 2, 2 bits cleared in alternate values for 3 or 4 consecutive 1 bits; 0 is an illegal entry
uint32_t CDiskEncoding::gcr_vorpal2[]= {
0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x12, 0x13, 0x15, 0x16, 0x17, 0x19, 0x1a, 0x1b, 0x1d, 0x1e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x06
};
// 6 bit GCR table used by CBM V-MAX! for normal encoding, alternate values are not used
uint32_t CDiskEncoding::gcr_vmax[]= {
0xf7, 0xf6, 0xf4, 0xf5, 0xf3, 0xf2, 0xef, 0xee,
0xec, 0xed, 0xea, 0xeb, 0xe9, 0xe7, 0xe6, 0xe4,
0xe5, 0xde, 0xdc, 0xdd, 0xd9, 0xdb, 0xd3, 0xd7,
0xdf, 0xcf, 0xce, 0xcc, 0xcd, 0xcb, 0xca, 0xc9,
0xbe, 0xbc, 0xb2, 0xbd, 0xb9, 0xb4, 0xbb, 0xba,
0xb6, 0xb7, 0xb5, 0xaf, 0xad, 0xae, 0xac, 0xab,
0xa7, 0x9f, 0x9e, 0x9d, 0x9b, 0x97, 0xaa, 0xa9,
0x9c, 0x99, 0x93, 0x92, 0x96, 0xa6, 0xa4, 0xa5
};
// 6 bit GCR table used by CBM V-MAX! for old, illegal encoding
uint32_t CDiskEncoding::gcr_vmaxold[]= {
0xf7, 0xf6, 0xf4, 0xf5, 0xf3, 0xf2, 0xef, 0xee,
0xec, 0xed, 0xe2, 0xeb, 0xe9, 0xe7, 0xe6, 0xe4,
0xe5, 0xde, 0xdc, 0xdd, 0xd9, 0xdb, 0xd3, 0xd7,
0xdf, 0xcf, 0xce, 0xcc, 0xcd, 0xcb, 0xca, 0xc9,
0xbe, 0xbc, 0xb2, 0xbd, 0xb9, 0xb4, 0xbb, 0xba,
0xb6, 0xb7, 0xb5, 0xaf, 0xa3, 0xae, 0xac, 0xab,
0xa7, 0x9f, 0x9e, 0x9d, 0x9b, 0x97, 0xaa, 0xa9,
0x9c, 0x99, 0x93, 0x92, 0x96, 0xa6, 0xa4, 0xa5
};
// 4 bit GCR table used by CBM Teque
uint32_t CDiskEncoding::gcr_teque[]= {
0xab, 0xb7, 0xad, 0xb5, 0x6b, 0x77, 0x6d, 0x75,
0xdb, 0xd7, 0xdd, 0xd5, 0x5b, 0x57, 0x5d, 0x55
};
// 4 bit GCR table used by CBM OziSoft
uint32_t CDiskEncoding::gcr_ozisoft[]= {
0x5d, 0x65, 0x66, 0x67, 0x6d, 0x77, 0x79, 0x7b,
0x99, 0xa5, 0xa6, 0xaa, 0xb7, 0xb9, 0xba, 0xbe
};
CDiskEncoding::CDiskEncoding()
{
}
CDiskEncoding::~CDiskEncoding()
{
delete [] fmcode;
delete [] fmdecode;
delete [] mfmcode;
delete [] mfmdecode;
delete [] gcrcode;
delete [] gcrdecode;
delete [] gcrcode_s;
delete [] gcrdecode_s;
delete [] gcrahcode;
delete [] gcrahdecode;
delete [] gcra5code;
delete [] gcra5decode;
delete [] gcra6code;
delete [] gcra6decode;
delete [] gcrvorpalcode;
delete [] gcrvorpaldecode;
delete [] gcrvorpal2code;
delete [] gcrvorpal2decode;
delete [] gcrvmaxcode;
delete [] gcrvmaxdecode;
delete [] gcr4bitcode;
delete [] gcr4bitdecode;
Clear();
}
// reset variables
void CDiskEncoding::Clear()
{
fminit=0;
fmcode=NULL;
fmdecode=NULL;
mfminit=0;
mfmcodebit=0;
mfmcode=NULL;
mfmdecode=NULL;
gcrinit=gcridNone;
gcrcode=NULL;
gcrdecode=NULL;
gcrinit_s=gcridNone;
gcrcode_s=NULL;
gcrdecode_s=NULL;
gcrahinit=0;
gcrahcode=NULL;
gcrahdecode=NULL;
gcra5init=0;
gcra5code=NULL;
gcra5decode=NULL;
gcra6init=0;
gcra6code=NULL;
gcra6decode=NULL;
gcrvorpalinit=0;
gcrvorpalcode=NULL;
gcrvorpaldecode=NULL;
gcrvorpal2init=0;
gcrvorpal2code=NULL;
gcrvorpal2decode=NULL;
gcrvmaxinit=0;
gcrvmaxcode=NULL;
gcrvmaxdecode=NULL;
gcr4bitinit=0;
gcr4bitcode=NULL;
gcr4bitdecode=NULL;
}
// initialize FM tables
void CDiskEncoding::InitFM()
{
// stop if correct tables are available
if (fminit)
return;
// create tables
if (!fmcode)
fmcode=new uint32_t[256];
if (!fmdecode)
fmdecode=new uint32_t[65536];
uint32_t sval;
// create FM word code table
for (sval=0x0000; sval < 256; sval++) {
uint32_t code=0;
// generate clock and data bits
for (uint32_t bit=0x80; bit; bit>>=1) {
code<<=2;
// always set clock to 1, and add data
code|=(sval & bit) ? 3 : 2;
}
// store encoding
fmcode[sval]=code;
}
// create FM decode table
for (sval=0x0000; sval < 0x10000; sval++) {
uint32_t code=0;
// all bits
for (uint32_t bit=0x4000; bit; bit>>=2) {
code<<=1;
if (sval & bit)
code|=1;
}
// store decoding, mark coding erros
uint32_t cd=fmcode[code] & 0xffff;
if (cd != sval)
code|=DF_31;
fmdecode[sval]=code;
}
fminit=1;
}
// initialize MFM tables
void CDiskEncoding::InitMFM(uint32_t mfmsize)
{
// cancel if correct tables are available
if (mfmsize && mfminit>=mfmsize)
return;
// clear tables
delete [] mfmcode;
mfmcode=NULL;
delete [] mfmdecode;
mfmdecode=NULL;
mfminit=0;
mfmcodebit=0;
// stop if empty tables
if (!mfmsize)
return;
// create tables
mfmcode=new uint32_t[mfmsize];
mfmdecode=new uint32_t[mfmsize];
// code only ever uses 8 or 16 bit indexing
mfmcodebit=(mfmsize > 0x100) ? 16 : 8;
uint32_t sval;
// create MFM word code table (last code bit assumed 0)
for (sval=0x0000; sval < mfmsize; sval++) {
uint32_t code=0;
// all bits
for (uint32_t bit=0x8000; bit; bit>>=1) {
code<<=2;
// bit 0 encoded as 00, if last bit is 1
// bit 0 encoded as 10, if last bit is 0
// bit 1 encoded as 01
if (sval & bit)
code|=1;
else
if (!(code & 4))
code|=2;
}
// store encoding
mfmcode[sval]=code;
}
// create MFM decode table, possible errors marked for analyser only
if (mfmsize > 0x100) {
for (sval=0x0000; sval < mfmsize; sval++) {
uint32_t code=0;
// all bits
for (uint32_t bit=0x4000; bit; bit>>=2) {
code<<=1;
if (sval & bit)
code|=1;
}
// store decoding, mark coding erros
uint32_t cd=mfmcode[code]&0xffff;
if (cd!=sval && (cd&0x7fff)!=sval)
code|=DF_31;
mfmdecode[sval]=code;
}
} else {
for (sval=0x0000; sval < mfmsize; sval++) {
uint32_t code=0;
// all bits
for (uint32_t bit=0x4000; bit; bit>>=2) {
code<<=1;
if (sval & bit)
code|=1;
}
// store decoding
mfmdecode[sval]=code;
}
}
mfminit=mfmsize;
}
// initialize GCR tables
void CDiskEncoding::InitGCRCBM(uint32_t *gcrtable, int gcrid)
{
// cancel if table initialized with the same gcr version
if (gcrid == gcrinit)
return;
// create tables
if (!gcrcode)
gcrcode=new uint32_t[256];
if (!gcrdecode)
gcrdecode=new uint32_t[1024];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 1024; sval++)
gcrdecode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 256; sval++) {
uint32_t ghi=gcrtable[sval >> 4];
uint32_t glo=gcrtable[sval & 0xf];
uint32_t code=ghi << 5 | glo;
gcrcode[sval]=code;
gcrdecode[code]=sval;
}
gcrinit=gcrid;
}
// initialize secondary GCR tables
void CDiskEncoding::InitGCRCBM_S(uint32_t *gcrtable, int gcrid)
{
// cancel if table initialized with the same gcr version
if (gcrid == gcrinit_s)
return;
// create tables
if (!gcrcode_s)
gcrcode_s=new uint32_t[256];
if (!gcrdecode_s)
gcrdecode_s=new uint32_t[1024];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 1024; sval++)
gcrdecode_s[sval]=DF_31;
// create GCR table
for (sval=0; sval < 256; sval++) {
uint32_t ghi=gcrtable[sval >> 4];
uint32_t glo=gcrtable[sval & 0xf];
uint32_t code=ghi << 5 | glo;
gcrcode_s[sval]=code;
gcrdecode_s[code]=sval;
}
gcrinit_s=gcrid;
}
// initialize GCR Apple Header tables
void CDiskEncoding::InitGCRAppleH()
{
// stop if correct tables are available
if (gcrahinit)
return;
// create tables
if (!gcrahcode)
gcrahcode=new uint32_t[256];
if (!gcrahdecode)
gcrahdecode=new uint32_t[65536];
uint32_t sval;
// create code table
for (sval=0x0000; sval < 256; sval++) {
// generate clock and data bits, like FM but bits are interleaved
// C7C5C3C1 C6C4C2C0
uint32_t ahi=(sval >> 1) | 0xaa;
uint32_t alo=sval | 0xaa;
uint32_t code=ahi << 8 | alo;
// store encoding
gcrahcode[sval]=code;
}
// create decode table
for (sval=0x0000; sval < 0x10000; sval++) {
uint32_t dhi=(sval >> 8) & 0x55;
uint32_t dlo=sval & 0x55;
uint32_t code=dhi << 1 | dlo;
// store decoding, mark coding erros
uint32_t cd=gcrahcode[code] & 0xffff;
if (cd != sval)
code|=DF_31;
gcrahdecode[sval]=code;
}
gcrahinit=1;
}
// initialize GCR Apple 5 bit tables
void CDiskEncoding::InitGCRApple5(uint32_t *gcrtable)
{
// stop if correct tables are available
if (gcra5init)
return;
// create tables
if (!gcra5code)
gcra5code=new uint32_t[32];
if (!gcra5decode)
gcra5decode=new uint32_t[256];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 256; sval++)
gcra5decode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 32; sval++) {
uint32_t code=gcrtable[sval];
gcra5code[sval]=code;
gcra5decode[code]=sval;
}
gcra5init=1;
}
// initialize GCR Apple 6 bit tables
void CDiskEncoding::InitGCRApple6(uint32_t *gcrtable)
{
// stop if correct tables are available
if (gcra6init)
return;
// create tables
if (!gcra6code)
gcra6code=new uint32_t[64];
if (!gcra6decode)
gcra6decode=new uint32_t[256];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 256; sval++)
gcra6decode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 64; sval++) {
uint32_t code=gcrtable[sval];
gcra6code[sval]=code;
gcra6decode[code]=sval;
}
gcra6init=1;
}
// initialize GCR CBM Vorpal 6 bit tables
void CDiskEncoding::InitGCRVorpal(uint32_t *gcrtable)
{
// stop if correct tables are available
if (gcrvorpalinit)
return;
// create tables
if (!gcrvorpalcode)
gcrvorpalcode=new uint32_t[64];
if (!gcrvorpaldecode)
gcrvorpaldecode=new uint32_t[256];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 256; sval++)
gcrvorpaldecode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 64; sval++) {
uint32_t code=gcrtable[sval];
gcrvorpalcode[sval]=code;
gcrvorpaldecode[code]=sval;
}
gcrvorpalinit=1;
}
// initialize GCR CBM Vorpal 5 bit tables
void CDiskEncoding::InitGCRVorpal2(uint32_t *gcrtable)
{
// stop if correct tables are available
if (gcrvorpal2init)
return;
// create tables
if (!gcrvorpal2code)
gcrvorpal2code=new uint32_t[32];
if (!gcrvorpal2decode)
gcrvorpal2decode=new uint32_t[1024];
// decoded 5 bit gcr value
int gdtab[32];
int i;
// mark all values as illegal
for (i=0; i < 32; i++)
gdtab[i]=-1;
// add valid gcr and decoded values
for (i=0; i < 32; i++) {
uint32_t code=gcrtable[i];
gcrvorpal2code[i]=code;
// skip illegal codes
if (!code)
continue;
// 4 bit decoded value
gdtab[code]=i & 0x0f;
}
// process all possible 10 bit combinations (5 bit hi nybble, 5 bit lo nybble)
for (uint32_t sval=0; sval < 1024; sval++) {
// set value as illegal by default
gcrvorpal2decode[sval]=DF_31;
// decode the 5 bit gcr values
int dechi=gdtab[sval >> 5];
int declo=gdtab[sval & 0x1f];
// the 10 bit encoded value is illegal if any of its nybbles decoded is an illegal code
if (dechi < 0 || declo < 0)
continue;
int lbv=-1;
int bc=0;
// check the 10 bit encoded value as a stream for illegal encoding
uint32_t bm;
for (bm=1 << 9; bm; bm >>= 1) {
// current bit value
int bitval=(sval & bm) ? 1 : 0;
if (lbv != bitval) {
// if different from previous bit, restart counting
lbv=bitval;
bc=1;
} else {
// same as previous bit, count it in
bc++;
// the stream is illegal if it contains 5 consecutive 1 bits or 3 consecutive 0 bits
if ((!lbv && bc >= 3) || (lbv && bc >= 5))
break;
}
}
// skip illegal value; the loop ended early
if (bm)
continue;
// set 8 bit decoded value
uint32_t code=dechi << 4 | declo;
gcrvorpal2decode[sval]=code;
}
gcrvorpal2init=1;
}
// initialize GCR CBM V-Max! 6 bit tables
void CDiskEncoding::InitGCRVMax(uint32_t *gcrtable, int vmaxid)
{
// cancel if table initialized with the same gcr version
if (gcrvmaxinit == vmaxid)
return;
// create tables
if (!gcrvmaxcode)
gcrvmaxcode=new uint32_t[64];
if (!gcrvmaxdecode)
gcrvmaxdecode=new uint32_t[256];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 256; sval++)
gcrvmaxdecode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 64; sval++) {
uint32_t code=gcrtable[sval];
if (!code)
continue;
gcrvmaxcode[sval]=code;
gcrvmaxdecode[code]=sval;
}
gcrvmaxinit=vmaxid;
}
// initialize 4 bit gcr tables
void CDiskEncoding::InitGCR4Bit(uint32_t *gcrtable)
{
// stop if correct tables are available
if (gcr4bitinit)
return;
// create tables
if (!gcr4bitcode)
gcr4bitcode=new uint32_t[16];
if (!gcr4bitdecode)
gcr4bitdecode=new uint32_t[256];
uint32_t sval;
// set GCR decode table to coding error as default
for (sval=0; sval < 256; sval++)
gcr4bitdecode[sval]=DF_31;
// create GCR table
for (sval=0; sval < 16; sval++) {
uint32_t code=gcrtable[sval];
gcr4bitcode[sval]=code;
gcr4bitdecode[code]=sval;
}
gcr4bitinit=1;
}
// find recording violation, that exceeds the maximum number of consecutive 0 or 1 bits
int CDiskEncoding::FindViolation(uint8_t *buffer, int bitpos, int bitcnt, int max0, int max1, int mode)
{
int vcnt=0;
// no violation if any of the parameters is incorrect or nothing to check
if (!buffer || bitpos < 0 || bitcnt <= 0 || (max0 < 0 && max1 < 0))
return mode ? vcnt : -1;
// calculate the buffer position and bit mask for the first bit to check
uint32_t bitmask=1 << ((bitpos & 7) ^ 7);
uint32_t pos=bitpos >> 3;
uint32_t sval=buffer[pos++];
// reset bit counter
int lbv=-1;
int bc=0;
// process all bits
while (bitcnt-- > 0) {
// if mask underflowed, reset the mask to b7 and read the next buffer value
if (!bitmask) {
bitmask=0x80;
sval=buffer[pos++];
}
// current bit value
int bitval=(sval & bitmask) ? 1 : 0;
if (lbv != bitval) {
// if different from previous bit, restart counting
lbv=bitval;
bc=1;
} else {
// same as previous bit, count it in
bc++;
// violation found if the stream contains max1 consecutive 1 bits or max0 consecutive 0 bits
if ((!lbv && max0 >= 0 && bc >= max0) || (lbv && max1 >= 0 && bc >= max1)) {
// count violations or return on first violation found depending on mode
if (mode)
vcnt++;
else
return bitpos;
}
}
// move to next bit
bitpos++;
bitmask >>= 1;
}
// return violation count or no violation found depending on mode
return mode ? vcnt : -1;
}