Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/enet/compress.c
9898 views
1
/**
2
@file compress.c
3
@brief An adaptive order-2 PPM range coder
4
*/
5
#define ENET_BUILDING_LIB 1
6
#include <string.h>
7
#include "enet/enet.h"
8
9
typedef struct _ENetSymbol
10
{
11
/* binary indexed tree of symbols */
12
enet_uint8 value;
13
enet_uint8 count;
14
enet_uint16 under;
15
enet_uint16 left, right;
16
17
/* context defined by this symbol */
18
enet_uint16 symbols;
19
enet_uint16 escapes;
20
enet_uint16 total;
21
enet_uint16 parent;
22
} ENetSymbol;
23
24
/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
25
enum
26
{
27
ENET_RANGE_CODER_TOP = 1<<24,
28
ENET_RANGE_CODER_BOTTOM = 1<<16,
29
30
ENET_CONTEXT_SYMBOL_DELTA = 3,
31
ENET_CONTEXT_SYMBOL_MINIMUM = 1,
32
ENET_CONTEXT_ESCAPE_MINIMUM = 1,
33
34
ENET_SUBCONTEXT_ORDER = 2,
35
ENET_SUBCONTEXT_SYMBOL_DELTA = 2,
36
ENET_SUBCONTEXT_ESCAPE_DELTA = 5
37
};
38
39
/* context exclusion roughly halves compression speed, so disable for now */
40
#undef ENET_CONTEXT_EXCLUSION
41
42
typedef struct _ENetRangeCoder
43
{
44
/* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
45
ENetSymbol symbols[4096];
46
} ENetRangeCoder;
47
48
void *
49
enet_range_coder_create (void)
50
{
51
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder));
52
if (rangeCoder == NULL)
53
return NULL;
54
55
return rangeCoder;
56
}
57
58
void
59
enet_range_coder_destroy (void * context)
60
{
61
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
62
if (rangeCoder == NULL)
63
return;
64
65
enet_free (rangeCoder);
66
}
67
68
#define ENET_SYMBOL_CREATE(symbol, value_, count_) \
69
{ \
70
symbol = & rangeCoder -> symbols [nextSymbol ++]; \
71
symbol -> value = value_; \
72
symbol -> count = count_; \
73
symbol -> under = count_; \
74
symbol -> left = 0; \
75
symbol -> right = 0; \
76
symbol -> symbols = 0; \
77
symbol -> escapes = 0; \
78
symbol -> total = 0; \
79
symbol -> parent = 0; \
80
}
81
82
#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \
83
{ \
84
ENET_SYMBOL_CREATE (context, 0, 0); \
85
(context) -> escapes = escapes_; \
86
(context) -> total = escapes_ + 256*minimum; \
87
(context) -> symbols = 0; \
88
}
89
90
static enet_uint16
91
enet_symbol_rescale (ENetSymbol * symbol)
92
{
93
enet_uint16 total = 0;
94
for (;;)
95
{
96
symbol -> count -= symbol->count >> 1;
97
symbol -> under = symbol -> count;
98
if (symbol -> left)
99
symbol -> under += enet_symbol_rescale (symbol + symbol -> left);
100
total += symbol -> under;
101
if (! symbol -> right) break;
102
symbol += symbol -> right;
103
}
104
return total;
105
}
106
107
#define ENET_CONTEXT_RESCALE(context, minimum) \
108
{ \
109
(context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \
110
(context) -> escapes -= (context) -> escapes >> 1; \
111
(context) -> total += (context) -> escapes + 256*minimum; \
112
}
113
114
#define ENET_RANGE_CODER_OUTPUT(value) \
115
{ \
116
if (outData >= outEnd) \
117
return 0; \
118
* outData ++ = value; \
119
}
120
121
#define ENET_RANGE_CODER_ENCODE(under, count, total) \
122
{ \
123
encodeRange /= (total); \
124
encodeLow += (under) * encodeRange; \
125
encodeRange *= (count); \
126
for (;;) \
127
{ \
128
if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \
129
{ \
130
if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
131
encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
132
} \
133
ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
134
encodeRange <<= 8; \
135
encodeLow <<= 8; \
136
} \
137
}
138
139
#define ENET_RANGE_CODER_FLUSH \
140
{ \
141
while (encodeLow) \
142
{ \
143
ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
144
encodeLow <<= 8; \
145
} \
146
}
147
148
#define ENET_RANGE_CODER_FREE_SYMBOLS \
149
{ \
150
if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \
151
{ \
152
nextSymbol = 0; \
153
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \
154
predicted = 0; \
155
order = 0; \
156
} \
157
}
158
159
#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \
160
{ \
161
under_ = value*minimum; \
162
count_ = minimum; \
163
if (! (context) -> symbols) \
164
{ \
165
ENET_SYMBOL_CREATE (symbol_, value_, update); \
166
(context) -> symbols = symbol_ - (context); \
167
} \
168
else \
169
{ \
170
ENetSymbol * node = (context) + (context) -> symbols; \
171
for (;;) \
172
{ \
173
if (value_ < node -> value) \
174
{ \
175
node -> under += update; \
176
if (node -> left) { node += node -> left; continue; } \
177
ENET_SYMBOL_CREATE (symbol_, value_, update); \
178
node -> left = symbol_ - node; \
179
} \
180
else \
181
if (value_ > node -> value) \
182
{ \
183
under_ += node -> under; \
184
if (node -> right) { node += node -> right; continue; } \
185
ENET_SYMBOL_CREATE (symbol_, value_, update); \
186
node -> right = symbol_ - node; \
187
} \
188
else \
189
{ \
190
count_ += node -> count; \
191
under_ += node -> under - node -> count; \
192
node -> under += update; \
193
node -> count += update; \
194
symbol_ = node; \
195
} \
196
break; \
197
} \
198
} \
199
}
200
201
#ifdef ENET_CONTEXT_EXCLUSION
202
static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
203
204
#define ENET_CONTEXT_WALK(context, body) \
205
{ \
206
const ENetSymbol * node = (context) + (context) -> symbols; \
207
const ENetSymbol * stack [256]; \
208
size_t stackSize = 0; \
209
while (node -> left) \
210
{ \
211
stack [stackSize ++] = node; \
212
node += node -> left; \
213
} \
214
for (;;) \
215
{ \
216
body; \
217
if (node -> right) \
218
{ \
219
node += node -> right; \
220
while (node -> left) \
221
{ \
222
stack [stackSize ++] = node; \
223
node += node -> left; \
224
} \
225
} \
226
else \
227
if (stackSize <= 0) \
228
break; \
229
else \
230
node = stack [-- stackSize]; \
231
} \
232
}
233
234
#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \
235
ENET_CONTEXT_WALK(context, { \
236
if (node -> value != value_) \
237
{ \
238
enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \
239
if (node -> value < value_) \
240
under -= parentCount; \
241
total -= parentCount; \
242
} \
243
})
244
#endif
245
246
size_t
247
enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit)
248
{
249
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
250
enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
251
const enet_uint8 * inData, * inEnd;
252
enet_uint32 encodeLow = 0, encodeRange = ~0;
253
ENetSymbol * root;
254
enet_uint16 predicted = 0;
255
size_t order = 0, nextSymbol = 0;
256
257
if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0)
258
return 0;
259
260
inData = (const enet_uint8 *) inBuffers -> data;
261
inEnd = & inData [inBuffers -> dataLength];
262
inBuffers ++;
263
inBufferCount --;
264
265
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
266
267
for (;;)
268
{
269
ENetSymbol * subcontext, * symbol;
270
#ifdef ENET_CONTEXT_EXCLUSION
271
const ENetSymbol * childContext = & emptyContext;
272
#endif
273
enet_uint8 value;
274
enet_uint16 count, under, * parent = & predicted, total;
275
if (inData >= inEnd)
276
{
277
if (inBufferCount <= 0)
278
break;
279
inData = (const enet_uint8 *) inBuffers -> data;
280
inEnd = & inData [inBuffers -> dataLength];
281
inBuffers ++;
282
inBufferCount --;
283
}
284
value = * inData ++;
285
286
for (subcontext = & rangeCoder -> symbols [predicted];
287
subcontext != root;
288
#ifdef ENET_CONTEXT_EXCLUSION
289
childContext = subcontext,
290
#endif
291
subcontext = & rangeCoder -> symbols [subcontext -> parent])
292
{
293
ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
294
* parent = symbol - rangeCoder -> symbols;
295
parent = & symbol -> parent;
296
total = subcontext -> total;
297
#ifdef ENET_CONTEXT_EXCLUSION
298
if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
299
ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0);
300
#endif
301
if (count > 0)
302
{
303
ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total);
304
}
305
else
306
{
307
if (subcontext -> escapes > 0 && subcontext -> escapes < total)
308
ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total);
309
subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
310
subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
311
}
312
subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
313
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
314
ENET_CONTEXT_RESCALE (subcontext, 0);
315
if (count > 0) goto nextInput;
316
}
317
318
ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM);
319
* parent = symbol - rangeCoder -> symbols;
320
parent = & symbol -> parent;
321
total = root -> total;
322
#ifdef ENET_CONTEXT_EXCLUSION
323
if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
324
ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM);
325
#endif
326
ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total);
327
root -> total += ENET_CONTEXT_SYMBOL_DELTA;
328
if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
329
ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
330
331
nextInput:
332
if (order >= ENET_SUBCONTEXT_ORDER)
333
predicted = rangeCoder -> symbols [predicted].parent;
334
else
335
order ++;
336
ENET_RANGE_CODER_FREE_SYMBOLS;
337
}
338
339
ENET_RANGE_CODER_FLUSH;
340
341
return (size_t) (outData - outStart);
342
}
343
344
#define ENET_RANGE_CODER_SEED \
345
{ \
346
if (inData < inEnd) decodeCode |= * inData ++ << 24; \
347
if (inData < inEnd) decodeCode |= * inData ++ << 16; \
348
if (inData < inEnd) decodeCode |= * inData ++ << 8; \
349
if (inData < inEnd) decodeCode |= * inData ++; \
350
}
351
352
#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total)))
353
354
#define ENET_RANGE_CODER_DECODE(under, count, total) \
355
{ \
356
decodeLow += (under) * decodeRange; \
357
decodeRange *= (count); \
358
for (;;) \
359
{ \
360
if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \
361
{ \
362
if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
363
decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
364
} \
365
decodeCode <<= 8; \
366
if (inData < inEnd) \
367
decodeCode |= * inData ++; \
368
decodeRange <<= 8; \
369
decodeLow <<= 8; \
370
} \
371
}
372
373
#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \
374
{ \
375
under_ = 0; \
376
count_ = minimum; \
377
if (! (context) -> symbols) \
378
{ \
379
createRoot; \
380
} \
381
else \
382
{ \
383
ENetSymbol * node = (context) + (context) -> symbols; \
384
for (;;) \
385
{ \
386
enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \
387
visitNode; \
388
if (code >= after) \
389
{ \
390
under_ += node -> under; \
391
if (node -> right) { node += node -> right; continue; } \
392
createRight; \
393
} \
394
else \
395
if (code < after - before) \
396
{ \
397
node -> under += update; \
398
if (node -> left) { node += node -> left; continue; } \
399
createLeft; \
400
} \
401
else \
402
{ \
403
value_ = node -> value; \
404
count_ += node -> count; \
405
under_ = after - before; \
406
node -> under += update; \
407
node -> count += update; \
408
symbol_ = node; \
409
} \
410
break; \
411
} \
412
} \
413
}
414
415
#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
416
ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0)
417
418
#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
419
ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \
420
{ \
421
value_ = code / minimum; \
422
under_ = code - code%minimum; \
423
ENET_SYMBOL_CREATE (symbol_, value_, update); \
424
(context) -> symbols = symbol_ - (context); \
425
}, \
426
exclude (node -> value, after, before), \
427
{ \
428
value_ = node->value + 1 + (code - after)/minimum; \
429
under_ = code - (code - after)%minimum; \
430
ENET_SYMBOL_CREATE (symbol_, value_, update); \
431
node -> right = symbol_ - node; \
432
}, \
433
{ \
434
value_ = node->value - 1 - (after - before - code - 1)/minimum; \
435
under_ = code - (after - before - code - 1)%minimum; \
436
ENET_SYMBOL_CREATE (symbol_, value_, update); \
437
node -> left = symbol_ - node; \
438
}) \
439
440
#ifdef ENET_CONTEXT_EXCLUSION
441
typedef struct _ENetExclude
442
{
443
enet_uint8 value;
444
enet_uint16 under;
445
} ENetExclude;
446
447
#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \
448
{ \
449
enet_uint16 under = 0; \
450
nextExclude = excludes; \
451
ENET_CONTEXT_WALK (context, { \
452
under += rangeCoder -> symbols [node -> parent].count + minimum; \
453
nextExclude -> value = node -> value; \
454
nextExclude -> under = under; \
455
nextExclude ++; \
456
}); \
457
total -= under; \
458
}
459
460
#define ENET_CONTEXT_EXCLUDED(value_, after, before) \
461
{ \
462
size_t low = 0, high = nextExclude - excludes; \
463
for(;;) \
464
{ \
465
size_t mid = (low + high) >> 1; \
466
const ENetExclude * exclude = & excludes [mid]; \
467
if (value_ < exclude -> value) \
468
{ \
469
if (low + 1 < high) \
470
{ \
471
high = mid; \
472
continue; \
473
} \
474
if (exclude > excludes) \
475
after -= exclude [-1].under; \
476
} \
477
else \
478
{ \
479
if (value_ > exclude -> value) \
480
{ \
481
if (low + 1 < high) \
482
{ \
483
low = mid; \
484
continue; \
485
} \
486
} \
487
else \
488
before = 0; \
489
after -= exclude -> under; \
490
} \
491
break; \
492
} \
493
}
494
#endif
495
496
#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before)
497
498
size_t
499
enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit)
500
{
501
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
502
enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
503
const enet_uint8 * inEnd = & inData [inLimit];
504
enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0;
505
ENetSymbol * root;
506
enet_uint16 predicted = 0;
507
size_t order = 0, nextSymbol = 0;
508
#ifdef ENET_CONTEXT_EXCLUSION
509
ENetExclude excludes [256];
510
ENetExclude * nextExclude = excludes;
511
#endif
512
513
if (rangeCoder == NULL || inLimit <= 0)
514
return 0;
515
516
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
517
518
ENET_RANGE_CODER_SEED;
519
520
for (;;)
521
{
522
ENetSymbol * subcontext, * symbol, * patch;
523
#ifdef ENET_CONTEXT_EXCLUSION
524
const ENetSymbol * childContext = & emptyContext;
525
#endif
526
enet_uint8 value = 0;
527
enet_uint16 code, under, count, bottom, * parent = & predicted, total;
528
529
for (subcontext = & rangeCoder -> symbols [predicted];
530
subcontext != root;
531
#ifdef ENET_CONTEXT_EXCLUSION
532
childContext = subcontext,
533
#endif
534
subcontext = & rangeCoder -> symbols [subcontext -> parent])
535
{
536
if (subcontext -> escapes <= 0)
537
continue;
538
total = subcontext -> total;
539
#ifdef ENET_CONTEXT_EXCLUSION
540
if (childContext -> total > 0)
541
ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0);
542
#endif
543
if (subcontext -> escapes >= total)
544
continue;
545
code = ENET_RANGE_CODER_READ (total);
546
if (code < subcontext -> escapes)
547
{
548
ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total);
549
continue;
550
}
551
code -= subcontext -> escapes;
552
#ifdef ENET_CONTEXT_EXCLUSION
553
if (childContext -> total > 0)
554
{
555
ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED);
556
}
557
else
558
#endif
559
{
560
ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED);
561
}
562
bottom = symbol - rangeCoder -> symbols;
563
ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total);
564
subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
565
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
566
ENET_CONTEXT_RESCALE (subcontext, 0);
567
goto patchContexts;
568
}
569
570
total = root -> total;
571
#ifdef ENET_CONTEXT_EXCLUSION
572
if (childContext -> total > 0)
573
ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM);
574
#endif
575
code = ENET_RANGE_CODER_READ (total);
576
if (code < root -> escapes)
577
{
578
ENET_RANGE_CODER_DECODE (0, root -> escapes, total);
579
break;
580
}
581
code -= root -> escapes;
582
#ifdef ENET_CONTEXT_EXCLUSION
583
if (childContext -> total > 0)
584
{
585
ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED);
586
}
587
else
588
#endif
589
{
590
ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED);
591
}
592
bottom = symbol - rangeCoder -> symbols;
593
ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total);
594
root -> total += ENET_CONTEXT_SYMBOL_DELTA;
595
if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
596
ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
597
598
patchContexts:
599
for (patch = & rangeCoder -> symbols [predicted];
600
patch != subcontext;
601
patch = & rangeCoder -> symbols [patch -> parent])
602
{
603
ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
604
* parent = symbol - rangeCoder -> symbols;
605
parent = & symbol -> parent;
606
if (count <= 0)
607
{
608
patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
609
patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
610
}
611
patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
612
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
613
ENET_CONTEXT_RESCALE (patch, 0);
614
}
615
* parent = bottom;
616
617
ENET_RANGE_CODER_OUTPUT (value);
618
619
if (order >= ENET_SUBCONTEXT_ORDER)
620
predicted = rangeCoder -> symbols [predicted].parent;
621
else
622
order ++;
623
ENET_RANGE_CODER_FREE_SYMBOLS;
624
}
625
626
return (size_t) (outData - outStart);
627
}
628
629
/** @defgroup host ENet host functions
630
@{
631
*/
632
633
/** Sets the packet compressor the host should use to the default range coder.
634
@param host host to enable the range coder for
635
@returns 0 on success, < 0 on failure
636
*/
637
int
638
enet_host_compress_with_range_coder (ENetHost * host)
639
{
640
ENetCompressor compressor;
641
memset (& compressor, 0, sizeof (compressor));
642
compressor.context = enet_range_coder_create();
643
if (compressor.context == NULL)
644
return -1;
645
compressor.compress = enet_range_coder_compress;
646
compressor.decompress = enet_range_coder_decompress;
647
compressor.destroy = enet_range_coder_destroy;
648
enet_host_compress (host, & compressor);
649
return 0;
650
}
651
652
/** @} */
653
654
655
656