diff --git a/3rdparty/bzip2/include/bzip2/bzlib.h b/3rdparty/bzip2/include/bzip2/bzlib.h new file mode 100644 index 000000000..8277123da --- /dev/null +++ b/3rdparty/bzip2/include/bzip2/bzlib.h @@ -0,0 +1,282 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/blocksort.c b/3rdparty/bzip2/src/blocksort.c new file mode 100644 index 000000000..d0d662cd4 --- /dev/null +++ b/3rdparty/bzip2/src/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/bzlib.c b/3rdparty/bzip2/src/bzlib.c new file mode 100644 index 000000000..2391f77a9 --- /dev/null +++ b/3rdparty/bzip2/src/bzlib.c @@ -0,0 +1,1580 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + Int32 ro_blockSize100k = s->blockSize100k; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# if defined(_MSC_VER) +# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) +# else +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +# endif +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else +# if defined(_MSC_VER) + fp = _fdopen(fd,mode2); +# else + fp = fdopen(fd,mode2); +# endif +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/bzlib_private.h b/3rdparty/bzip2/src/bzlib_private.h new file mode 100644 index 000000000..7de727d91 --- /dev/null +++ b/3rdparty/bzip2/src/bzlib_private.h @@ -0,0 +1,509 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzip2/bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.6, 6-Sept-2010" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/compress.c b/3rdparty/bzip2/src/compress.c new file mode 100644 index 000000000..caf769601 --- /dev/null +++ b/3rdparty/bzip2/src/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/crctable.c b/3rdparty/bzip2/src/crctable.c new file mode 100644 index 000000000..1fea7e946 --- /dev/null +++ b/3rdparty/bzip2/src/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/decompress.c b/3rdparty/bzip2/src/decompress.c new file mode 100644 index 000000000..311f5668f --- /dev/null +++ b/3rdparty/bzip2/src/decompress.c @@ -0,0 +1,646 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + /* Check that N doesn't get too big, so that es doesn't + go negative. The maximum value that can be + RUNA/RUNB encoded is equal to the block size (post + the initial RLE), viz, 900k, so bounding N at 2 + million should guard against overflow without + rejecting any legitimate inputs. */ + if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + /* Check: unzftab entries in range. */ + for (i = 0; i <= 255; i++) { + if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) + RETURN(BZ_DATA_ERROR); + } + /* Actually generate cftab. */ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + /* Check: cftab entries in range. */ + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + /* Check: cftab entries non-descending. */ + for (i = 1; i <= 256; i++) { + if (s->cftab[i-1] > s->cftab[i]) { + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/huffman.c b/3rdparty/bzip2/src/huffman.c new file mode 100644 index 000000000..2283fdbc5 --- /dev/null +++ b/3rdparty/bzip2/src/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/src/precompiled.c b/3rdparty/bzip2/src/precompiled.c new file mode 100644 index 000000000..ba90e07fc --- /dev/null +++ b/3rdparty/bzip2/src/precompiled.c @@ -0,0 +1 @@ +#include "bzlib_private.h" diff --git a/3rdparty/bzip2/src/randtable.c b/3rdparty/bzip2/src/randtable.c new file mode 100644 index 000000000..6d6245990 --- /dev/null +++ b/3rdparty/bzip2/src/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/wscript b/3rdparty/bzip2/wscript new file mode 100644 index 000000000..48f98a46e --- /dev/null +++ b/3rdparty/bzip2/wscript @@ -0,0 +1,20 @@ +#! /usr/bin/env python +# encoding: utf-8 + +import os + +def options(opt): + pass + +def configure(conf): + pass + +def build(bld): + bld.stlib( + source = bld.path.ant_glob(['src/*.c']), + target = 'bzip2', + features = 'c', + includes = ['src/', 'include/'], + subsystem = bld.env.MSVC_SUBSYSTEM, + export_includes = ['include/'] + ) diff --git a/engine/client/cl_debug.c b/engine/client/cl_debug.c index ec686ffe1..238c3fe28 100644 --- a/engine/client/cl_debug.c +++ b/engine/client/cl_debug.c @@ -49,8 +49,18 @@ const char *CL_MsgInfo( int cmd ) if( cmd >= 0 && cmd <= svc_lastmsg ) { + const char *svc_string = NULL; + + if( cls.legacymode == PROTO_LEGACY ) + svc_string = svc_legacy_strings[cmd]; + else if( cls.legacymode == PROTO_GOLDSRC ) + svc_string = svc_goldsrc_strings[cmd]; + + if( !svc_string ) + svc_string = svc_strings[cmd]; + // get engine message name - Q_strncpy( sz, svc_strings[cmd], sizeof( sz )); + Q_strncpy( sz, svc_string, sizeof( sz )); } else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES )) { diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index e947c76d4..b265039a7 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -674,7 +674,7 @@ void CL_DemoStartPlayback( int mode ) demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message - Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize ); + Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize, 0 ); memset( demo.cmds, 0, sizeof( demo.cmds )); demo.angle_position = 1; diff --git a/engine/client/cl_events.c b/engine/client/cl_events.c index cbc7cb303..80d3c4124 100644 --- a/engine/client/cl_events.c +++ b/engine/client/cl_events.c @@ -390,11 +390,19 @@ void CL_ParseReliableEvent( sizebuf_t *msg ) event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS ); - if( MSG_ReadOneBit( msg )) - delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f); - // reliable events not use delta-compression just null-compression - MSG_ReadDeltaEvent( msg, &nullargs, &args ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + Delta_ReadGSFields( msg, DT_EVENT_T, &nullargs, &args, 0.0f ); + if( MSG_ReadOneBit( msg )) + delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f); + } + else + { + if( MSG_ReadOneBit( msg )) + delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f); + MSG_ReadDeltaEvent( msg, &nullargs, &args ); + } if( args.entindex > 0 && args.entindex <= cl.maxclients ) args.angles[PITCH] *= -3.0f; @@ -426,15 +434,25 @@ void CL_ParseEvent( sizebuf_t *msg ) // parse events queue for( i = 0 ; i < num_events; i++ ) { + int entity_bits; + if( cls.legacymode == PROTO_GOLDSRC ) + entity_bits = MAX_GOLDSRC_ENTITY_BITS; + else if( cls.legacymode == PROTO_LEGACY ) + entity_bits = MAX_LEGACY_ENTITY_BITS; + else + entity_bits = MAX_ENTITY_BITS; + event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS ); if( MSG_ReadOneBit( msg )) - packet_index = MSG_ReadUBitLong( msg, cls.legacymode ? MAX_LEGACY_ENTITY_BITS : MAX_ENTITY_BITS ); + packet_index = MSG_ReadUBitLong( msg, entity_bits ); else packet_index = -1; if( MSG_ReadOneBit( msg )) { - MSG_ReadDeltaEvent( msg, &nullargs, &args ); + if( cls.legacymode == PROTO_GOLDSRC ) + Delta_ReadGSFields( msg, DT_EVENT_T, &nullargs, &args, 0.0f ); + else MSG_ReadDeltaEvent( msg, &nullargs, &args ); } if( MSG_ReadOneBit( msg )) diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 433d3382f..690de5b34 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -656,7 +656,7 @@ FRAME PARSING */ static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum ) { - if( cls.legacymode ) + if( cls.legacymode == PROTO_LEGACY ) { *newnum = MSG_ReadWord( msg ); if( *newnum == 0 ) @@ -679,7 +679,7 @@ CL_FlushEntityPacket Read and ignore whole entity packet. ================= */ -void CL_FlushEntityPacket( sizebuf_t *msg ) +static void CL_FlushEntityPacket( sizebuf_t *msg ) { int newnum; entity_state_t from, to; @@ -764,6 +764,47 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t frame->num_entities++; } +qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe ) +{ + int subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF; + + if( subtracted == 0 ) + { + Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" ); + return false; + } + + if( subtracted >= CL_UPDATE_MASK ) + { + // we can't use this, it is too old + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); + return false; + } + + if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES )) + { + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); + return false; + } + + return true; +} + +int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent ) +{ + if( !oldframe ) + { + *oldent = NULL; + return MAX_ENTNUMBER; + } + + if( oldindex >= oldframe->num_entities ) + return MAX_ENTNUMBER; + + *oldent = &cls.packet_entities[(oldframe->first_entity + oldindex) % cls.num_client_entities]; + return (*oldent)->number; +} + /* ================== CL_ParsePacketEntities @@ -777,7 +818,6 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) frame_t *newframe, *oldframe; int oldindex, newnum, oldnum; int playerbytes = 0; - int oldpacket; int bufStart; entity_state_t *oldent; qboolean player; @@ -788,7 +828,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) CL_WriteDemoJumpTime(); // sentinel count. save it for debug checking - if( cls.legacymode ) + if( cls.legacymode == PROTO_LEGACY ) count = MSG_ReadWord( msg ); else count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1; @@ -802,31 +842,11 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) if( delta ) { - int subtracted; - - oldpacket = MSG_ReadByte( msg ); - subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF; - - if( subtracted == 0 ) - { - Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" ); - CL_FlushEntityPacket( msg ); - return playerbytes; - } - - if( subtracted >= CL_UPDATE_MASK ) - { - // we can't use this, it is too old - Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); - CL_FlushEntityPacket( msg ); - return playerbytes; - } - + uint oldpacket = MSG_ReadByte( msg ); oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK]; - if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES )) + if( !CL_ValidateDeltaPacket( oldpacket, oldframe )) { - Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); CL_FlushEntityPacket( msg ); return playerbytes; } @@ -835,7 +855,6 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { // this is a full update that we can start delta compressing from now oldframe = NULL; - oldpacket = -1; // delta too old or is initial message cl.send_reply = true; // send reply cls.demowaiting = false; // we can start recording now } @@ -845,23 +864,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) oldent = NULL; oldindex = 0; - - if( !oldframe ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } - } + oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent ); while( 1 ) { @@ -877,17 +880,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, false ); - oldindex++; - - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); } if( oldnum == newnum ) @@ -896,17 +889,8 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) bufStart = MSG_GetNumBytesRead( msg ); CL_DeltaEntity( msg, newframe, newnum, oldent, true ); if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart; - oldindex++; - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); continue; } @@ -925,17 +909,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, false ); - oldindex++; - - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); } if( newframe->num_entities != count && newframe->num_entities != 0 ) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 182a83540..eaf65c860 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -223,7 +223,7 @@ void CL_SignonReply( void ) switch( cls.signon ) { case 1: - CL_ServerCommand( true, "begin" ); + CL_ServerCommand( true, cls.legacymode == PROTO_GOLDSRC ? "sendents" : "begin" ); if( host_developer.value >= DEV_EXTENDED ) Mem_PrintStats(); break; @@ -674,7 +674,13 @@ void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ) t = &cl.commands[to].cmd; // write it into the buffer - MSG_WriteDeltaUsercmd( msg, f, t ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + MSG_StartBitWriting( msg ); + Delta_WriteGSFields( msg, DT_USERCMD_T, f, t, 0.0 ); + MSG_EndBitWriting( msg ); + } + else MSG_WriteDeltaUsercmd( msg, f, t ); } /* @@ -773,6 +779,9 @@ void CL_WritePacket( void ) // begin a client move command MSG_BeginClientCmd( &buf, clc_move ); + if( cls.legacymode == PROTO_GOLDSRC ) + MSG_WriteByte( &buf, 0 ); + // save the position for a checksum byte key = MSG_GetRealBytesWritten( &buf ); MSG_WriteByte( &buf, 0 ); @@ -810,8 +819,16 @@ void CL_WritePacket( void ) // calculate a checksum over the move commands size = MSG_GetRealBytesWritten( &buf ) - key - 1; + if( cls.legacymode == PROTO_GOLDSRC ) + { + size = Q_min( size, 255 ); + buf.pData[key - 1] = size; + } buf.pData[key] = CRC32_BlockSequence( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); + if( cls.legacymode == PROTO_GOLDSRC ) + COM_Munge( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); + // message we are constructing. i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; @@ -1029,7 +1046,31 @@ void CL_SendConnectPacket( void ) Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) ); } - if( cls.legacymode ) + if( cls.legacymode == PROTO_GOLDSRC ) + { + byte send_buf[MAX_PRINT_MSG]; + byte steam_cert[512]; + sizebuf_t send; + + protinfo[0] = 0; + + memset( steam_cert, 0, sizeof( steam_cert )); + + Info_SetValueForKey( protinfo, "prot", "3", sizeof( protinfo )); // steam auth type + Info_SetValueForKey( protinfo, "raw", "steam", sizeof( protinfo )); + Info_SetValueForKey( protinfo, "cdkey", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", sizeof( protinfo )); + + Info_SetValueForStarKey( cls.userinfo, "*hltv", "0", sizeof( cls.userinfo )); + + MSG_Init( &send, "GoldSrcConnect", send_buf, sizeof( send_buf )); + MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET ); + MSG_WriteStringf( &send, "connect %i %i \"%s\" \"%s\"\n", + PROTOCOL_GOLDSRC_VERSION_REAL, cls.challenge, protinfo, cls.userinfo ); + MSG_WriteBytes( &send, steam_cert, sizeof( steam_cert )); + + NET_SendPacket( NS_CLIENT, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), adr ); + } + else if( cls.legacymode == PROTO_LEGACY ) { // set related userinfo keys if( cl_dlmax.value >= 40000 || cl_dlmax.value < 100 ) @@ -1228,12 +1269,15 @@ CL_Connect_f void CL_Connect_f( void ) { string server; - qboolean legacyconnect = false; + protocolstate_t protocol = PROTO_CURRENT; // hidden hint to connect by using legacy protocol if( Cmd_Argc() == 3 ) { - legacyconnect = !Q_strcmp( Cmd_Argv( 2 ), "legacy" ); + if( !Q_strcmp( Cmd_Argv( 2 ), "legacy" )) + protocol = PROTO_LEGACY; + else if( !Q_strcmp( Cmd_Argv( 2 ), "goldsrc" )) + protocol = PROTO_GOLDSRC; } else if( Cmd_Argc() != 2 ) { @@ -1255,7 +1299,7 @@ void CL_Connect_f( void ) Key_SetKeyDest( key_console ); cls.state = ca_connecting; - cls.legacymode = legacyconnect; + cls.legacymode = protocol; Q_strncpy( cls.servername, server, sizeof( cls.servername )); cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately cls.max_fragment_size = FRAGMENT_MAX_SIZE; // guess a we can establish connection with maximum fragment size @@ -1406,7 +1450,7 @@ int CL_GetSplitSize( void ) if( Host_IsDedicated() ) return 0; - if( !(cls.extensions & NET_EXT_SPLITSIZE) ) + if( !FBitSet( cls.extensions, NET_EXT_SPLITSIZE )) return 1400; splitsize = cl_dlmax.value; @@ -1428,16 +1472,19 @@ void CL_Reconnect( qboolean setup_netchan ) { if( setup_netchan ) { - Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize ); + uint flags = 0; - if( cls.legacymode ) + if( cls.legacymode == PROTO_GOLDSRC ) + { + SetBits( flags, NETCHAN_USE_MUNGE | NETCHAN_USE_BZIP2 | NETCHAN_GOLDSRC ); + } + else if( cls.legacymode == PROTO_LEGACY ) { - unsigned int extensions = Q_atoi( Cmd_Argv( 1 ) ); + unsigned int extensions = Q_atoi( Cmd_Argv( 1 )); - if( extensions & NET_LEGACY_EXT_SPLIT ) + if( FBitSet( extensions, NET_LEGACY_EXT_SPLIT )) { - // only enable incoming split for legacy mode - cls.netchan.split = true; + SetBits( flags, NETCHAN_USE_LEGACY_SPLIT ); Con_Reportf( "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", (int)cl_dlmax.value, 65536 ); } } @@ -1445,12 +1492,11 @@ void CL_Reconnect( qboolean setup_netchan ) { cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" )); - if( cls.extensions & NET_EXT_SPLITSIZE ) - { + if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE )) Con_Reportf( "^2NET_EXT_SPLITSIZE enabled^7 (packet size is %d)\n", (int)cl_dlmax.value ); - } } + Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize, flags ); } else { @@ -1485,7 +1531,7 @@ This is also called on Host_Error, so it shouldn't cause any errors */ void CL_Disconnect( void ) { - cls.legacymode = false; + cls.legacymode = PROTO_CURRENT; if( cls.state == ca_disconnected ) return; @@ -1664,7 +1710,7 @@ void CL_Reconnect_f( void ) if( COM_CheckString( cls.servername )) { - qboolean legacy = cls.legacymode; + protocolstate_t legacy = cls.legacymode; if( cls.state >= ca_connected ) CL_Disconnect(); @@ -1956,7 +2002,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) Con_Reportf( "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c ); // server connection - if( !Q_strcmp( c, "client_connect" )) + if( !Q_strcmp( c, "client_connect" ) || !Q_strcmp( c, S2C_CONNECTION )) { if( !CL_IsFromConnectingServer( from )) return; @@ -2074,7 +2120,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // ping from somewhere Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" ); } - else if( !Q_strcmp( c, "challenge" )) + else if( !Q_strcmp( c, "challenge" ) || !Q_strcmp( c, S2C_CHALLENGE )) { // this message only used during connection // it doesn't make sense after client_connect @@ -2117,12 +2163,19 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) memset( &cls.legacyserver, 0, sizeof( cls.legacyserver )); } } - else if( !Q_strcmp( c, "errormsg" )) + else if( !Q_strcmp( c, "errormsg" ) || c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD ) { + const char *fmt = "%s"; + if( !CL_IsFromConnectingServer( from )) return; args = MSG_ReadString( msg ); + if( c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD ) + { + fmt = "%s\n"; + args++; // skip one byte + } if( !Q_strcmp( args, "Server uses protocol version 48.\n" )) { @@ -2132,7 +2185,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) { if( UI_IsVisible() ) UI_ShowMessageBox( va("^3Server message^7\n%s", args ) ); - Msg( "%s", args ); + Msg( fmt, args ); } } else if( !Q_strcmp( c, "updatemsg" )) @@ -2286,8 +2339,13 @@ void CL_ReadNetMessage( void ) // run special handler for quake demos if( cls.demoplayback == DEMO_QUAKE1 ) CL_ParseQuakeMessage( &net_message, true ); - else if( cls.legacymode ) CL_ParseLegacyServerMessage( &net_message, true ); - else CL_ParseServerMessage( &net_message, true ); + else if( cls.legacymode == PROTO_LEGACY ) + CL_ParseLegacyServerMessage( &net_message, true ); + else if( cls.legacymode == PROTO_GOLDSRC ) + CL_ParseGoldSrcServerMessage( &net_message, true ); + else + CL_ParseServerMessage( &net_message, true ); + cl.send_reply = true; } @@ -2301,7 +2359,11 @@ void CL_ReadNetMessage( void ) if( Netchan_CopyNormalFragments( &cls.netchan, &net_message, &curSize )) { MSG_Init( &net_message, "ServerData", net_message_buffer, curSize ); - CL_ParseServerMessage( &net_message, false ); + + if( cls.legacymode == PROTO_GOLDSRC ) + CL_ParseGoldSrcServerMessage( &net_message, false ); + else + CL_ParseServerMessage( &net_message, false ); } if( Netchan_CopyFileFragments( &cls.netchan, &net_message )) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 81fd545f4..cd729a939 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -846,7 +846,7 @@ void CL_ParseFileTransferFailed( sizebuf_t *msg ) CL_ParseServerData ================== */ -void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ) +void CL_ParseServerData( sizebuf_t *msg, int protocol ) { char gamefolder[MAX_QPATH]; string mapfile; @@ -856,7 +856,18 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ) HPAK_CheckSize( CUSTOM_RES_PATH ); - Con_Reportf( "%s packet received.\n", legacy ? "Legacy serverdata" : "Serverdata" ); + switch( protocol ) + { + case PROTOCOL_VERSION: + Con_Reportf( "Serverdata packet received.\n" ); + break; + case PROTOCOL_LEGACY_VERSION: + Con_Reportf( "Legacy serverdata packet received.\n" ); + break; + case PROTOCOL_GOLDSRC_VERSION: + Con_Reportf( "GoldSrc serverdata packet received.\n" ); + break; + } cls.timestart = Sys_DoubleTime(); cls.demowaiting = false; // server is changed @@ -872,54 +883,69 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ) // parse protocol version number i = MSG_ReadLong( msg ); - - if( legacy ) - { - if( i != PROTOCOL_LEGACY_VERSION ) - Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_LEGACY_VERSION ); - } - else - { - if( i != PROTOCOL_VERSION ) - Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION ); - } + if( i != ( protocol & 0x7F )) + Host_Error( "Server use invalid protocol (%i should be %i)\n", i, ( protocol & 0x7F )); cl.servercount = MSG_ReadLong( msg ); cl.checksum = MSG_ReadLong( msg ); - cl.playernum = MSG_ReadByte( msg ); - cl.maxclients = MSG_ReadByte( msg ); - clgame.maxEntities = MSG_ReadWord( msg ); - if( legacy ) - { - clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_LEGACY_EDICTS ); + if( protocol == PROTOCOL_GOLDSRC_VERSION ) + { + byte clientdllmd5[16]; + byte unused; + + MSG_ReadBytes( msg, clientdllmd5, sizeof( clientdllmd5 )); + cl.maxclients = MSG_ReadByte( msg ); + cl.playernum = MSG_ReadByte( msg ); + unused = MSG_ReadByte( msg ); // coop flag + Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder )); + MSG_ReadString( msg ); // hostname + Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname )); + MSG_ReadString( msg ); // mapcycle????? + unused = MSG_ReadByte( msg ); // vac secure + + background = false; + clgame.maxEntities = GI->max_edicts + (( cl.maxclients - 1 ) * 15 ); + clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_GOLDSRC_EDICTS ); clgame.maxModels = 512; // ??? + Q_strncpy( clgame.maptitle, clgame.mapname, sizeof( clgame.maptitle )); } else { - clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS ); - clgame.maxModels = MSG_ReadWord( msg ); - } - Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname )); - Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle )); - background = MSG_ReadOneBit( msg ); - Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder )); - host.features = (uint)MSG_ReadLong( msg ); + cl.playernum = MSG_ReadByte( msg ); + cl.maxclients = MSG_ReadByte( msg ); + clgame.maxEntities = MSG_ReadWord( msg ); + if( protocol == PROTOCOL_LEGACY_VERSION ) + { + clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_LEGACY_EDICTS ); + clgame.maxModels = 512; // ??? + } + else + { + clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS ); + clgame.maxModels = MSG_ReadWord( msg ); + } + Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname )); + Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle )); + background = MSG_ReadOneBit( msg ); + Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder )); + host.features = (uint)MSG_ReadLong( msg ); - if( !legacy ) - { - // receive the player hulls - for( i = 0; i < MAX_MAP_HULLS * 3; i++ ) + if( protocol != PROTOCOL_LEGACY_VERSION ) { - host.player_mins[i/3][i%3] = MSG_ReadChar( msg ); - host.player_maxs[i/3][i%3] = MSG_ReadChar( msg ); + // receive the player hulls + for( i = 0; i < MAX_MAP_HULLS * 3; i++ ) + { + host.player_mins[i/3][i%3] = MSG_ReadChar( msg ); + host.player_maxs[i/3][i%3] = MSG_ReadChar( msg ); + } } } Q_snprintf( mapfile, sizeof( mapfile ), "maps/%s.bsp", clgame.mapname ); - if( CRC32_MapFile( &mapCRC, mapfile, cl.maxclients > 1 )) + if( CRC32_MapFile( &cl.worldmapCRC, mapfile, cl.maxclients > 1 )) { // validate map checksum - if( mapCRC != cl.checksum ) + if( cl.worldmapCRC != cl.checksum ) { Con_Printf( S_ERROR "Your map [%s] differs from the server's.\n", clgame.mapname ); CL_Disconnect_f(); // for local game, call EndGame @@ -1000,7 +1026,7 @@ void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ) COM_ClearCustomizationList( &cl.players[i].customdata, true ); CL_CreateCustomizationList(); - if( !legacy ) + if( protocol != PROTOCOL_LEGACY_VERSION ) { // request resources from server CL_ServerCommand( true, "sendres %i\n", cl.servercount ); @@ -1152,7 +1178,15 @@ void CL_ParseClientData( sizebuf_t *msg ) from_wd = nullwd; } - MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + Delta_ReadGSFields( msg, DT_CLIENTDATA_T, from_cd, to_cd, cl.mtime[0] ); + } + else + { + MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] ); + } + for( i = 0; i < 64; i++ ) { @@ -1160,9 +1194,16 @@ void CL_ParseClientData( sizebuf_t *msg ) if( !MSG_ReadOneBit( msg )) break; // read the weapon idx - idx = MSG_ReadUBitLong( msg, cls.legacymode ? MAX_LEGACY_WEAPON_BITS : MAX_WEAPON_BITS ); + idx = MSG_ReadUBitLong( msg, cls.legacymode == PROTO_LEGACY ? MAX_LEGACY_WEAPON_BITS : MAX_WEAPON_BITS ); - MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + Delta_ReadGSFields( msg, DT_WEAPONDATA_T, &from_wd[idx], &to_wd[idx], cl.mtime[0] ); + } + else + { + MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] ); + } } // make a local copy of physinfo @@ -1179,7 +1220,7 @@ void CL_ParseClientData( sizebuf_t *msg ) CL_ParseBaseline ================== */ -void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy ) +void CL_ParseBaseline( sizebuf_t *msg, int protocol ) { int i, newnum; entity_state_t nullstate; @@ -1190,17 +1231,31 @@ void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy ) memset( &nullstate, 0, sizeof( nullstate )); + if( protocol == PROTOCOL_GOLDSRC_VERSION ) + MSG_StartBitWriting( msg ); + while( 1 ) { - if( legacy ) + if( protocol == PROTOCOL_VERSION ) + { + newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); + if( newnum == LAST_EDICT ) break; // end of baselines + } + else if( protocol == PROTOCOL_LEGACY_VERSION ) { newnum = MSG_ReadWord( msg ); } - else + else if( protocol == PROTOCOL_GOLDSRC_VERSION ) { - newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); - if( newnum == LAST_EDICT ) break; // end of baselines + unsigned int value = MSG_ReadWord( msg ); + if( value == 0xFFFF ) + break; // end of baselines + + MSG_SeekToBit( msg, -16, SEEK_CUR ); + + newnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS ); } + player = CL_IsPlayerIndex( newnum ); if( newnum >= clgame.maxEntities ) @@ -1210,24 +1265,53 @@ void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy ) memset( &ent->prevstate, 0, sizeof( ent->prevstate )); ent->index = newnum; - MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f ); + if( protocol == PROTOCOL_GOLDSRC_VERSION ) + { + int type = MSG_ReadUBitLong( msg, 2 ); + + int bits = MSG_GetNumBitsWritten( msg ); - if( legacy ) + if( player ) + Delta_ReadGSFields( msg, DT_ENTITY_STATE_PLAYER_T, &ent->prevstate, &ent->baseline, 1.0f ); + else if( type != ENTITY_NORMAL ) + Delta_ReadGSFields( msg, DT_CUSTOM_ENTITY_STATE_T, &ent->prevstate, &ent->baseline, 1.0f ); + else + Delta_ReadGSFields( msg, DT_ENTITY_STATE_T, &ent->prevstate, &ent->baseline, 1.0f ); + + ent->baseline.entityType = type; + ent->baseline.number = newnum; + } + else + { + MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f ); + } + + if( protocol == PROTOCOL_LEGACY_VERSION ) { break; // only one baseline allowed in legacy protocol } } - if( !legacy ) + if( protocol != PROTOCOL_LEGACY_VERSION ) { cl.instanced_baseline_count = MSG_ReadUBitLong( msg, 6 ); for( i = 0; i < cl.instanced_baseline_count; i++ ) { - newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); - MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f ); + if( protocol == PROTOCOL_GOLDSRC_VERSION ) + { + Delta_ReadGSFields( msg, DT_ENTITY_STATE_T, &nullstate, &cl.instanced_baseline[i], 1.0f ); + } + else + { + newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); + MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f ); + } } } + + if( protocol == PROTOCOL_GOLDSRC_VERSION ) + MSG_EndBitWriting( msg ); } /* @@ -1239,11 +1323,12 @@ void CL_ParseLightStyle( sizebuf_t *msg ) { int style; const char *s; - float f; + float f = 0.0f; style = MSG_ReadByte( msg ); s = MSG_ReadString( msg ); - f = MSG_ReadFloat( msg ); + if( cls.legacymode != PROTO_GOLDSRC ) + f = MSG_ReadFloat( msg ); CL_SetLightstyle( style, s, f ); } @@ -1372,21 +1457,34 @@ CL_UpdateUserinfo collect userinfo from all players ================ */ -void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy ) +void CL_UpdateUserinfo( sizebuf_t *msg, int protocol ) { int slot, id; qboolean active; player_info_t *player; - slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS ); + if( protocol == PROTOCOL_VERSION ) + { + slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS ); + id = MSG_ReadLong( msg ); + active = MSG_ReadOneBit( msg ); + } + else if( protocol == PROTOCOL_LEGACY_VERSION ) + { + slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS ); + id = -1; + active = MSG_ReadOneBit( msg ); + } + else if( protocol == PROTOCOL_GOLDSRC_VERSION ) + { + slot = MSG_ReadByte( msg ); + id = MSG_ReadLong( msg ); + active = true; + } if( slot >= MAX_CLIENTS ) Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" ); - - if( !legacy ) - id = MSG_ReadLong( msg ); // unique user ID player = &cl.players[slot]; - active = MSG_ReadOneBit( msg ) ? true : false; if( active ) { @@ -1396,7 +1494,8 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy ) player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" )); player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" )); player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" )); - if( !legacy ) + + if( protocol != PROTOCOL_LEGACY_VERSION ) MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey )); if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t )); @@ -1664,7 +1763,13 @@ void CL_RegisterResources( sizebuf_t *msg ) // done with all resources, issue prespawn command. // Include server count in case server disconnects and changes level during d/l MSG_BeginClientCmd( msg, clc_stringcmd ); - MSG_WriteStringf( msg, "spawn %i", cl.servercount ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + int32_t crc = cl.worldmapCRC; + COM_Munge2( (byte *)&crc, sizeof( crc ), ( 0xFF - cl.servercount ) & 0xFF ); + MSG_WriteStringf( msg, "spawn %i %i", cl.servercount, crc ); + } + else MSG_WriteStringf( msg, "spawn %i", cl.servercount ); } } else @@ -1702,7 +1807,7 @@ void CL_ParseConsistencyInfo( sizebuf_t *msg ) isdelta = MSG_ReadOneBit( msg ); if( isdelta ) delta = MSG_ReadUBitLong( msg, 5 ) + lastcheck; - else delta = MSG_ReadUBitLong( msg, MAX_MODEL_BITS ); + else delta = MSG_ReadUBitLong( msg, cls.legacymode == PROTO_GOLDSRC ? 10 : MAX_MODEL_BITS ); skip = delta - lastcheck; @@ -1744,7 +1849,9 @@ void CL_ParseResourceList( sizebuf_t *msg ) resource_t *pResource; int i, total; - total = MSG_ReadUBitLong( msg, MAX_RESOURCE_BITS ); + if( cls.legacymode == PROTO_GOLDSRC ) + total = MSG_ReadUBitLong( msg, MAX_GOLDSRC_RESOURCE_BITS ); + else total = MSG_ReadUBitLong( msg, MAX_RESOURCE_BITS ); for( i = 0; i < total; i++ ) { @@ -1753,7 +1860,7 @@ void CL_ParseResourceList( sizebuf_t *msg ) Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName )); pResource->nIndex = MSG_ReadUBitLong( msg, MAX_MODEL_BITS ); - pResource->nDownloadSize = MSG_ReadSBitLong( msg, 24 ); + pResource->nDownloadSize = MSG_ReadBitLong( msg, 24, cls.legacymode != PROTO_GOLDSRC ); pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING; if( FBitSet( pResource->ucFlags, RES_CUSTOM )) @@ -2337,13 +2444,13 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message ) break; case svc_serverdata: Cbuf_Execute(); // make sure any stuffed commands are done - CL_ParseServerData( msg, false ); + CL_ParseServerData( msg, PROTOCOL_VERSION ); break; case svc_lightstyle: CL_ParseLightStyle( msg ); break; case svc_updateuserinfo: - CL_UpdateUserinfo( msg, false ); + CL_UpdateUserinfo( msg, PROTOCOL_VERSION ); break; case svc_deltatable: Delta_ParseTableField( msg ); @@ -2373,7 +2480,7 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message ) cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; break; case svc_spawnbaseline: - CL_ParseBaseline( msg, false ); + CL_ParseBaseline( msg, PROTOCOL_VERSION ); break; case svc_temp_entity: CL_ParseTempEntity( msg ); diff --git a/engine/client/cl_parse_48.c b/engine/client/cl_parse_48.c index 253994b7d..92ec4e710 100644 --- a/engine/client/cl_parse_48.c +++ b/engine/client/cl_parse_48.c @@ -457,13 +457,13 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ) break; case svc_serverdata: Cbuf_Execute(); // make sure any stuffed commands are done - CL_ParseServerData( msg, true ); + CL_ParseServerData( msg, PROTOCOL_LEGACY_VERSION ); break; case svc_lightstyle: CL_ParseLightStyle( msg ); break; case svc_updateuserinfo: - CL_UpdateUserinfo( msg, true ); + CL_UpdateUserinfo( msg, PROTOCOL_LEGACY_VERSION ); break; case svc_deltatable: Delta_ParseTableField( msg ); @@ -493,7 +493,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ) cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; break; case svc_spawnbaseline: - CL_ParseBaseline( msg, true ); + CL_ParseBaseline( msg, PROTOCOL_LEGACY_VERSION ); break; case svc_temp_entity: CL_ParseTempEntity( msg ); @@ -689,7 +689,7 @@ void CL_LegacyPrecache_f( void ) void CL_LegacyUpdateInfo( void ) { - if( !cls.legacymode ) + if( cls.legacymode == PROTO_LEGACY ) return; if( cls.state != ca_active ) @@ -701,5 +701,5 @@ void CL_LegacyUpdateInfo( void ) qboolean CL_LegacyMode( void ) { - return cls.legacymode; + return cls.legacymode == PROTO_LEGACY; } diff --git a/engine/client/cl_parse_gs.c b/engine/client/cl_parse_gs.c new file mode 100644 index 000000000..d56b8d502 --- /dev/null +++ b/engine/client/cl_parse_gs.c @@ -0,0 +1,800 @@ +/* +cl_parse.c - parse a message received from the server (GoldSrc 48 protocol) +Copyright (C) 2008 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "common.h" +#include "client.h" +#include "net_encode.h" +#include "particledef.h" +#include "cl_tent.h" +#include "shake.h" +#include "hltv.h" +#include "input.h" +#include "server.h" + +static void CL_ParseExtraInfo( sizebuf_t *msg ) +{ + string clientfallback; + + Q_strncpy( clientfallback, MSG_ReadString( msg ), sizeof( clientfallback )); + Cvar_FullSet( "sv_cheats", MSG_ReadByte( msg ) ? "1" : "0", FCVAR_READ_ONLY | FCVAR_SERVER ); +} + +static void CL_ParseNewMovevars( sizebuf_t *msg ) +{ + Delta_InitClient(); // finalize client delta's + + clgame.movevars.gravity = MSG_ReadFloat( msg ); + clgame.movevars.stopspeed = MSG_ReadFloat( msg ); + clgame.movevars.maxspeed = MSG_ReadFloat( msg ); + clgame.movevars.spectatormaxspeed = MSG_ReadFloat( msg ); + clgame.movevars.accelerate = MSG_ReadFloat( msg ); + clgame.movevars.airaccelerate = MSG_ReadFloat( msg ); + clgame.movevars.wateraccelerate = MSG_ReadFloat( msg ); + clgame.movevars.friction = MSG_ReadFloat( msg ); + clgame.movevars.edgefriction = MSG_ReadFloat( msg ); + clgame.movevars.waterfriction = MSG_ReadFloat( msg ); + clgame.movevars.entgravity = MSG_ReadFloat( msg ); + clgame.movevars.bounce = MSG_ReadFloat( msg ); + clgame.movevars.stepsize = MSG_ReadFloat( msg ); + clgame.movevars.maxvelocity = MSG_ReadFloat( msg ); + clgame.movevars.zmax = MSG_ReadFloat( msg ); + clgame.movevars.waveHeight = MSG_ReadFloat( msg ); + clgame.movevars.footsteps = MSG_ReadByte( msg ); + clgame.movevars.rollangle = MSG_ReadFloat( msg ); + clgame.movevars.rollspeed = MSG_ReadFloat( msg ); + clgame.movevars.skycolor_r = MSG_ReadFloat( msg ); + clgame.movevars.skycolor_g = MSG_ReadFloat( msg ); + clgame.movevars.skycolor_b = MSG_ReadFloat( msg ); + clgame.movevars.skyvec_x = MSG_ReadFloat( msg ); + clgame.movevars.skyvec_y = MSG_ReadFloat( msg ); + clgame.movevars.skyvec_z = MSG_ReadFloat( msg ); + + Q_strncpy( clgame.movevars.skyName, MSG_ReadString( msg ), sizeof( clgame.movevars.skyName )); + + // water alpha is not allowed + if( !FBitSet( world.flags, FWORLD_WATERALPHA )) + clgame.movevars.wateralpha = 1.0f; + + // update sky if changed + if( Q_strcmp( clgame.oldmovevars.skyName, clgame.movevars.skyName ) && cl.video_prepped ) + ref.dllFuncs.R_SetupSky( clgame.movevars.skyName ); + + memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t )); + clgame.entities->curstate.scale = clgame.movevars.waveHeight; + + // keep features an actual! + clgame.oldmovevars.features = clgame.movevars.features = host.features; +} + +static void CL_ParseNewUserMsg( sizebuf_t *msg ) +{ + int svc_num, size; + char s[16]; + + svc_num = MSG_ReadByte( msg ); + size = MSG_ReadByte( msg ); + MSG_ReadBytes( msg, s, sizeof( s )); + + s[15] = 0; + if( size == 255 ) + size = -1; + + CL_LinkUserMessage( s, svc_num, size ); +} + +typedef struct delta_header_t +{ + qboolean remove : 1; + qboolean custom : 1; + qboolean instanced : 1; + uint instanced_baseline_index : 6; + uint offset : 6; +} delta_header_t; + +static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr ) +{ + int entnum; + + hdr->remove = hdr->custom = hdr->instanced = false; + hdr->instanced_baseline_index = hdr->offset = 0; + entnum = oldnum; + + if( !delta ) + { + // if we have one bit set, then it's a next entity in line + // if we have next bit NON set, then it's a one of next 64 entities + // if not, it's a new entity + if( MSG_ReadOneBit( msg )) + entnum++; + else if( MSG_ReadOneBit( msg ) == 0 ) + entnum += MSG_ReadUBitLong( msg, 6 ); + else + entnum += MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS ); + } + else + { + // does this packet encode entity deletion? + hdr->remove = MSG_ReadOneBit( msg ); + + // same logic as above + if( MSG_ReadOneBit( msg ) == 0 ) + entnum += MSG_ReadUBitLong( msg, 6 ); + else entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS ); + } + + // if we are not removing this entity + if( !hdr->remove ) + { + hdr->custom = MSG_ReadOneBit( msg ); + + hdr->instanced = false; + hdr->instanced_baseline_index = 0; + + // do we got instanced baselines in svc_spawnbaselines? + if( cl.instanced_baseline_count ) + { + hdr->instanced = MSG_ReadOneBit( msg ); + if( hdr->instanced ) + hdr->instanced_baseline_index = MSG_ReadUBitLong( msg, 6 ); + } + + hdr->offset = 0; + if( !delta && !hdr->instanced ) + { + if( MSG_ReadOneBit( msg )) + hdr->offset = MSG_ReadUBitLong( msg, 6 ); + } + } + + return entnum; +} + +static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum ) +{ + if( hdr->custom ) + return DT_CUSTOM_ENTITY_STATE_T; + + if( CL_IsPlayerIndex( entnum )) + return DT_ENTITY_STATE_PLAYER_T; + + return DT_ENTITY_STATE_T; +} + +static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg ) +{ + frame->valid = false; + cl.validsequence = 0; // can't render a frame + + // read it all but ignore it + while( 1 ) + { + int num = 0; + entity_state_t from = { 0 }, to; + delta_header_t hdr; + + if( MSG_ReadWord( msg ) != 0 ) + { + MSG_SeekToBit( msg, -16, SEEK_CUR ); + + num = CL_ParseDeltaHeader( msg, false, num, &hdr ); + } + else break; + + if( MSG_CheckOverflow( msg )) + Host_Error( "%s: overflow\n", __func__ ); + + if( hdr.remove ) + continue; + + Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] ); + } + + MSG_EndBitWriting( msg ); +} + +static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t *from, qboolean has_update ) +{ + cl_entity_t *ent; + entity_state_t *to; + qboolean newent = from == NULL; + int pack = frame->num_entities; + + // alloc next slot to store update + to = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities]; + + if(( newnum < 0 ) || ( newnum >= clgame.maxEntities )) + { + Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum ); + Host_Error( "%s: bad delta entity number: %i", __func__, newnum ); + return; + } + + ent = CL_EDICT_NUM( newnum ); + if( hdr->remove ) + { + if( !newent ) + CL_KillDeadBeams( ent ); + return; + } + + ent->index = newnum; // enumerate entity index + if( newent ) + { + if( hdr->instanced ) + from = &cl.instanced_baseline[hdr->instanced_baseline_index]; + else if( hdr->offset != 0 ) + from = &cls.packet_entities[(cls.next_client_entities - hdr->offset) % cls.num_client_entities]; + else + from = &ent->baseline; + } + + if( has_update ) + Delta_ReadGSFields( msg, CL_GetEntityDelta( hdr, newnum ), from, to, cl.mtime[0] ); + else memcpy( to, from, sizeof( entity_state_t )); + + to->entityType = hdr->custom ? ENTITY_BEAM : ENTITY_NORMAL; + to->number = newnum; + + if( newent ) + { + // interpolation must be reset + SETVISBIT( frame->flags, pack ); + + // release beams from previous entity + CL_KillDeadBeams( ent ); + } + + // add entity to packet + cls.next_client_entities++; + frame->num_entities++; +} + +static void CL_CopyPacketEntity( frame_t *frame, int num, entity_state_t *from ) +{ + delta_header_t fakehdr = + { + .custom = FBitSet( from->entityType, ENTITY_BEAM ) == ENTITY_BEAM, + }; + CL_DeltaEntityGS( &fakehdr, NULL, frame, num, from, false ); +} + +static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta ) +{ + frame_t *frame, *oldframe; + int oldindex, newnum, oldnum, numbase = 0; + entity_state_t *oldent; + int count; + int playerbytes = 0; + + // save first uncompressed packet as timestamp + if( cls.changelevel && !delta && cls.demorecording ) + CL_WriteDemoJumpTime(); + + count = MSG_ReadWord( msg ); + + frame = &cl.frames[cl.parsecountmod]; + memset( frame->flags, 0, sizeof( frame->flags )); + frame->first_entity = cls.next_client_entities; + frame->num_entities = 0; + frame->valid = true; + + MSG_StartBitWriting( msg ); + + if( delta ) + { + uint oldpacket = MSG_ReadByte( msg ); + oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK]; + + if( !CL_ValidateDeltaPacket( oldpacket, oldframe )) + { + CL_FlushEntityPacketGS( frame, msg ); + return playerbytes; + } + } + else + { + oldframe = NULL; + cl.send_reply = true; + cls.demowaiting = false; + } + + cl.validsequence = cls.netchan.incoming_sequence; + + oldent = NULL; + oldindex = 0; + oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent ); + + // read it all but ignore it + while( 1 ) + { + int bufstart; + qboolean player; + delta_header_t hdr; + int val = MSG_ReadWord( msg ); + + if( val ) + { + MSG_SeekToBit( msg, -16, SEEK_CUR ); + numbase = newnum = CL_ParseDeltaHeader( msg, delta, numbase, &hdr ); + } + else break; + + if( MSG_CheckOverflow( msg )) + Host_Error( "%s: overflow\n", __func__ ); + + player = CL_IsPlayerIndex( newnum ); + + while( oldnum < newnum ) + { + // one or more entities from the old packet are unchanged + CL_CopyPacketEntity( frame, oldnum, oldent ); + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); + } + + bufstart = MSG_GetNumBytesRead( msg ); + + if( oldnum == newnum ) + { + // from delta + CL_DeltaEntityGS( &hdr, msg, frame, newnum, oldent, true ); + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); + } + else if( oldnum > newnum ) + { + // from baseline + CL_DeltaEntityGS( &hdr, msg, frame, newnum, NULL, true ); + } + + if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufstart; + } + + if( MSG_CheckOverflow( msg )) + Host_Error( "%s: overflow\n", __func__ ); + + // any remaining entities in the old frame are copied over + while( oldnum != MAX_ENTNUMBER ) + { + // one or more entities from the old packet are unchanged + CL_CopyPacketEntity( frame, oldnum, oldent ); + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); + } + + MSG_EndBitWriting( msg ); + + if( frame->num_entities != count ) + Con_Reportf( S_WARN "CL_Parse%sPacketEntitiesGS: (%i should be %i)\n", delta ? "Delta" : "", frame->num_entities, count ); + + if( !frame->valid ) + return playerbytes; + + CL_ProcessPacket( frame ); + CL_SetSolidEntities(); + + // first update is the final signon stage where we actually receive an entity (i.e., the world at least) + if( cls.signon == ( SIGNONS - 1 )) + { + // we are done with signon sequence. + cls.signon = SIGNONS; + + // Clear loading plaque. + CL_SignonReply (); + } + + return playerbytes; +} + +static float MSG_ReadGSBitCoord( sizebuf_t *sb ) +{ + float value = 0; + int ival, fval; + + ival = MSG_ReadOneBit( sb ); + fval = MSG_ReadOneBit( sb ); + + if( ival || fval ) + { + int sign = MSG_ReadOneBit( sb ); + + if( ival ) + ival = MSG_ReadUBitLong( sb, 12 ); + if( fval ) + fval = MSG_ReadUBitLong( sb, 3 ); + + value = (float)( fval / 8.0 + ival ); + if( sign ) + value = -value; + } + + return value; +} + +static void MSG_ReadGSBitVec3Coord( sizebuf_t *sb, vec3_t fa ) +{ + qboolean x, y, z; + + VectorClear( fa ); + + x = MSG_ReadOneBit( sb ); + y = MSG_ReadOneBit( sb ); + z = MSG_ReadOneBit( sb ); + if( x ) + fa[0] = MSG_ReadGSBitCoord( sb ); + if( y ) + fa[1] = MSG_ReadGSBitCoord( sb ); + if( z ) + fa[2] = MSG_ReadGSBitCoord( sb ); +} + +static void CL_ParseSoundPacketGS( sizebuf_t *msg ) +{ + vec3_t pos; + int chan, sound; + float volume, attn; + int flags, pitch, entnum; + sound_t handle = 0; + + MSG_StartBitWriting( msg ); + + flags = MSG_ReadUBitLong( msg, 9 ); + + if( FBitSet( flags, SND_VOLUME )) + volume = (float)MSG_ReadByte( msg ) / 255.0f; + else volume = VOL_NORM; + + if( FBitSet( flags, SND_ATTENUATION )) + attn = (float)MSG_ReadByte( msg ) / 64.0f; + else attn = ATTN_NONE; + + chan = MSG_ReadUBitLong( msg, 3 ); + entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS ); + sound = MSG_ReadUBitLong( msg, FBitSet( flags, SND_SEQUENCE ) ? 16 : 8 ); + MSG_ReadGSBitVec3Coord( msg, pos ); + + if( FBitSet( flags, SND_PITCH )) + pitch = MSG_ReadByte( msg ); + else pitch = PITCH_NORM; + + MSG_EndBitWriting( msg ); + + if( FBitSet( flags, SND_SENTENCE )) + { + char sentenceName[32]; + + if( FBitSet( flags, SND_SEQUENCE )) + Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS_NONSENTENCE ); + else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound ); + + handle = S_RegisterSound( sentenceName ); + } + else handle = cl.sound_index[sound]; // see precached sound + + if( !cl.audio_prepped ) + return; // too early + + // g-cont. sound and ambient sound have only difference with channel + if( chan == CHAN_STATIC ) + { + S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags ); + } + else + { + S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags ); + } +} + +static void CL_ParseSpawnStaticSound( sizebuf_t *msg ) +{ + vec3_t pos; + int handle, entnum, pitch, flags; + float volume, attn; + + MSG_ReadVec3Coord( msg, pos ); + handle = MSG_ReadShort( msg ); + volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f ); + attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f ); + entnum = MSG_ReadShort( msg ); + pitch = MSG_ReadByte( msg ); + flags = MSG_ReadByte( msg ); + + S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags ); +} + +/* +===================================================================== + +ACTION MESSAGES + +===================================================================== +*/ +/* +===================== +CL_ParseGoldSrcServerMessage + +dispatch messages +===================== +*/ +void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ) +{ + size_t bufStart, playerbytes; + int cmd, param1, param2; + int old_background; + const char *s; + + cls.starting_count = MSG_GetNumBytesRead( msg ); // updates each frame + CL_Parse_Debug( true ); // begin parsing + + if( normal_message ) + { + // assume no entity/player update this packet + if( cls.state == ca_active ) + { + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].valid = false; + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = false; + } + else + { + CL_ResetFrame( &cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK] ); + } + } + + // parse the message + while( 1 ) + { + if( MSG_CheckOverflow( msg )) + { + Host_Error( "CL_ParseServerMessage: overflow!\n" ); + return; + } + + // mark start position + bufStart = MSG_GetNumBytesRead( msg ); + + // end of message (align bits) + if( MSG_GetNumBitsLeft( msg ) < 8 ) + break; + + cmd = MSG_ReadServerCmd( msg ); + + // record command for debugging spew on parse problem + CL_Parse_RecordCommand( cmd, bufStart ); + + // other commands + switch( cmd ) + { + case svc_bad: + Host_Error( "svc_bad\n" ); + break; + case svc_nop: + // this does nothing + break; + case svc_disconnect: + CL_Drop (); + Host_AbortCurrentFrame (); + break; + case svc_event: + MSG_StartBitWriting( msg ); + CL_ParseEvent( msg ); + MSG_EndBitWriting( msg ); + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_setview: + CL_ParseViewEntity( msg ); + break; + case svc_sound: + CL_ParseSoundPacketGS( msg ); + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_time: + CL_ParseServerTime( msg ); + break; + case svc_print: + Con_Printf( "%s", MSG_ReadString( msg )); + break; + case svc_stufftext: + s = MSG_ReadString( msg ); +#ifdef HACKS_RELATED_HLMODS + // disable Cry Of Fear antisave protection + if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) + break; // too early +#endif + Cbuf_AddFilteredText( s ); + break; + case svc_setangle: + CL_ParseSetAngle( msg ); + break; + case svc_goldsrc_serverinfo: + Cbuf_Execute(); // make sure any stuffed commands are done + CL_ParseServerData( msg, PROTOCOL_GOLDSRC_VERSION ); + Delta_InitMeta(); + break; + case svc_lightstyle: + CL_ParseLightStyle( msg ); + break; + case svc_updateuserinfo: + CL_UpdateUserinfo( msg, PROTOCOL_GOLDSRC_VERSION ); + break; + case svc_goldsrc_deltadescription: + Delta_ParseTableField_GS( msg ); + break; + case svc_clientdata: + MSG_StartBitWriting( msg ); + CL_ParseClientData( msg ); + MSG_EndBitWriting( msg ); + cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_pings: + MSG_StartBitWriting( msg ); + CL_UpdateUserPings( msg ); + MSG_EndBitWriting( msg ); + break; + case svc_particle: + CL_ParseParticles( msg ); + break; + case svc_spawnstatic: + CL_ParseStaticEntity( msg ); + break; + case svc_event_reliable: + MSG_StartBitWriting( msg ); + CL_ParseReliableEvent( msg ); + MSG_EndBitWriting( msg ); + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_spawnbaseline: + CL_ParseBaseline( msg, PROTOCOL_GOLDSRC_VERSION ); + break; + case svc_temp_entity: + CL_ParseTempEntity( msg ); + cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_setpause: + cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); + break; + case svc_signonnum: + CL_ParseSignon( msg ); + break; + case svc_centerprint: + CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); + break; + case svc_goldsrc_spawnstaticsound: + CL_ParseSpawnStaticSound( msg ); + break; + case svc_intermission: + cl.intermission = 1; + break; + case svc_finale: + CL_ParseFinaleCutscene( msg, 2 ); + break; + case svc_cdtrack: + param1 = MSG_ReadByte( msg ); + param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum + param2 = MSG_ReadByte( msg ); + param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum + S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false ); + break; + case svc_restore: + CL_ParseRestore( msg ); + break; + case svc_cutscene: + CL_ParseFinaleCutscene( msg, 3 ); + break; + case svc_weaponanim: + param1 = MSG_ReadByte( msg ); // iAnim + param2 = MSG_ReadByte( msg ); // body + CL_WeaponAnim( param1, param2 ); + break; + case svc_roomtype: + param1 = MSG_ReadShort( msg ); + Cvar_SetValue( "room_type", param1 ); + break; + case svc_addangle: + CL_ParseAddAngle( msg ); + break; + case svc_goldsrc_newusermsg: + CL_ParseNewUserMsg( msg ); + break; + case svc_packetentities: + playerbytes = CL_ParsePacketEntitiesGS( msg, false ); + cl.frames[cl.parsecountmod].graphdata.players += playerbytes; + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; + break; + case svc_deltapacketentities: + playerbytes = CL_ParsePacketEntitiesGS( msg, true ); + cl.frames[cl.parsecountmod].graphdata.players += playerbytes; + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; + break; + case svc_choke: + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; + break; + case svc_resourcelist: + MSG_StartBitWriting( msg ); + CL_ParseResourceList( msg ); + MSG_EndBitWriting( msg ); + break; + case svc_goldsrc_newmovevars: + CL_ParseNewMovevars( msg ); + break; + case svc_resourcerequest: + CL_ParseResourceRequest( msg ); + break; + case svc_customization: + CL_ParseCustomization( msg ); + break; + case svc_crosshairangle: + CL_ParseCrosshairAngle( msg ); + break; + case svc_soundfade: + CL_ParseSoundFade( msg ); + break; + case svc_filetxferfailed: + CL_ParseFileTransferFailed( msg ); + break; + case svc_hltv: + CL_ParseHLTV( msg ); + break; + case svc_director: + CL_ParseDirector( msg ); + break; + case svc_voiceinit: + CL_ParseVoiceInit( msg ); + break; + case svc_voicedata: + CL_ParseVoiceData( msg ); + cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_resourcelocation: + CL_ParseResLocation( msg ); + break; + case svc_goldsrc_sendextrainfo: + CL_ParseExtraInfo( msg ); + break; + case svc_querycvarvalue: + CL_ParseCvarValue( msg, false ); + break; + case svc_querycvarvalue2: + CL_ParseCvarValue( msg, true ); + break; + case svc_exec: + CL_ParseExec( msg ); + break; + default: + CL_ParseUserMessage( msg, cmd ); + cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; + break; + } + } + + cl.frames[cl.parsecountmod].graphdata.msgbytes += MSG_GetNumBytesRead( msg ) - cls.starting_count; + CL_Parse_Debug( false ); // done + + // we don't know if it is ok to save a demo message until + // after we have parsed the frame + if( !cls.demoplayback ) + { + if( cls.demorecording && !cls.demowaiting ) + { + CL_WriteDemoMessage( false, cls.starting_count, msg ); + } + else if( cls.state != ca_active ) + { + CL_WriteDemoMessage( true, cls.starting_count, msg ); + } + } +} + +qboolean CL_GoldSrcMode( void ) +{ + return cls.legacymode == PROTO_GOLDSRC; +} diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 9f2a7e496..af55da442 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -1894,8 +1894,8 @@ handle temp-entity messages */ void CL_ParseTempEntity( sizebuf_t *msg ) { - sizebuf_t buf; - byte pbuf[2048]; + sizebuf_t buf, *pbuf; + byte msg_data[2048]; int iSize; int type, color, count, flags; int decalIndex, modelIndex, entityIndex; @@ -1908,23 +1908,32 @@ void CL_ParseTempEntity( sizebuf_t *msg ) dlight_t *dl; sound_t hSound; - if( cls.legacymode ) - iSize = MSG_ReadByte( msg ); - else iSize = MSG_ReadWord( msg ); - decalIndex = modelIndex = entityIndex = 0; - // this will probably be fatal anyway - if( iSize > sizeof( pbuf )) - Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __FUNCTION__ ); + if( cls.legacymode != PROTO_GOLDSRC ) + { + if( cls.legacymode == PROTO_LEGACY ) + iSize = MSG_ReadByte( msg ); + else iSize = MSG_ReadWord( msg ); + + // this will probably be fatal anyway + if( iSize > sizeof( pbuf )) + Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __FUNCTION__ ); + + // parse user message into buffer + MSG_ReadBytes( msg, msg_data, iSize ); - // parse user message into buffer - MSG_ReadBytes( msg, pbuf, iSize ); + // init a safe tempbuffer + MSG_Init( &buf, "TempEntity", msg_data, iSize ); - // init a safe tempbuffer - MSG_Init( &buf, "TempEntity", pbuf, iSize ); + pbuf = &buf; + } + else + { + pbuf = msg; // no safe guards! + } - type = MSG_ReadByte( &buf ); + type = MSG_ReadByte( pbuf ); switch( type ) { @@ -1941,77 +1950,77 @@ void CL_ParseTempEntity( sizebuf_t *msg ) case TE_BEAMRING: case TE_BEAMHOSE: case TE_KILLBEAM: - CL_ParseViewBeam( &buf, type ); + CL_ParseViewBeam( pbuf, type ); break; case TE_GUNSHOT: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); R_RicochetSound( pos ); R_RunParticleEffect( pos, vec3_origin, 0, 20 ); break; case TE_EXPLOSION: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - scale = (float)(MSG_ReadByte( &buf ) * 0.1f); - frameRate = MSG_ReadByte( &buf ); - flags = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + scale = (float)(MSG_ReadByte( pbuf ) * 0.1f); + frameRate = MSG_ReadByte( pbuf ); + flags = MSG_ReadByte( pbuf ); R_Explosion( pos, modelIndex, scale, frameRate, flags ); break; case TE_TAREXPLOSION: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); R_BlobExplosion( pos ); hSound = S_RegisterSound( cl_explode_sounds[0] ); S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 ); break; case TE_SMOKE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - scale = (float)(MSG_ReadByte( &buf ) * 0.1f); - frameRate = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + scale = (float)(MSG_ReadByte( pbuf ) * 0.1f); + frameRate = MSG_ReadByte( pbuf ); pTemp = R_DefaultSprite( pos, modelIndex, frameRate ); R_Sprite_Smoke( pTemp, scale ); break; case TE_TRACER: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); R_TracerEffect( pos, pos2 ); break; case TE_SPARKS: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); R_SparkShower( pos ); break; case TE_LAVASPLASH: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); R_LavaSplash( pos ); break; case TE_TELEPORT: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); R_TeleportSplash( pos ); break; case TE_EXPLOSION2: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - color = MSG_ReadByte( &buf ); - count = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + color = MSG_ReadByte( pbuf ); + count = MSG_ReadByte( pbuf ); R_ParticleExplosion2( pos, color, count ); dl = CL_AllocDlight( 0 ); @@ -2028,25 +2037,25 @@ void CL_ParseTempEntity( sizebuf_t *msg ) case TE_WORLDDECAL: case TE_WORLDDECALHIGH: case TE_DECALHIGH: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); if( type == TE_BSPDECAL ) { - decalIndex = MSG_ReadShort( &buf ); - entityIndex = MSG_ReadShort( &buf ); + decalIndex = MSG_ReadShort( pbuf ); + entityIndex = MSG_ReadShort( pbuf ); if( entityIndex ) - modelIndex = MSG_ReadShort( &buf ); + modelIndex = MSG_ReadShort( pbuf ); else modelIndex = 0; } else { - decalIndex = MSG_ReadByte( &buf ); + decalIndex = MSG_ReadByte( pbuf ); if( type == TE_DECALHIGH || type == TE_WORLDDECALHIGH ) decalIndex += 256; if( type == TE_DECALHIGH || type == TE_DECAL ) - entityIndex = MSG_ReadShort( &buf ); + entityIndex = MSG_ReadShort( pbuf ); else entityIndex = 0; pEnt = CL_GetEntityByIndex( entityIndex ); @@ -2055,197 +2064,197 @@ void CL_ParseTempEntity( sizebuf_t *msg ) CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, pos, type == TE_BSPDECAL ? FDECAL_PERMANENT : 0 ); break; case TE_IMPLOSION: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - scale = MSG_ReadByte( &buf ); - count = MSG_ReadByte( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + scale = MSG_ReadByte( pbuf ); + count = MSG_ReadByte( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_Implosion( pos, scale, count, life ); break; case TE_SPRITETRAIL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - life = (float)MSG_ReadByte( &buf ) * 0.1f; - scale = (float)MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + life = (float)MSG_ReadByte( pbuf ) * 0.1f; + scale = (float)MSG_ReadByte( pbuf ); if( !scale ) scale = 1.0f; else scale *= 0.1f; - vel = (float)MSG_ReadByte( &buf ) * 10; - random = (float)MSG_ReadByte( &buf ) * 10; + vel = (float)MSG_ReadByte( pbuf ) * 10; + random = (float)MSG_ReadByte( pbuf ) * 10; R_Sprite_Trail( type, pos, pos2, modelIndex, count, life, scale, random, 255, vel ); break; case TE_SPRITE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - scale = (float)MSG_ReadByte( &buf ) * 0.1f; - brightness = (float)MSG_ReadByte( &buf ) / 255.0f; + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + scale = (float)MSG_ReadByte( pbuf ) * 0.1f; + brightness = (float)MSG_ReadByte( pbuf ) / 255.0f; R_TempSprite( pos, vec3_origin, scale, modelIndex, kRenderTransAdd, kRenderFxNone, brightness, 0.0, FTENT_SPRANIMATE ); break; case TE_GLOWSPRITE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - life = (float)MSG_ReadByte( &buf ) * 0.1f; - scale = (float)MSG_ReadByte( &buf ) * 0.1f; - brightness = (float)MSG_ReadByte( &buf ) / 255.0f; + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + life = (float)MSG_ReadByte( pbuf ) * 0.1f; + scale = (float)MSG_ReadByte( pbuf ) * 0.1f; + brightness = (float)MSG_ReadByte( pbuf ) / 255.0f; R_TempSprite( pos, vec3_origin, scale, modelIndex, kRenderGlow, kRenderFxNoDissipation, brightness, life, FTENT_FADEOUT ); break; case TE_STREAK_SPLASH: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - color = MSG_ReadByte( &buf ); - count = MSG_ReadShort( &buf ); - vel = (float)MSG_ReadShort( &buf ); - random = (float)MSG_ReadShort( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + color = MSG_ReadByte( pbuf ); + count = MSG_ReadShort( pbuf ); + vel = (float)MSG_ReadShort( pbuf ); + random = (float)MSG_ReadShort( pbuf ); R_StreakSplash( pos, pos2, color, count, vel, -random, random ); break; case TE_DLIGHT: dl = CL_AllocDlight( 0 ); - dl->origin[0] = MSG_ReadCoord( &buf ); - dl->origin[1] = MSG_ReadCoord( &buf ); - dl->origin[2] = MSG_ReadCoord( &buf ); - dl->radius = (float)(MSG_ReadByte( &buf ) * 10.0f); - dl->color.r = MSG_ReadByte( &buf ); - dl->color.g = MSG_ReadByte( &buf ); - dl->color.b = MSG_ReadByte( &buf ); - dl->die = cl.time + (float)(MSG_ReadByte( &buf ) * 0.1f); - dl->decay = (float)(MSG_ReadByte( &buf ) * 10.0f); + dl->origin[0] = MSG_ReadCoord( pbuf ); + dl->origin[1] = MSG_ReadCoord( pbuf ); + dl->origin[2] = MSG_ReadCoord( pbuf ); + dl->radius = (float)(MSG_ReadByte( pbuf ) * 10.0f); + dl->color.r = MSG_ReadByte( pbuf ); + dl->color.g = MSG_ReadByte( pbuf ); + dl->color.b = MSG_ReadByte( pbuf ); + dl->die = cl.time + (float)(MSG_ReadByte( pbuf ) * 0.1f); + dl->decay = (float)(MSG_ReadByte( pbuf ) * 10.0f); break; case TE_ELIGHT: - dl = CL_AllocElight( MSG_ReadShort( &buf )); - dl->origin[0] = MSG_ReadCoord( &buf ); - dl->origin[1] = MSG_ReadCoord( &buf ); - dl->origin[2] = MSG_ReadCoord( &buf ); - dl->radius = MSG_ReadCoord( &buf ); - dl->color.r = MSG_ReadByte( &buf ); - dl->color.g = MSG_ReadByte( &buf ); - dl->color.b = MSG_ReadByte( &buf ); - life = (float)MSG_ReadByte( &buf ) * 0.1f; + dl = CL_AllocElight( MSG_ReadShort( pbuf )); + dl->origin[0] = MSG_ReadCoord( pbuf ); + dl->origin[1] = MSG_ReadCoord( pbuf ); + dl->origin[2] = MSG_ReadCoord( pbuf ); + dl->radius = MSG_ReadCoord( pbuf ); + dl->color.r = MSG_ReadByte( pbuf ); + dl->color.g = MSG_ReadByte( pbuf ); + dl->color.b = MSG_ReadByte( pbuf ); + life = (float)MSG_ReadByte( pbuf ) * 0.1f; dl->die = cl.time + life; - dl->decay = MSG_ReadCoord( &buf ); + dl->decay = MSG_ReadCoord( pbuf ); if( life != 0 ) dl->decay /= life; break; case TE_TEXTMESSAGE: - CL_ParseTextMessage( &buf ); + CL_ParseTextMessage( pbuf ); break; case TE_LINE: case TE_BOX: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - life = (float)(MSG_ReadShort( &buf ) * 0.1f); - r = MSG_ReadByte( &buf ); - g = MSG_ReadByte( &buf ); - b = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + life = (float)(MSG_ReadShort( pbuf ) * 0.1f); + r = MSG_ReadByte( pbuf ); + g = MSG_ReadByte( pbuf ); + b = MSG_ReadByte( pbuf ); if( type == TE_LINE ) R_ParticleLine( pos, pos2, r, g, b, life ); else R_ParticleBox( pos, pos2, r, g, b, life ); break; case TE_LARGEFUNNEL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - flags = MSG_ReadShort( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + flags = MSG_ReadShort( pbuf ); R_LargeFunnel( pos, flags ); R_FunnelSprite( pos, modelIndex, flags ); break; case TE_BLOODSTREAM: case TE_BLOOD: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - color = MSG_ReadByte( &buf ); - count = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + color = MSG_ReadByte( pbuf ); + count = MSG_ReadByte( pbuf ); if( type == TE_BLOOD ) R_Blood( pos, pos2, color, count ); else R_BloodStream( pos, pos2, color, count ); break; case TE_SHOWLINE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); R_ShowLine( pos, pos2 ); break; case TE_FIZZ: - entityIndex = MSG_ReadShort( &buf ); - modelIndex = MSG_ReadShort( &buf ); - scale = MSG_ReadByte( &buf ); // same as density + entityIndex = MSG_ReadShort( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + scale = MSG_ReadByte( pbuf ); // same as density pEnt = CL_GetEntityByIndex( entityIndex ); R_FizzEffect( pEnt, modelIndex, scale ); break; case TE_MODEL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); ang[0] = 0.0f; - ang[1] = MSG_ReadAngle( &buf ); // yaw angle + ang[1] = MSG_ReadAngle( pbuf ); // yaw angle ang[2] = 0.0f; - modelIndex = MSG_ReadShort( &buf ); - flags = MSG_ReadByte( &buf ); // sound flags - life = (float)(MSG_ReadByte( &buf ) * 0.1f); + modelIndex = MSG_ReadShort( pbuf ); + flags = MSG_ReadByte( pbuf ); // sound flags + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_TempModel( pos, pos2, ang, life, modelIndex, flags ); break; case TE_EXPLODEMODEL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - vel = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadShort( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + vel = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadShort( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_TempSphereModel( pos, vel, life, count, modelIndex ); break; case TE_BREAKMODEL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - ang[0] = MSG_ReadCoord( &buf ); - ang[1] = MSG_ReadCoord( &buf ); - ang[2] = MSG_ReadCoord( &buf ); - random = (float)MSG_ReadByte( &buf ) * 10.0f; - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); - flags = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + ang[0] = MSG_ReadCoord( pbuf ); + ang[1] = MSG_ReadCoord( pbuf ); + ang[2] = MSG_ReadCoord( pbuf ); + random = (float)MSG_ReadByte( pbuf ) * 10.0f; + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); + flags = MSG_ReadByte( pbuf ); R_BreakModel( pos, pos2, ang, random, life, count, modelIndex, (char)flags ); break; case TE_GUNSHOTDECAL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - entityIndex = MSG_ReadShort( &buf ); - decalIndex = MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + entityIndex = MSG_ReadShort( pbuf ); + decalIndex = MSG_ReadByte( pbuf ); CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 ); R_BulletImpactParticles( pos ); flags = COM_RandomLong( 0, 0x7fff ); @@ -2254,139 +2263,139 @@ void CL_ParseTempEntity( sizebuf_t *msg ) break; case TE_SPRAY: case TE_SPRITE_SPRAY: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - vel = (float)MSG_ReadByte( &buf ); - random = (float)MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + vel = (float)MSG_ReadByte( pbuf ); + random = (float)MSG_ReadByte( pbuf ); if( type == TE_SPRAY ) { - flags = MSG_ReadByte( &buf ); // rendermode + flags = MSG_ReadByte( pbuf ); // rendermode R_Spray( pos, pos2, modelIndex, count, vel, random, flags ); } else R_Sprite_Spray( pos, pos2, modelIndex, count, vel * 2.0f, random ); break; case TE_ARMOR_RICOCHET: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - scale = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + scale = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_RicochetSprite( pos, cl_sprite_ricochet, 0.1f, scale ); R_RicochetSound( pos ); break; case TE_PLAYERDECAL: - color = MSG_ReadByte( &buf ) - 1; // playernum - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - entityIndex = MSG_ReadShort( &buf ); - decalIndex = MSG_ReadByte( &buf ); + color = MSG_ReadByte( pbuf ) - 1; // playernum + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + entityIndex = MSG_ReadShort( pbuf ); + decalIndex = MSG_ReadByte( pbuf ); CL_PlayerDecal( color, decalIndex, entityIndex, pos ); break; case TE_BUBBLES: case TE_BUBBLETRAIL: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - scale = MSG_ReadCoord( &buf ); // water height - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - vel = MSG_ReadCoord( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + scale = MSG_ReadCoord( pbuf ); // water height + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + vel = MSG_ReadCoord( pbuf ); if( type == TE_BUBBLES ) R_Bubbles( pos, pos2, scale, modelIndex, count, vel ); else R_BubbleTrail( pos, pos2, scale, modelIndex, count, vel ); break; case TE_BLOODSPRITE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); // sprite #1 - decalIndex = MSG_ReadShort( &buf ); // sprite #2 - color = MSG_ReadByte( &buf ); - scale = (float)MSG_ReadByte( &buf ); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); // sprite #1 + decalIndex = MSG_ReadShort( pbuf ); // sprite #2 + color = MSG_ReadByte( pbuf ); + scale = (float)MSG_ReadByte( pbuf ); R_BloodSprite( pos, color, modelIndex, decalIndex, scale ); break; case TE_PROJECTILE: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - modelIndex = MSG_ReadShort( &buf ); - life = MSG_ReadByte( &buf ); - color = MSG_ReadByte( &buf ); // playernum + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + life = MSG_ReadByte( pbuf ); + color = MSG_ReadByte( pbuf ); // playernum R_Projectile( pos, pos2, modelIndex, life, color, NULL ); break; case TE_PLAYERSPRITES: - color = MSG_ReadShort( &buf ); // entitynum - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - random = (float)MSG_ReadByte( &buf ); + color = MSG_ReadShort( pbuf ); // entitynum + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + random = (float)MSG_ReadByte( pbuf ); R_PlayerSprites( color, modelIndex, count, random ); break; case TE_PARTICLEBURST: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - scale = (float)MSG_ReadShort( &buf ); - color = MSG_ReadByte( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + scale = (float)MSG_ReadShort( pbuf ); + color = MSG_ReadByte( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_ParticleBurst( pos, scale, color, life ); break; case TE_FIREFIELD: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - scale = (float)MSG_ReadShort( &buf ); - modelIndex = MSG_ReadShort( &buf ); - count = MSG_ReadByte( &buf ); - flags = MSG_ReadByte( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + scale = (float)MSG_ReadShort( pbuf ); + modelIndex = MSG_ReadShort( pbuf ); + count = MSG_ReadByte( pbuf ); + flags = MSG_ReadByte( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_FireField( pos, scale, modelIndex, count, flags, life ); break; case TE_PLAYERATTACHMENT: - color = MSG_ReadByte( &buf ); // playernum - scale = MSG_ReadCoord( &buf ); // height - modelIndex = MSG_ReadShort( &buf ); - life = (float)(MSG_ReadShort( &buf ) * 0.1f); + color = MSG_ReadByte( pbuf ); // playernum + scale = MSG_ReadCoord( pbuf ); // height + modelIndex = MSG_ReadShort( pbuf ); + life = (float)(MSG_ReadShort( pbuf ) * 0.1f); R_AttachTentToPlayer( color, modelIndex, scale, life ); break; case TE_KILLPLAYERATTACHMENTS: - color = MSG_ReadByte( &buf ); // playernum + color = MSG_ReadByte( pbuf ); // playernum R_KillAttachedTents( color ); break; case TE_MULTIGUNSHOT: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ) * 0.1f; - pos2[1] = MSG_ReadCoord( &buf ) * 0.1f; - pos2[2] = MSG_ReadCoord( &buf ) * 0.1f; - ang[0] = MSG_ReadCoord( &buf ) * 0.01f; - ang[1] = MSG_ReadCoord( &buf ) * 0.01f; + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ) * 0.1f; + pos2[1] = MSG_ReadCoord( pbuf ) * 0.1f; + pos2[2] = MSG_ReadCoord( pbuf ) * 0.1f; + ang[0] = MSG_ReadCoord( pbuf ) * 0.01f; + ang[1] = MSG_ReadCoord( pbuf ) * 0.01f; ang[2] = 0.0f; - count = MSG_ReadByte( &buf ); - decalIndices[0] = MSG_ReadByte( &buf ); + count = MSG_ReadByte( pbuf ); + decalIndices[0] = MSG_ReadByte( pbuf ); R_MultiGunshot( pos, pos2, ang, count, 1, decalIndices ); break; case TE_USERTRACER: - pos[0] = MSG_ReadCoord( &buf ); - pos[1] = MSG_ReadCoord( &buf ); - pos[2] = MSG_ReadCoord( &buf ); - pos2[0] = MSG_ReadCoord( &buf ); - pos2[1] = MSG_ReadCoord( &buf ); - pos2[2] = MSG_ReadCoord( &buf ); - life = (float)(MSG_ReadByte( &buf ) * 0.1f); - color = MSG_ReadByte( &buf ); - scale = (float)(MSG_ReadByte( &buf ) * 0.1f); + pos[0] = MSG_ReadCoord( pbuf ); + pos[1] = MSG_ReadCoord( pbuf ); + pos[2] = MSG_ReadCoord( pbuf ); + pos2[0] = MSG_ReadCoord( pbuf ); + pos2[1] = MSG_ReadCoord( pbuf ); + pos2[2] = MSG_ReadCoord( pbuf ); + life = (float)(MSG_ReadByte( pbuf ) * 0.1f); + color = MSG_ReadByte( pbuf ); + scale = (float)(MSG_ReadByte( pbuf ) * 0.1f); R_UserTracerParticle( pos, pos2, life, color, scale, 0, NULL ); break; default: @@ -2395,7 +2404,7 @@ void CL_ParseTempEntity( sizebuf_t *msg ) } // throw warning - if( MSG_CheckOverflow( &buf )) + if( MSG_CheckOverflow( pbuf )) Con_DPrintf( S_WARN "ParseTempEntity: overflow TE message %i\n", type ); } @@ -2454,7 +2463,8 @@ void CL_SetLightstyle( int style, const char *s, float f ) } } - Con_Reportf( "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" ); + if( COM_CheckStringEmpty( ls->pattern )) + Con_Reportf( "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" ); } /* diff --git a/engine/client/client.h b/engine/client/client.h index c1e8aba7d..da9a15a70 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -270,6 +270,7 @@ typedef struct model_t *worldmodel; // pointer to world int lostpackets; // count lost packets and show dialog in menu + uint worldmapCRC; } client_t; /* @@ -301,6 +302,13 @@ typedef enum CL_CHANGELEVEL, // draw 'loading' during changelevel } scrstate_t; +typedef enum +{ + PROTO_CURRENT = 0, // Xash3D 49 + PROTO_LEGACY, // Xash3D 48 + PROTO_GOLDSRC, // GoldSrc 48 +} protocolstate_t; + typedef struct { char name[32]; @@ -624,7 +632,7 @@ typedef struct uint32_t internetservers_query_len; // legacy mode support - qboolean legacymode; // one-way 48 protocol compatibility + protocolstate_t legacymode; netadr_t legacyserver; int extensions; @@ -873,20 +881,22 @@ _inline cl_entity_t *CL_EDICT_NUM( int n ) // cl_parse.c // void CL_ParseSetAngle( sizebuf_t *msg ); -void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ); +void CL_ParseServerData( sizebuf_t *msg, int protocol ); void CL_ParseLightStyle( sizebuf_t *msg ); -void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy ); +void CL_UpdateUserinfo( sizebuf_t *msg, int protocol ); void CL_ParseResource( sizebuf_t *msg ); void CL_ParseClientData( sizebuf_t *msg ); void CL_UpdateUserPings( sizebuf_t *msg ); void CL_ParseParticles( sizebuf_t *msg ); void CL_ParseRestoreSoundPacket( sizebuf_t *msg ); -void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy ); +void CL_ParseStaticEntity( sizebuf_t *msg ); +void CL_ParseBaseline( sizebuf_t *msg, int protocol ); void CL_ParseSignon( sizebuf_t *msg ); void CL_ParseRestore( sizebuf_t *msg ); void CL_ParseStaticDecal( sizebuf_t *msg ); void CL_ParseAddAngle( sizebuf_t *msg ); void CL_RegisterUserMessage( sizebuf_t *msg ); +void CL_ParseResourceList( sizebuf_t *msg ); void CL_ParseMovevars( sizebuf_t *msg ); void CL_ParseResourceRequest( sizebuf_t *msg ); void CL_ParseCustomization( sizebuf_t *msg ); @@ -895,14 +905,18 @@ void CL_ParseSoundFade( sizebuf_t *msg ); void CL_ParseFileTransferFailed( sizebuf_t *msg ); void CL_ParseHLTV( sizebuf_t *msg ); void CL_ParseDirector( sizebuf_t *msg ); +void CL_ParseVoiceInit( sizebuf_t *msg ); +void CL_ParseVoiceData( sizebuf_t *msg ); void CL_ParseResLocation( sizebuf_t *msg ); void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext ); +void CL_ParseExec( sizebuf_t *msg ); void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message ); void CL_ParseTempEntity( sizebuf_t *msg ); qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ); qboolean CL_RequestMissingResources( void ); void CL_RegisterResources ( sizebuf_t *msg ); void CL_ParseViewEntity( sizebuf_t *msg ); +void CL_ParseSoundPacket( sizebuf_t *msg ); void CL_ParseServerTime( sizebuf_t *msg ); // @@ -911,6 +925,11 @@ void CL_ParseServerTime( sizebuf_t *msg ); void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ); void CL_LegacyPrecache_f( void ); +// +// cl_parse_gs.c +// +void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ); + // // cl_scrn.c // @@ -979,6 +998,8 @@ void CL_ParseQuakeMessage( sizebuf_t *msg, qboolean normal_message ); // struct channel_s; struct rawchan_s; +qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe ); +int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent ); int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ); qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ); void CL_ResetLatchedVars( cl_entity_t *ent, qboolean full_reset ); diff --git a/engine/common/common.h b/engine/common/common.h index 3ae439365..de3fde090 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -832,6 +832,16 @@ void NET_MasterClear( void ); void NET_MasterShutdown( void ); qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat ); +// +// munge.c +// +void COM_Munge( byte *data, size_t len, int seq ); +void COM_UnMunge( byte *data, size_t len, int seq ); +void COM_Munge2( byte *data, size_t len, int seq ); +void COM_UnMunge2( byte *data, size_t len, int seq ); +void COM_Munge3( byte *data, size_t len, int seq ); +void COM_UnMunge3( byte *data, size_t len, int seq ); + #ifdef REF_DLL #error "common.h in ref_dll" #endif diff --git a/engine/common/munge.c b/engine/common/munge.c new file mode 100644 index 000000000..9dc86f34e --- /dev/null +++ b/engine/common/munge.c @@ -0,0 +1,161 @@ +/* +munge.c - protocol mangling for GoldSrc +Copyright (C) ReHLDS developers +Copyright (C) 2023 Alibek Omarov + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "common.h" + +static const byte mungify_table[] = +{ + 0x7A, 0x64, 0x05, 0xF1, 0x1B, 0x9B, 0xA0, 0xB5, + 0xCA, 0xED, 0x61, 0x0D, 0x4A, 0xDF, 0x8E, 0xC7, +}; + +static const byte mungify_table2[] = +{ + 0x05, 0x61, 0x7A, 0xED, 0x1B, 0xCA, 0x0D, 0x9B, + 0x4A, 0xF1, 0x64, 0xC7, 0xB5, 0x8E, 0xDF, 0xA0, +}; + +static const byte mungify_table3[] = +{ + 0x20, 0x07, 0x13, 0x61, 0x03, 0x45, 0x17, 0x72, + 0x0A, 0x2D, 0x48, 0x0C, 0x4A, 0x12, 0xA9, 0xB5, +}; + +static int COM_SwapLong( int c ) +{ + return ((( c >> 0 ) & 0xFF) << 24 ) + + ((( c >> 8 ) & 0xFF) << 16 ) + + ((( c >> 16 ) & 0xFF) << 8 ) + + ((( c >> 24 ) & 0xFF) << 0 ); +} + +static void COM_GenericMunge( byte *data, const size_t len, const int seq, const byte *table, const qboolean reverse ) +{ + const size_t mungelen = len / 4; + int i; + + for( i = 0; i < mungelen; i++ ) + { + uint *pc, c; + byte *p; + int j; + + pc = (uint *)&data[i * 4]; + c = *pc; + c ^= seq; + if( !reverse ) + c = COM_SwapLong( c ); + + p = (byte *)&c; + for( j = 0; j < 4; j++ ) + *p++ ^= (0xa5 | (j << j) | j | table[(i + j) & 0x0f]); + + if( reverse ) + c = COM_SwapLong( c ); + c ^= ~seq; + *pc = c; + } +} + +// Anti-proxy/aimbot obfuscation code +// COM_UnMunge should reversably fixup the data +void COM_Munge( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table, false ); +} + +void COM_UnMunge( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table, true ); +} + +void COM_Munge2( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table2, false ); +} + +void COM_UnMunge2( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table2, true ); +} + +void COM_Munge3( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table3, false ); +} + +void COM_UnMunge3( byte *data, size_t len, int seq ) +{ + COM_GenericMunge( data, len, seq, mungify_table3, true ); +} + +#if XASH_ENGINE_TESTS +#include "tests.h" + +void Test_RunMunge( void ) +{ + const char *msg = "0123456789qwertyuiopasdfghjklzxcvbnmaa"; + const char *expected[][3] = + { + { + "\x33\x2a\x61\x30\x2d\x6e\x35\x74\x2d\x79\x79\x78\x73\x34\x32\x25\x30\x2f\x39\x35\x26\x3c\x33\x61\x31\x22\x78\x67\x29\x68\x6a\x6c\x7d\x7e\x72\x36\x61\x61", + "\x69\x2a\x31\x30\x2d\x36\x25\x74\x77\x61\x79\x38\x6b\x34\x62\x25\x30\x7f\x39\x35\x76\x34\x33\x61\x39\x2a\x78\x67\x23\x68\x7a\x6c\x7d\x66\x72\x76\x61\x61", + "\x69\x6a\x71\x30\x6f\x7e\x25\x74\x3f\x69\x69\x38\x63\x2c\x62\x25\x28\x77\x29\x75\x7c\x2c\x73\x21\x23\x62\x38\x27\x6b\x28\x2a\x6c\x3d\x3e\x72\x36\x61\x61", + }, { + "\x32\x2a\x61\x31\x2c\x6e\x35\x75\x2c\x79\x79\x79\x72\x34\x32\x24\x31\x2f\x39\x34\x27\x3c\x33\x60\x30\x22\x78\x66\x28\x68\x6a\x6d\x7c\x7e\x72\x37\x61\x61", + "\x68\x2a\x31\x31\x2c\x36\x25\x75\x76\x61\x79\x39\x6a\x34\x62\x24\x31\x7f\x39\x34\x77\x34\x33\x60\x38\x2a\x78\x66\x22\x68\x7a\x6d\x7c\x66\x72\x77\x61\x61", + "\x68\x6a\x71\x31\x6e\x7e\x25\x75\x3e\x69\x69\x39\x62\x2c\x62\x24\x29\x77\x29\x74\x7d\x2c\x73\x20\x22\x62\x38\x26\x6a\x28\x2a\x6d\x3c\x3e\x72\x37\x61\x61", + } + }; + string buf; + size_t msglen = Q_strlen( msg ) + 1; + int i; + + Q_strncpy( buf, msg, msglen ); + + for( i = 0; i < 0xFF; i++ ) + { + COM_Munge( buf, msglen, i ); + if( i < sizeof( expected ) / sizeof( expected[0] )) + { + //for( int j = 0; j < msglen; j++ ) + // printf( "\\x%02x", buf[j] ); + //printf( "\n" ); + TASSERT( !memcmp( buf, expected[i][0], msglen )); + } + COM_UnMunge( buf, msglen, i ); + + TASSERT( !Q_strcmp( buf, msg )); + + COM_Munge2( buf, msglen, i ); + if( i < sizeof( expected ) / sizeof( expected[0] )) + { + TASSERT( !memcmp( buf, expected[i][1], msglen )); + } + COM_UnMunge2( buf, msglen, i ); + + TASSERT( !Q_strcmp( buf, msg )); + + COM_Munge3( buf, msglen, i ); + if( i < sizeof( expected ) / sizeof( expected[0] )) + { + TASSERT( !memcmp( buf, expected[i][2], msglen )); + } + COM_UnMunge3( buf, msglen, i ); + + TASSERT( !Q_strcmp( buf, msg )); + } +} +#endif diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index c219e8c79..8e3ad8b4d 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -81,7 +81,7 @@ const char *svc_strings[svc_lastmsg+1] = "svc_director", "svc_voiceinit", "svc_voicedata", - "svc_deltapacketbones", + "svc_unused54", "svc_unused55", "svc_resourcelocation", "svc_querycvarvalue", @@ -89,6 +89,36 @@ const char *svc_strings[svc_lastmsg+1] = "svc_exec", }; +const char *svc_legacy_strings[svc_lastmsg+1] = +{ + [svc_legacy_changing] = "svc_legacy_changing", + [svc_legacy_ambientsound] = "svc_legacy_ambientsound", + [svc_legacy_soundindex] = "svc_legacy_soundindex", + [svc_legacy_ambientsound] = "svc_legacy_ambientsound", + [svc_legacy_modelindex] = "svc_legacy_modelindex", + [svc_legacy_eventindex] = "svc_legacy_eventindex", + [svc_legacy_chokecount] = "svc_legacy_chokecount", +}; + +const char *svc_goldsrc_strings[svc_lastmsg+1] = +{ + [svc_goldsrc_version] = "svc_goldsrc_version", + [svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo", + [svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription", + [svc_goldsrc_stopsound] = "svc_goldsrc_stopsound", + [svc_goldsrc_damage] = "svc_goldsrc_damage", + [svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster", + [svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret", + [svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound", + [svc_goldsrc_decalname] = "svc_goldsrc_decalname", + [svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg", + [svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars", + [svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo", + [svc_goldsrc_timescale] = "svc_goldsrc_timescale", + [svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue", + [svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2", +}; + void MSG_InitMasks( void ) { uint startbit, endbit; @@ -136,6 +166,7 @@ void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, in sb->iCurBit = iStartBit; sb->bOverflow = false; + sb->iAlternateSign = 0; } /* @@ -257,17 +288,35 @@ void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits ) // do we have a valid # of bits to encode with? Assert( numbits >= 1 && numbits <= 32 ); - // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer. - // (Some old code writes direct integers right into the buffer). - if( data < 0 ) + if( sb->iAlternateSign ) { - MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 ); - MSG_WriteOneBit( sb, 1 ); + // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer. + // (Some old code writes direct integers right into the buffer). + if( data < 0 ) + { + MSG_WriteOneBit( sb, 1 ); + MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 ); + } + else + { + MSG_WriteOneBit( sb, 0 ); + MSG_WriteUBitLong( sb, (uint)data, numbits - 1 ); + } } else { - MSG_WriteUBitLong( sb, (uint)data, numbits - 1 ); - MSG_WriteOneBit( sb, 0 ); + // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer. + // (Some old code writes direct integers right into the buffer). + if( data < 0 ) + { + MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 ); + MSG_WriteOneBit( sb, 1 ); + } + else + { + MSG_WriteUBitLong( sb, (uint)data, numbits - 1 ); + MSG_WriteOneBit( sb, 0 ); + } } } @@ -572,12 +621,24 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits ) { int r, sign; - r = MSG_ReadUBitLong( sb, numbits - 1 ); + if( sb->iAlternateSign ) + { + sign = MSG_ReadOneBit( sb ); + r = MSG_ReadUBitLong( sb, numbits - 1 ); - // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer. - // (Some old code writes direct integers right into the buffer). - sign = MSG_ReadOneBit( sb ); - if( sign ) r = -( BIT( numbits - 1 ) - r ); + if( sign ) + r = -r; + } + else + { + r = MSG_ReadUBitLong( sb, numbits - 1 ); + + // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer. + // (Some old code writes direct integers right into the buffer). + sign = MSG_ReadOneBit( sb ); + + if( sign ) r = -( BIT( numbits - 1 ) - r ); + } return r; } @@ -608,7 +669,14 @@ int MSG_ReadCmd( sizebuf_t *sb, netsrc_t type ) int MSG_ReadChar( sizebuf_t *sb ) { - return MSG_ReadSBitLong( sb, sizeof( int8_t ) << 3 ); + int alt = sb->iAlternateSign; + int ret; + + sb->iAlternateSign = 0; + ret = MSG_ReadSBitLong( sb, sizeof( int8_t ) << 3 ); + sb->iAlternateSign = alt; + + return ret; } int MSG_ReadByte( sizebuf_t *sb ) @@ -618,7 +686,14 @@ int MSG_ReadByte( sizebuf_t *sb ) int MSG_ReadShort( sizebuf_t *sb ) { - return MSG_ReadSBitLong( sb, sizeof( int16_t ) << 3 ); + int alt = sb->iAlternateSign; + int ret; + + sb->iAlternateSign = 0; + ret = MSG_ReadSBitLong( sb, sizeof( int16_t ) << 3 ); + sb->iAlternateSign = alt; + + return ret; } int MSG_ReadWord( sizebuf_t *sb ) @@ -650,7 +725,14 @@ void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa ) int MSG_ReadLong( sizebuf_t *sb ) { - return MSG_ReadSBitLong( sb, sizeof( int32_t ) << 3 ); + int alt = sb->iAlternateSign; + int ret; + + sb->iAlternateSign = 0; + ret = MSG_ReadSBitLong( sb, sizeof( int32_t ) << 3 ); + sb->iAlternateSign = alt; + + return ret; } uint MSG_ReadDword( sizebuf_t *sb ) diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index f31b32c6c..8a4869fd7 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -43,6 +43,9 @@ struct sizebuf_s byte *pData; int iCurBit; int nDataBits; + + // to support GoldSrc broken signed integers + int iAlternateSign; }; #define MSG_StartReading MSG_StartWriting @@ -113,6 +116,24 @@ _inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCu _inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; } _inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; } _inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias +_inline void MSG_EndBitWriting( sizebuf_t *sb ) +{ + sb->iAlternateSign--; + + if( sb->iAlternateSign < 0 ) + { + Con_Printf( "%s: non-even MSG_Start/EndBitWriting\n", __func__ ); + sb->iAlternateSign = 0; + } + + // we have native bit ops here, just pad to closest byte + MSG_SeekToBit( sb, MSG_GetNumBytesWritten( sb ) << 3, SEEK_SET ); +} + +_inline void MSG_StartBitWriting( sizebuf_t *sb ) +{ + sb->iAlternateSign++; +} // Bit-read functions int MSG_ReadOneBit( sizebuf_t *sb ); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index c1974ec8b..377d15ad3 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -18,6 +18,9 @@ GNU General Public License for more details. #include "xash3d_mathlib.h" #include "net_encode.h" #include "protocol.h" +#if !XASH_DEDICATED +#include "bzip2/bzlib.h" +#endif // !XASH_DEDICATED #define MAKE_FRAGID( id, count ) ((( id & 0xffff ) << 16 ) | ( count & 0xffff )) #define FRAG_GETID( fragid ) (( fragid >> 16 ) & 0xffff ) @@ -303,7 +306,7 @@ Netchan_Setup called to open a channel to a remote system ============== */ -void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode )) +void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ), unsigned int flags ) { Netchan_Clear( chan ); @@ -319,6 +322,10 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, voi chan->qport = qport; chan->client = client; chan->pfnBlockSize = pfnBlockSize; + chan->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? 1 : 0; + chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? 1 : 0; + chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? 1 : 0; + chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? 1 : 0; MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf )); } @@ -718,7 +725,19 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg ) wait = (fragbufwaiting_t *)Mem_Calloc( net_mempool, sizeof( fragbufwaiting_t )); - if( !LZSS_IsCompressed( MSG_GetData( msg ))) + if( chan->use_bz2 && memcmp( MSG_GetData( msg ), "BZ2", 4 )) + { + byte pbOut[0x10000]; + uint uCompressedSize = MSG_GetNumBytesWritten( msg ) - 4; + if( !BZ2_bzBuffToBuffCompress( pbOut, &uCompressedSize, MSG_GetData( msg ), MSG_GetNumBytesWritten( msg ), 9, 0, 30 )) + { + Con_Reportf( "Compressing split packet with BZip2 (%d -> %d bytes)\n", MSG_GetNumBytesWritten( msg ), uCompressedSize ); + memcpy( msg->pData, "BZ2", 4 ); + memcpy( msg->pData + 4, pbOut, uCompressedSize ); + MSG_SeekToBit( msg, uCompressedSize << 3, SEEK_SET ); + } + } + else if( !chan->use_bz2 && !LZSS_IsCompressed( MSG_GetData( msg ))) { uint uCompressedSize = 0; uint uSourceSize = MSG_GetNumBytesWritten( msg ); @@ -726,7 +745,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg ) if( pbOut && uCompressedSize > 0 && uCompressedSize < uSourceSize ) { - Con_Reportf( "Compressing split packet (%d -> %d bytes)\n", uSourceSize, uCompressedSize ); + Con_Reportf( "Compressing split packet with LZSS (%d -> %d bytes)\n", uSourceSize, uCompressedSize ); memcpy( msg->pData, pbOut, uCompressedSize ); MSG_SeekToBit( msg, uCompressedSize << 3, SEEK_SET ); } @@ -1123,7 +1142,16 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l p = n; } - if( LZSS_IsCompressed( MSG_GetData( msg ))) + if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ) ) + { + byte buf[0x10000]; + uint uDecompressedLen = sizeof( buf ); + + BZ2_bzBuffToBuffDecompress( buf, &uDecompressedLen, MSG_GetData( msg ) + 4, MSG_GetNumBytesWritten( msg ) - 4, 1, 0 ); + memcpy( msg->pData, buf, uDecompressedLen ); + size = uDecompressedLen; + } + else if( !chan->use_bz2 && LZSS_IsCompressed( MSG_GetData( msg ))) { uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg )); byte buf[NET_MAX_MESSAGE]; @@ -1160,7 +1188,8 @@ Netchan_CopyFileFragments */ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) { - char filename[MAX_OSPATH]; + char filename[MAX_OSPATH], compressor[32]; + uint uncompressedSize; int nsize, pos; byte *buffer; fragbuf_t *p, *n; @@ -1183,6 +1212,15 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) MSG_Clear( msg ); Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename )); + if( chan->gs_netchan ) + { + Q_strncpy( compressor, MSG_ReadString( msg ), sizeof( compressor )); + uncompressedSize = MSG_ReadLong( msg ); + } + else + { + compressor[0] = 0; + } if( !COM_CheckString( filename )) { @@ -1253,10 +1291,25 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) p = n; } - if( LZSS_IsCompressed( buffer )) + if( chan->gs_netchan && chan->use_bz2 ) { - uint uncompressedSize = LZSS_GetActualSize( buffer ) + 1; - byte *uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize ); + if( !Q_stricmp( compressor, "bz2" )) + { + byte *uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize ); + + Con_DPrintf( "Decompressing file %s (%d -> %d bytes)\n", filename, nsize, uncompressedSize ); + BZ2_bzBuffToBuffDecompress( uncompressedBuffer, &uncompressedSize, buffer, nsize, 1, 0 ); + Mem_Free( buffer ); + nsize = uncompressedSize; + buffer = uncompressedBuffer; + } + } + else if( LZSS_IsCompressed( buffer )) + { + byte *uncompressedBuffer; + + uncompressedSize = LZSS_GetActualSize( buffer ) + 1; + uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize ); nsize = LZSS_Decompress( buffer, uncompressedBuffer ); Mem_Free( buffer ); @@ -1619,7 +1672,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) MSG_WriteLong( &send, w2 ); // send the qport if we are a client - if( chan->sock == NS_CLIENT ) + if( chan->sock == NS_CLIENT && !chan->gs_netchan ) { MSG_WriteWord( &send, Cvar_VariableInteger( "net_qport" )); } @@ -1632,8 +1685,16 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) { MSG_WriteByte( &send, 1 ); MSG_WriteLong( &send, chan->reliable_fragid[i] ); - MSG_WriteLong( &send, chan->frag_startpos[i] ); - MSG_WriteLong( &send, chan->frag_length[i] ); + if( chan->gs_netchan ) + { + MSG_WriteShort( &send, chan->frag_startpos[i] >> 3 ); + MSG_WriteShort( &send, chan->frag_length[i] >> 3 ); + } + else + { + MSG_WriteLong( &send, chan->frag_startpos[i] ); + MSG_WriteLong( &send, chan->frag_length[i] ); + } } else { @@ -1690,6 +1751,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) int splitsize = 0; if( chan->pfnBlockSize ) splitsize = chan->pfnBlockSize( chan->client, FRAGSIZE_SPLIT ); + + if( chan->use_munge ) + COM_Munge2( send.pData + 8, MSG_GetNumBytesWritten( &send ) - 8, (byte)( chan->outgoing_sequence - 1 )); + NET_SendPacketEx( chan->sock, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), chan->remote_address, splitsize ); } @@ -1741,6 +1806,9 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) sequence = MSG_ReadLong( msg ); sequence_ack = MSG_ReadLong( msg ); + if( chan->use_munge ) + COM_UnMunge2( msg->pData + 8, ( msg->nDataBits >> 3 ) - 8, sequence & 0xFF ); + // read the qport if we are a server if( chan->sock == NS_SERVER ) qport = MSG_ReadShort( msg ); @@ -1758,8 +1826,16 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) { frag_message[i] = true; fragid[i] = MSG_ReadLong( msg ); - frag_offset[i] = MSG_ReadLong( msg ); - frag_length[i] = MSG_ReadLong( msg ); + if( chan->gs_netchan ) + { + frag_offset[i] = MSG_ReadShort( msg ) << 3; + frag_length[i] = MSG_ReadShort( msg ) << 3; + } + else + { + frag_offset[i] = MSG_ReadLong( msg ); + frag_length[i] = MSG_ReadLong( msg ); + } } } diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 60657e017..6ccf7bdd2 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -37,6 +37,7 @@ GNU General Public License for more details. #define DT_TIMEWINDOW_BIG BIT( 6 ) // and re-encoded on the client relative to the client's clock #define DT_STRING BIT( 7 ) // A null terminated string, sent as 8 byte chars #define DT_SIGNED BIT( 8 ) // sign modificator +#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator #define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1) @@ -47,6 +48,7 @@ GNU General Public License for more details. #define PHYS_DEF( x ) #x, offsetof( movevars_t, x ), sizeof( ((movevars_t *)0)->x ) #define CLDT_DEF( x ) #x, offsetof( clientdata_t, x ), sizeof( ((clientdata_t *)0)->x ) #define WPDT_DEF( x ) #x, offsetof( weapon_data_t, x ), sizeof( ((weapon_data_t *)0)->x ) +#define DESC_DEF( x ) #x, offsetof( goldsrc_delta_t, x ), sizeof( ((goldsrc_delta_t *)0)->x ) static qboolean delta_init = false; @@ -315,16 +317,16 @@ static const delta_field_t ent_fields[] = { NULL }, }; -enum +static const delta_field_t meta_fields[] = { - DT_EVENT_T = 0, - DT_MOVEVARS_T, - DT_USERCMD_T, - DT_CLIENTDATA_T, - DT_WEAPONDATA_T, - DT_ENTITY_STATE_T, - DT_ENTITY_STATE_PLAYER_T, - DT_CUSTOM_ENTITY_STATE_T, +{ DESC_DEF( fieldType ), }, +{ DESC_DEF( fieldName ), }, +{ DESC_DEF( fieldOffset ), }, +{ DESC_DEF( fieldSize ), }, +{ DESC_DEF( significant_bits ), }, +{ DESC_DEF( premultiply ), }, +{ DESC_DEF( postmultiply ), }, +{ NULL }, }; static delta_info_t dt_info[] = @@ -337,6 +339,7 @@ static delta_info_t dt_info[] = [DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) }, [DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) }, [DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) }, +[DT_GOLDSRC_DELTA_T] = { "goldsrc_delta_t", meta_fields, NUM_FIELDS( meta_fields ) }, { NULL }, }; @@ -451,7 +454,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags, int i; // check for coexisting field - for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ) + for( i = 0, pField = dt->pFields; i < dt->numFields && pField; i++, pField++ ) { if( !Q_strcmp( pField->name, pName )) { @@ -579,6 +582,46 @@ void Delta_ParseTableField( sizebuf_t *msg ) Delta_AddField( dt, pName, flags, bits, mul, post_mul ); } +void Delta_ParseTableField_GS( sizebuf_t *msg ) +{ + const char *s = MSG_ReadString( msg ); + delta_info_t *dt = Delta_FindStruct( s ); + goldsrc_delta_t null = { 0 }; + int i, num_fields; + + + // delta encoders it's already initialized on this machine (local game) + if( delta_init ) + { + Delta_Shutdown(); + Delta_InitMeta(); + } + + if( !dt ) + Host_Error( "%s: not initialized", __func__ ); + + num_fields = MSG_ReadShort( msg ); + if( num_fields > dt->maxFields ) + Host_Error( "%s: numFields > maxFields", __func__ ); + + MSG_StartBitWriting( msg ); + + for( i = 0; i < num_fields; i++ ) + { + goldsrc_delta_t to; + + Delta_ReadGSFields( msg, DT_GOLDSRC_DELTA_T, &null, &to, 0.0f ); + + // patch our DT_SIGNED flag + if( FBitSet( to.fieldType, DT_SIGNED_GS )) + SetBits( to.fieldType, DT_SIGNED ); + + Delta_AddField( dt, to.fieldName, to.fieldType, to.significant_bits, to.premultiply, to.postmultiply ); + } + + MSG_EndBitWriting( msg ); +} + static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost ) { string token; @@ -886,6 +929,24 @@ void Delta_InitClient( void ) if( numActive ) delta_init = true; } +void Delta_InitMeta( void ) +{ + delta_info_t *dt = Delta_FindStructByIndex( DT_GOLDSRC_DELTA_T ); + + if( dt->bInitialized ) + return; + + Delta_AddField( dt, "fieldType", DT_INTEGER, 32, 1.0f, 1.0f ); + Delta_AddField( dt, "fieldName", DT_STRING, 1, 1.0f, 1.0f ); + Delta_AddField( dt, "fieldOffset", DT_INTEGER, 16, 1.0f, 1.0f ); + Delta_AddField( dt, "fieldSize", DT_INTEGER, 8, 1.0f, 1.0f ); + Delta_AddField( dt, "significant_bits", DT_INTEGER, 8, 1.0f, 1.0f ); + Delta_AddField( dt, "premultiply", DT_FLOAT, 32, 4000.0f, 1.0f ); + Delta_AddField( dt, "postmultiply", DT_FLOAT, 32, 4000.0f, 1.0f ); + dt->numFields = dt->maxFields; + dt->bInitialized = true; +} + void Delta_Shutdown( void ) { int i; @@ -1132,29 +1193,13 @@ int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean playe return countBits; } -/* -===================== -Delta_WriteField - -write fields by offsets -assume from and to is valid -===================== -*/ -static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase ) +static void Delta_WriteField_( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase ) { int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0; float flValue, flAngle; uint iValue; const char *pStr; - if( Delta_CompareField( pField, from, to, timebase )) - { - MSG_WriteOneBit( msg, 0 ); // unchanged - return false; - } - - MSG_WriteOneBit( msg, 1 ); // changed - if( pField->flags & DT_BYTE ) { if( signbit ) @@ -1230,6 +1275,28 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v pStr = (char *)((byte *)to + pField->offset ); MSG_WriteString( msg, pStr ); } +} + +/* +===================== +Delta_WriteField + +write fields by offsets +assume from and to is valid +===================== +*/ +static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase ) +{ + if( Delta_CompareField( pField, from, to, timebase )) + { + MSG_WriteOneBit( msg, 0 ); // unchanged + return false; + } + + MSG_WriteOneBit( msg, 1 ); // changed + + Delta_WriteField_( msg, pField, from, to, timebase ); + return true; } @@ -1280,15 +1347,7 @@ static void Delta_CopyField( delta_t *pField, void *from, void *to, double timeb } } -/* -===================== -Delta_ReadField - -read fields by offsets -assume 'from' and 'to' is valid -===================== -*/ -static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase ) +static void Delta_ReadField_( sizebuf_t *msg, delta_t *pField, void *to, double timebase ) { qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false; float flValue, flAngle, flTime; @@ -1296,12 +1355,6 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo const char *pStr; char *pOut; - if( !MSG_ReadOneBit( msg ) ) - { - Delta_CopyField( pField, from, to, timebase ); - return false; - } - Assert( pField->multiplier != 0.0f ); if( pField->flags & DT_BYTE ) @@ -1384,9 +1437,88 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo pOut = (char *)((byte *)to + pField->offset ); Q_strncpy( pOut, pStr, pField->size ); } +} + +/* +===================== +Delta_ReadField + +read fields by offsets +assume 'from' and 'to' is valid +===================== +*/ +static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, double timebase ) +{ + if( !MSG_ReadOneBit( msg ) ) + { + Delta_CopyField( pField, from, to, timebase ); + return false; + } + + Delta_ReadField_( msg, pField, to, timebase ); return true; } +void Delta_ReadGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase ) +{ + delta_info_t *dt = Delta_FindStructByIndex( index ); + uint8_t bits[8] = { 0 }; + delta_t *pField; + byte c; + int i; + + c = MSG_ReadUBitLong( msg, 3 ); + + for( i = 0; i < c; i++ ) + bits[i] = MSG_ReadByte( msg ); + + for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ) + { + int b = i >> 3; + int n = 1 << ( i & 7 ); + + if( FBitSet( bits[b], n )) + Delta_ReadField_( msg, pField, to, timebase ); + else Delta_CopyField( pField, from, to, timebase ); + } +} + +void Delta_WriteGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase ) +{ + delta_info_t *dt = Delta_FindStructByIndex( index ); + delta_t *pField; + uint8_t bits[8] = { 0 }; + uint c = 0; + int i; + + Delta_CustomEncode( dt, from, to ); + + for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ) + { + if( !Delta_CompareField( pField, from, to, timebase )) + { + int b = i >> 3; + int n = 1 << ( i & 7 ); + + SetBits( bits[b], n ); + c = b + 1; + } + } + + MSG_WriteUBitLong( msg, c, 3 ); + for( i = 0; i < c; i++ ) + MSG_WriteByte( msg, bits[i] ); + + for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ) + { + int b = i >> 3; + int n = 1 << ( i & 7 ); + + if( FBitSet( bits[b], n )) + Delta_WriteField_( msg, pField, from, to, timebase ); + } +} + /* ============================================================================= @@ -1856,7 +1988,10 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state int baseline_offset = 0; if( number < 0 || number >= clgame.maxEntities ) - Host_Error( "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number ); + { + Con_Printf( S_ERROR "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number ); + return false; + } fRemoveType = MSG_ReadUBitLong( msg, 2 ); @@ -1878,7 +2013,8 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state return false; } - Host_Error( "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType ); + Con_Printf( S_ERROR "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType ); + return false; } if( !cls.legacymode ) @@ -1926,7 +2062,11 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state dt = Delta_FindStructByIndex( DT_ENTITY_STATE_T ); } - Assert( dt && dt->bInitialized ); + if( !(dt && dt->bInitialized) ) + { + Con_Printf( S_ERROR "MSG_ReadDeltaEntity: broken delta\n"); + return true; + } pField = dt->pFields; Assert( pField != NULL ); diff --git a/engine/common/net_encode.h b/engine/common/net_encode.h index 98e9d19e2..489cc18ba 100644 --- a/engine/common/net_encode.h +++ b/engine/common/net_encode.h @@ -33,6 +33,19 @@ enum DELTA_STATIC, }; +enum +{ + DT_EVENT_T = 0, + DT_MOVEVARS_T, + DT_USERCMD_T, + DT_CLIENTDATA_T, + DT_WEAPONDATA_T, + DT_ENTITY_STATE_T, + DT_ENTITY_STATE_PLAYER_T, + DT_CUSTOM_ENTITY_STATE_T, + DT_GOLDSRC_DELTA_T, +}; + // struct info (filled by engine) typedef struct { @@ -54,6 +67,17 @@ struct delta_s qboolean bInactive; // unsetted by user request }; +typedef struct goldsrc_delta_s +{ + int fieldType; + char fieldName[32]; + int fieldOffset; + short fieldSize; + int significant_bits; + float premultiply; + float postmultiply; +} goldsrc_delta_t; + typedef void (*pfnDeltaEncode)( struct delta_s *pFields, const byte *from, const byte *to ); typedef struct @@ -76,6 +100,7 @@ typedef struct // void Delta_Init( void ); void Delta_InitClient( void ); +void Delta_InitMeta( void ); void Delta_Shutdown( void ); void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc ); int Delta_FindField( delta_t *pFields, const char *fieldname ); @@ -87,7 +112,7 @@ void Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber ); // send table over network void Delta_WriteDescriptionToClient( sizebuf_t *msg ); void Delta_ParseTableField( sizebuf_t *msg ); - +void Delta_ParseTableField_GS( sizebuf_t *msg ); // encode routines struct entity_state_s; @@ -109,5 +134,7 @@ void MSG_ReadWeaponData( sizebuf_t *msg, struct weapon_data_s *from, struct weap void MSG_WriteDeltaEntity( struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, int type, double timebase, int ofs ); qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, struct entity_state_s *from, struct entity_state_s *to, int num, int type, double timebase ); int Delta_TestBaseline( struct entity_state_s *from, struct entity_state_s *to, qboolean player, double timebase ); +void Delta_ReadGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase ); +void Delta_WriteGSFields( sizebuf_t *msg, int index, void *from, void *to, double timebase ); #endif//NET_ENCODE_H diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c index 49738d3eb..9a6ebe65b 100644 --- a/engine/common/net_ws.c +++ b/engine/common/net_ws.c @@ -84,6 +84,13 @@ typedef struct int sequence_number; short packet_id; } SPLITPACKET; + +typedef struct +{ + int net_id; + int sequence_number; + unsigned char packet_id; +} SPLITPACKETGS; #pragma pack(pop) typedef struct @@ -1357,28 +1364,40 @@ NET_GetLong receive long packet from network ================== */ -qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize ) +static qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize, qboolean small_split ) { int i, sequence_number, offset; - SPLITPACKET *pHeader = (SPLITPACKET *)pData; int packet_number; int packet_count; short packet_id; - int body_size = splitsize - sizeof( SPLITPACKET ); + size_t header_size = small_split ? sizeof( SPLITPACKETGS ) : sizeof( SPLITPACKET ); + SPLITPACKET *pHeader = (SPLITPACKET *)pData; + SPLITPACKETGS *pHeaderGS = (SPLITPACKETGS *)pData; + int body_size = splitsize - header_size; if( body_size < 0 ) return false; - if( size < sizeof( SPLITPACKET )) + if( size < header_size ) { Con_Printf( S_ERROR "invalid split packet length %i\n", size ); return false; } - sequence_number = pHeader->sequence_number; - packet_id = pHeader->packet_id; - packet_count = ( packet_id & 0xFF ); - packet_number = ( packet_id >> 8 ); + if( small_split ) + { + sequence_number = pHeaderGS->sequence_number; + packet_id = pHeaderGS->packet_id; + packet_count = ( packet_id & 0xF ); + packet_number = ( packet_id >> 4 ); + } + else + { + sequence_number = pHeader->sequence_number; + packet_id = pHeader->packet_id; + packet_count = ( packet_id & 0xFF ); + packet_number = ( packet_id >> 8 ); + } if( packet_number >= NET_MAX_FRAGMENTS || packet_count > NET_MAX_FRAGMENTS ) { @@ -1400,7 +1419,7 @@ qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize ) Con_Printf( "<-- Split packet restart %i count %i seq\n", net.split.split_count, sequence_number ); } - size -= sizeof( SPLITPACKET ); + size -= header_size; if( net.split_flags[packet_number] != sequence_number ) { @@ -1419,7 +1438,7 @@ qboolean NET_GetLong( byte *pData, int size, size_t *outSize, int splitsize ) } offset = (packet_number * body_size); - memcpy( net.split.buffer + offset, pData + sizeof( SPLITPACKET ), size ); + memcpy( net.split.buffer + offset, pData + header_size, size ); // have we received all of the pieces to the packet? if( net.split.split_count <= 0 ) @@ -1488,7 +1507,7 @@ static qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size // check for split message if( sock == NS_CLIENT && *(int *)data == NET_HEADER_SPLITPACKET ) { - return NET_GetLong( data, ret, length, CL_GetSplitSize( )); + return NET_GetLong( data, ret, length, CL_GetSplitSize( ), CL_GoldSrcMode( )); } #endif // lag the packet, if needed diff --git a/engine/common/net_ws.h b/engine/common/net_ws.h index 7d95a6673..23b63d99b 100644 --- a/engine/common/net_ws.h +++ b/engine/common/net_ws.h @@ -80,6 +80,7 @@ void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr ); #if !XASH_DEDICATED qboolean CL_LegacyMode( void ); +qboolean CL_GoldSrcMode( void ); int CL_GetSplitSize( void ); #endif diff --git a/engine/common/netchan.h b/engine/common/netchan.h index fd69fd7a2..0a283629e 100644 --- a/engine/common/netchan.h +++ b/engine/common/netchan.h @@ -209,6 +209,14 @@ typedef enum fragsize_e FRAGSIZE_UNRELIABLE } fragsize_t; +typedef enum +{ + NETCHAN_USE_LEGACY_SPLIT = BIT( 0 ), + NETCHAN_USE_MUNGE = BIT( 1 ), + NETCHAN_USE_BZIP2 = BIT( 2 ), + NETCHAN_GOLDSRC = BIT( 3 ) +} netchan_flags_t; + // Network Connection Channel typedef struct netchan_s { @@ -271,10 +279,14 @@ typedef struct netchan_s // added for net_speeds size_t total_sended; size_t total_received; - qboolean split; unsigned int maxpacket; unsigned int splitid; netsplit_t netsplit; + + qboolean split : 1; + qboolean use_munge : 1; + qboolean use_bz2 : 1; + qboolean gs_netchan : 1; } netchan_t; extern netadr_t net_from; @@ -288,7 +300,7 @@ extern int net_drop; void Netchan_Init( void ); void Netchan_Shutdown( void ); -void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ) ); +void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ), unsigned int flags ); void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filename, byte *pbuf, int size ); qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length ); qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 868ebbeaf..84531d673 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -73,7 +73,7 @@ GNU General Public License for more details. #define svc_director 51 // #define svc_voiceinit 52 // #define svc_voicedata 53 // [byte][short][...] -#define svc_deltapacketbones 54 // [short][byte][...] +// reserved // reserved #define svc_resourcelocation 56 // [string] #define svc_querycvarvalue 57 // [string] @@ -278,22 +278,24 @@ GNU General Public License for more details. #define SU_WEAPON (1<<14) extern const char *svc_strings[svc_lastmsg+1]; +extern const char *svc_legacy_strings[svc_lastmsg+1]; +extern const char *svc_goldsrc_strings[svc_lastmsg+1]; extern const char *clc_strings[clc_lastmsg+1]; // FWGS extensions #define NET_EXT_SPLITSIZE (1U<<0) // set splitsize by cl_dlmax // legacy protocol definitons -#define PROTOCOL_LEGACY_VERSION 48 -#define svc_legacy_modelindex 31 // [index][modelpath] -#define svc_legacy_soundindex 28 // [index][soundpath] -#define svc_legacy_eventindex 34 // [index][eventname] -#define svc_legacy_ambientsound 29 -#define svc_legacy_chokecount 42 // old client specified count, new just sends svc_choke -#define svc_legacy_event 27 // playback event queue -#define svc_legacy_changing 3 // changelevel by server request +#define PROTOCOL_LEGACY_VERSION 48 +#define svc_legacy_changing svc_event // changelevel by server request +#define svc_legacy_event 27 // playback event queue +#define svc_legacy_soundindex 28 // [index][soundpath] +#define svc_legacy_ambientsound 29 +#define svc_legacy_modelindex svc_finale // [index][modelpath] +#define svc_legacy_eventindex svc_cutscene // [index][eventname] +#define svc_legacy_chokecount svc_choke // old client specified count, new just sends svc_choke -#define clc_legacy_userinfo 6 // [[userinfo string] +#define clc_legacy_userinfo 6 // [[userinfo string] #define SND_LEGACY_LARGE_INDEX (1<<2) // a send sound as short #define MAX_LEGACY_ENTITY_BITS 12 @@ -308,4 +310,40 @@ extern const char *clc_strings[clc_lastmsg+1]; // Master Server protocol #define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter +// GoldSrc protocol definitions +#define PROTOCOL_GOLDSRC_VERSION_REAL 48 +#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION + +#define svc_goldsrc_version svc_changing +#define svc_goldsrc_serverinfo svc_serverdata +#define svc_goldsrc_deltadescription svc_deltatable +#define svc_goldsrc_stopsound svc_resource +#define svc_goldsrc_damage svc_restoresound +#define svc_goldsrc_killedmonster 27 +#define svc_goldsrc_foundsecret 28 +#define svc_goldsrc_spawnstaticsound 29 +#define svc_goldsrc_decalname svc_bspdecal +#define svc_goldsrc_newusermsg svc_usermessage +#define svc_goldsrc_newmovevars svc_deltamovevars +#define svc_goldsrc_sendextrainfo 54 +#define svc_goldsrc_timescale 55 +#define svc_goldsrc_sendcvarvalue svc_querycvarvalue +#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2 + +#define clc_goldsrc_hltv clc_requestcvarvalue // 9 +#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10 +#define clc_goldsrc_requestcvarvalue2 11 +#define clc_goldsrc_lastmsg 12 + +#define S2C_REJECT_BADPASSWORD '8' +#define S2C_REJECT '9' +#define S2C_CHALLENGE "A00000000" +#define S2C_CONNECTION "B" + +#define MAX_GOLDSRC_RESOURCE_BITS 12 +#define MAX_GOLDSRC_ENTITY_BITS 11 +// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS ) +#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 )) +#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 ) + #endif//NET_PROTOCOL_H diff --git a/engine/common/tests.h b/engine/common/tests.h index a88b6b225..47d551e47 100644 --- a/engine/common/tests.h +++ b/engine/common/tests.h @@ -38,13 +38,15 @@ void Test_RunCvar( void ); void Test_RunCon( void ); void Test_RunVOX( void ); void Test_RunIPFilter( void ); +void Test_RunMunge( void ); #define TEST_LIST_0 \ Test_RunLibCommon(); \ Test_RunCommon(); \ Test_RunCmd(); \ Test_RunCvar(); \ - Test_RunIPFilter(); + Test_RunIPFilter(); \ + Test_RunMunge(); #define TEST_LIST_0_CLIENT \ Test_RunCon(); diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 21dda2c6b..f87b5580b 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -426,7 +426,7 @@ void SV_ConnectClient( netadr_t from ) newcl->listeners = -1; // initailize netchan - Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize ); + Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, 0 ); MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 ); diff --git a/engine/wscript b/engine/wscript index 6f009913e..6302b7f75 100644 --- a/engine/wscript +++ b/engine/wscript @@ -219,7 +219,7 @@ def build(bld): 'client/*.c', 'client/vgui/*.c', 'client/avi/*.c']) - libs += ['opus'] + libs += ['opus', 'bzip2'] includes = ['server', 'client', 'client/vgui' ] diff --git a/wscript b/wscript index 38b0d3da5..1333a3e5c 100644 --- a/wscript +++ b/wscript @@ -75,6 +75,7 @@ SUBDIRS = [ Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES), Subproject('ref/gl', lambda x: not x.env.DEDICATED and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES)), Subproject('ref/soft', lambda x: not x.env.DEDICATED and x.env.SOFT), + Subproject('3rdparty/bzip2', lambda x: not x.env.DEDICATED), Subproject('3rdparty/mainui', lambda x: not x.env.DEDICATED), Subproject('3rdparty/vgui_support', lambda x: not x.env.DEDICATED), Subproject('stub/client', lambda x: not x.env.DEDICATED), @@ -294,7 +295,7 @@ def configure(conf): '-Werror=cast-align=strict', '-Werror=duplicated-cond', # '-Werror=format=2', - '-Werror=implicit-fallthrough=2', +# '-Werror=implicit-fallthrough=2', '-Werror=logical-op', '-Werror=nonnull', '-Werror=packed',