intel_error_decode: Inflate compressed error state

Recent kernels compress the active objects using zlib + ascii85
encoding. This adapts the tool to decompress those inplace.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
diff --git a/tools/intel_error_decode.c b/tools/intel_error_decode.c
index a7a65e8..70a256f 100644
--- a/tools/intel_error_decode.c
+++ b/tools/intel_error_decode.c
@@ -51,6 +51,7 @@
 #include <err.h>
 #include <assert.h>
 #include <intel_bufmgr.h>
+#include <zlib.h>
 
 #include "intel_chipset.h"
 #include "intel_io.h"
@@ -458,6 +459,87 @@
 	*count = 0;
 }
 
+static int zlib_inflate(uint32_t **ptr, int len)
+{
+	struct z_stream_s zstream;
+	void *out;
+
+	memset(&zstream, 0, sizeof(zstream));
+
+	zstream.next_in = (unsigned char *)*ptr;
+	zstream.avail_in = 4*len;
+
+	if (inflateInit(&zstream) != Z_OK)
+		return 0;
+
+	out = malloc(128*4096); /* approximate obj size */
+	zstream.next_out = out;
+	zstream.avail_out = 40*len;
+
+	do {
+		switch (inflate(&zstream, Z_SYNC_FLUSH)) {
+		case Z_STREAM_END:
+			goto end;
+		case Z_OK:
+			break;
+		default:
+			inflateEnd(&zstream);
+			return 0;
+		}
+
+		if (zstream.avail_out)
+			break;
+
+		out = realloc(out, 2*zstream.total_out);
+		if (out == NULL) {
+			inflateEnd(&zstream);
+			return 0;
+		}
+
+		zstream.next_out = (unsigned char *)out + zstream.total_out;
+		zstream.avail_out = zstream.total_out;
+	} while (1);
+end:
+	inflateEnd(&zstream);
+	free(*ptr);
+	*ptr = out;
+	return zstream.total_out / 4;
+}
+
+static int ascii85_decode(const char *in, uint32_t **out)
+{
+	int len = 0, size = 1024;
+
+	*out = realloc(*out, sizeof(uint32_t)*size);
+	if (*out == NULL)
+		return 0;
+
+	while (*in >= '!' && *in <= 'z') {
+		uint32_t v = 0;
+
+		if (len == size) {
+			size *= 2;
+			*out = realloc(*out, sizeof(uint32_t)*size);
+			if (*out == NULL)
+				return 0;
+		}
+
+		if (*in == 'z') {
+			in++;
+		} else {
+			v += in[0] - 33; v *= 85;
+			v += in[1] - 33; v *= 85;
+			v += in[2] - 33; v *= 85;
+			v += in[3] - 33; v *= 85;
+			v += in[4] - 33;
+			in += 5;
+		}
+		(*out)[len++] = v;
+	}
+
+	return zlib_inflate(out, len);
+}
+
 static void
 read_data_file(FILE *file)
 {
@@ -511,6 +593,17 @@
 			}
 		}
 
+		if (line[0] == ':') {
+			count = ascii85_decode(line+1, &data);
+			if (count == 0) {
+				fprintf(stderr, "ASCII85 decode failed.\n");
+				exit(1);
+			}
+			decode(decode_ctx, is_batch, ring_name, gtt_offset,
+			       data, &count);
+			continue;
+		}
+
 		matched = sscanf(line, "%08x : %08x", &offset, &value);
 		if (matched != 2) {
 			unsigned int reg, reg2;