|
Odamex
Setting the Standard in Multiplayer Doom
|
00001 // Emacs style mode select -*- C++ -*- 00002 //----------------------------------------------------------------------------- 00003 // 00004 // $Id: huffman.h 1788 2010-08-24 04:42:57Z russellrice $ 00005 // 00006 // Copyright (C) 2006-2010 by The Odamex Team. 00007 // 00008 // This program is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU General Public License 00010 // as published by the Free Software Foundation; either version 2 00011 // of the License, or (at your option) any later version. 00012 // 00013 // This program is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 // GNU General Public License for more details. 00017 // 00018 // DESCRIPTION: 00019 // The idea here is to use huffman coding without having to send 00020 // the huffman tree explicitly across the network. 00021 // 00022 // * For each packet, the client sends an ACK 00023 // * For each ACK the server gets back, both client and server have a 00024 // copy of the packet 00025 // * Statistically over time, packets contain similar data 00026 // 00027 // Therefore: 00028 // -> Client and server can build huffman trees using past packet data 00029 // -> Client and server can use this tree to compress new data 00030 // 00031 //----------------------------------------------------------------------------- 00032 00033 00034 #ifndef __C_HUFFMAN_H__ 00035 #define __C_HUFFMAN_H__ 00036 00037 #include <iostream> 00038 #include <cstring> 00039 00040 class huffman 00041 { 00042 // Structures 00043 struct huff_bitstream_t 00044 { 00045 unsigned char *BytePtr; 00046 unsigned int BitPos; 00047 }; 00048 00049 struct huff_sym_t 00050 { 00051 int Symbol; 00052 unsigned int Count; 00053 unsigned int Code; 00054 unsigned int Bits; 00055 }; 00056 00057 struct huff_encodenode_t 00058 { 00059 huff_encodenode_t *ChildA, *ChildB; 00060 int Count; 00061 int Symbol; 00062 }; 00063 00064 // Histogram of character frequency 00065 huff_sym_t sym[256]; 00066 unsigned int total_count; 00067 00068 // Flag to indicate that tree needs rebuilding 00069 bool fresh_histogram; 00070 00071 // Tree generated from the histogram 00072 /* The maximum number of nodes in the Huffman tree is 2^(8+1)-1 = 511 */ 00073 huff_encodenode_t nodes[511]; 00074 huff_encodenode_t *root; 00075 00076 void _Huffman_InitBitstream( huff_bitstream_t *stream, unsigned char *buf ); 00077 unsigned int _Huffman_ReadBit( huff_bitstream_t *stream ); 00078 unsigned int _Huffman_Read8Bits( huff_bitstream_t *stream ); 00079 void _Huffman_WriteBits( huff_bitstream_t *stream, unsigned int x, unsigned int bits ); 00080 void _Huffman_Hist( unsigned char *in, huff_sym_t *sym, unsigned int size ); 00081 huff_encodenode_t *_Huffman_MakeTree( huff_sym_t *sym, huff_encodenode_t *nodes); 00082 void _Huffman_StoreTree( huff_encodenode_t *node, huff_sym_t *sym, unsigned int code, unsigned int bits ); 00083 00084 bool Huffman_Compress_Using_Histogram( unsigned char *in, size_t insize, unsigned char *out, size_t &outsize, huff_sym_t *sym ); 00085 bool Huffman_Uncompress_Using_Tree( unsigned char *in, size_t insize, unsigned char *out, size_t &outsize, huff_encodenode_t *tree_root ); 00086 00087 public: 00088 00089 // Clear statistics 00090 void reset(); 00091 00092 // Analyse some raw data and add it to the compression statistics 00093 void extend( unsigned char *data, size_t len); 00094 00095 // Compress a chunk of data using only previously generated stats 00096 bool compress( unsigned char *in_data, size_t in_len, unsigned char *out_data, size_t &out_len); 00097 00098 // Decompress a chunk of data using only previously generated stats 00099 bool decompress( unsigned char *in_data, size_t in_len, unsigned char *out_data, size_t &out_len); 00100 00101 // For debugging, this count can be used to see if two codecs have had the same length input 00102 int get_count() { return total_count; } 00103 00104 // Constructor 00105 huffman(); 00106 00107 // Copying invalidates all tree pointers 00108 huffman(const huffman &other) : total_count(other.total_count), fresh_histogram(true) 00109 { 00110 memcpy(sym, other.sym, sizeof(sym)); 00111 } 00112 }; 00113 00114 #define HUFFMAN_RENEGOTIATE_DELAY 256 00115 00116 class huffman_server 00117 { 00118 huffman alpha, beta, tmpcodec; 00119 bool active_codec; 00120 00121 unsigned int last_packet_id, last_ack_id; 00122 00123 unsigned int missed_acks; 00124 00125 bool awaiting_ack; 00126 00127 public: 00128 00129 huffman &get_codec() { return active_codec ? alpha : beta; } 00130 unsigned char get_codec_id() { return active_codec ? 1 : 0; } 00131 00132 bool packet_sent(unsigned int id, unsigned char *in_data, size_t len); 00133 void packet_acked(unsigned int id); 00134 00135 huffman_server() : active_codec(0), last_packet_id(0), last_ack_id(0), 00136 missed_acks(0), awaiting_ack(false) 00137 {} 00138 huffman_server(const huffman_server &other) : 00139 alpha(other.alpha), 00140 beta(other.beta), 00141 tmpcodec(other.tmpcodec), 00142 active_codec(other.active_codec), 00143 last_packet_id(other.last_packet_id), 00144 last_ack_id(other.last_ack_id), 00145 missed_acks(other.missed_acks), 00146 awaiting_ack(other.awaiting_ack) 00147 {} 00148 }; 00149 00150 class huffman_client 00151 { 00152 huffman alpha, beta, tmpcodec; 00153 bool active_codec; 00154 00155 bool awaiting_ackack; 00156 00157 public: 00158 00159 void reset(); 00160 00161 void ack_sent(unsigned char *in_data, size_t len); 00162 huffman &codec_for_received(unsigned char id); 00163 00164 huffman_client() { reset(); } 00165 huffman_client(const huffman_client &other) : 00166 alpha(other.alpha), 00167 beta(other.beta), 00168 tmpcodec(other.tmpcodec), 00169 active_codec(other.active_codec), 00170 awaiting_ackack(other.awaiting_ackack) 00171 {} 00172 }; 00173 00174 #endif 00175