#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mhmt-types.h"
#include "mhmt-globals.h"
#include "mhmt-depack.h"
#include "mhmt-lz.h"
#include "mhmt-emit.h"
ULONG buf_size=0;
ULONG buf_ptr=0;
UBYTE * buffer=NULL;
LONG backptr, frontptr;
ULONG depack(void)
{
ULONG (*checker) (void) = NULL;
ULONG (*depacker)(void) = NULL;
ULONG success=1;
// some preparations
//
if( wrk.packtype==PK_MLZ )
{
checker = &checker_megalz;
depacker = &depacker_megalz;
}
else if( wrk.packtype==PK_HRM )
{
checker = &checker_hrum;
depacker = &depacker_hrum;
}
else if( wrk.packtype==PK_HST )
{
// checker = &checker_hrust;
depacker = &depacker_hrust;
}
else if( wrk.packtype==PK_ZX7 )
{
checker = &checker_zx7;
depacker = &depacker_zx7;
}
else
{
printf("mhmt-depack.c:depack() - format unsupported!\n");
return 0;
}
// allocate buffer used for depacking
//
//////buf_size = ( wrk.maxwin==4352 ) ? 8192 : wrk.maxwin; // provided there are no other non-2^n sizes
if( wrk.maxwin==4352 )
buf_size = 8192;
else if( wrk.maxwin==2176 )
buf_size = 4096;
else
buf_size = wrk.maxwin;
buffer
=(UBYTE
*)malloc(buf_size
);
if( !buffer )
{
printf("mhmt-depack.c:depack() cannot allocate memory for depack buffer!\n");
return 0;
}
buf_ptr=0;
success = success && emit_file(NULL,EMIT_FILE_INIT);
if( wrk.packtype==PK_MLZ || wrk.packtype==PK_ZX7 )
success = success && (*checker) ();
//#ifdef DBG
// printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
//#endif
depack_outbyte( 0, DEPACK_OUTBYTE_INIT );
success = success && (*depacker)();
/*success = success && */depack_outbyte( 0, DEPACK_OUTBYTE_FLUSH );
/*success = success && */emit_file(NULL,EMIT_FILE_FINISH);
if( buffer )
return success;
}
// checks input file for consistency
#undef DPK_DEPACK
#define DPK_CHECK
#define DPK_REPERR
ULONG checker_megalz(void)
#include "mhmt-depack-megalz.c"
ULONG checker_hrum(void)
#include "mhmt-depack-hrum.c"
ULONG checker_zx7(void)
#include "mhmt-depack-zx7.c"
//ULONG checker_hrust(void)
//#include "mhmt-depack-hrust.c"
//
// actually depacks without checkings
#define DPK_DEPACK
#undef DPK_CHECK
#undef DPK_REPERR
ULONG depacker_megalz(void)
#include "mhmt-depack-megalz.c"
ULONG depacker_hrum(void)
#include "mhmt-depack-hrum.c"
ULONG depacker_zx7(void)
#include "mhmt-depack-zx7.c"
#define DPK_CHECK
#define DPK_REPERR
ULONG depacker_hrust(void)
#include "mhmt-depack-hrust.c"
// rewind - to the beginning of input stream, byte - next byte
// returns 0xFFFFFFFF if error (exhausted stream), otherwise byte (0..255)
ULONG depack_getbyte(ULONG operation)
{
static ULONG position;
if( operation==DEPACK_GETBYTE_REWIND )
{
position=0;
return 0;
}
else if( operation==DEPACK_GETBYTE_NEXT )
{
if( position < wrk.inlen )
{
return (ULONG)wrk.indata[position++];
}
else
{
printf("mhmt-depack.c:depack_getbyte() - input file exhausted!\n");
return 0xFFFFFFFF;
}
}
else // should never happen in a correct program
printf("mhmt-depack.c:depack_getbyte() - wrong operation code\n");
return 0xFFFFFFFF;
}
//#define DEPACK_GETBITS_FORCE 1
//#define DEPACK_GETBITS_NEXT 2
//
// returns 0xFFFFFFFF if error, otherwise LSB-aligned, zero-extended bits
ULONG depack_getbits(ULONG numbits, ULONG operation)
{ static ULONG bits;
static ULONG num_bits_left;
ULONG fetched_bits;
if( operation==DEPACK_GETBITS_FORCE ) // force word retrieval (for start of stream)
{
bits = depack_getbits_word();
if( bits==0xFFFFFFFF) return 0xFFFFFFFF;
num_bits_left = wrk.wordbit ? 16 : 8;
return 0;
}
else if( operation==DEPACK_GETBITS_NEXT ) // return bits and fetch new as needed (wrk.fullbits accounted for)
{
if( (numbits==0) || (numbits>31) )
{
printf("mhmt-depack.c:depack_getbits() - too many (>31) or zero bits requested\n");
return 0xFFFFFFFF;
}
fetched_bits = 0;
do
{
if( !wrk.fullbits ) // empty bits
{
if( !num_bits_left )
{
bits = depack_getbits_word();
if( bits==0xFFFFFFFF) return 0xFFFFFFFF;
num_bits_left = wrk.wordbit ? 16 : 8;
}
}
fetched_bits = ( fetched_bits<<1 ) | ( 1&(bits>>31) );
bits <<= 1;
num_bits_left--;
if( wrk.fullbits )
{
if( !num_bits_left )
{
bits = depack_getbits_word();
if( (bits==0xFFFFFFFF) && (numbits>1) ) return 0xFFFFFFFF;
num_bits_left = wrk.wordbit ? 16 : 8;
}
}
} while( --numbits );
return fetched_bits;
}
else
{
printf("mhmt-depack.c:depack_getbits() - wrong operation code\n");
return 0xFFFFFFFF;
}
}
// gets word of bits (UBYTE or UWORD), accounts for big-little endian
// returns 0xFFFFFFFF if no bytes in input stream (depack_getbyte()), otherwise
// left-aligned bits.
ULONG depack_getbits_word(void)
{
ULONG bits,bits2;
if( wrk.wordbit ) // 16bits
{
if( wrk.bigend )
{
bits = depack_getbyte(DEPACK_GETBYTE_NEXT);
if( bits == 0xFFFFFFFF ) return 0xFFFFFFFF;
bits2 = depack_getbyte(DEPACK_GETBYTE_NEXT);
if( bits2 == 0xFFFFFFFF ) return 0xFFFFFFFF;
}
else
{
bits2 = depack_getbyte(DEPACK_GETBYTE_NEXT);
if( bits2 == 0xFFFFFFFF ) return 0xFFFFFFFF;
bits = depack_getbyte(DEPACK_GETBYTE_NEXT);
if( bits == 0xFFFFFFFF ) return 0xFFFFFFFF;
}
bits = (bits<<24) | ( 0x00FF0000&(bits2<<16) );
}
else // 8bits
{
bits=depack_getbyte(DEPACK_GETBYTE_NEXT);
if( bits!=0xFFFFFFFF)
bits <<= 24;
}
return bits;
}
// puts byte to the output buffer. if it is full, flushes via mhmt-emit.c:emit_file()
// relies on initialized globals: buffer, buf_size, buf_ptr
// returns zero if error (in emit_file()), otherwise non-zero
ULONG depack_outbyte(UBYTE byte, ULONG operation)
{
LONG pre_size;
if( operation==DEPACK_OUTBYTE_INIT )
{
frontptr = 0;
if( wrk.prebin )
{
// copy some data from prebinary buffer
pre_size = wrk.prelen;
if( pre_size > (LONG)buf_size )
pre_size = buf_size;
//
memcpy(buffer
+buf_size
-pre_size
, wrk.
indata-pre_size
, pre_size
);
// set backptr
backptr = 0-pre_size;
}
else
{
backptr = 0;
}
}
else if( operation==DEPACK_OUTBYTE_ADD )
{
buffer[buf_ptr++] = byte;
frontptr++;
if( buf_ptr >= buf_size )
{
buf_ptr=0;
return emit_file( buffer, buf_size );
}
return 1;
}
else if( operation==DEPACK_OUTBYTE_FLUSH )
{
if( buf_ptr ) return emit_file( buffer, buf_ptr );
return 1;
}
else
{
printf("mhmt-depack.c:depack_outbyte() - bad operation requested\n");
return 0;
}
}
// repeats data in output buffer, flushes buffer if needed.
// relies on initialized globals, also relies on buf_size being 2^N
// displacement is back-displacement (negative)
// non-zero if success
ULONG depack_repeat(LONG disp, ULONG length)
{
ULONG back_ptr;
ULONG success=1;
// in a self-consistent system, these three errors should never appear, since there is input stream check before actual depacking
if( !length )
{
printf("mhmt-depack.c:depack_repeat() - zero length!\n");
return 0;
}
else if( disp>=0 )
{
printf("mhmt-depack.c:depack_repeat() - non-negative displacement!\n");
return 0;
}
else if( (ULONG)(-disp)>buf_size )
{
printf("mhmt-depack.c:depack_repeat() - displacement greater than buffer size!\n");
return 0;
}
else
{
back_ptr = (disp+buf_ptr) & (buf_size-1); // buf_size MUST BE 2^N!
if( (frontptr+disp) < backptr )
{
printf("mhmt-depack.c:depack_repeat() - displacement is out of prebinary or already depacked data!\n");
return 0;
}
do
{
success = success && depack_outbyte( buffer[back_ptr], DEPACK_OUTBYTE_ADD ); // also increases buf_ptr
back_ptr = (back_ptr+1) & (buf_size-1); // buf_size MUST BE 2^N!
} while( --length );
}
return success;
}