Compression restructure

This commit is contained in:
krrios 2006-09-23 03:25:29 +00:00
parent 93f6301be8
commit ab636feb59
2 changed files with 85 additions and 60 deletions

View file

@ -27,7 +27,7 @@ namespace Server.Network {
/// Handles outgoing packet compression for the network. /// Handles outgoing packet compression for the network.
/// </summary> /// </summary>
public class Compression { public class Compression {
private static int[] m_Table = new int[514] private static int[] _huffmanTable = new int[514]
{ {
0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032, 0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032,
0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057, 0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057,
@ -64,91 +64,113 @@ namespace Server.Network {
0x4, 0x00D 0x4, 0x00D
}; };
private const int CountIndex = 0;
private const int ValueIndex = 1;
// UO packets may not exceed 64kb in length // UO packets may not exceed 64kb in length
private const int BufferSize = 0x10000; private const int BufferSize = 0x10000;
// Optimal compression ratio is 2 / 8. // Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8
private const int MinimalCodeLength = 2; private const int MinimalCodeLength = 2;
private const int MaximalCodeLength = 11;
// If our input exceeds this length, we cannot possibly compress it in // Fixed overhead, in bits, per compression call
private const int EarlyOverflow = ( BufferSize * 8 ) / MinimalCodeLength; private const int TerminalCodeLength = 4;
private static byte[] m_OutputBuffer = new byte[BufferSize]; // If our input exceeds this length, we cannot possibly compress it within the buffer
private static object m_SyncRoot = new object(); private const int DefiniteOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MinimalCodeLength;
public unsafe static void Compress( byte[] input, int length, out byte[] output, out int outputLength ) { // If our input exceeds this length, we may potentially overflow the buffer
if ( length >= EarlyOverflow ) { private const int PossibleOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MaximalCodeLength;
output = null;
outputLength = length; private static object _syncRoot = new object();
return;
private static byte[] _outputBuffer = new byte[BufferSize];
[Obsolete( "Use Compress( byte[], int, int, ref int ) instead.", false )]
public static void Compress( byte[] input, int length, out byte[] output, out int outputLength ) {
outputLength = 0;
output = Compress( input, 0, length, ref outputLength );
}
public unsafe static byte[] Compress( byte[] input, int offset, int count, ref int length ) {
if ( input == null ) {
throw new ArgumentNullException( "input" );
} else if ( offset < 0 || offset >= input.Length ) {
throw new ArgumentOutOfRangeException( "offset" );
} else if ( count < 0 || count > input.Length ) {
throw new ArgumentOutOfRangeException( "count" );
} else if ( ( input.Length - offset ) < count ) {
throw new ArgumentException();
} }
lock ( m_SyncRoot ) { length = 0;
int holdCount = 0;
int holdValue = 0;
int packCount = 0; if ( count > DefiniteOverflow ) {
int packValue = 0; return null;
}
int byteValue = 0; lock ( _syncRoot ) {
int bitCount = 0;
int bitValue = 0;
int inputLength = length; fixed ( int* pTable = _huffmanTable ) {
int inputIndex = 0; int* pEntry;
int outputCount = 0; fixed ( byte* pInputBuffer = input ) {
byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count;
fixed ( int* pTable = m_Table ) { fixed ( byte* pOutputBuffer = _outputBuffer ) {
fixed ( byte* pOutputBuffer = m_OutputBuffer ) { byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize;
while ( inputIndex < inputLength ) {
byteValue = input[inputIndex++] << 1;
packCount = pTable[byteValue]; while ( pInput < pInputEnd ) {
packValue = pTable[byteValue | 1]; pEntry = &pTable[*pInput++ << 1];
holdValue <<= packCount; bitCount += pEntry[CountIndex];
holdValue |= packValue;
holdCount += packCount;
if ( ( outputCount + ( holdCount / 8 ) ) >= BufferSize ) { bitValue <<= pEntry[CountIndex];
output = null; bitValue |= pEntry[ValueIndex];
outputLength = length;
return; while ( bitCount >= 8 ) {
bitCount -= 8;
if ( pOutput < pOutputEnd ) {
*pOutput++ = ( byte ) ( bitValue >> bitCount );
} else {
return null;
}
}
} }
while ( holdCount >= 8 ) { // terminal code
holdCount -= 8; pEntry = &pTable[0x200];
pOutputBuffer[outputCount++] = ( byte ) ( holdValue >> holdCount ); bitCount += pEntry[CountIndex];
bitValue <<= pEntry[CountIndex];
bitValue |= pEntry[ValueIndex];
// align on byte boundary
if ( ( bitCount & 7 ) != 0 ) {
bitValue <<= ( 8 - ( bitCount & 7 ) );
bitCount += ( 8 - ( bitCount & 7 ) );
} }
}
packCount = pTable[0x200]; while ( bitCount >= 8 ) {
packValue = pTable[0x201]; bitCount -= 8;
holdValue <<= packCount; if ( pOutput < pOutputEnd ) {
holdValue |= packValue; *pOutput++ = ( byte ) ( bitValue >> bitCount );
holdCount += packCount; } else {
return null;
}
}
if ( ( outputCount + ( ( holdCount + 7 ) / 8 ) ) >= BufferSize ) { length = ( int ) ( pOutput - pOutputBuffer );
output = null; return _outputBuffer;
outputLength = length;
return;
}
while ( holdCount >= 8 ) {
holdCount -= 8;
pOutputBuffer[outputCount++] = ( byte ) ( holdValue >> holdCount );
}
if ( holdCount > 0 ) {
pOutputBuffer[outputCount++] = ( byte ) ( holdValue << ( 8 - holdCount ) );
} }
} }
} }
output = m_OutputBuffer;
outputLength = outputCount;
} }
} }

View file

@ -3646,7 +3646,10 @@ namespace Server.Network
if ( compress ) if ( compress )
{ {
Compression.Compress( m_CompiledBuffer, length, out m_CompiledBuffer, out length ); m_CompiledBuffer = Compression.Compress(
m_CompiledBuffer, 0, length,
ref length
);
if ( m_CompiledBuffer == null ) if ( m_CompiledBuffer == null )
{ {