/******************************************************************************
 *                                                                            *
 *          Overlay loader nagyon 1.1 by Tsc/Shock! - 19.01.1996 -            *
 *                                                                            *
 *                         --> Internal use only! <--                         *
 *                                                                            *
 *                     Usage: loader (filenumber, buffer)                     *
 *                                                                            *
 ******************************************************************************/

 dword *headerbuf;
 byte *tempbuff;
 static char *overlayname = {"one.exe"};
 int overlayhandle;
 int headerbufsize = 2;
 int actfilelength;
 int fileoffset;
 int overlaysize;
 int overlayheadersize;
 int readsize;

byte *tempbuf;
dword bufpointer;
unsigned long int  textsize = 0;
static unsigned int  buffer, mask = 0;

int GetBit(byte *tempbuf)  /* Get one bit (0 or 1) */
{
        if ((mask >>= 1) == 0) {
                buffer = *(tempbuf+bufpointer); mask = 128;
                bufpointer++;
        }
        return ((buffer & mask) != 0);
}

/********** LZSS with multiple binary trees **********/

#define N               4096
#define F               60
#define THRESHOLD       2
#define NIL             N

unsigned char  text_buf[N + F - 1];
int match_position, match_length, lson[N + 1], rson[N + 257], dad[N + 1];

/********** Arithmetic Compression **********/

#define M   15

#define Q1  (1UL << M)
#define Q2  (2 * Q1)
#define Q3  (3 * Q1)
#define Q4  (4 * Q1)
#define MAX_CUM (Q1 - 1)

#define N_CHAR  (256 - THRESHOLD + F)
unsigned long int  low = 0, high = Q4, value = 0;
int  char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
unsigned int
        sym_freq[N_CHAR + 1],  /* frequency for symbols */
        sym_cum[N_CHAR + 1],   /* cumulative freq for symbols */
        position_cum[N + 1];   /* cumulative freq for positions */

void StartModel(void)  /* Initialize model */
{
        int ch, sym, i;
        sym_cum[N_CHAR] = 0;
        for (sym = N_CHAR; sym >= 1; sym--) {
                ch = sym - 1;
                char_to_sym[ch] = sym;  sym_to_char[sym] = ch;
                sym_freq[sym] = 1;
                sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
        }
        sym_freq[0] = 0;  /* sentinel (!= sym_freq[1]) */
        position_cum[N] = 0;
        for (i = N; i >= 1; i--)
                position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
}

void UpdateModel(int sym)
{
        int i, c, ch_i, ch_sym;
        if (sym_cum[0] >= MAX_CUM) {
                c = 0;
                for (i = N_CHAR; i > 0; i--) {
                        sym_cum[i] = c;
                        c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
                }
                sym_cum[0] = c;
        }
        for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
        if (i < sym) {
                ch_i = sym_to_char[i];    ch_sym = sym_to_char[sym];
                sym_to_char[i] = ch_sym;  sym_to_char[sym] = ch_i;
                char_to_sym[ch_i] = sym;  char_to_sym[ch_sym] = i;
        }
        sym_freq[i]++;
        while (--i >= 0) sym_cum[i]++;
}

int BinarySearchSym(unsigned int x)
{
        int i, j, k;
        i = 1;  j = N_CHAR;
        while (i < j) {
                k = (i + j) / 2;
                if (sym_cum[k] > x) i = k + 1;  else j = k;
        }
        return i;
}

int BinarySearchPos(unsigned int x)
{
        int i, j, k;

        i = 1;  j = N;
        while (i < j) {
                k = (i + j) / 2;
                if (position_cum[k] > x) i = k + 1;  else j = k;
        }
        return i - 1;
}


void StartDecode(void)
{
        int i;

        for (i = 0; i < M + 2; i++)
                value = 2 * value + GetBit(tempbuf);
}

