// 2015 jrra

#include <inttypes.h>
#include <endian.h>
#include <strings.h>
#include "yay1.h"

uint32_t yay1_get_size(uint8_t *s)
{
    return be32toh( *(uint32_t*)(s+4) );
}

int yay1_decode(uint8_t *s, uint8_t *d)
{
    if( bcmp( s, "Yay1", 4 ) )
    {
        return -1;
    }
    
    uint8_t *endOfDest, *linkTable, *chunks;
    int bitsLeft = 0;
    int32_t bits = 0;
    
    uint32_t decodedSize     = yay1_get_size( s );
    uint32_t linkTableOffset = be32toh( *(uint32_t*)(s+8) );
    uint32_t chunksOffset = be32toh( *(uint32_t*)(s+0xC) );
    endOfDest = d + decodedSize;
    linkTable = s + linkTableOffset;
    chunks    = s + chunksOffset;
    
    s += 0x10;
    
    do {
        if( bitsLeft == 0 )
        {
            bitsLeft = 32;
            bits = be32toh( *(uint32_t*) s );
            s += 4;
        }
        if( bits >= 0 )
        {
            uint16_t codeword = be16toh( *(uint16_t*)linkTable );
            linkTable += 2;
            unsigned int count = codeword >> 12;
            unsigned int offset = codeword & 0xfff;
            
            uint8_t *backReference = d - offset;
            if( count == 0 )
                count = *(chunks++) + 0x12;
            else
                count += 2;
            
            do {
                count--;
                *(d++) = *(backReference++ - 1);
            } while( count != 0 );
        } else {
            *(d++) = *(chunks++);
        }
        bitsLeft--;
        bits<<=1;
    } while( d < endOfDest );
    
    return 0;
}