decompress(packet_info* pinfo, proto_tree* tree, tvbuff_t* tvb, gint offset, gint length)
{
	if(PINFO_FD_VISITED(pinfo)) {
		const decompress_result_t* saved_data = (decompress_result_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_blip, 0);
		if(!saved_data) {
			proto_tree_add_string(tree, hf_blip_message_body, tvb, offset, tvb_reported_length_remaining(tvb, offset), "<Error decompressing data>");
			return NULL;
		}

		if(saved_data->domain) {
			proto_item* field = proto_tree_add_string(tree, hf_blip_message_body, tvb, offset, tvb_reported_length_remaining(tvb, offset), "<Error decompressing data>");
			if(saved_data->domain == zlib_error) {
				expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, got zlib error %d", saved_data->code);
			} else {
				expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, buffer too small (%u Kb).  Please adjust in settings.", max_uncompressed_size);
			}

			return NULL;
		} else {
			tvbuff_t* decompressedChild = tvb_new_child_real_data(tvb, (guint8 *)saved_data->buf,
				(gint)saved_data->size, (gint)saved_data->size);
			add_new_data_source(pinfo, decompressedChild, "Decompressed Payload");
			return decompressedChild;
		}
	}

	static gboolean size_overflow = FALSE;
	const guint8* buf = tvb_get_ptr(tvb, offset, length);
	z_stream* decompress_stream = get_decompress_stream(pinfo);
	static Byte trailer[4] = { 0x00, 0x00, 0xff, 0xff };
	if(!decompress_stream->next_out) {
		decompress_stream->zalloc = 0;
		decompress_stream->zfree = 0;
		decompress_stream->opaque = 0;
		int err = inflateInit2(decompress_stream, -MAX_WBITS);
		if(err != Z_OK) {
			decompress_stream->next_out = 0;
			REPORT_DISSECTOR_BUG("Unable to create INFLATE context to decompress messages");
			return NULL;
		}
	}

	// Create a temporary buffer of the maximum size, which will get cleaned up later
	// when the packet scope is freed
	uInt buffer_size = max_uncompressed_size * 1024;
	Bytef* decompress_buffer = (Bytef*)wmem_alloc(wmem_packet_scope(), buffer_size);
	decompress_stream->next_in = (Bytef*)buf;
	decompress_stream->avail_in = length;
	decompress_stream->next_out = decompress_buffer;
	decompress_stream->avail_out = buffer_size;
	uLong start = decompress_stream->total_out;
	int err = inflate(decompress_stream, Z_NO_FLUSH);
	if(err != Z_OK) {
		proto_item* field = proto_tree_add_string(tree, hf_blip_message_body, tvb, offset, tvb_reported_length_remaining(tvb, offset), "<Error decompressing data>");
		decompress_result_t* data_to_save = wmem_new0(wmem_file_scope(), decompress_result_t);
		if(size_overflow && err == Z_DATA_ERROR) {
			data_to_save->domain = overflow_error;
			expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, buffer too small (%u Kb).  Please adjust in settings.", max_uncompressed_size);
		} else {
			data_to_save->domain = zlib_error;
			data_to_save->code = err;
			expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, got zlib error %d", err);
		}

		p_add_proto_data(wmem_file_scope(), pinfo, proto_blip, 0, data_to_save);
		return NULL;
	}

	decompress_stream->next_in = trailer;
	decompress_stream->avail_in = 4;
	err = inflate(decompress_stream, Z_SYNC_FLUSH);
	if(err != Z_OK) {
		proto_item* field = proto_tree_add_string(tree, hf_blip_message_body, tvb, offset, tvb_reported_length_remaining(tvb, offset), "<Error decompressing data>");
		decompress_result_t* data_to_save = wmem_new0(wmem_file_scope(), decompress_result_t);
		if(err == Z_BUF_ERROR) {
			data_to_save->domain = overflow_error;
			size_overflow = TRUE;
			expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, buffer too small (%u Kb).  Please adjust in settings.", max_uncompressed_size);
		} else {
			data_to_save->domain = zlib_error;
			data_to_save->code = err;
			expert_add_info_format(pinfo, field, &ei_blip_decompress_buffer_too_small, "Unable to decompress message, got zlib error %d", err);
		}

		p_add_proto_data(wmem_file_scope(), pinfo, proto_blip, 0, data_to_save);
		return NULL;
	}

	// Shrink the buffer so that there is not wasted space on the end of it since
	// it will be long lived in the file scope
	uLong bodyLength = decompress_stream->total_out - start;
	Bytef* shortened_buffer = (Bytef *)wmem_memdup(wmem_file_scope(), decompress_buffer, bodyLength);

	tvbuff_t* decompressedChild = tvb_new_child_real_data(tvb, shortened_buffer, (guint)bodyLength, (gint)bodyLength);
	add_new_data_source(pinfo, decompressedChild, "Decompressed Payload");
	decompress_result_t* data_to_save = wmem_new0(wmem_file_scope(), decompress_result_t);
	data_to_save->size = (size_t)bodyLength;
	data_to_save->buf = shortened_buffer;
	p_add_proto_data(wmem_file_scope(), pinfo, proto_blip, 0, data_to_save);

	return decompressedChild;
}