diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 2a582cd6..738697d5 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -119,6 +119,68 @@ void getstring(char *text, ucharbuf &p, int len) DEBUGVAR(text); } +#define GZMSGBUFSIZE ((MAXGZMSGSIZE * 11) / 10) +static uchar *gzbuf = new uchar[GZMSGBUFSIZE]; // not thread-safe, but nesting is no problem + +void putgzbuf(vector &d, vector &s) // zips a vector into a stream, stored in another vector; adds a header to simplify decompression +{ + int size = s.length(); + if(size < 1 || size > MAXGZMSGSIZE) size = 0; + uLongf gzbufsize = GZMSGBUFSIZE; + if(size && compress2(gzbuf, &gzbufsize, s.getbuf(), size, 9) == Z_OK) + { + if(gzbufsize > (uint)size) + { // use zipped + putuint(d, size); + putuint(d, (int) gzbufsize); + d.put(gzbuf, (int) gzbufsize); + return; + } + } + // use raw because it's smaller or because zipping failed + putuint(d, size); + putuint(d, 0); + if(size) d.put(s.getbuf(), size); +} + +ucharbuf *getgzbuf(ucharbuf &p) // fetch a gzipped buffer; needs to be freed properly later +{ + int size = getuint(p); + int sizegz = getuint(p); + if(sizegz == 0) sizegz = size; // uncompressed was smaller + if(sizegz > 0 && p.remaining() >= sizegz && sizegz <= MAXGZMSGSIZE && size >= 0 && size <= MAXGZMSGSIZE) + { + uchar *data = new uchar[size + 1]; + uLongf rawsize = size; + if(data) + { + if(size == sizegz) + { + memcpy(data, &p.buf[p.len], size); + } + else if(uncompress(data, &rawsize, &p.buf[p.len], sizegz) != Z_OK || rawsize - size != 0) + { + p.forceoverread(); + delete[] data; + return NULL; + } + p.len += sizegz; + return new ucharbuf(data, size); + } + } + p.forceoverread(); + return NULL; +} + +void freegzbuf(ucharbuf *p) // free a ucharbuf created by getgzbuf() +{ + if(p) + { + delete[] p->buf; + delete p; + } +} + // filter text according to rules // dst can be identical to src; dst needs to be of size "min(len, strlen(s)) + 1" // returns dst diff --git a/source/src/protocol.h b/source/src/protocol.h index 14fa90e4..c0377893 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -11,6 +11,7 @@ #define DEMO_MINTIME 10000 // don't keep demo recordings with less than 10 seconds #define MAXMAPSENDSIZE 65536 #define MAXCFGFILESIZE 65536 +#define MAXGZMSGSIZE 65536 #define MAXMEDIADOWNLOADFILESIZE 1024000 // hard cap on filesizes (raw and unzipped) - to limit the effect of zip bombs - no nice error messages: just cap #define MAXMODDOWNLOADSIZE 1024000 // hard cap on the filesize of downloaded mod packages - to keep stuff reasonable #define MAXFILESINADZIP 21 // max number of files extracted from a zip by autodownload diff --git a/source/src/protos.h b/source/src/protos.h index 1b73e402..bce6b2e5 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -1048,6 +1048,9 @@ extern void sendstring(const char *t, ucharbuf &p); extern void sendstring(const char *t, packetbuf &p); extern void sendstring(const char *t, vector &p); extern void getstring(char *t, ucharbuf &p, int len = MAXTRANS); +extern void putgzbuf(vector &d, vector &s); // zips a vector into a stream, stored in another vector +extern ucharbuf *getgzbuf(ucharbuf &p); // fetch a gzipped buffer; needs to be freed properly later +extern void freegzbuf(ucharbuf *p); // free a ucharbuf created by getgzbuf() extern char *filtertext(char *dst, const char *src, int flags = 1, int len = sizeof(string)-1); extern void filterrichtext(char *dst, const char *src, int len = sizeof(string)-1); extern void filterlang(char *d, const char *s);