2014-12-29 20:34:41 +00:00
|
|
|
/*
|
2015-09-05 17:22:52 +00:00
|
|
|
* Bled (Base Library for Easy Decompression)
|
2014-12-29 20:34:41 +00:00
|
|
|
*
|
2015-01-01 23:39:28 +00:00
|
|
|
* Copyright © 2014-2015 Pete Batard <pete@akeo.ie>
|
2014-12-29 20:34:41 +00:00
|
|
|
*
|
|
|
|
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "libbb.h"
|
|
|
|
#include "bb_archive.h"
|
|
|
|
#include "bled.h"
|
|
|
|
|
|
|
|
typedef long long int(*unpacker_t)(transformer_state_t *xstate);
|
|
|
|
|
|
|
|
/* Globals */
|
|
|
|
smallint bb_got_signal;
|
|
|
|
uint64_t bb_total_rb;
|
|
|
|
printf_t bled_printf = NULL;
|
2019-12-26 23:19:48 +00:00
|
|
|
read_t bled_read = NULL;
|
|
|
|
write_t bled_write = NULL;
|
2014-12-29 20:34:41 +00:00
|
|
|
progress_t bled_progress = NULL;
|
2015-01-01 23:39:28 +00:00
|
|
|
unsigned long* bled_cancel_request;
|
2014-12-29 20:34:41 +00:00
|
|
|
static bool bled_initialized = 0;
|
2014-12-30 19:46:13 +00:00
|
|
|
jmp_buf bb_error_jmp;
|
2019-03-23 13:59:20 +00:00
|
|
|
char* bb_virtual_buf = NULL;
|
|
|
|
size_t bb_virtual_len = 0, bb_virtual_pos = 0;
|
|
|
|
int bb_virtual_fd = -1;
|
2014-12-29 20:34:41 +00:00
|
|
|
|
|
|
|
static long long int unpack_none(transformer_state_t *xstate)
|
|
|
|
{
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("This compression type is not supported");
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unpacker_t unpacker[BLED_COMPRESSION_MAX] = {
|
|
|
|
unpack_none,
|
2015-06-20 17:40:55 +00:00
|
|
|
unpack_zip_stream,
|
2014-12-29 20:34:41 +00:00
|
|
|
unpack_Z_stream,
|
|
|
|
unpack_gz_stream,
|
|
|
|
unpack_lzma_stream,
|
|
|
|
unpack_bz2_stream,
|
2015-02-11 23:22:18 +00:00
|
|
|
unpack_xz_stream,
|
|
|
|
unpack_none
|
2014-12-29 20:34:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Uncompress file 'src', compressed using 'type', to file 'dst' */
|
|
|
|
int64_t bled_uncompress(const char* src, const char* dst, int type)
|
|
|
|
{
|
|
|
|
transformer_state_t xstate;
|
|
|
|
int64_t ret;
|
|
|
|
|
2019-03-23 13:59:20 +00:00
|
|
|
if (!bled_initialized) {
|
|
|
|
bb_error_msg("The library has not been initialized");
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
2019-03-23 13:59:20 +00:00
|
|
|
}
|
2014-12-29 20:34:41 +00:00
|
|
|
|
|
|
|
bb_total_rb = 0;
|
|
|
|
init_transformer_state(&xstate);
|
|
|
|
xstate.src_fd = -1;
|
|
|
|
xstate.dst_fd = -1;
|
|
|
|
xstate.check_signature = 1;
|
|
|
|
|
|
|
|
xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0);
|
|
|
|
if (xstate.src_fd < 0) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Could not open '%s' (errno: %d)", src, errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
xstate.dst_fd = _openU(dst, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, _S_IREAD | _S_IWRITE);
|
|
|
|
if (xstate.dst_fd < 0) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Could not open '%s' (errno: %d)", dst, errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Unsupported compression format");
|
2014-12-29 20:34:41 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-12-30 19:46:13 +00:00
|
|
|
if (setjmp(bb_error_jmp))
|
|
|
|
goto err;
|
2014-12-29 20:34:41 +00:00
|
|
|
ret = unpacker[type](&xstate);
|
|
|
|
_close(xstate.src_fd);
|
|
|
|
_close(xstate.dst_fd);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (xstate.src_fd > 0)
|
|
|
|
_close(xstate.src_fd);
|
|
|
|
if (xstate.dst_fd > 0)
|
|
|
|
_close(xstate.dst_fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Uncompress using Windows handles */
|
|
|
|
int64_t bled_uncompress_with_handles(HANDLE hSrc, HANDLE hDst, int type)
|
|
|
|
{
|
|
|
|
transformer_state_t xstate;
|
|
|
|
|
2019-03-23 13:59:20 +00:00
|
|
|
if (!bled_initialized) {
|
|
|
|
bb_error_msg("The library has not been initialized");
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
2019-03-23 13:59:20 +00:00
|
|
|
}
|
2014-12-29 20:34:41 +00:00
|
|
|
|
|
|
|
bb_total_rb = 0;
|
|
|
|
init_transformer_state(&xstate);
|
|
|
|
xstate.src_fd = -1;
|
|
|
|
xstate.dst_fd = -1;
|
|
|
|
xstate.check_signature = 1;
|
|
|
|
|
|
|
|
xstate.src_fd = _open_osfhandle((intptr_t)hSrc, _O_RDONLY);
|
|
|
|
if (xstate.src_fd < 0) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Could not get source descriptor (errno: %d)", errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
xstate.dst_fd = _open_osfhandle((intptr_t)hDst, 0);
|
|
|
|
if (xstate.dst_fd < 0) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Could not get target descriptor (errno: %d)", errno);
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Unsupported compression format");
|
2014-12-29 20:34:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-12-30 19:46:13 +00:00
|
|
|
if (setjmp(bb_error_jmp))
|
|
|
|
return -1;
|
2014-12-29 20:34:41 +00:00
|
|
|
return unpacker[type](&xstate);
|
|
|
|
}
|
|
|
|
|
2015-02-11 23:22:18 +00:00
|
|
|
/* Uncompress file 'src', compressed using 'type', to buffer 'buf' of size 'size' */
|
|
|
|
int64_t bled_uncompress_to_buffer(const char* src, char* buf, size_t size, int type)
|
|
|
|
{
|
|
|
|
transformer_state_t xstate;
|
|
|
|
int64_t ret;
|
|
|
|
|
2019-03-23 13:59:20 +00:00
|
|
|
if (!bled_initialized) {
|
|
|
|
bb_error_msg("The library has not been initialized");
|
2015-02-11 23:22:18 +00:00
|
|
|
return -1;
|
2019-03-23 13:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((src == NULL) || (buf == NULL)) {
|
|
|
|
bb_error_msg("Invalid parameter");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-11 23:22:18 +00:00
|
|
|
|
|
|
|
bb_total_rb = 0;
|
|
|
|
init_transformer_state(&xstate);
|
|
|
|
xstate.src_fd = -1;
|
|
|
|
xstate.dst_fd = -1;
|
|
|
|
xstate.check_signature = 1;
|
|
|
|
|
2019-03-23 13:59:20 +00:00
|
|
|
if (src[0] == 0) {
|
|
|
|
xstate.src_fd = bb_virtual_fd;
|
|
|
|
} else {
|
|
|
|
xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0);
|
|
|
|
}
|
2015-02-11 23:22:18 +00:00
|
|
|
if (xstate.src_fd < 0) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Could not open '%s' (errno: %d)", src, errno);
|
2015-02-11 23:22:18 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
xstate.mem_output_buf = buf;
|
|
|
|
xstate.mem_output_size = 0;
|
|
|
|
xstate.mem_output_size_max = size;
|
|
|
|
|
|
|
|
if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) {
|
2017-01-11 01:12:00 +00:00
|
|
|
bb_error_msg("Unsupported compression format");
|
2015-02-11 23:22:18 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setjmp(bb_error_jmp))
|
|
|
|
goto err;
|
|
|
|
ret = unpacker[type](&xstate);
|
2019-03-23 13:59:20 +00:00
|
|
|
if (src[0] != 0)
|
|
|
|
_close(xstate.src_fd);
|
2015-02-11 23:22:18 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (xstate.src_fd > 0)
|
|
|
|
_close(xstate.src_fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-23 13:59:20 +00:00
|
|
|
int64_t bled_uncompress_from_buffer_to_buffer(const char* src, const size_t src_len, char* dst, size_t dst_len, int type)
|
|
|
|
{
|
|
|
|
int64_t ret;
|
|
|
|
|
|
|
|
if (!bled_initialized) {
|
|
|
|
bb_error_msg("The library has not been initialized");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((src == NULL) || (dst == NULL)) {
|
|
|
|
bb_error_msg("Invalid parameter");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bb_virtual_buf != NULL) {
|
|
|
|
bb_error_msg("Can not decompress more than one buffer at once");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bb_virtual_buf = (char*)src;
|
|
|
|
bb_virtual_len = src_len;
|
|
|
|
bb_virtual_pos = 0;
|
|
|
|
bb_virtual_fd = 0;
|
|
|
|
|
|
|
|
ret = bled_uncompress_to_buffer("", dst, dst_len, type);
|
|
|
|
|
|
|
|
bb_virtual_buf = NULL;
|
|
|
|
bb_virtual_len = 0;
|
|
|
|
bb_virtual_fd = -1;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
/* Initialize the library.
|
|
|
|
* When the parameters are not NULL you can:
|
|
|
|
* - specify the printf-like function you want to use to output message
|
|
|
|
* void print_function(const char* format, ...);
|
|
|
|
* - specify the function you want to use to display progress, based on number of source archive bytes read
|
|
|
|
* void progress_function(const uint64_t read_bytes);
|
|
|
|
* - point to an unsigned long variable, to be used to cancel operations when set to non zero
|
|
|
|
*/
|
2019-12-26 23:19:48 +00:00
|
|
|
int bled_init(printf_t print_function, read_t read_function, write_t write_function,
|
|
|
|
progress_t progress_function, unsigned long* cancel_request)
|
2014-12-29 20:34:41 +00:00
|
|
|
{
|
|
|
|
if (bled_initialized)
|
|
|
|
return -1;
|
|
|
|
bled_initialized = true;
|
|
|
|
bled_printf = print_function;
|
2019-12-26 23:19:48 +00:00
|
|
|
bled_read = read_function;
|
|
|
|
bled_write = write_function;
|
2014-12-29 20:34:41 +00:00
|
|
|
bled_progress = progress_function;
|
2015-01-01 23:39:28 +00:00
|
|
|
bled_cancel_request = cancel_request;
|
2014-12-29 20:34:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
/* This call frees any resource used by the library */
|
2014-12-29 20:34:41 +00:00
|
|
|
void bled_exit(void)
|
|
|
|
{
|
|
|
|
bled_printf = NULL;
|
|
|
|
bled_progress = NULL;
|
2015-01-01 23:39:28 +00:00
|
|
|
bled_cancel_request = NULL;
|
2015-02-11 23:22:18 +00:00
|
|
|
if (global_crc32_table) {
|
2014-12-29 20:34:41 +00:00
|
|
|
free(global_crc32_table);
|
2015-02-11 23:22:18 +00:00
|
|
|
global_crc32_table = NULL;
|
|
|
|
}
|
2014-12-29 20:34:41 +00:00
|
|
|
bled_initialized = false;
|
|
|
|
}
|