summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/decompress_unlzo.c180
1 files changed, 92 insertions, 88 deletions
diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c
index 8f9cdcf27b..fc5c49f455 100644
--- a/lib/decompress_unlzo.c
+++ b/lib/decompress_unlzo.c
@@ -47,98 +47,73 @@ static const unsigned char lzop_magic[] = {
#define LZO_BLOCK_SIZE (256*1024l)
#define HEADER_HAS_FILTER 0x00000800L
-static inline int parse_header(int in_fd)
+static inline int parse_header(u8 *input, u8 *skip)
{
- u8 l;
+ int l;
+ u8 *parse = input;
+ u8 level = 0;
u16 version;
- int ret;
- unsigned char buf[256]; /* maximum filename length + 1 */
- /* read magic (9), library version (2), 'need to be extracted'
- * version (2) and method (1)
- */
- ret = read(in_fd, buf, 9);
- if (ret < 0)
- return ret;
-
- /* check magic */
+ /* read magic: 9 first bits */
for (l = 0; l < 9; l++) {
- if (buf[l] != lzop_magic[l])
- return -EINVAL;
+ if (*parse++ != lzop_magic[l])
+ return 0;
}
-
- ret = read(in_fd, buf, 4); /* version, lib_version */
- if (ret < 0)
- return ret;
- version = get_unaligned_be16(buf);
-
- if (version >= 0x0940) {
- ret = read(in_fd, buf, 2); /* version to extract */
- if (ret < 0)
- return ret;
- }
-
- ret = read(in_fd, buf, 1); /* method */
- if (ret < 0)
- return ret;
-
+ /* get version (2bytes), skip library version (2),
+ * 'need to be extracted' version (2) and
+ * method (1) */
+ version = get_unaligned_be16(parse);
+ parse += 7;
if (version >= 0x0940)
- read(in_fd, buf, 1); /* level */
-
- ret = read(in_fd, buf, 4); /* flags */
- if (ret < 0)
- return ret;
-
- if (get_unaligned_be32(buf) & HEADER_HAS_FILTER) {
- ret = read(in_fd, buf, 4); /* skip filter info */
- if (ret < 0)
- return ret;
- }
+ level = *parse++;
+ if (get_unaligned_be32(parse) & HEADER_HAS_FILTER)
+ parse += 8; /* flags + filter info */
+ else
+ parse += 4; /* flags */
/* skip mode and mtime_low */
- ret = read(in_fd, buf, 8);
- if (ret < 0)
- return ret;
-
- if (version >= 0x0940) {
- ret = read(in_fd, buf, 4); /* skip mtime_high */
- if (ret < 0)
- return ret;
- }
+ parse += 8;
+ if (version >= 0x0940)
+ parse += 4; /* skip mtime_high */
- ret = read(in_fd, &l, 1);
- if (ret < 0)
- return ret;
+ l = *parse++;
/* don't care about the file name, and skip checksum */
- ret = read(in_fd, buf, l + 4);
- if (ret < 0)
- return ret;
+ parse += l + 4;
- return 0;
+ *skip = parse - input;
+ return 1;
}
-int unlzo(int in_fd, int out_fd, int *dest_len)
+static int __unlzo(int *dest_len,
+ int (*fill) (void *, unsigned int),
+ int (*flush) (void *, unsigned int))
{
- u8 r = 0;
+ u8 skip = 0, r = 0;
u32 src_len, dst_len;
size_t tmp;
- u8 *in_buf, *out_buf;
+ u8 *in_buf, *in_buf_save, *out_buf, *out_buf_save;
int obytes_processed = 0;
- unsigned char buf[8];
- int ret;
-
- if (parse_header(in_fd))
- return -EINVAL;
+ int ret = -1;
out_buf = xmalloc(LZO_BLOCK_SIZE);
in_buf = xmalloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
+ in_buf_save = in_buf;
+ out_buf_save = out_buf;
+
+ ret = fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
+ if (ret < 0)
+ goto exit_free;
+
+ if (!parse_header(in_buf, &skip))
+ return -EINVAL;
+
+ in_buf += skip;
+
for (;;) {
/* read uncompressed block size */
- ret = read(in_fd, buf, 4);
- if (ret < 0)
- goto exit_free;
- dst_len = get_unaligned_be32(buf);
+ dst_len = get_unaligned_be32(in_buf);
+ in_buf += 4;
/* exit if last block */
if (dst_len == 0)
@@ -150,43 +125,53 @@ int unlzo(int in_fd, int out_fd, int *dest_len)
}
/* read compressed block size, and skip block checksum info */
- ret = read(in_fd, buf, 8);
- if (ret < 0)
- goto exit_free;
-
- src_len = get_unaligned_be32(buf);
+ src_len = get_unaligned_be32(in_buf);
+ in_buf += 8;
if (src_len <= 0 || src_len > dst_len) {
printf("file corrupted");
goto exit_free;
}
- ret = read(in_fd, in_buf, src_len);
- if (ret < 0)
- goto exit_free;
/* decompress */
tmp = dst_len;
- if (src_len < dst_len) {
- r = lzo1x_decompress_safe((u8 *) in_buf, src_len,
- out_buf, &tmp);
- if (r != LZO_E_OK || dst_len != tmp) {
+
+ /* When the input data is not compressed at all,
+ * lzo1x_decompress_safe will fail, so call memcpy()
+ * instead */
+ if (unlikely(dst_len == src_len)) {
+ if (src_len != dst_len) {
printf("Compressed data violation");
goto exit_free;
}
- ret = write(out_fd, out_buf, dst_len);
- if (ret < 0)
- goto exit_free;
+ out_buf = in_buf;
} else {
- if (src_len != dst_len) {
+ r = lzo1x_decompress_safe((u8 *) in_buf, src_len,
+ out_buf, &tmp);
+
+ if (r != LZO_E_OK || dst_len != tmp) {
printf("Compressed data violation");
goto exit_free;
}
- ret = write(out_fd, in_buf, dst_len);
- if (ret < 0)
- goto exit_free;
}
+ ret = flush(out_buf, dst_len);
+ if (ret < 0)
+ goto exit_free;
+
+ out_buf = in_buf + src_len;
+ in_buf = in_buf_save;
+ ret = fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
+ if (ret < 0)
+ goto exit_free;
+
+ if (ret == 0)
+ in_buf = out_buf;
+
+ out_buf = out_buf_save;
+
obytes_processed += dst_len;
+
}
exit_free:
@@ -197,3 +182,22 @@ exit_free:
return 0;
}
+static int in_fd;
+static int out_fd;
+
+static int unlzo_fill(void *buf, unsigned int len)
+{
+ return read(in_fd, buf, len);
+}
+
+static int unlzo_flush(void *buf, unsigned int len)
+{
+ return write(out_fd, buf, len);
+}
+
+int unlzo(int _in_fd, int _out_fd, int *dest_len)
+{
+ in_fd = _in_fd;
+ out_fd = _out_fd;
+ return __unlzo(dest_len, unlzo_fill, unlzo_flush);
+}