mcu_hi3321_watch/middleware/utils/update/local_update/upg_lzmadec.c
2025-05-26 20:15:20 +08:00

286 lines
8.4 KiB
C

/*
* Copyright (c) @CompanyNameMagicTag 2021-2021. All rights reserved.
* Description: UPG lzma decode functions source file
*/
#include <stddef.h>
#include <stdint.h>
#include "securec.h"
#include "common_def.h"
#include "upg_alloc.h"
#include "upg_porting.h"
#include "upg_common.h"
#include "upg_debug.h"
#if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
#include "dfx_file_operation.h"
#endif
#include "upg_lzmadec.h"
STATIC void *upg_lzma_alloc(const ISzAllocPtr unused, size_t size)
{
unused(unused);
void *p;
p = upg_malloc((uint32_t)size);
if (p == NULL) {
upg_msg1("upg_lzma_alloc failed!!! size = ", size);
return NULL;
}
return p;
}
STATIC void upg_lzma_free(const ISzAllocPtr unused, void *address)
{
unused(unused);
if (address == NULL) {
return;
}
upg_free(address);
}
static inline void lzmadec_init(CLzmaDec *p)
{
return LzmaDec_Init(p);
}
static inline int32_t lzmadec_decodetodic(CLzmaDec *p, SizeT dic_limit, const Byte *src, SizeT *srclen,
ELzmaFinishMode finish_mode, ELzmaStatus *status)
{
return LzmaDec_DecodeToDic(p, dic_limit, src, srclen, finish_mode, status);
}
static inline void lzmadec_freeprobs(CLzmaDec *p, ISzAllocPtr alloc)
{
return LzmaDec_FreeProbs(p, alloc);
}
static inline int32_t lzmadec_allocateprobs(CLzmaDec *p, const Byte *props, unsigned props_size, ISzAllocPtr alloc)
{
return LzmaDec_AllocateProbs(p, props, props_size, alloc);
}
STATIC SRes lzmadec_decodetobuf(CLzmaDec *p, Byte *dest, SizeT *dest_len, const Byte *src, SizeT *src_len,
ELzmaFinishMode finish_mode, ELzmaStatus *status)
{
return LzmaDec_DecodeToBuf(p, dest, dest_len, src, src_len, finish_mode, status);
}
uint32_t upg_lzma_init(CLzmaDec *p, upg_lzma_decode2_data_t *val_data, const Byte *props, uint32_t props_len)
{
LzmaDec_Construct(p);
ISzAlloc alloc;
alloc.Alloc = upg_lzma_alloc;
alloc.Free = upg_lzma_free;
if (props_len < LZMA_PROPS_SIZE) {
return ERRCODE_UPG_INVALID_PARAMETER;
}
int32_t res = lzmadec_allocateprobs(p, props, LZMA_PROPS_SIZE, &alloc);
if (res != 0) {
return (uint32_t)res;
}
uint32_t unpack_size = 0;
for (uint32_t i = 0; i < props_len - LZMA_PROPS_SIZE; i++) {
unpack_size += (uint32_t)props[LZMA_PROPS_SIZE + i] << (i * 8); /* 8: 用于计算偏移位数 */
}
uint32_t dic_size = unpack_size;
if ((p->prop).dicSize <= unpack_size) {
dic_size = (p->prop).dicSize;
}
if (dic_size == 0) {
return ERRCODE_UPG_INVALID_PARAMETER;
}
p->dic = upg_lzma_alloc(&alloc, dic_size);
if (p->dic == NULL) {
return ERRCODE_MALLOC;
}
p->dicBufSize = dic_size;
val_data->inbuf = upg_lzma_alloc(&alloc, IN_BUF_SIZE);
if (val_data->inbuf == NULL) {
upg_lzma_free(&alloc, p->dic);
p->dic = NULL;
return ERRCODE_MALLOC;
}
val_data->outbuf = upg_lzma_alloc(&alloc, OUT_BUF_SIZE);
if (val_data->outbuf == NULL) {
upg_lzma_free(&alloc, p->dic);
p->dic = NULL;
upg_lzma_free(&alloc, val_data->inbuf);
val_data->inbuf = NULL;
return ERRCODE_MALLOC;
}
val_data->decompress_len = unpack_size;
lzmadec_init(p);
return ERRCODE_SUCC;
}
void upg_lzma_deinit(CLzmaDec *p, upg_lzma_decode2_data_t *val_data)
{
ISzAlloc alloc;
alloc.Alloc = upg_lzma_alloc;
alloc.Free = upg_lzma_free;
upg_lzma_free(&alloc, p->dic);
p->dic = NULL;
lzmadec_freeprobs(p, &alloc);
upg_lzma_free(&alloc, val_data->inbuf);
val_data->inbuf = NULL;
upg_lzma_free(&alloc, val_data->outbuf);
val_data->outbuf = NULL;
}
STATIC bool upg_lzma_dec_check_ret(SRes res, uint32_t unpack_size, bool in_out_zero, ELzmaStatus status, SRes *ret)
{
if ((res != SZ_OK) || (unpack_size == 0)) {
*ret = res;
return true;
}
if (in_out_zero) {
if (status != LZMA_STATUS_FINISHED_WITH_MARK) {
*ret = SZ_ERROR_DATA;
return true;
}
*ret = res;
return true;
}
return false;
}
uint32_t upg_lzma_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data)
{
size_t in_pos = 0;
size_t in_size = 0;
uint32_t compress_len = data->compress_len; /* 压缩包的总长度,即需要解压缩的总长度 */
uint32_t unpack_size = data->decompress_len;
uint32_t in_offset = data->in_offset; /* 已解压数据的压缩包的偏移位置 */
uint32_t out_offset = data->out_offset; /* 已解压数据解压后的总长度, 用作写入的偏移位置 */
ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED;
for (;;) {
if (in_pos == in_size) {
in_size = (compress_len > IN_BUF_SIZE) ? IN_BUF_SIZE : compress_len;
if (upg_read_fota_pkg_data(in_offset, data->inbuf, (uint32_t *)(uintptr_t)&in_size) != ERRCODE_SUCC) {
return SZ_ERROR_DATA;
}
compress_len -= in_size;
in_pos = 0;
}
SizeT in_processed = in_size - in_pos;
SizeT out_processed = OUT_BUF_SIZE;
ELzmaFinishMode finish_mode = LZMA_FINISH_ANY;
if (out_processed > unpack_size) {
out_processed = (SizeT)unpack_size;
finish_mode = LZMA_FINISH_END;
}
SRes res = lzmadec_decodetobuf(p, data->outbuf, &out_processed, data->inbuf + in_pos,
&in_processed, finish_mode, &status);
in_pos += in_processed;
unpack_size -= out_processed;
errcode_t ret = upg_write_new_image_data(out_offset, data->outbuf, (uint32_t *)(uintptr_t)&out_processed,
data->image_id);
if (ret != ERRCODE_SUCC) {
return SZ_ERROR_DATA;
}
upg_calculate_and_notify_process((uint32_t)out_processed);
in_offset += in_processed;
out_offset += out_processed;
// 踢狗
upg_watchdog_kick();
SRes res_ret;
if (upg_lzma_dec_check_ret(res, unpack_size, (in_processed == 0 && out_processed == 0), status, &res_ret)) {
return (uint32_t)res_ret;
}
}
}
#if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
errcode_t upg_resource_file_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data, upg_resource_node_t *file_info)
{
errcode_t ret = ERRCODE_SUCC;
size_t in_size = 0; /* 待读出压缩数据的大小 */
size_t out_len = 0; /* 解压缩后数据的大小 */
uint32_t file_len = file_info->file_len; /* 文件的大小,即本次需要解压缩出来的原始数据长度 */
uint32_t in_offset = data->in_offset; /* 已解压数据的压缩包的偏移位置 */
uint32_t file_offset = 0; /* 本次解压出的数据长度, 用作写入的偏移位置 */
ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED;
if (file_info->offset != data->out_offset) {
return ERRCODE_UPG_INVALID_OFFSET;
}
int32_t write_fd = dfx_file_open_for_write(file_info->file_path);
if (write_fd < 0) {
return ERRCODE_UPG_FILE_OPEN_FAIL;
}
while (file_len > 0) {
in_size = (data->compress_len > IN_BUF_SIZE) ? IN_BUF_SIZE : data->compress_len;
ret = upg_read_fota_pkg_data(in_offset, data->inbuf, (uint32_t *)(uintptr_t)&in_size);
if (ret != ERRCODE_SUCC) {
break;
}
out_len = (file_len > OUT_BUF_SIZE) ? OUT_BUF_SIZE : file_len;
if (lzmadec_decodetobuf(p, data->outbuf, &out_len, data->inbuf, &in_size, LZMA_FINISH_ANY, &status) != SZ_OK) {
ret = ERRCODE_UPG_DECOMPRESS_FAIL;
break;
}
if (dfx_file_write_fd(write_fd, file_offset, data->outbuf, out_len) != (int32_t)out_len) {
ret = ERRCODE_UPG_FILE_WRITE_FAIL;
break;
}
in_offset += in_size;
data->compress_len -= in_size;
file_offset += out_len;
file_len -= out_len;
upg_calculate_and_notify_process((uint32_t)out_len);
if (data->compress_len == 0 || (in_size == 0 && out_len == 0)) {
break;
}
}
data->in_offset = in_offset;
data->out_offset += file_offset;
if (in_size == 0 && out_len == 0 && status != LZMA_STATUS_FINISHED_WITH_MARK && file_info->file_len != 0) {
ret = ERRCODE_UPG_DECOMPRESS_FAIL;
}
dfx_file_fsync(write_fd);
dfx_file_close(write_fd);
return ret;
}
#else
errcode_t upg_resource_file_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data, upg_resource_node_t *file_info)
{
unused(p);
unused(data);
unused(file_info);
return ERRCODE_SUCC;
}
#endif