demo-reader 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/dm68/dm68.c ADDED
@@ -0,0 +1,57 @@
1
+ #include "ruby.h"
2
+ #include "main.h"
3
+
4
+
5
+ static VALUE rb_mDM68;
6
+ static VALUE rb_cDM68;
7
+
8
+
9
+
10
+
11
+ static VALUE parse_file(VALUE obj, VALUE path)
12
+ {
13
+ Check_Type(path, T_STRING);
14
+
15
+ // reset global state
16
+ memset(result, 0, MAXRESULT);
17
+ demo.demoMessageSequence = 0;
18
+ demo.gameStatesParsed = 0;
19
+
20
+ if(!(demo.demofile=fopen(RSTRING(path)->ptr, "rb")))
21
+ {
22
+ Com_Error(ERR_FATAL, "Couldn't open demofile");
23
+ }
24
+
25
+ Huff_Init();
26
+
27
+ append_result("---\n");
28
+
29
+ while(!demo.gameStatesParsed) {
30
+ if(!Parse_NextDemoMessage()) {
31
+ break;
32
+ }
33
+ }
34
+
35
+ GameStateParsed();
36
+
37
+ append_result("prints:\n");
38
+
39
+ while(1) {
40
+ if(!Parse_NextDemoMessage()) {
41
+ break;
42
+ }
43
+ NewFrameParsed();
44
+ }
45
+
46
+ fclose(demo.demofile);
47
+
48
+ return rb_str_new2(result);
49
+ }
50
+
51
+
52
+ void Init_dm68()
53
+ {
54
+ rb_mDM68 = rb_define_module("DM68");
55
+ rb_define_module_function(rb_mDM68, "parse_file", parse_file, 1);
56
+ }
57
+
data/ext/dm68/dump.c ADDED
@@ -0,0 +1,196 @@
1
+ //
2
+ // dump.c - ugly stuff, don't look!
3
+ //
4
+
5
+ #include "main.h"
6
+
7
+ typedef struct {
8
+ entityState_t currentState; // zeiger auf ringbuff pso
9
+ qboolean currentValid; // true if cg.frame holds this entity
10
+ int previousEvent;
11
+ } centity_t;
12
+
13
+ static char clientNames[MAX_CLIENTS][36];
14
+ static centity_t centities[MAX_GENTITIES];
15
+
16
+ static void UpdateClientInfo( int clientNum, const char *info ) {
17
+ if( !info || !info[0] ) {
18
+ Q_strncpyz( clientNames[clientNum], "BADNAME", sizeof( clientNames[0] ) );
19
+ } else {
20
+ Q_strncpyz( clientNames[clientNum], Info_ValueForKey( info, "n" ), sizeof( clientNames[0] ) );
21
+ }
22
+ }
23
+
24
+ static void CG_CheckEvents( centity_t *cent ) {
25
+ entityState_t *es = &cent->currentState;
26
+ int event;
27
+ int mod;
28
+ int target, attacker;
29
+ char *targetName, *attackerName;
30
+ char *message;
31
+ char *message2 = "";
32
+
33
+ // check for event-only entities
34
+ if( es->eType > ET_EVENTS ) {
35
+ if( cent->previousEvent ) {
36
+ return; // already fired
37
+ }
38
+ cent->previousEvent = 1;
39
+
40
+ es->event = es->eType - ET_EVENTS;
41
+ } else {
42
+ // check for events riding with another entity
43
+ if ( es->event == cent->previousEvent ) {
44
+ return;
45
+ }
46
+ cent->previousEvent = es->event;
47
+ if( ( es->event & ~EV_EVENT_BITS ) == 0 ) {
48
+ return;
49
+ }
50
+ }
51
+
52
+ event = es->event & ~EV_EVENT_BITS;
53
+ if( event != EV_OBITUARY ) {
54
+ return;
55
+ }
56
+
57
+ target = es->otherEntityNum;
58
+ attacker = es->otherEntityNum2;
59
+ mod = es->eventParm;
60
+
61
+ if( target < 0 || target >= MAX_CLIENTS ) {
62
+ return;
63
+ }
64
+
65
+ if( attacker < 0 || attacker >= MAX_CLIENTS ) {
66
+ attacker = target;
67
+ }
68
+
69
+ targetName = clientNames[target];
70
+ attackerName = clientNames[attacker];
71
+
72
+ if (attacker == target) // selbstmord oder "unfall"
73
+ {
74
+ switch (mod)
75
+ {
76
+ case MOD_GRENADE_SPLASH:message = "tripped on own grenade."; break;
77
+ case MOD_ROCKET_SPLASH: message = "blew up by own rocket.";break;
78
+ case MOD_PLASMA_SPLASH: message = "melted by own plasma."; break;
79
+ case MOD_BFG_SPLASH: message = "should have used a smaller gun."; break;
80
+ case MOD_SUICIDE: message = "suicides";break;
81
+ case MOD_FALLING: message = "cratered";break;
82
+ case MOD_CRUSH: message = "was squished";break;
83
+ case MOD_WATER: message = "sank like a rock";break;
84
+ case MOD_SLIME: message = "melted"; break;
85
+ case MOD_LAVA: message = "does a back flip into the lava"; break;
86
+ case MOD_TARGET_LASER: message = "saw the light";break;
87
+ case MOD_TRIGGER_HURT: message = "was in the wrong place"; break;
88
+ default: message = "committed suicid."; break;
89
+ }
90
+ Com_Printf( "%s %s.\n", targetName, message );
91
+ return;
92
+ }
93
+
94
+ switch (mod)
95
+ {
96
+ case MOD_GRAPPLE: message = "was caught by"; break;
97
+ case MOD_GAUNTLET: message = "was pummeled by";break;
98
+ case MOD_MACHINEGUN: message = "was machinegunned by";break;
99
+ case MOD_SHOTGUN: message = "was gunned down by"; break;
100
+ case MOD_GRENADE: message = "ate";message2 = "'s grenade";break;
101
+ case MOD_GRENADE_SPLASH:message = "was shredded by";message2 = "'s shrapnel";break;
102
+ case MOD_ROCKET: message = "ate";message2 = "'s rocket";break;
103
+ case MOD_ROCKET_SPLASH: message = "almost dodged";message2 = "'s rocket";break;
104
+ case MOD_PLASMA: message = "was melted by";message2 = "'s plasmagun";break;
105
+ case MOD_PLASMA_SPLASH: message = "was melted by";message2 = "'s plasmagun";break;
106
+ case MOD_RAILGUN: message = "was railed by";break;
107
+ case MOD_LIGHTNING: message = "was electrocuted by";break;
108
+ case MOD_BFG:
109
+ case MOD_BFG_SPLASH: message = "was blasted by";message2 = "'s BFG"; break;
110
+ case MOD_TELEFRAG: message = "tried to invade";message2 = "'s personal space"; break;
111
+ default: message = "was killed by";break;
112
+ }
113
+ Com_Printf( "%s %s %s%s.\n", targetName, message, attackerName, message2);
114
+ return;
115
+
116
+
117
+ // we don't know what it was
118
+ Com_Printf( "%s died.\n", targetName );
119
+ }
120
+
121
+ void GameStateParsed( void ) {
122
+ int i;
123
+ char *configString;
124
+
125
+ for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
126
+ configString = Com_GetStringFromGameState( &ds.gameState, i );
127
+ if( configString[0] ) {
128
+ if( i < RESERVED_CONFIGSTRINGS ) {
129
+ append_result( "%s_info:\n", (i == CS_SERVERINFO) ? "server" : "system" );
130
+ Info_Print( configString );
131
+ append_result( "\n" );
132
+ }/* else {
133
+ Com_Printf( "configString %i: \"%s\"\n", i, configString );
134
+ }*/
135
+ }
136
+ }
137
+
138
+ for( i=0 ; i<MAX_CLIENTS ; i++ ) {
139
+ configString = Com_GetStringFromGameState( &ds.gameState, CS_PLAYERS + i );
140
+ UpdateClientInfo( i, configString );
141
+ }
142
+ }
143
+
144
+ static void UpdateConfigString( int index, char *string ) {
145
+ Com_InsertIntoGameState( &ds.gameState, index, string );
146
+
147
+ if( index > CS_PLAYERS && index < CS_PLAYERS + MAX_CLIENTS ) {
148
+ UpdateClientInfo( index, string );
149
+ }
150
+ }
151
+
152
+ void NewFrameParsed( void ) {
153
+ int i;
154
+ entityState_t *es;
155
+ char *serverCommand;
156
+ char *args;
157
+
158
+ for( i=ds.currentServerCommandNum+1 ; i<=ds.lastServerCommandNum ; i++ ) {
159
+ serverCommand = ds.serverCommands[i & SERVERCMD_MASK];
160
+ Cmd_TokenizeString( serverCommand );
161
+
162
+ if( !Q_stricmp( Cmd_Argv( 0 ), "print" ) || !Q_stricmp( Cmd_Argv( 0 ), "cp" ) ) {
163
+ args = Cmd_Args();
164
+ args[strlen(args)-2] = 0;
165
+ args++;
166
+
167
+ append_result(" - \"%s\"\n", args);
168
+ } else if( !Q_stricmp( Cmd_Argv( 0 ), "cs" ) ) {
169
+ UpdateConfigString( atoi( Cmd_Argv( 1 ) ), Cmd_Argv( 2 ) );
170
+ }
171
+
172
+ // Com_Printf( "serverCommand: %i \"%s\"\n", i, Com_TranslateLinefeeds( ) );
173
+ }
174
+ ds.currentServerCommandNum = ds.lastServerCommandNum;
175
+
176
+ if( !ds.snap || !ds.snap->valid ) {
177
+ return;
178
+ }
179
+
180
+ for( i=0 ; i<MAX_GENTITIES ; i++ ) {
181
+ centities[i].currentValid = qfalse;
182
+ }
183
+
184
+ for( i=0 ; i<ds.snap->numEntities ; i++ ) {
185
+ es = &ds.parseEntities[(ds.snap->firstEntity+i) & PARSE_ENTITIES_MASK];
186
+ memcpy( &centities[es->number].currentState, es, sizeof( entityState_t ) );
187
+ centities[es->number].currentValid = qtrue;
188
+ CG_CheckEvents( &centities[es->number] );
189
+ }
190
+
191
+ for( i=0 ; i<MAX_GENTITIES ; i++ ) {
192
+ if( !centities[i].currentValid ) {
193
+ centities[i].previousEvent = 0;
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,16 @@
1
+ require "mkmf"
2
+
3
+ dir_config("dm68")
4
+
5
+ # have_library("common")
6
+ # have_library("huff")
7
+ # have_library("msg")
8
+
9
+ # have_library("dump")
10
+ # have_library("parse")
11
+ # have_library("main")
12
+
13
+ # $CFLAGS =
14
+ # $CFLAGS = "-Wall"
15
+ create_makefile("dm68")
16
+
data/ext/dm68/huff.c ADDED
@@ -0,0 +1,542 @@
1
+ /*
2
+ Quake III *.dm_6? Demo Specifications
3
+
4
+ Copyright (C) 2003 Andrey '[SkulleR]' Nazarov
5
+ Based on Argus and Quake II source code
6
+ Also contains some stuff from Q3A SDK
7
+
8
+ Argus is Copyright (C) 2000 Martin Otten
9
+ Quake II and Quake III are Copyright (C) 1997-2001 ID Software, Inc
10
+
11
+ This program is free software; you can redistribute it and/or
12
+ modify it under the terms of the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2
14
+ of the License, or (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
+
20
+ See the GNU General Public License for more details.
21
+
22
+ You should have received a copy of the GNU General Public License
23
+ along with this program; if not, write to the Free Software
24
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
+ */
26
+
27
+ //
28
+ // huff.c - Huffman compression routines for data bitstream
29
+ //
30
+
31
+ #include "common.h"
32
+ #include "huff.h"
33
+
34
+ #define VALUE(a) (*(int *)&(a))
35
+ #define NODE(a) ((void*)(a))
36
+
37
+ #define NODE_START NODE( 1)
38
+ #define NODE_NONE NODE(256)
39
+ #define NODE_NEXT NODE(257)
40
+
41
+ #define HUFF_TREE_SIZE 7175
42
+ typedef void *tree_t[HUFF_TREE_SIZE];
43
+
44
+ //
45
+ // pre-defined frequency counts for all bytes [0..255]
46
+ //
47
+ static int huffCounts[256] = {
48
+ 0x3D1CB, 0x0A0E9, 0x01894, 0x01BC2, 0x00E92, 0x00EA6, 0x017DE, 0x05AF3,
49
+ 0x08225, 0x01B26, 0x01E9E, 0x025F2, 0x02429, 0x0436B, 0x00F6D, 0x006F2,
50
+ 0x02060, 0x00644, 0x00636, 0x0067F, 0x0044C, 0x004BD, 0x004D6, 0x0046E,
51
+ 0x006D5, 0x00423, 0x004DE, 0x0047D, 0x004F9, 0x01186, 0x00AF5, 0x00D90,
52
+ 0x0553B, 0x00487, 0x00686, 0x0042A, 0x00413, 0x003F4, 0x0041D, 0x0042E,
53
+ 0x006BE, 0x00378, 0x0049C, 0x00352, 0x003C0, 0x0030C, 0x006D8, 0x00CE0,
54
+ 0x02986, 0x011A2, 0x016F9, 0x00A7D, 0x0122A, 0x00EFD, 0x0082D, 0x0074B,
55
+ 0x00A18, 0x0079D, 0x007B4, 0x003AC, 0x0046E, 0x006FC, 0x00686, 0x004B6,
56
+ 0x01657, 0x017F0, 0x01C36, 0x019FE, 0x00E7E, 0x00ED3, 0x005D4, 0x005F4,
57
+ 0x008A7, 0x00474, 0x0054B, 0x003CB, 0x00884, 0x004E0, 0x00530, 0x004AB,
58
+ 0x006EA, 0x00436, 0x004F0, 0x004F2, 0x00490, 0x003C5, 0x00483, 0x004A2,
59
+ 0x00543, 0x004CC, 0x005F9, 0x00640, 0x00A39, 0x00800, 0x009F2, 0x00CCB,
60
+ 0x0096A, 0x00E01, 0x009C8, 0x00AF0, 0x00A73, 0x01802, 0x00E4F, 0x00B18,
61
+ 0x037AD, 0x00C5C, 0x008AD, 0x00697, 0x00C88, 0x00AB3, 0x00DB8, 0x012BC,
62
+ 0x00FFB, 0x00DBB, 0x014A8, 0x00FB0, 0x01F01, 0x0178F, 0x014F0, 0x00F54,
63
+ 0x0131C, 0x00E9F, 0x011D6, 0x012C7, 0x016DC, 0x01900, 0x01851, 0x02063,
64
+ 0x05ACB, 0x01E9E, 0x01BA1, 0x022E7, 0x0153D, 0x01183, 0x00E39, 0x01488,
65
+ 0x014C0, 0x014D0, 0x014FA, 0x00DA4, 0x0099A, 0x0069E, 0x0071D, 0x00849,
66
+ 0x0077C, 0x0047D, 0x005EC, 0x00557, 0x004D4, 0x00405, 0x004EA, 0x00450,
67
+ 0x004DD, 0x003EE, 0x0047D, 0x00401, 0x004D9, 0x003B8, 0x00507, 0x003E5,
68
+ 0x006B1, 0x003F1, 0x004A3, 0x0036F, 0x0044B, 0x003A1, 0x00436, 0x003B7,
69
+ 0x00678, 0x003A2, 0x00481, 0x00406, 0x004EE, 0x00426, 0x004BE, 0x00424,
70
+ 0x00655, 0x003A2, 0x00452, 0x00390, 0x0040A, 0x0037C, 0x00486, 0x003DE,
71
+ 0x00497, 0x00352, 0x00461, 0x00387, 0x0043F, 0x00398, 0x00478, 0x00420,
72
+ 0x00D86, 0x008C0, 0x0112D, 0x02F68, 0x01E4E, 0x00541, 0x0051B, 0x00CCE,
73
+ 0x0079E, 0x00376, 0x003FF, 0x00458, 0x00435, 0x00412, 0x00425, 0x0042F,
74
+ 0x005CC, 0x003E9, 0x00448, 0x00393, 0x0041C, 0x003E3, 0x0042E, 0x0036C,
75
+ 0x00457, 0x00353, 0x00423, 0x00325, 0x00458, 0x0039B, 0x0044F, 0x00331,
76
+ 0x0076B, 0x00750, 0x003D0, 0x00349, 0x00467, 0x003BC, 0x00487, 0x003B6,
77
+ 0x01E6F, 0x003BA, 0x00509, 0x003A5, 0x00467, 0x00C87, 0x003FC, 0x0039F,
78
+ 0x0054B, 0x00300, 0x00410, 0x002E9, 0x003B8, 0x00325, 0x00431, 0x002E4,
79
+ 0x003F5, 0x00325, 0x003F0, 0x0031C, 0x003E4, 0x00421, 0x02CC1, 0x034C0
80
+ };
81
+
82
+
83
+ //
84
+ // static Huffman tree
85
+ //
86
+ static tree_t huffTree;
87
+
88
+ //
89
+ // received from MSG_* code
90
+ //
91
+ static int huffBitPos;
92
+
93
+
94
+ /*
95
+ =======================================================================================
96
+
97
+ HUFFMAN TREE CONSTRUCTION
98
+
99
+ =======================================================================================
100
+ */
101
+
102
+
103
+ /*
104
+ ============
105
+ Huff_PrepareTree
106
+ ============
107
+ */
108
+ static ID_INLINE void Huff_PrepareTree( tree_t tree ) {
109
+ void **node;
110
+
111
+ memset( tree, 0, sizeof( tree_t ) );
112
+
113
+ // create first node
114
+ node = &tree[263];
115
+ tree[0] = NODE((VALUE(tree[0])+1));
116
+
117
+ node[7] = NODE_NONE;
118
+ tree[2] = node;
119
+ tree[3] = node;
120
+ tree[4] = node;
121
+ tree[261] = node;
122
+ }
123
+
124
+ /*
125
+ ============
126
+ Huff_GetNode
127
+ ============
128
+ */
129
+ static ID_INLINE void **Huff_GetNode( void **tree ) {
130
+ void **node;
131
+ int value;
132
+
133
+ node = tree[262];
134
+ if( !node ) {
135
+ value = VALUE( tree[1] )++;
136
+ node = &tree[value + 6407];
137
+ return node;
138
+ }
139
+
140
+ tree[262] = node[0];
141
+ return node;
142
+ }
143
+
144
+ /*
145
+ ============
146
+ Huff_Swap
147
+ ============
148
+ */
149
+ static ID_INLINE void Huff_Swap( void **tree1, void **tree2, void **tree3 ) {
150
+ void **a, **b;
151
+
152
+ a = tree2[2];
153
+ if( a ) {
154
+ if( a[0] == tree2 ) {
155
+ a[0] = tree3;
156
+ } else {
157
+ a[1] = tree3;
158
+ }
159
+ } else {
160
+ tree1[2] = tree3;
161
+ }
162
+
163
+ b = tree3[2];
164
+
165
+ if( b ) {
166
+ if( b[0] == tree3 ) {
167
+ b[0] = tree2;
168
+ tree2[2] = b;
169
+ tree3[2] = a;
170
+ return;
171
+ }
172
+
173
+ b[1] = tree2;
174
+ tree2[2] = b;
175
+ tree3[2] = a;
176
+ return;
177
+ }
178
+
179
+ tree1[2] = tree2;
180
+ tree2[2] = NULL;
181
+ tree3[2] = a;
182
+ }
183
+
184
+ /*
185
+ ============
186
+ Huff_SwapTrees
187
+ ============
188
+ */
189
+ static ID_INLINE void Huff_SwapTrees( void **tree1, void **tree2 ) {
190
+ void **temp;
191
+
192
+ temp = tree1[3];
193
+ tree1[3] = tree2[3];
194
+ tree2[3] = temp;
195
+
196
+ temp = tree1[4];
197
+ tree1[4] = tree2[4];
198
+ tree2[4] = temp;
199
+
200
+ if( tree1[3] == tree1 ) {
201
+ tree1[3] = tree2;
202
+ }
203
+
204
+ if( tree2[3] == tree2 ) {
205
+ tree2[3] = tree1;
206
+ }
207
+
208
+ temp = tree1[3];
209
+ if( temp ) {
210
+ temp[4] = tree1;
211
+ }
212
+
213
+ temp = tree2[3];
214
+ if( temp ) {
215
+ temp[4] = tree2;
216
+ }
217
+
218
+ temp = tree1[4];
219
+ if( temp ) {
220
+ temp[3] = tree1;
221
+ }
222
+
223
+ temp = tree2[4];
224
+ if( temp ) {
225
+ temp[3] = tree2;
226
+ }
227
+
228
+ }
229
+
230
+ /*
231
+ ============
232
+ Huff_DeleteNode
233
+ ============
234
+ */
235
+ static ID_INLINE void Huff_DeleteNode( void **tree1, void **tree2 ) {
236
+ tree2[0] = tree1[262];
237
+ tree1[262] = tree2;
238
+ }
239
+
240
+ /*
241
+ ============
242
+ Huff_IncrementFreq_r
243
+ ============
244
+ */
245
+ static void Huff_IncrementFreq_r( void **tree1, void **tree2 ) {
246
+ void **a, **b;
247
+
248
+ if( !tree2 ) {
249
+ return;
250
+ }
251
+
252
+ a = tree2[3];
253
+ if( a && a[6] == tree2[6] ) {
254
+ b = tree2[5];
255
+ if( b[0] != tree2[2] ) {
256
+ Huff_Swap( tree1, b[0], tree2 );
257
+ }
258
+ Huff_SwapTrees( b[0], tree2 );
259
+ }
260
+
261
+ a = tree2[4];
262
+ if( a && a[6] == tree2[6] ) {
263
+ b = tree2[5];
264
+ b[0] = a;
265
+ } else {
266
+ a = tree2[5];
267
+ a[0] = 0;
268
+ Huff_DeleteNode( tree1, a );
269
+ }
270
+
271
+
272
+ VALUE( tree2[6] )++;
273
+ a = tree2[3];
274
+ if( a && a[6] == tree2[6] ) {
275
+ tree2[5] = a[5];
276
+ } else {
277
+ a = Huff_GetNode( tree1 );
278
+ tree2[5] = a;
279
+ a[0] = tree2;
280
+ }
281
+
282
+ if( tree2[2] ) {
283
+ Huff_IncrementFreq_r( tree1, tree2[2] );
284
+
285
+ if( tree2[4] == tree2[2] ) {
286
+ Huff_SwapTrees( tree2, tree2[2] );
287
+ a = tree2[5];
288
+
289
+ if( a[0] == tree2 ) {
290
+ a[0] = tree2[2];
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ /*
297
+ ============
298
+ Huff_AddReference
299
+
300
+ Insert 'ch' into the tree or increment it's frequency
301
+ ============
302
+ */
303
+ static void Huff_AddReference( void **tree, int ch ) {
304
+ void **a, **b, **c, **d;
305
+ int value;
306
+
307
+ ch &= 255;
308
+ if( tree[ch + 5] ) {
309
+ Huff_IncrementFreq_r( tree, tree[ch + 5] );
310
+ return; // already added
311
+ }
312
+
313
+ value = VALUE( tree[0] )++;
314
+ b = &tree[value * 8 + 263];
315
+
316
+ value = VALUE( tree[0] )++;
317
+ a = &tree[value * 8 + 263];
318
+
319
+ a[7] = NODE_NEXT;
320
+ a[6] = NODE_START;
321
+ d = tree[3];
322
+ a[3] = d[3];
323
+ if( a[3] ) {
324
+ d = a[3];
325
+ d[4] = a;
326
+ d = a[3];
327
+ if( d[6] == NODE_START ) {
328
+ a[5] = d[5];
329
+ } else {
330
+ d = Huff_GetNode( tree );
331
+ a[5] = d;
332
+ d[0] = a;
333
+ }
334
+ } else {
335
+ d = Huff_GetNode( tree );
336
+ a[5] = d;
337
+ d[0] = a;
338
+
339
+ }
340
+
341
+ d = tree[3];
342
+ d[3] = a;
343
+ a[4] = tree[3];
344
+ b[7] = NODE( ch );
345
+ b[6] = NODE_START;
346
+ d = tree[3];
347
+ b[3] = d[3];
348
+ if( b[3] ) {
349
+ d = b[3];
350
+ d[4] = b;
351
+ if( d[6] == NODE_START ) {
352
+ b[5] = d[5];
353
+ } else {
354
+ d = Huff_GetNode( tree );
355
+ b[5] = d;
356
+ d[0] = a;
357
+ }
358
+ } else {
359
+ d = Huff_GetNode( tree );
360
+ b[5] = d;
361
+ d[0] = b;
362
+ }
363
+
364
+ d = tree[3];
365
+ d[3] = b;
366
+ b[4] = tree[3];
367
+ b[1] = NULL;
368
+ b[0] = NULL;
369
+ d = tree[3];
370
+ c = d[2];
371
+ if( c ) {
372
+ if( c[0] == tree[3] ) {
373
+ c[0] = a;
374
+ } else {
375
+ c[1] = a;
376
+ }
377
+ } else {
378
+ tree[2] = a;
379
+ }
380
+
381
+ a[1] = b;
382
+ d = tree[3];
383
+ a[0] = d;
384
+ a[2] = d[2];
385
+ b[2] = a;
386
+ d = tree[3];
387
+ d[2] = a;
388
+ tree[ch + 5] = b;
389
+
390
+ Huff_IncrementFreq_r( tree, a[2] );
391
+ }
392
+
393
+ /*
394
+ =======================================================================================
395
+
396
+ BITSTREAM I/O
397
+
398
+ =======================================================================================
399
+ */
400
+
401
+ /*
402
+ ============
403
+ Huff_EmitBit
404
+
405
+ Put one bit into buffer
406
+ ============
407
+ */
408
+ static ID_INLINE void Huff_EmitBit( int bit, byte *buffer ) {
409
+ if( !(huffBitPos & 7) ) {
410
+ buffer[huffBitPos >> 3] = 0;
411
+ }
412
+
413
+ buffer[huffBitPos >> 3] |= bit << (huffBitPos & 7);
414
+ huffBitPos++;
415
+ }
416
+
417
+ /*
418
+ ============
419
+ Huff_GetBit
420
+
421
+ Read one bit from buffer
422
+ ============
423
+ */
424
+ static ID_INLINE int Huff_GetBit( byte *buffer ) {
425
+ int bit;
426
+
427
+ bit = buffer[huffBitPos >> 3] >> (huffBitPos & 7);
428
+ huffBitPos++;
429
+
430
+ return (bit & 1);
431
+ }
432
+
433
+ /*
434
+ ============
435
+ Huff_EmitPathToByte
436
+ ============
437
+ */
438
+ static ID_INLINE void Huff_EmitPathToByte( void **tree, void **subtree, byte *buffer ) {
439
+ if( tree[2] ) {
440
+ Huff_EmitPathToByte( tree[2], tree, buffer );
441
+ }
442
+
443
+ if( !subtree ) {
444
+ return;
445
+ }
446
+
447
+ //
448
+ // emit tree walking control bits
449
+ //
450
+ if( tree[1] == subtree ) {
451
+ Huff_EmitBit( 1, buffer );
452
+ } else {
453
+ Huff_EmitBit( 0, buffer );
454
+ }
455
+ }
456
+
457
+ /*
458
+ ============
459
+ Huff_GetByteFromTree
460
+
461
+ Get one byte using dynamic or static tree
462
+ ============
463
+ */
464
+ static ID_INLINE int Huff_GetByteFromTree( void **tree, byte *buffer ) {
465
+ if( !tree ) {
466
+ return 0;
467
+ }
468
+
469
+ //
470
+ // walk through the tree until we get a value
471
+ //
472
+ while( tree[7] == NODE_NEXT ) {
473
+ if( !Huff_GetBit( buffer ) ) {
474
+ tree = tree[0];
475
+ } else {
476
+ tree = tree[1];
477
+ }
478
+
479
+ if( !tree ) {
480
+ return 0;
481
+ }
482
+ }
483
+
484
+ return VALUE( tree[7] );
485
+ }
486
+
487
+ /*
488
+ =======================================================================================
489
+
490
+ PUBLIC INTERFACE
491
+
492
+ =======================================================================================
493
+ */
494
+
495
+ /*
496
+ ============
497
+ Huff_EmitByte
498
+ ============
499
+ */
500
+ void Huff_EmitByte( int ch, byte *buffer, int *count ) {
501
+ huffBitPos = *count;
502
+ Huff_EmitPathToByte( huffTree[ch + 5], NULL, buffer );
503
+ *count = huffBitPos;
504
+ }
505
+
506
+ /*
507
+ ============
508
+ Huff_GetByte
509
+ ============
510
+ */
511
+ int Huff_GetByte( byte *buffer, int *count ) {
512
+ int ch;
513
+
514
+ huffBitPos = *count;
515
+ ch = Huff_GetByteFromTree( huffTree[2], buffer );
516
+ *count = huffBitPos;
517
+
518
+ return ch;
519
+ }
520
+
521
+ /*
522
+ ============
523
+ Huff_Init
524
+ ============
525
+ */
526
+ void Huff_Init( void ) {
527
+ int i, j;
528
+
529
+ // build empty tree
530
+ Huff_PrepareTree( huffTree );
531
+
532
+ // add all pre-defined byte references
533
+ for( i=0 ; i<256 ; i++ ) {
534
+ for( j=0 ; j<huffCounts[i] ; j++ ) {
535
+ Huff_AddReference( huffTree, i );
536
+ }
537
+ }
538
+
539
+ }
540
+
541
+
542
+