summaryrefslogtreecommitdiffstats
path: root/lib/zlib/tf_gunzip.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zlib/tf_gunzip.c')
-rw-r--r--lib/zlib/tf_gunzip.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/zlib/tf_gunzip.c b/lib/zlib/tf_gunzip.c
new file mode 100644
index 0000000..3ac80bc
--- /dev/null
+++ b/lib/zlib/tf_gunzip.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+#include <lib/utils.h>
+#include <tf_gunzip.h>
+
+#include "zutil.h"
+
+/*
+ * memory allocated by malloc() is supposed to be aligned for any built-in type
+ */
+#define ZALLOC_ALIGNMENT sizeof(void *)
+
+static uintptr_t zalloc_start;
+static uintptr_t zalloc_end;
+static uintptr_t zalloc_current;
+
+static void * ZLIB_INTERNAL zcalloc(void *opaque, unsigned int items,
+ unsigned int size)
+{
+ uintptr_t p, p_end;
+
+ size *= items;
+
+ p = round_up(zalloc_current, ZALLOC_ALIGNMENT);
+ p_end = p + size;
+
+ if (p_end > zalloc_end)
+ return NULL;
+
+ memset((void *)p, 0, size);
+
+ zalloc_current = p_end;
+
+ return (void *)p;
+}
+
+static void ZLIB_INTERNAL zfree(void *opaque, void *ptr)
+{
+}
+
+/*
+ * gunzip - decompress gzip data
+ * @in_buf: source of compressed input. Upon exit, the end of input.
+ * @in_len: length of in_buf
+ * @out_buf: destination of decompressed output. Upon exit, the end of output.
+ * @out_len: length of out_buf
+ * @work_buf: workspace
+ * @work_len: length of workspace
+ */
+int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf,
+ size_t out_len, uintptr_t work_buf, size_t work_len)
+{
+ z_stream stream;
+ int zret, ret;
+
+ zalloc_start = work_buf;
+ zalloc_end = work_buf + work_len;
+ zalloc_current = zalloc_start;
+
+ stream.next_in = (typeof(stream.next_in))*in_buf;
+ stream.avail_in = in_len;
+ stream.next_out = (typeof(stream.next_out))*out_buf;
+ stream.avail_out = out_len;
+ stream.zalloc = zcalloc;
+ stream.zfree = zfree;
+ stream.opaque = (voidpf)0;
+
+ zret = inflateInit(&stream);
+ if (zret != Z_OK) {
+ ERROR("zlib: inflate init failed (ret = %d)\n", zret);
+ return (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
+ }
+
+ zret = inflate(&stream, Z_NO_FLUSH);
+ if (zret == Z_STREAM_END) {
+ ret = 0;
+ } else {
+ if (stream.msg)
+ ERROR("%s\n", stream.msg);
+ ERROR("zlib: inflate failed (ret = %d)\n", zret);
+ ret = (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
+ }
+
+ VERBOSE("zlib: %lu byte input\n", stream.total_in);
+ VERBOSE("zlib: %lu byte output\n", stream.total_out);
+
+ *in_buf = (uintptr_t)stream.next_in;
+ *out_buf = (uintptr_t)stream.next_out;
+
+ inflateEnd(&stream);
+
+ return ret;
+}
+
+/* Wrapper function to calculate CRC
+ * @crc: previous accumulated CRC
+ * @buf: buffer base address
+ * @size: size of the buffer
+ *
+ * Return calculated CRC32 value
+ */
+uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size)
+{
+ return (uint32_t)crc32((unsigned long)crc, buf, size);
+}