int DecodeChar(void)
{
        int      sym, ch;
        unsigned long int  range;
        range = high - low;
        sym = BinarySearchSym((unsigned int)
                (((value - low + 1) * sym_cum[0] - 1) / range));
        high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
        low +=       (range * sym_cum[sym    ]) / sym_cum[0];
        for ( ; ; ) {
                if (low >= Q2) {
                        value -= Q2;  low -= Q2;  high -= Q2;
                } else if (low >= Q1 && high <= Q3) {
                        value -= Q1;  low -= Q1;  high -= Q1;
                } else if (high > Q2) break;
                low += low;  high += high;
                value = 2 * value + GetBit(tempbuf);
        }
        ch = sym_to_char[sym];
        UpdateModel(sym);
        return ch;
}

int DecodePosition(void)
{
        int position;
        unsigned long int  range;
        range = high - low;
        position = BinarySearchPos((unsigned int)
                (((value - low + 1) * position_cum[0] - 1) / range));
        high = low + (range * position_cum[position    ]) / position_cum[0];
        low +=       (range * position_cum[position + 1]) / position_cum[0];
        for ( ; ; ) {            
                if (low >= Q2) {
                        value -= Q2;  low -= Q2;  high -= Q2;
                } else if (low >= Q1 && high <= Q3) {
                        value -= Q1;  low -= Q1;  high -= Q1;
                } else if (high > Q2) break;
                low += low;  high += high;
                value = 2 * value + GetBit(tempbuf);
        }
        return position;
}

void decrunch_LZW(byte *bufferke,byte *ptr) {
        int  i, j, k, r, c;
        unsigned long int  count;
        tempbuf=bufferke;
        bufpointer=4;
        low = 0;
        high = Q4;
        value = 0;
        mask = 0;
        count = 0;
        textsize=*(tempbuf+3);
        textsize=textsize<<8;
        textsize=textsize+*(tempbuf+2);
        textsize=textsize<<8;
        textsize=textsize+*(tempbuf+1);
        textsize=textsize<<8;
        textsize=textsize+*(tempbuf+0);
        StartDecode();
        StartModel();
        for (i = 0; i < N - F; i++) {
            text_buf[i] = ' ';
        }
        r = N - F;
        for (count = 0; count < textsize; ) {
                c = DecodeChar();
                if (c < 256) {
                        *(ptr+count) = c;
                        text_buf[r++] = c;
                        r &= (N - 1);
                        count++;
                } else {
                        i = (r - DecodePosition() - 1) & (N - 1);
                        j = c - 255 + THRESHOLD;
                        for (k = 0; k < j; k++) {
                                c = text_buf[(i + k) & (N - 1)];
                                *(ptr+count) = c;
                                text_buf[r++] = c;
                                r &= (N - 1);
                                count++;
                        }
                }
        }
}


void loader(filenumber,filebuffer)

        int filenumber;
        byte *filebuffer;

{
        overlayheadersize = 0;
        overlaysize = 0;
        fileoffset = 0;
        actfilelength = 0;

        OverlayAllocateMem();

        overlayhandle = open (overlayname,O_RDONLY | O_BINARY);
        if (overlayhandle == -1) {
         printf("DEMO_INIT: OVERLAY NOT FOUND. TERMINATING... \n");
         exit(1);
	}
        lseek(overlayhandle, -8, SEEK_END);
        read(overlayhandle, headerbuf, 8);
        overlaysize       = headerbuf[0];
        overlayheadersize = headerbuf[1];
        lseek(overlayhandle, -(overlayheadersize - (filenumber * 8)), SEEK_END);
        readsize = read(overlayhandle, headerbuf, 8);
        fileoffset = headerbuf[0];
        actfilelength = headerbuf[1];
        lseek(overlayhandle, -(overlaysize - fileoffset), SEEK_END);
        tempbuff=(byte* )malloc(actfilelength);                     
        readsize = read(overlayhandle, tempbuff, actfilelength);    
        decrunch_LZW(tempbuff,filebuffer);                          
        free(tempbuff);                                             
        close(overlayhandle);
        OverlayDeallocateMem();
}

void OverlayAllocateMem() {
        dword n;
        headerbuf  = (dword *)malloc(headerbufsize);
        for (n = 0; n < headerbufsize; n++){
         *(headerbuf + n) = 0x00;
        }}
void OverlayDeAllocateMem() {
        free (headerbuf);
	}

