demo-reader 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+