bool inflate_gzip(char const* in, int size, std::vector<char>& buffer, int maximum_size, std::string& error) { LIBED2K_ASSERT(maximum_size > 0); int header_len = gzip_header(in, size); if (header_len < 0) { error = "invalid gzip header"; return true; } // start off with one kilobyte and grow // if needed buffer.resize(maximum_size); boost::uint32_t destlen = buffer.size(); boost::uint32_t srclen = size - header_len; in += header_len; int ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen); if (ret == -1) { error = "inflated data too big"; return true; } buffer.resize(destlen); if (ret != 0) { error = "error while inflating data"; return true; } return false; }
TORRENT_EXTRA_EXPORT void inflate_gzip( char const* in , int size , std::vector<char>& buffer , int maximum_size , error_code& ec) { ec.clear(); TORRENT_ASSERT(maximum_size > 0); int header_len = gzip_header(in, size); if (header_len < 0) { ec = gzip_errors::invalid_gzip_header; return; } // start off with 4 kilobytes and grow // if needed boost::uint32_t destlen = 4096; int ret = 0; boost::uint32_t srclen = size - header_len; in += header_len; do { TORRENT_TRY { buffer.resize(destlen); } TORRENT_CATCH(std::exception&) { ec = errors::no_memory; return; } ret = puff(reinterpret_cast<unsigned char*>(&buffer[0]), &destlen , reinterpret_cast<const unsigned char*>(in), &srclen); // if the destination buffer wasn't large enough, double its // size and try again. Unless it's already at its max, in which // case we fail if (ret == 1) // 1: output space exhausted before completing inflate { if (destlen == boost::uint32_t(maximum_size)) { ec = gzip_errors::inflated_data_too_large; return; } destlen *= 2; if (destlen > boost::uint32_t(maximum_size)) destlen = maximum_size; } } while (ret == 1);
// TODO: 2 it would be nice to use proper error handling here TORRENT_EXTRA_EXPORT bool inflate_gzip( char const* in , int size , std::vector<char>& buffer , int maximum_size , std::string& error) { TORRENT_ASSERT(maximum_size > 0); int header_len = gzip_header(in, size); if (header_len < 0) { error = "invalid gzip header"; return true; } // start off with 4 kilobytes and grow // if needed boost::uint32_t destlen = 4096; int ret = 0; boost::uint32_t srclen = size - header_len; in += header_len; do { TORRENT_TRY { buffer.resize(destlen); } TORRENT_CATCH(std::exception& e) { error = "out of memory: "; error += e.what(); return true; } ret = puff((unsigned char*)&buffer[0], &destlen, (unsigned char*)in, &srclen); // if the destination buffer wasn't large enough, double its // size and try again. Unless it's already at its max, in which // case we fail if (ret == 1) // 1: output space exhausted before completing inflate { if (destlen == boost::uint32_t(maximum_size)) { error = "inflated data too big"; return true; } destlen *= 2; if (destlen > (unsigned int)maximum_size) destlen = maximum_size; } } while (ret == 1);
bool inflate_gzip( char const* in , int size , std::vector<char>& buffer , int maximum_size , std::string& error) { TORRENT_ASSERT(maximum_size > 0); int header_len = gzip_header(in, size); if (header_len < 0) { error = "invalid gzip header in tracker response"; return true; } // start off with one kilobyte and grow // if needed buffer.resize(1024); // initialize the zlib-stream z_stream str; // subtract 8 from the end of the buffer since that's CRC32 and input size // and those belong to the gzip file str.avail_in = (int)size - header_len - 8; str.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in + header_len)); str.next_out = reinterpret_cast<Bytef*>(&buffer[0]); str.avail_out = (int)buffer.size(); str.zalloc = Z_NULL; str.zfree = Z_NULL; str.opaque = 0; // -15 is really important. It will make inflate() not look for a zlib header // and just deflate the buffer if (inflateInit2(&str, -15) != Z_OK) { error = "gzip out of memory"; return true; } // inflate and grow inflate_buffer as needed int ret = inflate(&str, Z_SYNC_FLUSH); while (ret == Z_OK) { if (str.avail_out == 0) { if (buffer.size() >= (unsigned)maximum_size) { inflateEnd(&str); error = "response too large"; return true; } int new_size = (int)buffer.size() * 2; if (new_size > maximum_size) new_size = maximum_size; int old_size = (int)buffer.size(); buffer.resize(new_size); str.next_out = reinterpret_cast<Bytef*>(&buffer[old_size]); str.avail_out = new_size - old_size; } ret = inflate(&str, Z_SYNC_FLUSH); } buffer.resize(buffer.size() - str.avail_out); inflateEnd(&str); if (ret != Z_STREAM_END) { error = "gzip error"; return true; } // commit the resulting buffer return false; }