182 lines
6.2 KiB
C
182 lines
6.2 KiB
C
// Copyright (c) 2020-2021 HexHacking Team
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
|
|
// Created by caikelun on 2020-11-08.
|
|
|
|
#include "xdl_lzma.h"
|
|
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "xdl.h"
|
|
#include "xdl_util.h"
|
|
|
|
// LZMA library pathname & symbol names
|
|
#ifndef __LP64__
|
|
#define XDL_LZMA_PATHNAME "/system/lib/liblzma.so"
|
|
#else
|
|
#define XDL_LZMA_PATHNAME "/system/lib64/liblzma.so"
|
|
#endif
|
|
#define XDL_LZMA_SYM_CRCGEN "CrcGenerateTable"
|
|
#define XDL_LZMA_SYM_CRC64GEN "Crc64GenerateTable"
|
|
#define XDL_LZMA_SYM_CONSTRUCT "XzUnpacker_Construct"
|
|
#define XDL_LZMA_SYM_ISFINISHED "XzUnpacker_IsStreamWasFinished"
|
|
#define XDL_LZMA_SYM_FREE "XzUnpacker_Free"
|
|
#define XDL_LZMA_SYM_CODE "XzUnpacker_Code"
|
|
|
|
// LZMA data type definition
|
|
#define SZ_OK 0
|
|
typedef struct ISzAlloc ISzAlloc;
|
|
typedef const ISzAlloc *ISzAllocPtr;
|
|
struct ISzAlloc {
|
|
void *(*Alloc)(ISzAllocPtr p, size_t size);
|
|
void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
|
|
};
|
|
typedef enum {
|
|
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
|
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
|
CODER_STATUS_NOT_FINISHED, /* stream was not finished */
|
|
CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
|
|
} ECoderStatus;
|
|
typedef enum {
|
|
CODER_FINISH_ANY, /* finish at any point */
|
|
CODER_FINISH_END /* block must be finished at the end */
|
|
} ECoderFinishMode;
|
|
|
|
// LZMA function type definition
|
|
typedef void (*xdl_lzma_crcgen_t)(void);
|
|
typedef void (*xdl_lzma_crc64gen_t)(void);
|
|
typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr);
|
|
typedef int (*xdl_lzma_isfinished_t)(const void *);
|
|
typedef void (*xdl_lzma_free_t)(void *);
|
|
typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, ECoderFinishMode,
|
|
ECoderStatus *);
|
|
typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int,
|
|
ECoderFinishMode, ECoderStatus *);
|
|
|
|
// LZMA function pointor
|
|
static xdl_lzma_construct_t xdl_lzma_construct = NULL;
|
|
static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL;
|
|
static xdl_lzma_free_t xdl_lzma_free = NULL;
|
|
static void *xdl_lzma_code = NULL;
|
|
|
|
// LZMA init
|
|
static void xdl_lzma_init() {
|
|
void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD);
|
|
if (NULL == lzma) return;
|
|
|
|
xdl_lzma_crcgen_t crcgen = NULL;
|
|
xdl_lzma_crc64gen_t crc64gen = NULL;
|
|
if (NULL == (crcgen = (xdl_lzma_crcgen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRCGEN, NULL))) goto end;
|
|
if (NULL == (crc64gen = (xdl_lzma_crc64gen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRC64GEN, NULL))) goto end;
|
|
if (NULL == (xdl_lzma_construct = (xdl_lzma_construct_t)xdl_sym(lzma, XDL_LZMA_SYM_CONSTRUCT, NULL)))
|
|
goto end;
|
|
if (NULL == (xdl_lzma_isfinished = (xdl_lzma_isfinished_t)xdl_sym(lzma, XDL_LZMA_SYM_ISFINISHED, NULL)))
|
|
goto end;
|
|
if (NULL == (xdl_lzma_free = (xdl_lzma_free_t)xdl_sym(lzma, XDL_LZMA_SYM_FREE, NULL))) goto end;
|
|
if (NULL == (xdl_lzma_code = xdl_sym(lzma, XDL_LZMA_SYM_CODE, NULL))) goto end;
|
|
crcgen();
|
|
crc64gen();
|
|
|
|
end:
|
|
xdl_close(lzma);
|
|
}
|
|
|
|
// LZMA internal alloc / free
|
|
static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) {
|
|
(void)p;
|
|
return malloc(size);
|
|
}
|
|
static void xdl_lzma_internal_free(ISzAllocPtr p, void *address) {
|
|
(void)p;
|
|
free(address);
|
|
}
|
|
|
|
int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size) {
|
|
size_t src_offset = 0;
|
|
size_t dst_offset = 0;
|
|
size_t src_remaining;
|
|
size_t dst_remaining;
|
|
ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free};
|
|
long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned
|
|
ECoderStatus status;
|
|
int api_level = xdl_util_get_api_level();
|
|
|
|
// init and check
|
|
static bool inited = false;
|
|
if (!inited) {
|
|
xdl_lzma_init();
|
|
inited = true;
|
|
}
|
|
if (NULL == xdl_lzma_code) return -1;
|
|
|
|
xdl_lzma_construct(&state, &alloc);
|
|
|
|
*dst_size = 2 * src_size;
|
|
*dst = NULL;
|
|
do {
|
|
*dst_size *= 2;
|
|
if (NULL == (*dst = realloc(*dst, *dst_size))) {
|
|
xdl_lzma_free(&state);
|
|
return -1;
|
|
}
|
|
|
|
src_remaining = src_size - src_offset;
|
|
dst_remaining = *dst_size - dst_offset;
|
|
|
|
int result;
|
|
if (api_level >= __ANDROID_API_Q__) {
|
|
xdl_lzma_code_q_t lzma_code_q = (xdl_lzma_code_q_t)xdl_lzma_code;
|
|
result = lzma_code_q(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, 1,
|
|
CODER_FINISH_ANY, &status);
|
|
} else {
|
|
xdl_lzma_code_t lzma_code = (xdl_lzma_code_t)xdl_lzma_code;
|
|
result = lzma_code(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining,
|
|
CODER_FINISH_ANY, &status);
|
|
}
|
|
if (SZ_OK != result) {
|
|
free(*dst);
|
|
xdl_lzma_free(&state);
|
|
return -1;
|
|
}
|
|
|
|
src_offset += src_remaining;
|
|
dst_offset += dst_remaining;
|
|
} while (status == CODER_STATUS_NOT_FINISHED);
|
|
|
|
xdl_lzma_free(&state);
|
|
|
|
if (!xdl_lzma_isfinished(&state)) {
|
|
free(*dst);
|
|
return -1;
|
|
}
|
|
|
|
*dst_size = dst_offset;
|
|
*dst = realloc(*dst, *dst_size);
|
|
return 0;
|
|
}
|