Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[C#] MPPC packer

Newbie Spellweaver
Joined
Jul 19, 2016
Messages
25
Reaction score
25
Code:
using System;
using System.Linq;

namespace MPPC
{
    class MPPCPacker
    {
        private const int BLOCK_SIZE = 0x2000;

        private readonly byte[] history;
        private readonly ushort[] hash;
        private int histoff;
        private int legacy_in;

        public MPPCPacker()
        {
            history = new byte[BLOCK_SIZE];
            hash = new ushort[BLOCK_SIZE];
            histoff = 0;
            legacy_in = 0;
        }

        public byte[] Final(byte[] input)
        {
            byte[] ret;
            if (input.Length > 0 || legacy_in > 0)
            {
                ret = new byte[(9 * (legacy_in + input.Length) >> 3) + 6];
                BitStream outbits = Update(input, ret);
                CompressBlock(outbits, legacy_in);
                ret = ret.Take(outbits.Offset >> 3).ToArray();
            }
            else
            {
                ret = input;
            }
            return ret;
        }

        private BitStream Update(byte[] input, byte[] output)
        {
            int remain = BLOCK_SIZE - histoff - legacy_in;
            int isize = input.Length;
            int ioffset = 0;
            BitStream ostream = new BitStream(output);
            if (isize >= remain)
            {
                Buffer.BlockCopy(input, 0, history, histoff + legacy_in, remain);
                isize -= remain;
                ioffset += remain;
                CompressBlock(ostream, remain + legacy_in);
                histoff = 0;
                while (isize >= BLOCK_SIZE)
                {
                    Buffer.BlockCopy(input, ioffset, history, 0, BLOCK_SIZE);
                    CompressBlock(ostream, BLOCK_SIZE);
                    histoff = 0;
                    isize -= BLOCK_SIZE;
                    ioffset += BLOCK_SIZE;
                }
            }
            Buffer.BlockCopy(input, ioffset, history, histoff + legacy_in, isize);
            legacy_in += isize;
            return ostream;
        }

        private void CompressBlock(BitStream stream, int size)
        {
            int r = histoff + size;
            int s = histoff;
            while (r - s > 2)
            {
                int p = GetPredecitAddr(s);
                if (p < s)
                {
                    if (history[p++] == history[s++] && history[p++] == history[s])
                    {
                        if (history[p++] == history[++s])
                        {
                            for (++s; s < r && history[p] == history[s]; ++s) ++p;
                            int len = s - histoff;
                            histoff = s;
                            PutOff(stream, s - p);
                            int val = 0, n = 1;
                            if (len > 3)
                            {
                                int high = GetHighestBit(len);
                                val = len & (1 << high) - 1 | ((1 << (high - 1)) - 1) << high + 1;
                                n = high << 1;
                            }
                            PutBits(stream, val, n);
                        }
                        else
                        {
                            PutLit(stream, history[histoff++]);
                            s = histoff;
                        }
                    }
                    else
                    {
                        PutLit(stream, history[histoff++]);
                    }
                }
                else
                {
                    PutLit(stream, history[histoff++]);
                    s = histoff;
                }
            }
            if (r - s == 1 || r - s == 2)
            {
                for (int i = 0; i < r - s; i++)
                    PutLit(stream, history[histoff++]);
            }
            PutOff(stream, 0);
            stream.Pad();
            legacy_in = 0;
        }

        private void PutBits(BitStream bits, int val, int n)
        {
            //mm0 keeps the last byte of the previous write so the value can be properly written with mov dword (old_bits OR new_bits)
            //mm1 keeps byte offset
            //mm2 keeps bit offset
            //mm3 temporary register, used for keeping the calculated val and shifting mm0
            //mm4 is used for getting the final size of the packed array
            //mm5 is used for moding mm2
            bits.WriteBits(val, n);
        }
        private void PutLit(BitStream bits, int c)
        {
            int newc = ((c & 0xFFFF) | ((c & 0x80) << 1)) & 0x17F;
            int n = 8 | ((c & 0x80) >> 7);
            PutBits(bits, newc, n);
        }
        private void PutOff(BitStream bits, int off)
        {
            int newoff = off | 0x3C0;
            int n = 0x0A;
            if (off > 0x3F)
            {
                if (off > 0x13F)
                {
                    newoff = (off - 0x140) | 0xC000;
                    n = 0x10;
                }
                else
                {
                    newoff = (off - 0x40) | 0xE00;
                    n = 0x0C;
                }
            }
            PutBits(bits, newoff, n);
        }
        private int GetPredecitAddr(int offset)
        {
            int index = (0x9E5F * (history[offset + 2] ^ 16 * (history[offset + 1] ^ 16 * history[offset])) >> 4) & 0x1FFF;
            int ret = hash[index];
            hash[index] = (ushort)offset;
            return ret;
        }

        private int GetHighestBit(int val)
        {
            int ret = 31;
            while ((val & 1 << ret) == 0) ret--;
            return ret;
        }
    }

    class BitStream
    {
        private readonly byte[] buffer;
        public int Offset { get; private set; }

        public BitStream(byte[] buf)
        {
            buffer = buf;
            Offset = 0;
        }

        public void WriteBits(int val, int n)
        {
            int off = Offset & 7;
            int idx = Offset >> 3;
            uint v = (uint)((ulong)val << 32 - n - off) | (uint)buffer[idx] << 24;
            for (int i = 0; i < 4; i++)
                buffer[idx + i] = (byte)(v >> 24 - (i << 3) & 0xFF);
            Offset += n;
        }
        public void Pad()
        {
            int pad_length = (8 - (Offset & 7)) & 7;
            if (pad_length > 0)
                WriteBits(0, pad_length);
        }
    }
}
 
Back
Top