Changes from V1 to V2:
- Add a configuration option for the LZO compression
- Add a comment line specifying the origin of the source code

In some case, LZO compression function is needed in U-Boot.

This patch supports LZO compression feature which is originated from Linux 
kernel.

Thanks.
-Donggeun Kim

Signed-off-by: Donggeun Kim <dg77....@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.p...@samsung.com>
---
 lib/lzo/Makefile         |    1 +
 lib/lzo/lzo1x_compress.c |  221 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 222 insertions(+), 0 deletions(-)
 create mode 100644 lib/lzo/lzo1x_compress.c

diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
index 5dd1bf5..ca2253a 100644
--- a/lib/lzo/Makefile
+++ b/lib/lzo/Makefile
@@ -28,6 +28,7 @@ LIB   = $(obj)liblzo.a
 SOBJS  =
 
 COBJS-$(CONFIG_LZO) += lzo1x_decompress.o
+COBJS-$(CONFIG_LZO_COMPRESSION) += lzo1x_compress.o
 
 COBJS  = $(COBJS-y)
 SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c
new file mode 100644
index 0000000..1743727
--- /dev/null
+++ b/lib/lzo/lzo1x_compress.c
@@ -0,0 +1,221 @@
+/*
+ *  LZO1X Compressor from MiniLZO
+ *
+ *  Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <mar...@oberhumer.com>
+ *
+ *  The full LZO package can be found at:
+ *  http://www.oberhumer.com/opensource/lzo/
+ *
+ *  Changed for kernel use by:
+ *  Nitin Gupta <nitingupta...@gmail.com>
+ *  Richard Purdie <rpur...@openedhand.com>
+ *
+ *  Note : This code is taken from linux kernel.
+ */
+#include <common.h>
+#include <linux/lzo.h>
+#include <asm/unaligned.h>
+#include "lzodefs.h"
+
+static size_t
+_lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
+               unsigned char *out, size_t *out_len, void *wrkmem)
+{
+       const unsigned char * const in_end = in + in_len;
+       const unsigned char * const ip_end = in + in_len - M2_MAX_LEN - 5;
+       const unsigned char ** const dict = wrkmem;
+       const unsigned char *ip = in, *ii = ip;
+       const unsigned char *end, *m, *m_pos;
+       size_t m_off, m_len, dindex;
+       unsigned char *op = out;
+
+       ip += 4;
+
+       for (;;) {
+               dindex = ((size_t)(0x21 * DX3(ip, 5, 5, 6)) >> 5) & D_MASK;
+               m_pos = dict[dindex];
+
+               if (m_pos < in)
+                       goto literal;
+
+               if (ip == m_pos || ((size_t)(ip - m_pos) > M4_MAX_OFFSET))
+                       goto literal;
+
+               m_off = ip - m_pos;
+               if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+                       goto try_match;
+
+               dindex = (dindex & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f);
+               m_pos = dict[dindex];
+
+               if (m_pos < in)
+                       goto literal;
+
+               if (ip == m_pos || ((size_t)(ip - m_pos) > M4_MAX_OFFSET))
+                       goto literal;
+
+               m_off = ip - m_pos;
+               if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+                       goto try_match;
+
+               goto literal;
+
+try_match:
+               if (get_unaligned((const unsigned short *)m_pos)
+                               == get_unaligned((const unsigned short *)ip)) {
+                       if (likely(m_pos[2] == ip[2]))
+                                       goto match;
+               }
+
+literal:
+               dict[dindex] = ip;
+               ++ip;
+               if (unlikely(ip >= ip_end))
+                       break;
+               continue;
+
+match:
+               dict[dindex] = ip;
+               if (ip != ii) {
+                       size_t t = ip - ii;
+
+                       if (t <= 3) {
+                               op[-2] |= t;
+                       } else if (t <= 18) {
+                               *op++ = (t - 3);
+                       } else {
+                               size_t tt = t - 18;
+
+                               *op++ = 0;
+                               while (tt > 255) {
+                                       tt -= 255;
+                                       *op++ = 0;
+                               }
+                               *op++ = tt;
+                       }
+                       do {
+                               *op++ = *ii++;
+                       } while (--t > 0);
+               }
+
+               ip += 3;
+               if (m_pos[3] != *ip++ || m_pos[4] != *ip++
+                               || m_pos[5] != *ip++ || m_pos[6] != *ip++
+                               || m_pos[7] != *ip++ || m_pos[8] != *ip++) {
+                       --ip;
+                       m_len = ip - ii;
+
+                       if (m_off <= M2_MAX_OFFSET) {
+                               m_off -= 1;
+                               *op++ = (((m_len - 1) << 5)
+                                               | ((m_off & 7) << 2));
+                               *op++ = (m_off >> 3);
+                       } else if (m_off <= M3_MAX_OFFSET) {
+                               m_off -= 1;
+                               *op++ = (M3_MARKER | (m_len - 2));
+                               goto m3_m4_offset;
+                       } else {
+                               m_off -= 0x4000;
+
+                               *op++ = (M4_MARKER | ((m_off & 0x4000) >> 11)
+                                               | (m_len - 2));
+                               goto m3_m4_offset;
+                       }
+               } else {
+                       end = in_end;
+                       m = m_pos + M2_MAX_LEN + 1;
+
+                       while (ip < end && *m == *ip) {
+                               m++;
+                               ip++;
+                       }
+                       m_len = ip - ii;
+
+                       if (m_off <= M3_MAX_OFFSET) {
+                               m_off -= 1;
+                               if (m_len <= 33) {
+                                       *op++ = (M3_MARKER | (m_len - 2));
+                               } else {
+                                       m_len -= 33;
+                                       *op++ = M3_MARKER | 0;
+                                       goto m3_m4_len;
+                               }
+                       } else {
+                               m_off -= 0x4000;
+                               if (m_len <= M4_MAX_LEN) {
+                                       *op++ = (M4_MARKER
+                                               | ((m_off & 0x4000) >> 11)
+                                               | (m_len - 2));
+                               } else {
+                                       m_len -= M4_MAX_LEN;
+                                       *op++ = (M4_MARKER
+                                               | ((m_off & 0x4000) >> 11));
+m3_m4_len:
+                                       while (m_len > 255) {
+                                               m_len -= 255;
+                                               *op++ = 0;
+                                       }
+
+                                       *op++ = (m_len);
+                               }
+                       }
+m3_m4_offset:
+                       *op++ = ((m_off & 63) << 2);
+                       *op++ = (m_off >> 6);
+               }
+
+               ii = ip;
+               if (unlikely(ip >= ip_end))
+                       break;
+       }
+
+       *out_len = op - out;
+       return in_end - ii;
+}
+
+int lzo1x_1_compress(const unsigned char *in, size_t in_len, unsigned char 
*out,
+                       size_t *out_len, void *wrkmem)
+{
+       const unsigned char *ii;
+       unsigned char *op = out;
+       size_t t;
+
+       if (unlikely(in_len <= M2_MAX_LEN + 5)) {
+               t = in_len;
+       } else {
+               t = _lzo1x_1_do_compress(in, in_len, op, out_len, wrkmem);
+               op += *out_len;
+       }
+
+       if (t > 0) {
+               ii = in + in_len - t;
+
+               if (op == out && t <= 238) {
+                       *op++ = (17 + t);
+               } else if (t <= 3) {
+                       op[-2] |= t;
+               } else if (t <= 18) {
+                       *op++ = (t - 3);
+               } else {
+                       size_t tt = t - 18;
+
+                       *op++ = 0;
+                       while (tt > 255) {
+                               tt -= 255;
+                               *op++ = 0;
+                       }
+
+                       *op++ = tt;
+               }
+               do {
+                       *op++ = *ii++;
+               } while (--t > 0);
+       }
+
+       *op++ = M4_MARKER | 1;
+       *op++ = 0;
+       *op++ = 0;
+
+       *out_len = op - out;
+       return LZO_E_OK;
+}
-- 
1.6.3.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to