Panel de Pon (SFC)/Compression

Code to decompress data.

````
/*
 * Data decompression algorithm
 * Honestly, data compression isn't my expertise so I don't fully understand how
 * this even works. You're on your own here, buddy.
 * srcBuffer    Byte buffer to read compressed data from
 * destBuffer   Byte buffer to write decompressed data to
 * srcAddr      Offset within source buffer of the start of the compressed data
 * destAddr     Offset within the destination buffer to start storing data
*/
static void DecompressData(
    u8 *srcBuffer, u8 *destBuffer, u32 srcAddr, u32 destAddr
) {
    // Self-explanatory
    u32 readAddr = srcAddr;
    // Address to continue reading data from after copying a back-reference
    u32 oldAddr;
    // Self-explanatory
    u32 writeAddr = destAddr;
    // Bytes left to copy from a back-reference
    u8 count = 0;

    while ( true )
    {
        ACC_08 = srcBuffer[readAddr++];
        if ( count != 0 && --count == 0 ) readAddr = oldAddr;

        u8 flag = ACC_08 & 0x80;
        ACC_08 <<= 1;

        if ( !flag )
        {
            if ( ACC_08 & 0x80 )
            {
                ACC_08 >>= 1;
                s8 writeCount = ACC_08 & 0x0F;

                if ( ACC_08 >= 0x60 )
                {
                    SwapA();
                    ACC_08 = srcBuffer[readAddr++];
                    if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                    u8 byte = ACC_08;

                    SwapA();

                    if ( ACC_08 < 0x70 )
                    {
                        for ( int i = writeCount + 1; i >= 0; i-- )
                        {
                            ACC_08 = srcBuffer[readAddr++];
                            if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                            destBuffer[writeAddr++] = byte;
                            destBuffer[writeAddr++] = ACC_08;
                        }
                    } else
                    {
                        for ( int i = writeCount + 1; i >= 0; i-- )
                        {
                            ACC_08 = srcBuffer[readAddr++];
                            if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                            destBuffer[writeAddr++] = ACC_08;
                            destBuffer[writeAddr++] = byte;
                        }
                    }
                } else if ( ACC_08 >= 0x50 )
                {
                    for( int i = writeCount; i >= 0; i-- )
                    {
                        ACC_08 = srcBuffer[readAddr++];
                        if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                        destBuffer[writeAddr++] = ACC_08;
                        destBuffer[writeAddr++] = ACC_08;
                    }
                } else
                {
                    ACC_08 = srcBuffer[readAddr++];
                    if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                    if ( ACC_08 & 0x80 )
                    {
                        if ( ACC_08 & 0x40 )
                        {
                            if ( ACC_08 & 0x10 )
                            {
                                destBuffer[writeAddr++] = ( ACC_08 << 4 ) | 0x0F;
                                ACC_08 = 0x1F;
                            } else
                            {
                                destBuffer[writeAddr++] = ( ACC_08 & 0x0F ) | 0xF0;
                                ACC_08 = 0x0F;
                            }
                        } else
                        {
                            if ( ACC_08 & 0x10 )
                            {
                                destBuffer[writeAddr++] = ACC_08 << 4;
                                ACC_08 = 0x10;
                            } else
                            {
                                destBuffer[writeAddr++] = ACC_08 & 0x0F;
                                ACC_08 = 0x00;
                            }
                        }
                    }

                    if ( ACC_08 >= 0x10 )
                    {
                        u8 nybble = ACC_08 & 0x0F;

                        for ( int i = writeCount + 1; i >= 0; i-- )
                        {
                            ACC_08 = srcBuffer[readAddr++];
                            if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                            destBuffer[writeAddr++] = ( ACC_08 & 0xF0 ) | nybble;

                            if ( --i < 0 ) break;

                            destBuffer[writeAddr++] = ( ACC_08 << 4 ) | nybble;
                        }
                    } else
                    {
                        u8 nybble = ACC_08 << 4;

                        for ( int i = writeCount + 1; i >= 0; i-- )
                        {
                            ACC_08 = srcBuffer[readAddr++];
                            if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                            destBuffer[writeAddr++] = ( ACC_08 >> 4 ) | nybble;

                            if ( --i < 0 ) break;

                            destBuffer[writeAddr++] = ( ACC_08 & 0x0F ) | nybble;
                        }
                    }
                }
            } else
            {
                for ( int i = ACC_08 >> 1; i >= 0; i-- )
                {
                    ACC_08 = srcBuffer[readAddr++];
                    if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                    destBuffer[writeAddr++] = ACC_08;
                }
            }
        } else if ( ACC_08 & 0x80 )
        {
            // Restore accumulator
            ACC_08 = ( ACC_08 >> 1 ) | flag;

            if ( ACC_08 < 0xF8 )
            {
                if ( ACC_08 < 0xE0 )
                {
                    ACC_08 &= 0x1F;
                    SwapA();

                    ACC_08 = srcBuffer[readAddr++];
                    if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                    ACC_16 <<= 1;
                    ACC_08 >>= 1;
                    SwapA();
                    s8 writeCount = ACC_08 + 1;
                    ACC_08 = srcBuffer[readAddr++];

                    u16 refAddr = writeAddr - ACC_16;

                    for ( int i = writeCount; i >= 0; i-- )
                        destBuffer[writeAddr++] = destBuffer[refAddr++];
                } else if ( ACC_08 < 0xF0 )
                {
                    destBuffer[0x80] = ACC_08 & 0x0F;
                    destBuffer[0x7F] = srcBuffer[readAddr++];

                    if ( count != 0 && --count == 0 ) readAddr = oldAddr;

                    ACC_08 = srcBuffer[readAddr++];

                    u16 tempCount = *(short*)&destBuffer[0x7F] + 3;

                    for ( int i = tempCount; i != 0; i-- )
                        destBuffer[writeAddr++] = ACC_08;
                } else
                {
                    s8 writeCount = ( ACC_08 & 0x07 ) + 2;
                    ACC_08 = srcBuffer[readAddr++];

                    for ( int i = writeCount; i >= 0; i-- )
                        destBuffer[writeAddr++] = ACC_08;
                }

                if ( count != 0 && --count == 0 ) readAddr = oldAddr;
            } else if ( ACC_08 < 0xFE )
            {
                u16 length;

                if ( ACC_08 < 0xFC )
                {
                    ACC_08 &= 0x03;
                    SwapA();
                    ACC_08 = srcBuffer[readAddr++];
                    ACC_16 <<= 3;
                    ACC_08 >>= 3;
                    SwapA();
                    length = ACC_08;
                    ACC_08 = srcBuffer[readAddr++];
                    ACC_16 += 3;
                } else
                {
                    ACC_08 &= 0x01;
                    SwapA();
                    ACC_08 = srcBuffer[readAddr++];
                    ACC_16 <<= 2;
                    SwapA();
                    length = ACC_08;
                    SwapA();
                    ACC_08 >>= 2;
                    ACC_16 = ( ACC_16 & 0x003F ) + 2;
                }
                oldAddr = readAddr;
                readAddr -= ACC_16;
                count = length + 3;
            } else break;
        } else
        {
            ACC_08 >>= 1;
            s8 writeCount = ( ACC_08 >> 2 ) + 1;
            ACC_08 &= 0x03;
            SwapA();

            ACC_08 = srcBuffer[readAddr++];

            u16 refAddr = writeAddr - ACC_16;

            for ( int i = writeCount; i >= 0; i-- )
                destBuffer[writeAddr++] = destBuffer[refAddr++];

            if ( count != 0 && --count == 0 ) readAddr = oldAddr;
        }
    }
    compressedSize = readAddr - srcAddr;
    decompressedSize = writeAddr - destAddr;
}

````