109 lines
2.3 KiB
C
109 lines
2.3 KiB
C
// SPDX-License-Identifier: GPL 2.0+ OR BSD-3-Clause
|
|
/*
|
|
* Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd
|
|
*
|
|
* Copyright (C) 2013, LG Electronics, Kyungsik Lee <[email protected]>
|
|
*/
|
|
|
|
#include <amlogic/unlz4_android.h>
|
|
#include <common.h>
|
|
#include <compiler.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <amlogic/lz4.h>
|
|
|
|
typedef uint8_t BYTE;
|
|
typedef uint16_t U16;
|
|
typedef uint32_t U32;
|
|
typedef int32_t S32;
|
|
typedef uint64_t U64;
|
|
|
|
/* Unaltered (except removing unrelated code) from github.com/Cyan4973/lz4. */
|
|
#include "lz4.c" /* #include for inlining, do not link! */
|
|
|
|
/*
|
|
* Note: Uncompressed chunk size is used in the compressor side
|
|
* (userspace side for compression).
|
|
* It is hardcoded because there is not proper way to extract it
|
|
* from the binary stream which is generated by the preliminary
|
|
* version of LZ4 tool so far.
|
|
*/
|
|
#define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20)
|
|
#define ARCHIVE_MAGICNUMBER 0x184C2102
|
|
|
|
int unlz4(const void *src, size_t srcn, void *dst, size_t *dstn)
|
|
{
|
|
int ret = -1;
|
|
size_t chunksize = 0;
|
|
size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE;
|
|
long size = srcn;
|
|
size_t dest_len;
|
|
const void *inp = src;
|
|
void *outp = dst;
|
|
*dstn = 0;
|
|
|
|
chunksize = le32_to_cpu(*(u32 *)inp);
|
|
printf("magic: 0x%lX, LZ4F_MAGIC: 0x%X\n", chunksize, ARCHIVE_MAGICNUMBER);
|
|
if (chunksize == ARCHIVE_MAGICNUMBER) {
|
|
inp += 4;
|
|
size -= 4;
|
|
} else {
|
|
printf("invalid header\n");
|
|
goto exit;
|
|
}
|
|
|
|
for (;;) {
|
|
if (size < 4) {
|
|
/* empty or end-of-file */
|
|
printf("empty or end-of-file\n");
|
|
goto exit1;
|
|
}
|
|
|
|
chunksize = le32_to_cpu(*(u32 *)inp);
|
|
if (chunksize == ARCHIVE_MAGICNUMBER) {
|
|
inp += 4;
|
|
size -= 4;
|
|
continue;
|
|
}
|
|
|
|
if (chunksize == 0) {
|
|
/* empty or end-of-file */
|
|
printf("empty or end-of-file\n");
|
|
goto exit1;
|
|
}
|
|
|
|
inp += 4;
|
|
size -= 4;
|
|
dest_len = uncomp_chunksize;
|
|
|
|
ret = LZ4_decompress_generic(inp, outp, chunksize,
|
|
dest_len, endOnInputSize,
|
|
decode_full_block, noDict, outp, NULL, 0);
|
|
dest_len = ret;
|
|
|
|
if (ret < 0) {
|
|
printf("Decoding failed\n");
|
|
goto exit;
|
|
}
|
|
|
|
ret = -1;
|
|
outp += dest_len;
|
|
*dstn += dest_len;
|
|
size -= chunksize;
|
|
|
|
if (size == 0) {
|
|
break;
|
|
} else if (size < 0) {
|
|
printf("data corrupted\n");
|
|
goto exit;
|
|
}
|
|
inp += chunksize;
|
|
}
|
|
|
|
exit1:
|
|
ret = 0;
|
|
|
|
exit:
|
|
return ret;
|
|
}
|