Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

#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 )
                free(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;
}