mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 04:11:53 +00:00
9ae7e2621d
Lots of changes. CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit. Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit. Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
810 lines
15 KiB
C
810 lines
15 KiB
C
/*
|
|
Q3Fusion - Quake III Clone Engine
|
|
|
|
Copyright (C) 2003 Andrey Nazarov
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
//
|
|
// huff.c - Huffman compression routines for data bitstream
|
|
//
|
|
#include "quakedef.h"
|
|
#ifdef HUFFNETWORK
|
|
#define ID_INLINE
|
|
|
|
#define VALUE(a) (*(int *)&(a))
|
|
#define NODE(a) ((void*)(a))
|
|
|
|
#define NODE_START NODE( 1)
|
|
#define NODE_NONE NODE(256)
|
|
#define NODE_NEXT NODE(257)
|
|
|
|
#define NOT_REFERENCED 256
|
|
|
|
#define HUFF_TREE_SIZE 7175
|
|
typedef void *tree_t[HUFF_TREE_SIZE];
|
|
|
|
//
|
|
// pre-defined frequency counts for all bytes [0..255]
|
|
//
|
|
static int q3huffCounts[256] = {
|
|
0x3D1CB, 0x0A0E9, 0x01894, 0x01BC2, 0x00E92, 0x00EA6, 0x017DE, 0x05AF3,
|
|
0x08225, 0x01B26, 0x01E9E, 0x025F2, 0x02429, 0x0436B, 0x00F6D, 0x006F2,
|
|
0x02060, 0x00644, 0x00636, 0x0067F, 0x0044C, 0x004BD, 0x004D6, 0x0046E,
|
|
0x006D5, 0x00423, 0x004DE, 0x0047D, 0x004F9, 0x01186, 0x00AF5, 0x00D90,
|
|
0x0553B, 0x00487, 0x00686, 0x0042A, 0x00413, 0x003F4, 0x0041D, 0x0042E,
|
|
0x006BE, 0x00378, 0x0049C, 0x00352, 0x003C0, 0x0030C, 0x006D8, 0x00CE0,
|
|
0x02986, 0x011A2, 0x016F9, 0x00A7D, 0x0122A, 0x00EFD, 0x0082D, 0x0074B,
|
|
0x00A18, 0x0079D, 0x007B4, 0x003AC, 0x0046E, 0x006FC, 0x00686, 0x004B6,
|
|
0x01657, 0x017F0, 0x01C36, 0x019FE, 0x00E7E, 0x00ED3, 0x005D4, 0x005F4,
|
|
0x008A7, 0x00474, 0x0054B, 0x003CB, 0x00884, 0x004E0, 0x00530, 0x004AB,
|
|
0x006EA, 0x00436, 0x004F0, 0x004F2, 0x00490, 0x003C5, 0x00483, 0x004A2,
|
|
0x00543, 0x004CC, 0x005F9, 0x00640, 0x00A39, 0x00800, 0x009F2, 0x00CCB,
|
|
0x0096A, 0x00E01, 0x009C8, 0x00AF0, 0x00A73, 0x01802, 0x00E4F, 0x00B18,
|
|
0x037AD, 0x00C5C, 0x008AD, 0x00697, 0x00C88, 0x00AB3, 0x00DB8, 0x012BC,
|
|
0x00FFB, 0x00DBB, 0x014A8, 0x00FB0, 0x01F01, 0x0178F, 0x014F0, 0x00F54,
|
|
0x0131C, 0x00E9F, 0x011D6, 0x012C7, 0x016DC, 0x01900, 0x01851, 0x02063,
|
|
0x05ACB, 0x01E9E, 0x01BA1, 0x022E7, 0x0153D, 0x01183, 0x00E39, 0x01488,
|
|
0x014C0, 0x014D0, 0x014FA, 0x00DA4, 0x0099A, 0x0069E, 0x0071D, 0x00849,
|
|
0x0077C, 0x0047D, 0x005EC, 0x00557, 0x004D4, 0x00405, 0x004EA, 0x00450,
|
|
0x004DD, 0x003EE, 0x0047D, 0x00401, 0x004D9, 0x003B8, 0x00507, 0x003E5,
|
|
0x006B1, 0x003F1, 0x004A3, 0x0036F, 0x0044B, 0x003A1, 0x00436, 0x003B7,
|
|
0x00678, 0x003A2, 0x00481, 0x00406, 0x004EE, 0x00426, 0x004BE, 0x00424,
|
|
0x00655, 0x003A2, 0x00452, 0x00390, 0x0040A, 0x0037C, 0x00486, 0x003DE,
|
|
0x00497, 0x00352, 0x00461, 0x00387, 0x0043F, 0x00398, 0x00478, 0x00420,
|
|
0x00D86, 0x008C0, 0x0112D, 0x02F68, 0x01E4E, 0x00541, 0x0051B, 0x00CCE,
|
|
0x0079E, 0x00376, 0x003FF, 0x00458, 0x00435, 0x00412, 0x00425, 0x0042F,
|
|
0x005CC, 0x003E9, 0x00448, 0x00393, 0x0041C, 0x003E3, 0x0042E, 0x0036C,
|
|
0x00457, 0x00353, 0x00423, 0x00325, 0x00458, 0x0039B, 0x0044F, 0x00331,
|
|
0x0076B, 0x00750, 0x003D0, 0x00349, 0x00467, 0x003BC, 0x00487, 0x003B6,
|
|
0x01E6F, 0x003BA, 0x00509, 0x003A5, 0x00467, 0x00C87, 0x003FC, 0x0039F,
|
|
0x0054B, 0x00300, 0x00410, 0x002E9, 0x003B8, 0x00325, 0x00431, 0x002E4,
|
|
0x003F5, 0x00325, 0x003F0, 0x0031C, 0x003E4, 0x00421, 0x02CC1, 0x034C0
|
|
};
|
|
|
|
static int countinghuffCounts[256];
|
|
|
|
|
|
//
|
|
// static Huffman tree
|
|
//
|
|
static tree_t huffTree;
|
|
|
|
//
|
|
// received from MSG_* code
|
|
//
|
|
static int huffBitPos;
|
|
|
|
|
|
/*
|
|
=======================================================================================
|
|
|
|
HUFFMAN TREE CONSTRUCTION
|
|
|
|
=======================================================================================
|
|
*/
|
|
|
|
/*
|
|
============
|
|
Huff_PrepareTree
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_PrepareTree( tree_t tree ) {
|
|
void **node;
|
|
|
|
memset( tree, 0, sizeof( tree_t ) );
|
|
|
|
// create first node
|
|
node = &tree[263];
|
|
tree[0] = (void*)(VALUE( tree[0] )+1);
|
|
|
|
node[7] = NODE_NONE;
|
|
tree[2] = node;
|
|
tree[3] = node;
|
|
tree[4] = node;
|
|
tree[261] = node;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
============
|
|
Huff_GetNode
|
|
============
|
|
*/
|
|
static ID_INLINE void **Huff_GetNode( void **tree ) {
|
|
void **node;
|
|
int value;
|
|
|
|
node = tree[262];
|
|
if( !node ) {
|
|
value = VALUE( tree[1] )++;
|
|
node = &tree[value + 6407];
|
|
return node;
|
|
}
|
|
|
|
tree[262] = node[0];
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_Swap
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_Swap( void **tree1, void **tree2, void **tree3 ) {
|
|
void **a, **b;
|
|
|
|
a = tree2[2];
|
|
if( a ) {
|
|
if( a[0] == tree2 ) {
|
|
a[0] = tree3;
|
|
} else {
|
|
a[1] = tree3;
|
|
}
|
|
} else {
|
|
tree1[2] = tree3;
|
|
}
|
|
|
|
b = tree3[2];
|
|
|
|
if( b ) {
|
|
if( b[0] == tree3 ) {
|
|
b[0] = tree2;
|
|
tree2[2] = b;
|
|
tree3[2] = a;
|
|
return;
|
|
}
|
|
|
|
b[1] = tree2;
|
|
tree2[2] = b;
|
|
tree3[2] = a;
|
|
return;
|
|
}
|
|
|
|
tree1[2] = tree2;
|
|
tree2[2] = NULL;
|
|
tree3[2] = a;
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_SwapTrees
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_SwapTrees( void **tree1, void **tree2 ) {
|
|
void **temp;
|
|
|
|
temp = tree1[3];
|
|
tree1[3] = tree2[3];
|
|
tree2[3] = temp;
|
|
|
|
temp = tree1[4];
|
|
tree1[4] = tree2[4];
|
|
tree2[4] = temp;
|
|
|
|
if( tree1[3] == tree1 ) {
|
|
tree1[3] = tree2;
|
|
}
|
|
|
|
if( tree2[3] == tree2 ) {
|
|
tree2[3] = tree1;
|
|
}
|
|
|
|
temp = tree1[3];
|
|
if( temp ) {
|
|
temp[4] = tree1;
|
|
}
|
|
|
|
temp = tree2[3];
|
|
if( temp ) {
|
|
temp[4] = tree2;
|
|
}
|
|
|
|
temp = tree1[4];
|
|
if( temp ) {
|
|
temp[3] = tree1;
|
|
}
|
|
|
|
temp = tree2[4];
|
|
if( temp ) {
|
|
temp[3] = tree2;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_DeleteNode
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_DeleteNode( void **tree1, void **tree2 ) {
|
|
tree2[0] = tree1[262];
|
|
tree1[262] = tree2;
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_IncrementFreq_r
|
|
============
|
|
*/
|
|
static void Huff_IncrementFreq_r( void **tree1, void **tree2 ) {
|
|
void **a, **b;
|
|
|
|
if( !tree2 ) {
|
|
return;
|
|
}
|
|
|
|
a = tree2[3];
|
|
if( a ) {
|
|
a = a[6];
|
|
if( a == tree2[6] ) {
|
|
b = tree2[5];
|
|
if( b[0] != tree2[2] ) {
|
|
Huff_Swap( tree1, b[0], tree2 );
|
|
}
|
|
Huff_SwapTrees( b[0], tree2 );
|
|
}
|
|
}
|
|
|
|
a = tree2[4];
|
|
if( a && a[6] == tree2[6] ) {
|
|
b = tree2[5];
|
|
b[0] = a;
|
|
} else {
|
|
a = tree2[5];
|
|
a[0] = 0;
|
|
Huff_DeleteNode( tree1, tree2[5] );
|
|
}
|
|
|
|
|
|
VALUE( tree2[6] )++;
|
|
a = tree2[3];
|
|
if( a && a[6] == tree2[6] ) {
|
|
tree2[5] = a[5];
|
|
} else {
|
|
a = Huff_GetNode( tree1 );
|
|
tree2[5] = a;
|
|
a[0] = tree2;
|
|
}
|
|
|
|
if( tree2[2] ) {
|
|
Huff_IncrementFreq_r( tree1, tree2[2] );
|
|
|
|
if( tree2[4] == tree2[2] ) {
|
|
Huff_SwapTrees( tree2, tree2[2] );
|
|
a = tree2[5];
|
|
|
|
if( a[0] == tree2 ) {
|
|
a[0] = tree2[2];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_AddReference
|
|
|
|
Insert 'ch' into the tree or increment it's frequency
|
|
============
|
|
*/
|
|
static void Huff_AddReference( void **tree, int ch ) {
|
|
void **a, **b, **c, **d;
|
|
int value;
|
|
|
|
ch &= 255;
|
|
if( tree[ch + 5] ) {
|
|
Huff_IncrementFreq_r( tree, tree[ch + 5] );
|
|
return; // already added
|
|
}
|
|
|
|
value = VALUE( tree[0] )++;
|
|
b = &tree[value * 8 + 263];
|
|
|
|
value = VALUE( tree[0] )++;
|
|
a = &tree[value * 8 + 263];
|
|
|
|
a[7] = NODE_NEXT;
|
|
a[6] = NODE_START;
|
|
d = tree[3];
|
|
a[3] = d[3];
|
|
if( a[3] ) {
|
|
d = a[3];
|
|
d[4] = a;
|
|
d = a[3];
|
|
if( d[6] == NODE_START ) {
|
|
a[5] = d[5];
|
|
} else {
|
|
d = Huff_GetNode( tree );
|
|
a[5] = d;
|
|
d[0] = a;
|
|
}
|
|
} else {
|
|
d = Huff_GetNode( tree );
|
|
a[5] = d;
|
|
d[0] = a;
|
|
|
|
}
|
|
|
|
d = tree[3];
|
|
d[3] = a;
|
|
a[4] = tree[3];
|
|
b[7] = NODE( ch );
|
|
b[6] = NODE_START;
|
|
d = tree[3];
|
|
b[3] = d[3];
|
|
if( b[3] ) {
|
|
d = b[3];
|
|
d[4] = b;
|
|
if( d[6] == NODE_START ) {
|
|
b[5] = d[5];
|
|
} else {
|
|
d = Huff_GetNode( tree );
|
|
b[5] = d;
|
|
d[0] = a;
|
|
}
|
|
} else {
|
|
d = Huff_GetNode( tree );
|
|
b[5] = d;
|
|
d[0] = b;
|
|
}
|
|
|
|
d = tree[3];
|
|
d[3] = b;
|
|
b[4] = tree[3];
|
|
b[1] = NULL;
|
|
b[0] = NULL;
|
|
d = tree[3];
|
|
c = d[2];
|
|
if( c ) {
|
|
if( c[0] == tree[3] ) {
|
|
c[0] = a;
|
|
} else {
|
|
c[1] = a;
|
|
}
|
|
} else {
|
|
tree[2] = a;
|
|
}
|
|
|
|
a[1] = b;
|
|
d = tree[3];
|
|
a[0] = d;
|
|
a[2] = d[2];
|
|
b[2] = a;
|
|
d = tree[3];
|
|
d[2] = a;
|
|
tree[ch + 5] = b;
|
|
|
|
Huff_IncrementFreq_r( tree, a[2] );
|
|
}
|
|
|
|
/*
|
|
=======================================================================================
|
|
|
|
BITSTREAM I/O
|
|
|
|
=======================================================================================
|
|
*/
|
|
|
|
/*
|
|
============
|
|
Huff_EmitBit
|
|
|
|
Put one bit into buffer
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_EmitBit( int bit, qbyte *buffer ) {
|
|
if( !(huffBitPos & 7) ) {
|
|
buffer[huffBitPos >> 3] = 0;
|
|
}
|
|
|
|
buffer[huffBitPos >> 3] |= bit << (huffBitPos & 7);
|
|
huffBitPos++;
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_GetBit
|
|
|
|
Read one bit from buffer
|
|
============
|
|
*/
|
|
static ID_INLINE int Huff_GetBit( qbyte *buffer ) {
|
|
int bit;
|
|
|
|
bit = buffer[huffBitPos >> 3] >> (huffBitPos & 7);
|
|
huffBitPos++;
|
|
|
|
return (bit & 1);
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_EmitPathToByte
|
|
============
|
|
*/
|
|
static ID_INLINE void Huff_EmitPathToByte( void **tree, void **subtree, qbyte *buffer ) {
|
|
if( tree[2] ) {
|
|
Huff_EmitPathToByte( tree[2], tree, buffer );
|
|
}
|
|
|
|
if( !subtree ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// emit tree walking control bits
|
|
//
|
|
if( tree[1] == subtree ) {
|
|
Huff_EmitBit( 1, buffer );
|
|
} else {
|
|
Huff_EmitBit( 0, buffer );
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_GetByteFromTree
|
|
|
|
Get one qbyte using dynamic or static tree
|
|
============
|
|
*/
|
|
static ID_INLINE int Huff_GetByteFromTree( void **tree, qbyte *buffer ) {
|
|
if( !tree ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// walk through the tree until we get a value
|
|
//
|
|
while( tree[7] == NODE_NEXT ) {
|
|
if( !Huff_GetBit( buffer ) ) {
|
|
tree = tree[0];
|
|
} else {
|
|
tree = tree[1];
|
|
}
|
|
|
|
if( !tree ) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return VALUE( tree[7] );
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_EmitByteDynamic
|
|
|
|
Emit one qbyte using dynamic tree
|
|
============
|
|
*/
|
|
static void Huff_EmitByteDynamic( void **tree, int value, qbyte *buffer ) {
|
|
void **subtree;
|
|
int i;
|
|
|
|
//
|
|
// if qbyte was already referenced, emit path to it
|
|
//
|
|
subtree = tree[value + 5];
|
|
if( subtree ) {
|
|
if( subtree[2] ) {
|
|
Huff_EmitPathToByte( subtree[2], subtree, buffer );
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// qbyte was not referenced, just emit 8 bits
|
|
//
|
|
Huff_EmitByteDynamic( tree, NOT_REFERENCED, buffer );
|
|
|
|
for( i=7 ; i>=0 ; i-- ) {
|
|
Huff_EmitBit( (value >> i) & 1, buffer );
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
=======================================================================================
|
|
|
|
PUBLIC INTERFACE
|
|
|
|
=======================================================================================
|
|
*/
|
|
|
|
/*
|
|
============
|
|
Huff_CompressPacket
|
|
|
|
Compress message using dynamic Huffman tree,
|
|
beginning from specified offset
|
|
============
|
|
*/
|
|
void Huff_EncryptPacket( sizebuf_t *msg, int offset ) {
|
|
tree_t tree;
|
|
qbyte buffer[MAX_NQMSGLEN];
|
|
qbyte *data;
|
|
int outLen;
|
|
int inLen;
|
|
int i;
|
|
|
|
data = msg->data + offset;
|
|
inLen = msg->cursize - offset;
|
|
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
|
|
return;
|
|
}
|
|
|
|
Huff_PrepareTree( tree );
|
|
|
|
buffer[0] = inLen >> 8;
|
|
buffer[1] = inLen & 0xFF;
|
|
huffBitPos = 16;
|
|
|
|
for( i=0 ; i<inLen ; i++ ) {
|
|
Huff_EmitByteDynamic( tree, data[i], buffer );
|
|
Huff_AddReference( tree, data[i] );
|
|
}
|
|
|
|
outLen = (huffBitPos >> 3) + 1;
|
|
|
|
msg->cursize = offset + outLen;
|
|
memcpy( data, buffer, outLen );
|
|
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_DecompressPacket
|
|
|
|
Decompress message using dynamic Huffman tree,
|
|
beginning from specified offset
|
|
============
|
|
*/
|
|
void Huff_DecryptPacket( sizebuf_t *msg, int offset ) {
|
|
tree_t tree;
|
|
qbyte buffer[MAX_NQMSGLEN];
|
|
qbyte *data;
|
|
int outLen;
|
|
int inLen;
|
|
int i, j;
|
|
int ch;
|
|
|
|
data = msg->data + offset;
|
|
inLen = msg->cursize - offset;
|
|
if( inLen <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
Huff_PrepareTree( tree );
|
|
|
|
outLen = (data[0] << 8) + data[1];
|
|
huffBitPos = 16;
|
|
|
|
if( outLen > msg->maxsize - offset ) {
|
|
outLen = msg->maxsize - offset;
|
|
}
|
|
|
|
for( i=0 ; i<outLen ; i++ ) {
|
|
if( (huffBitPos >> 3) > inLen ) {
|
|
buffer[i] = 0;
|
|
break;
|
|
}
|
|
|
|
ch = Huff_GetByteFromTree( tree[2], data );
|
|
|
|
if( ch == NOT_REFERENCED ) {
|
|
ch = 0; // just read 8 bits
|
|
for( j=0 ; j<8 ; j++ ) {
|
|
ch <<= 1;
|
|
ch |= Huff_GetBit( data );
|
|
}
|
|
}
|
|
|
|
buffer[i] = ch;
|
|
Huff_AddReference( tree, ch );
|
|
}
|
|
|
|
|
|
msg->cursize = offset + outLen;
|
|
memcpy( data, buffer, outLen );
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_EmitByte
|
|
============
|
|
*/
|
|
void Huff_EmitByte( int ch, qbyte *buffer, int *count ) {
|
|
huffBitPos = *count;
|
|
Huff_EmitPathToByte( huffTree[ch + 5], NULL, buffer );
|
|
*count = huffBitPos;
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_GetByte
|
|
============
|
|
*/
|
|
int Huff_GetByte( qbyte *buffer, int *count ) {
|
|
int ch;
|
|
|
|
huffBitPos = *count;
|
|
ch = Huff_GetByteFromTree( huffTree[2], buffer );
|
|
*count = huffBitPos;
|
|
|
|
return ch;
|
|
}
|
|
|
|
static int madetable;
|
|
/*
|
|
============
|
|
Huff_Init
|
|
============
|
|
*/
|
|
void Huff_Init( int *huffCounts ) {
|
|
int i, j;
|
|
|
|
if (!huffCounts)
|
|
huffCounts = q3huffCounts;
|
|
|
|
// build empty tree
|
|
Huff_PrepareTree( huffTree );
|
|
|
|
// add all pre-defined qbyte references
|
|
for( i=0 ; i<256 ; i++ ) {
|
|
for( j=0 ; j<huffCounts[i] ; j++ ) {
|
|
Huff_AddReference( huffTree, i );
|
|
}
|
|
}
|
|
madetable=Com_BlockChecksum(huffCounts, sizeof(huffCounts));
|
|
}
|
|
|
|
void Huff_LoadTable(char *filename)
|
|
{
|
|
}
|
|
|
|
int Huff_PreferedCompressionCRC (void)
|
|
{
|
|
if (!madetable)
|
|
Huff_Init(NULL);
|
|
return madetable;
|
|
}
|
|
|
|
qboolean Huff_CompressionCRC(int crc)
|
|
{
|
|
if (!madetable)
|
|
Huff_Init(NULL);
|
|
if (crc != madetable)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
============
|
|
Huff_CompressPacket
|
|
|
|
Compress message using loaded Huffman tree,
|
|
beginning from specified offset
|
|
============
|
|
*/
|
|
void Huff_CompressPacket( sizebuf_t *msg, int offset )
|
|
{
|
|
qbyte buffer[MAX_NQMSGLEN];
|
|
qbyte *data;
|
|
int outLen;
|
|
int inLen;
|
|
int i;
|
|
|
|
if (!madetable)
|
|
Huff_Init(NULL);
|
|
|
|
data = msg->data + offset;
|
|
inLen = msg->cursize - offset;
|
|
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
|
|
return;
|
|
}
|
|
|
|
outLen = 0;
|
|
for( i=0 ; i<inLen ; i++ )
|
|
{
|
|
if (i == MAX_NQMSGLEN)
|
|
Sys_Error("Compression became too large\n");
|
|
Huff_EmitByte(data[i], buffer, &outLen);
|
|
|
|
countinghuffCounts[data[i]]++;
|
|
}
|
|
|
|
outLen = (huffBitPos >> 3) + 1;
|
|
|
|
if (outLen > inLen)
|
|
{
|
|
memmove( data+1, data, inLen );
|
|
data[0] = 0x80; //this would have grown the packet.
|
|
msg->cursize+=1;
|
|
return; //cap it at only 1 qbyte growth.
|
|
}
|
|
|
|
msg->cursize = offset + outLen;
|
|
{ //add the bitcount
|
|
data[0] = (outLen<<3) - huffBitPos;
|
|
data+=1;
|
|
msg->cursize+=1;
|
|
}
|
|
if (msg->cursize > msg->maxsize)
|
|
Sys_Error("Compression became too large\n");
|
|
memcpy( data, buffer, outLen );
|
|
}
|
|
|
|
/*
|
|
============
|
|
Huff_DecompressPacket
|
|
|
|
Decompress message using loaded Huffman tree,
|
|
beginning from specified offset
|
|
============
|
|
*/
|
|
void Huff_DecompressPacket( sizebuf_t *msg, int offset )
|
|
{
|
|
qbyte buffer[MAX_NQMSGLEN];
|
|
qbyte *data;
|
|
int outLen;
|
|
int inLen;
|
|
int i;
|
|
|
|
if (!madetable)
|
|
Huff_Init(NULL);
|
|
|
|
data = msg->data + offset;
|
|
inLen = msg->cursize - offset;
|
|
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
|
|
return;
|
|
}
|
|
|
|
inLen<<=3;
|
|
{ //add the bitcount
|
|
inLen = inLen-8-data[0];
|
|
if (data[0]&0x80)
|
|
{ //packet would have grown.
|
|
msg->cursize -= 1;
|
|
memmove(data, data+1, msg->cursize);
|
|
return; //this never happened, okay?
|
|
}
|
|
data+=1;
|
|
}
|
|
|
|
outLen = 0;
|
|
for( i=0 ; outLen<inLen ; i++ )
|
|
{
|
|
if (i == MAX_NQMSGLEN)
|
|
Sys_Error("Decompression became too large\n");
|
|
buffer[i] = Huff_GetByte(data, &outLen);
|
|
}
|
|
|
|
msg->cursize = offset + i;
|
|
if (msg->cursize > msg->maxsize)
|
|
Sys_Error("Decompression became too large\n");
|
|
memcpy( msg->data + offset, buffer, i );
|
|
}
|
|
|
|
#endif
|