summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-obj-comp.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-obj-comp.c')
-rw-r--r--cpukit/libdl/rtl-obj-comp.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-obj-comp.c b/cpukit/libdl/rtl-obj-comp.c
new file mode 100644
index 0000000000..d9c5462e1e
--- /dev/null
+++ b/cpukit/libdl/rtl-obj-comp.c
@@ -0,0 +1,179 @@
+/*
+ * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Object Compression manages a compress
+ * stream of data.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rtems/rtl/rtl-allocator.h>
+#include "rtl-obj-comp.h"
+#include "rtl-error.h"
+
+#include "fastlz.h"
+
+#include <stdio.h>
+
+bool
+rtems_rtl_obj_comp_open (rtems_rtl_obj_comp_t* comp,
+ size_t size)
+{
+ comp->cache = NULL;
+ comp->fd = -1;
+ comp->compression = RTEMS_RTL_COMP_LZ77;
+ comp->offset = 0;
+ comp->size = size;
+ comp->level = 0;
+ comp->buffer = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
+ if (!comp->buffer)
+ {
+ rtems_rtl_set_error (ENOMEM, "no memory for compressor buffer");
+ return false;
+ }
+ comp->read = 0;
+ return true;
+}
+
+void
+rtems_rtl_obj_comp_close (rtems_rtl_obj_comp_t* comp)
+{
+ rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, comp->buffer);
+ comp->cache = NULL;
+ comp->fd = -1;
+ comp->compression = RTEMS_RTL_COMP_LZ77;
+ comp->level = 0;
+ comp->size = 0;
+ comp->offset = 0;
+ comp->read = 0;
+}
+
+void
+rtems_rtl_obj_comp_set (rtems_rtl_obj_comp_t* comp,
+ rtems_rtl_obj_cache_t* cache,
+ int fd,
+ int compression,
+ off_t offset)
+{
+ comp->cache = cache;
+ comp->fd = fd;
+ comp->compression = compression;
+ comp->offset = offset;
+ comp->level = 0;
+ comp->read = 0;
+}
+
+bool
+rtems_rtl_obj_comp_read (rtems_rtl_obj_comp_t* comp,
+ void* buffer,
+ size_t length)
+{
+ uint8_t* bin = buffer;
+
+ if (!comp->cache)
+ {
+ rtems_rtl_set_error (EINVAL, "not open");
+ return false;
+ }
+
+ if (comp->fd != comp->cache->fd)
+ {
+ comp->level = 0;
+ }
+
+ while (length)
+ {
+ size_t buffer_level;
+
+ buffer_level = length > comp->level ? comp->level : length;
+
+ if (buffer_level)
+ {
+ memcpy (bin, comp->buffer, buffer_level);
+
+ if ((comp->level - buffer_level) != 0)
+ {
+ memmove (comp->buffer,
+ comp->buffer + buffer_level,
+ comp->level - buffer_level);
+ }
+
+ bin += buffer_level;
+ length -= buffer_level;
+ comp->level -= buffer_level;
+ comp->read += buffer_level;
+ }
+
+ if (length)
+ {
+ uint8_t* input = NULL;
+ uint16_t block_size;
+ size_t in_length = sizeof (block_size);
+ int decompressed;
+
+ if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
+ (void**) &input, &in_length))
+ return false;
+
+ block_size = (input[0] << 8) | input[1];
+
+ comp->offset += sizeof (block_size);
+
+ in_length = block_size;
+
+ if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
+ (void**) &input, &in_length))
+ return false;
+
+ if (in_length != block_size)
+ {
+ rtems_rtl_set_error (EIO, "compressed read failed: bs=%u in=%u",
+ block_size, in_length);
+ return false;
+ }
+
+ switch (comp->compression)
+ {
+ case RTEMS_RTL_COMP_NONE:
+ memcpy (comp->buffer, input, in_length);
+ decompressed = in_length;
+ break;
+
+ case RTEMS_RTL_COMP_LZ77:
+ decompressed = fastlz_decompress (input, in_length,
+ comp->buffer, comp->size);
+ if (decompressed == 0)
+ {
+ rtems_rtl_set_error (EBADF, "decompression failed");
+ return false;
+ }
+ break;
+
+ default:
+ rtems_rtl_set_error (EINVAL, "bad compression type");
+ return false;
+ }
+
+ comp->offset += block_size;
+
+ comp->level = decompressed;
+ }
+ }
+
+ return true;
+}