blob: fd2e15b45477268c642bdb9bb4ae3cd54d769e88 [file] [log] [blame]
/*
* Copyright (C) 2018 Synaptics Incorporated. All rights reserved.
* Copyright 2014, MARVELL SEMICONDUCTOR, LTD.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND
* SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY
* INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE
* OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND
* BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF
* COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT
* DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY
* TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS.
*/
///////////////////////////////////////////////////////////////////////////////
//! \file lz4dec.c
//! \brief decode a lz4 compressed input stream.
///////////////////////////////////////////////////////////////////////////////
/****************************
* Includes
*****************************/
#include <stdint.h>
#include "lgpl_printf.h"
#include "lz4frame.h"
#define LZ4IO_MAGICNUMBER (0x184D2204)
/** @brief decode a compressed lz4input stream, only
* started with LZ4IO_MAGICNUMBER supported.
*
*
* @param in_buf the input stream buffer, contains the full
* input data, started with LZ4IO_MAGICNUMBER.
* @param input_size the whole input tream size, including the magic,
* in bytes.
* @param out_buf the decode result.
* @param output_size the decode output buffer size when used as input,
* and final decoded stream length in bytes as output.
* @return 0 if success, negative if failed.
*/
int lz4_decompress(const unsigned char *in_buf, const unsigned int input_size, unsigned char *out_buf, unsigned int *output_size)
{
int ret = 0;
if (in_buf == NULL || out_buf == NULL || output_size == NULL || *output_size < input_size) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
return -1;
}
uint32_t lz4_dec_magic = *(uint32_t *)in_buf;
if (lz4_dec_magic != LZ4IO_MAGICNUMBER) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
return -1;
}
LZ4F_decompressionContext_t ctx;
LZ4F_errorCode_t err;
/* init */
err = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
if (LZ4F_isError(err)) {
lgpl_printf("%s, %d, Can't create context : %s", __func__, __LINE__, LZ4F_getErrorName(err));
return -1;
}
unsigned int pos = 0;
unsigned int decoded = 0;
size_t dec_out_size = *output_size;
size_t remaining = input_size - pos;
while (remaining > 0) {
dec_out_size = *output_size - decoded;
err = LZ4F_decompress(ctx, out_buf + decoded, &dec_out_size, (char*)in_buf + pos, &remaining, NULL);
if (LZ4F_isError(err)) {
lgpl_printf("%s, %d, Decompression error : %s", __func__, __LINE__, LZ4F_getErrorName(err));
return -1;
}
pos += remaining;
remaining = input_size - pos;
decoded += dec_out_size;
if (pos > input_size) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
return -1;
}
if (decoded > *output_size) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
return -1;
}
}
*output_size = decoded;
err = LZ4F_freeDecompressionContext(ctx);
if (LZ4F_isError(err)) {
lgpl_printf("%s, %d, Error : can't free LZ4F context resource : %s", __func__, __LINE__, LZ4F_getErrorName(err));
return -1;
}
return ret;
}
#ifdef _PC_TEST
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
FILE *in_file, *out_file;
in_file = fopen(argv[1], "rb");
if (in_file == NULL) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
exit(0);
}
out_file = fopen(argv[2], "wb");
if (out_file == NULL) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
exit(0);
}
fseek(in_file, 0L, SEEK_END);
long input_size = ftell(in_file);
fseek(in_file, 0L, SEEK_SET);
unsigned char *in_buf = (unsigned char *)malloc(input_size);
if (in_buf == NULL){
lgpl_printf("%s, %d.\n", __func__, __LINE__);
exit(0);
}
fread(in_buf, 1, input_size, in_file);
fclose(in_file);
unsigned char *out_buf = (unsigned char *)malloc(input_size*3);
if (out_buf == NULL){
lgpl_printf("%s, %d.\n", __func__, __LINE__);
exit(0);
}
//used as output buffer size when input, and actuall decoded size as output
unsigned int output_size = input_size*3;
int ret = lz4_decompress(in_buf, input_size, out_buf, &output_size);
if (ret != 0) {
lgpl_printf("%s, %d.\n", __func__, __LINE__);
exit(0);
}
fwrite(out_buf, 1, output_size, out_file);
free(in_buf);
free(out_buf);
fclose(out_file);
return 0;
}
#endif //_PC_TEST