// (c) 1995-2007 Electronic Arts Inc.

#ifndef __RIFREAD
#define __RIFREAD 1

#include <string.h>
#include "codex.h"
#include "rifcodex.h"

/****************************************************************/
/*  Information Functions                                       */
/****************************************************************/

/* check for reasonable header: */
/* 10fb header */

bool GCALL RIF_is(const void *compresseddata)
{
    bool ok=false;
    int packtype=ggetm(compresseddata,2);

    if (packtype==0x10fb
     || packtype==0x11fb
     || packtype==0x90fb
     || packtype==0x91fb)
        ok = true;

    return(ok);
}


/****************************************************************/
/*  Decode Functions                                            */
/****************************************************************/

int GCALL RIF_size(const void *compresseddata)
{
    int len=0;
    int packtype=ggetm(compresseddata,2);
    int ssize=(packtype&0x8000)?4:3;

    if (packtype&0x100)     /* 11fb */
    {
        len = ggetm((char *)compresseddata+2+ssize,ssize);
    }
    else                    /* 10fb */
    {
        len = ggetm((char *)compresseddata+2,ssize);
    }

    return(len);
}


int GCALL RIF_decode(void *dest, const void *compresseddata, int *compressedsize)
{
    unsigned char *s;
    unsigned char *rif;
    unsigned char *d;
    unsigned char first;
    unsigned char second;
    unsigned char third;
    unsigned char forth;
    unsigned int  run;
    unsigned int  type;
    int          ulen;

    s = (unsigned char *) compresseddata;
    d = (unsigned char *) dest;
    ulen = 0L;

    if (s)
    {
        type = *s++;
        type = (type<<8) + *s++;

        if (type&0x8000) /* 4 byte size field */
        {
            if (type&0x100)                       /* skip ulen */
                s += 4;

            ulen = *s++;
            ulen = (ulen<<8) + *s++;
            ulen = (ulen<<8) + *s++;
            ulen = (ulen<<8) + *s++;
        }
        else
        {
            if (type&0x100)                       /* skip ulen */
                s += 3;

            ulen = *s++;
            ulen = (ulen<<8) + *s++;
            ulen = (ulen<<8) + *s++;
        }

        for (;;)
        {
            first = *s++;
            if (!(first&0x80))          /* short form */
            {
                second = *s++;
                run = first&3;
                while (run--)
                    *d++ = *s++;
                rif = d-1 - (((first&0x60)<<3) + second);
                run = ((first&0x1c)>>2)+3-1;
                do
                {
                    *d++ = *rif++;
                } while (run--);
                continue;
            }
            if (!(first&0x40))          /* long form */
            {
                second = *s++;
                third = *s++;
                run = second>>6;
                while (run--)
                    *d++ = *s++;

                rif = d-1 - (((second&0x3f)<<8) + third);

                run = (first&0x3f)+4-1;
                do
                {
                    *d++ = *rif++;
                } while (run--);
                continue;
            }
            if (!(first&0x20))          /* very long form */
            {
                second = *s++;
                third = *s++;
                forth = *s++;
                run = first&3;
                while (run--)
                    *d++ = *s++;

                rif = d-1 - (((first&0x10)>>4<<16) +  (second<<8) + third);

                run = ((first&0x0c)>>2<<8) + forth + 5-1;
                do
                {
                    *d++ = *rif++;
                } while (run--);
                continue;
            }
            run = ((first&0x1f)<<2)+4;  /* literal */
            if (run<=112)
            {
                while (run--)
                    *d++ = *s++;
                continue;
            }
            run = first&3;              /* eof (+0..3 literal) */
            while (run--)
                *d++ = *s++;
            break;
        }
    }
    if (compressedsize)
        *compressedsize = (int)((char *)s-(char *)compresseddata);
    return(ulen);
}

#endif

