add lzop decompression support

Add lzop decompression support to the existing lzo bitstream handling
(think gzip versus zlib), and support it for uImage decompression if
CONFIG_LZO is enabled.

Lzop doesn't compress as good as gzip (~10% worse), but decompression
is very fast (~0.7s faster here on a slow ppc). The lzop decompression
code is based on Albin Tonnerre's recent ARM Linux lzo support patch.

Cc: albin.tonnerre@free-electrons.com
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
diff --git a/lib_generic/lzo/lzo1x_decompress.c b/lib_generic/lzo/lzo1x_decompress.c
index 2780e11..09bdc8f 100644
--- a/lib_generic/lzo/lzo1x_decompress.c
+++ b/lib_generic/lzo/lzo1x_decompress.c
@@ -24,6 +24,93 @@
 #define COPY4(dst, src)	\
 		put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst))
 
+static const unsigned char lzop_magic[] = {
+	0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
+};
+
+#define HEADER_HAS_FILTER	0x00000800L
+
+static inline const unsigned char *parse_header(const unsigned char *src)
+{
+	u8 level = 0;
+	u16 version;
+	int i;
+
+	/* read magic: 9 first bytes */
+	for (i = 0; i < ARRAY_SIZE(lzop_magic); i++) {
+		if (*src++ != lzop_magic[i])
+			return NULL;
+	}
+	/* get version (2bytes), skip library version (2),
+	 * 'need to be extracted' version (2) and
+	 * method (1) */
+	version = get_unaligned_be16(src);
+	src += 7;
+	if (version >= 0x0940)
+		level = *src++;
+	if (get_unaligned_be32(src) & HEADER_HAS_FILTER)
+		src += 4; /* filter info */
+
+	/* skip flags, mode and mtime_low */
+	src += 12;
+	if (version >= 0x0940)
+		src += 4;	/* skip mtime_high */
+
+	i = *src++;
+	/* don't care about the file name, and skip checksum */
+	src += i + 4;
+
+	return src;
+}
+
+int lzop_decompress(const unsigned char *src, size_t src_len,
+		    unsigned char *dst, size_t *dst_len)
+{
+	unsigned char *start = dst;
+	const unsigned char *send = src + src_len;
+	u32 slen, dlen;
+	size_t tmp;
+	int r;
+
+	src = parse_header(src);
+	if (!src)
+		return LZO_E_ERROR;
+
+	while (src < send) {
+		/* read uncompressed block size */
+		dlen = get_unaligned_be32(src);
+		src += 4;
+
+		/* exit if last block */
+		if (dlen == 0) {
+			*dst_len = dst - start;
+			return LZO_E_OK;
+		}
+
+		/* read compressed block size, and skip block checksum info */
+		slen = get_unaligned_be32(src);
+		src += 8;
+
+		if (slen <= 0 || slen > dlen)
+			return LZO_E_ERROR;
+
+		/* decompress */
+		tmp = dlen;
+		r = lzo1x_decompress_safe((u8 *) src, slen, dst, &tmp);
+
+		if (r != LZO_E_OK)
+			return r;
+
+		if (dlen != tmp)
+			return LZO_E_ERROR;
+
+		src += slen;
+		dst += dlen;
+	}
+
+	return LZO_E_INPUT_OVERRUN;
+}
+
 int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
 			unsigned char *out, size_t *out_len)
 {