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 *
enet_range_coder_create(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
enet_range_coder_destroy(void * context)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
enet_symbol_rescale(ENetSymbol * symbol)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
enet_range_coder_compress(void * context,const ENetBuffer * inBuffers,size_t inBufferCount,size_t inLimit,enet_uint8 * outData,size_t outLimit)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 |= (enet_uint32)(* inData ++) << 24; \
347     if (inData < inEnd) decodeCode |= (enet_uint32)(* inData ++) << 16; \
348     if (inData < inEnd) decodeCode |= (enet_uint32)(* inData ++) << 8; \
349     if (inData < inEnd) decodeCode |= (enet_uint32)(* 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
enet_range_coder_decompress(void * context,const enet_uint8 * inData,size_t inLimit,enet_uint8 * outData,size_t outLimit)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
enet_host_compress_with_range_coder(ENetHost * host)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