+
+
+ void expandCompressedData(const char* s, int n)
+ {
+ int reqSize = n + zlib.avail_in;
+ if (reqSize > zlibInflateBufferSize) {
+ // reallocate
+ unsigned char* newBuf = (unsigned char*) malloc(reqSize);
+ memcpy(newBuf, zlib.next_in, zlib.avail_in);
+ memcpy(newBuf + zlib.avail_in, s, n);
+ free(zlibInflateBuffer);
+ zlibInflateBuffer = newBuf;
+ zlibInflateBufferSize = reqSize;
+ } else {
+ // important to use memmove here, since it's very likely
+ // the source and destination ranges overlap
+ memmove(zlibInflateBuffer, zlib.next_in, zlib.avail_in);
+ memcpy(zlibInflateBuffer + zlib.avail_in, s, n);
+ }
+
+ zlib.next_in = (unsigned char*) zlibInflateBuffer;
+ zlib.avail_in = reqSize;
+ zlib.next_out = zlibOutputBuffer;
+ zlib.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE;
+
+ if (contentGZip && !handleGZipHeader()) {
+ return;
+ }
+
+ int writtenSize = 0;
+ do {
+ int result = inflate(&zlib, Z_NO_FLUSH);
+ if (result == Z_OK || result == Z_STREAM_END) {
+ // nothing to do
+ } else {
+ SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result);
+ return;
+ }
+
+ writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - zlib.avail_out;
+ if (result == Z_STREAM_END) {
+ break;
+ }
+ } while ((writtenSize == 0) && (zlib.avail_in > 0));
+
+ if (writtenSize > 0) {
+ activeRequest->processBodyBytes((const char*) zlibOutputBuffer, writtenSize);
+ }
+ }
+
+ bool handleGZipHeader()
+ {
+ // we clear this down to contentDeflate once the GZip header has been seen
+ if (zlib.avail_in < GZIP_HEADER_SIZE) {
+ return false; // need more header bytes
+ }
+
+ if ((zlibInflateBuffer[0] != GZIP_HEADER_ID1) ||
+ (zlibInflateBuffer[1] != GZIP_HEADER_ID2) ||
+ (zlibInflateBuffer[2] != GZIP_HEADER_METHOD_DEFLATE))
+ {
+ return false; // invalid GZip header
+ }
+
+ char flags = zlibInflateBuffer[3];
+ int gzipHeaderSize = GZIP_HEADER_SIZE;
+ if (flags & GZIP_HEADER_FEXTRA) {
+ gzipHeaderSize += 2;
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
+ }
+
+ unsigned short extraHeaderBytes = *(reinterpret_cast<unsigned short*>(zlibInflateBuffer + GZIP_HEADER_FEXTRA));
+ if ( sgIsBigEndian() ) {
+ sgEndianSwap( &extraHeaderBytes );
+ }
+
+ gzipHeaderSize += extraHeaderBytes;
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
+ }
+ }
+
+ if (flags & GZIP_HEADER_FNAME) {
+ gzipHeaderSize++;
+ while (gzipHeaderSize <= zlib.avail_in) {
+ if (zlibInflateBuffer[gzipHeaderSize-1] == 0) {
+ break; // found terminating NULL character
+ }
+ }
+ }
+
+ if (flags & GZIP_HEADER_COMMENT) {
+ gzipHeaderSize++;
+ while (gzipHeaderSize <= zlib.avail_in) {
+ if (zlibInflateBuffer[gzipHeaderSize-1] == 0) {
+ break; // found terminating NULL character
+ }
+ }
+ }
+
+ if (flags & GZIP_HEADER_CRC) {
+ gzipHeaderSize += 2;
+ }
+
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
+ }
+
+ zlib.next_in += gzipHeaderSize;
+ zlib.avail_in -= gzipHeaderSize;
+ // now we've processed the GZip header, can decode as deflate
+ contentGZip = false;
+ contentDeflate = true;
+ return true;
+ }