using System;
using System.IO;
namespace Dwg2000Reader
{
internal static class R2004Compression
{
public static unsafe void Compress(byte* source, int index, int length, Stream dest)
{
// TODO
byte*[] historyBuffer
= new byte*[0x8000
];
byte* startPtr = source + index;
byte* endPtr = startPtr + length;
byte* tempPtr = startPtr;
byte* lookAheadBuffer = startPtr + 4;
int length_ = 0;
int offset = 0;
int matchLength = 0;
int matchOffset = 0;
int literalLength;
while (lookAheadBuffer < (endPtr - 0x13))
{
if (!FindMatch(historyBuffer, lookAheadBuffer, startPtr, endPtr, ref matchLength, ref matchOffset))
{
lookAheadBuffer++;
}
else
{
literalLength = (int)(lookAheadBuffer - tempPtr);
if (length_ != 0)
WriteCompressed(offset, length_, literalLength, dest);
WriteLiteral(tempPtr, literalLength, dest);
lookAheadBuffer += matchLength;
tempPtr = lookAheadBuffer;
length_ = matchLength;
offset = matchOffset;
}
}
literalLength = (int)(endPtr - tempPtr);
if (length_ != 0)
WriteCompressed(offset, length_, literalLength, dest);
WriteLiteral(tempPtr, literalLength, dest);
dest.WriteByte(0x11);
dest.WriteByte(0);
dest.WriteByte(0);
}
public static unsafe void Compress(byte[] source, int index, int length, Stream dest)
{
fixed (byte* dataPtr = source)
Compress(dataPtr, 0, source.Length, dest);
}
public static void Compress(byte[] source, Stream dest)
{
Compress(source, 0, source.Length, dest);
}
private static unsafe bool FindMatch(byte*[] historyBuffer, byte* lookAheadBuffer, byte* startPtr, byte* endPtr, ref int matchLength, ref int matchOffset)
{
matchLength = 0;
byte num = lookAheadBuffer[0];
byte num2 = lookAheadBuffer[1];
byte num3 = lookAheadBuffer[2];
byte num4 = lookAheadBuffer[3];
int index = (((((num4 << 6) ^ num3) << 5) ^ num2) << 5) ^ num;
index += index >> 5;
index &= 0x7fff;
byte* wordPtr = historyBuffer[index];
matchOffset = (int)(lookAheadBuffer - wordPtr);
if ((wordPtr >= startPtr) && (matchOffset <= 0xbfff))
{
if ((matchOffset > 0x400) && (num4 != wordPtr[3]))
{
index &= 0x7ff;
index ^= 0x401f;
wordPtr = historyBuffer[index];
matchOffset = (int)(lookAheadBuffer - wordPtr);
if (((wordPtr < startPtr) || (matchOffset > 0xbfff)) || ((matchOffset > 0x400) && (num4 != wordPtr[3])))
{
historyBuffer[index] = lookAheadBuffer;
return false;
}
}
if (((num == wordPtr[0]) && (num2 == wordPtr[1])) && (num3 == wordPtr[2]))
{
matchLength = 3;
byte* numPtr = wordPtr + 3;
byte* numPtr2 = lookAheadBuffer + 3;
while (numPtr2 < endPtr)
{
numPtr++;
numPtr2++;
if (numPtr != numPtr2)
break;
matchLength++;
}
}
}
historyBuffer[index] = lookAheadBuffer;
return (matchLength >= 3);
}
private static void WriteCompressed(int offset, int length, int literalLength, Stream dest)
{
int num;
int num2;
if ((length < 0xf) && (offset <= 0x400))
{
offset--;
num = ((length + 1) << 4) | ((offset & 3) << 2);
num2 = offset >> 2;
}
else
{
if (offset <= 0x4000)
{
offset--;
WriteOpcode(0x20, length, 0x21, dest);
}
else
{
offset -= 0x4000;
WriteOpcode(0x10 | ((offset >> 11) & 8), length, 9, dest);
}
num = (offset & 0xff) << 2;
num2 = offset >> 6;
}
if (literalLength < 4)
num |= literalLength;
dest.WriteByte((byte)num);
dest.WriteByte((byte)num2);
}
private static unsafe void WriteLiteral(byte* source, int literalLength, Stream dest)
{
if (literalLength > 0)
{
if (literalLength > 3)
WriteOpcode(0, literalLength - 1, 0x11, dest);
byte* ptr = source;
for (int i = 0; i < literalLength; i++)
{
dest.WriteByte(*ptr);
ptr++;
}
}
}
private static void WriteOpcode(int opcode, int length, int threshold, Stream dest)
{
if (length <= threshold)
{
opcode |= length - 2;
dest.WriteByte((byte)opcode);
}
else
{
dest.WriteByte((byte)opcode);
int value = length - threshold;
while (value > 0xff)
{
value -= 0xff;
dest.WriteByte(0);
}
dest.WriteByte((byte)value);
}
}
}
}