Odamex
Setting the Standard in Multiplayer Doom
common/huffman.h
Go to the documentation of this file.
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 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends