// this is not a code to be separately compiled!
// instead, it is included in mhmt-depack.c several times and depends on existing at include moment #define's to generate some compiling code
//
// // example defines:
//#define DPK_CHECK // check input stream for consistency
//#define DPK_DEPACK // do depacking
//#define DPK_REPERR // report errors via printf
{
LONG i;
ULONG check;
ULONG byte,bits;//,bitlen;
LONG disp=0;
LONG length=0; // if -3 - insertion match, if 0 - nothing to do
ULONG skipdisp,skiplen;
ULONG disptype;
// fetch byte and add to existing disp
#define DISP_PLUSBYTE 0
// fetch 5 bits to disp
#define DISP_ABCDE 1
// common disp for 3+ lengthes
#define DISP_COMMON 2
ULONG docopy; // do copy from input instead of repeating
ULONG expbitlen = 2; // expandable displacement
ULONG stop;
ULONG success = 1;
// rewind input stream
//
check = depack_getbyte(DEPACK_GETBYTE_REWIND);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check )
{
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Can't rewind input stream!\n");
#endif
return 0;
}
#endif
// manage zx header if needed
if( wrk.zxheader )
{
// check for "HR" in beginning
check = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
if( check != 'H' )
{
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Bad zx-header!\n");
#endif
return 0;
}
#endif
check = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
if( check != 'R' )
{
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Bad zx-header!\n");
#endif
return 0;
}
#endif
// skip 10 bytes
for(i=0;i<10;i++)
{
check = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
#endif
}
}
// initialize bitstream first
//
check = depack_getbits(16,DEPACK_GETBITS_FORCE); // number 16 is ignored! - just for convenience here...
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check )
{
NO_BITS_HST:
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Can't get bits from input stream!\n");
#endif
return 0;
}
#endif
// then byte of input stream goes to the output unchanged
//
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte )
{
NO_BYTE_HST:
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Can't get byte from input stream!\n");
#endif
return 0;
}
#endif
#ifdef DPK_DEPACK
success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
#endif
// now normal depacking loop
//
stop = 0;
while( (!stop) && success )
{
skiplen = 0;
skipdisp = 0;
disptype = DISP_PLUSBYTE;
docopy = 0;
bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
if( 1&bits ) // %1<byte>
{
docopy = 1;
length = 1;
}
else // %0xx
{
bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
switch( bits&3 )
{
case 0: // %000xxx
bits = depack_getbits(3,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
disp = (-8) | (bits&0x07); // FFFFFFF8..FFFFFFFF (-8..-1)
length = 1;
skiplen = 1;
skipdisp = 1;
break;
case 1: // %001 - 2 bytes or insertion match part 1
length = 2;
skiplen = 1;
bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
switch( bits&3 )
{
case 0: // %001 00 - disp FDxx
//disptype = DISP_PLUSBYTE; // default value
disp = (-768);
break;
case 1: // %001 01 - disp FExx
//disptype = DISP_PLUSBYTE; // default value
disp = (-512);
break;
case 2: // %001 10 - ff00..ffdf or insertion match
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
#endif
skipdisp = 1;
if( byte<0x00E0 ) // ff00..ffdf
{
disp = (-256) | (byte&0x00FF);
}
else if( byte==0x00FE ) // expand bitlen of expandable displacement
{
#ifdef DBG
#endif
length = 0; // nothing to do
expbitlen++;
//#ifdef DPK_CHECK
// if( expbitlen>8 )
// {
// #ifdef DPK_REPERR
// printf("mhmt-depack-hrust.c:{} - bitlen of expandable displacement expanded more than 16 bits!\n");
// #endif
// return 0;
// }
//#endif
// this is the fix to mimic Z80 depacker (what seems to be perfectly correct!)
if( expbitlen > 8 )
expbitlen = 1;
}
else // insertion match - xor 2
{
length = (-3); // mark insertion match
byte = ((byte<<1)&0x00FE) | ((byte>>7)&0x01); // byte<<<1
byte ^= 0x02;
byte -= 15;
disp = (-256) | (byte&0x00FF);
}
break;
case 3: // %001 11 - disp FFE0+[abcde]
disptype = DISP_ABCDE;
break;
}
break;
case 2: // %010 - 3 bytes or something
length = 3;
skiplen = 1;
disptype = DISP_COMMON;
break;
case 3: // %011 - varlen
disptype = DISP_COMMON;
break;
}
}
if( (!stop) && (!skiplen) && (!docopy) )
{
// read variable length
bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
switch( bits&3 )
{
case 0: // special cases
bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
if( bits&1 ) // %011 001abcd<byte> - insertion match, displacements -1..-16
{
bits = depack_getbits(4,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
length = (-3); // mark insertion match
skipdisp = 1; // prepare displacement
disp = (-16) | (bits&15);
}
else
{
bits = depack_getbits(1,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
if( bits&1 ) // %011 0001abcd - copy-many-bytes
{
bits = depack_getbits(4,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
length = ((bits&15)+6)<<1;
skipdisp = 1;
docopy = 1;
}
else // %011 0000abcdefg[<byte>] - longer lengthes
{
bits = depack_getbits(7,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
bits &= 127;
if( bits==15 ) // stop depack
{
stop=1;
}
else if( bits>15 ) // 16..127
{
length = bits;
}
else // 0..14: longer lengthes
{
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
#endif
length = (bits<<8) + (byte&0x00FF);
}
}
}
break;
case 1: // %01101
length = 4;
break;
case 2: // %01110
length = 5;
break;
case 3: // variable length (6-15), %01111...
length = 6;
do
{
bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
bits &= 3;
length += bits;
} while( (bits==3) && (length<15) );
break;
}
}
if( (!stop) && (!skipdisp) && (!docopy) )
{
// extract displacement
switch( disptype )
{
case DISP_COMMON:
bits = depack_getbits(2,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
bits &= 3;
if( !bits ) // %00<byte> - fe00..feff
{
disp = (-512);
disptype=DISP_PLUSBYTE; // we fall in next section and there is check
__attribute__((fallthrough));
// NO break!
}
else if( bits==1 ) // %01<byte> - ff00..ffdf
{
disp = (-256);
__attribute__((fallthrough));
// NO break!
// no check for byte in range e0..ff here - but in next switch section!
}
else if( bits==2 ) // %10abcde - ffe0..ffff
{
bits = depack_getbits(5,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
disp = (-32) | (bits&31);
break;
}
else // %11... - expanding displacement
{
bits = depack_getbits(expbitlen,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
//disp = (-1)<<expbitlen;
disp = (-1UL)<<expbitlen;
disp |= (bits&(~disp));
disp <<= 8;
disptype = DISP_PLUSBYTE;
__attribute__((fallthrough));
// NO break!
}
case DISP_PLUSBYTE:
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
#endif
if( disptype==DISP_COMMON ) // if we here from previous section of switch()
{ // we must check for insertion match!
if( byte<0x00E0 ) // ff00..ffdf
{
disp = (-256) | (byte&0x00FF);
}
else // insertion match - xor 3
{
length = (-3); // mark insertion match
byte = ((byte<<1)&0x00FE) | ((byte>>7)&0x01); // byte<<<1
byte ^= 0x03;
byte -= 15;
disp = (-256) | (byte&0x00FF);
}
}
else
{
disp = disp + (byte&0x00FF);
}
break;
case DISP_ABCDE:
bits = depack_getbits(5,DEPACK_GETBITS_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == bits )
{
#ifdef DBG
#endif
goto NO_BITS_HST;
}
#endif
disp = (-32) | (bits&31);
break;
default:
#ifdef DPK_CHECK
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Wrong displacement in disptype!\n");
#endif
return 0;
#endif
break;
}
}
#ifdef DPK_CHECK
if( success && (!docopy) && (!stop) && ((ULONG)(-disp)>wrk.maxwin) )
{
WRONG_DISP_HST:
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Wrong lookback displacement of %d, greater than maxwin\n",(-disp
) );
#endif
return 0;
}
#endif
if( docopy && (!stop) )
{
#ifdef DBG
printf("copy.len=%d\n",length
);
#endif
for(i=0;i<length;i++)
{
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
#endif
#ifdef DPK_DEPACK
success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
#endif
}
}
else if( (!docopy) && (!stop) )// not do-copy
{
if( length!=(-3) )
{
#ifdef DBG
if(length
) printf("match.len=%d,disp=%d\n",length
,disp
);
#endif
#ifdef DPK_DEPACK
if( length )
success = success && depack_repeat(disp,length);
#endif
}
else // (-3)
{
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == byte ) goto NO_BYTE_HST;
#endif
#ifdef DBG
printf("insert-match.len=%d,disp=%d\n",(-length
),disp
);
#endif
#ifdef DPK_DEPACK
success = success && depack_repeat(disp,1);
success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
success = success && depack_repeat(disp,1);
#endif
}
}
}
#ifdef DBG
#endif
//manage zxheader again (copy to the end of output)
#ifdef DPK_DEPACK
if( wrk.zxheader )
{
check = depack_getbyte(DEPACK_GETBYTE_REWIND);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check )
{
#ifdef DPK_REPERR
printf("mhmt-depack-hrust.c:{} - Can't rewind input stream!\n");
#endif
return 0;
}
#endif
for(i=0;i<6;i++) // skip bytes
{
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
#endif
}
// place 6 bytes of header to the end
for(i=0;i<6;i++)
{
byte = depack_getbyte(DEPACK_GETBYTE_NEXT);
#ifdef DPK_CHECK
if( 0xFFFFFFFF == check ) goto NO_BYTE_HST;
#endif
success = success && depack_outbyte( (UBYTE)(0x00FF&byte), DEPACK_OUTBYTE_ADD );
}
}
#endif
return success;
}