/**
    NVT utilities for all-in-one image pack

    @file       nvt_ivot_pack.c
    @ingroup
    @note
    Copyright   Novatek Microelectronics Corp. 2019.  All rights reserved.

    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.
*/

#define NVTPACK_UBOOT // NVTPACK_WIN32, NVTPACK_UITRON, NVTPACK_UBOOT, NVTPACK_LINUX_KERNEL, NVTPACK_LINUX_APP

#if defined(NVTPACK_WIN32)
#elif defined(NVTPACK_UITRON)
#include "Type.h"
#elif defined(NVTPACK_UBOOT)
#include <common.h>
#elif defined(NVTPACK_LINUX_KERNEL)
#include <linux/string.h> //for linux include
#include <linux/printk.h> //for linux include
#elif defined(NVTPACK_LINUX_APP)
#include <stdio.h>
#include <string.h>
#endif

#include <asm/nvt-common/nvt_types.h>
#include <asm/nvt-common/modelext/emb_partition_info.h>
#include "nvt_ivot_pack.h"

#ifdef __cplusplus
#define _NVTPACK_EXTERN_C extern "C"
#else
#define _NVTPACK_EXTERN_C
#endif

#ifndef UINT32_SWAP
#define UINT32_SWAP(data)           (((((unsigned int)(data)) & 0x000000FF) << 24) | \
									 ((((unsigned int)(data)) & 0x0000FF00) << 8) | \
									 ((((unsigned int)(data)) & 0x00FF0000) >> 8) | \
									 ((((unsigned int)(data)) & 0xFF000000) >> 24))   ///< Swap [31:24] with [7:0] and [23:16] with [15:8].
#endif
#if defined(NVTPACK_UITRON)
#define __MODULE__          nvtpack
#define __DBGLVL__          1 // 0=OFF, 1=ERROR, 2=TRACE
#define __DBGFLT__          "*" //*=All, [mark]=CustomClass
#include "DebugModule.h"
#endif

// {B5CB64AE-05DD-46FA-B906-0C62D22958D6}
static const GUID GUID_RES =
{ 0xb5cb64ae, 0x05dd, 0x46fa, { 0xb9, 0x06, 0x0c, 0x62, 0xd2, 0x29, 0x58, 0xd6 } };

// {8827BE90-36CD-4FC2-A987-73A8484E84B1}
static const GUID GUID_FW =
{ 0x8827be90, 0x36cd, 0x4fc2, { 0xa9, 0x87, 0x73, 0xa8, 0x48, 0x4e, 0x84, 0xb1 } };

// {D6012E07-10BC-4F91-B28A-352F82261A50}
static const GUID GUID_FW2 =
{ 0xd6012e07, 0x10bc, 0x4f91, { 0xb2, 0x8a, 0x35, 0x2f, 0x82, 0x26, 0x1a, 0x50 } };

static NVTPACK_ER nvtpack_er(NVTPACK_ER er)
{
	if(er == NVTPACK_ER_SUCCESS) {
		return er;
	}

	#if defined(NVTPACK_WIN32) || defined(NVTPACK_UBOOT) || defined(NVTPACK_LINUX_APP)
	printf("nvtpack:%d\r\n", er);
	#elif defined(NVTPACK_LINUX_KERNEL)
	pr_info("nvtpack:%d\r\n", er);
	#elif defined(NVTPACK_UITRON)
	DBG_ERR("%d\r\n", er);
	#endif

	return er;
}

static NVTPACK_ER nvtpack_get_uitron_offset(NVTPACK_MEM *p_mem, NVTPACK_MEM *p_uitron)
{
	unsigned char *p_curr = (unsigned char *)p_mem->p_data;
	unsigned char *p_end = (unsigned char *)p_mem->p_data + p_mem->len;
	NVTPACK_BFC_HDR *pBFC = (NVTPACK_BFC_HDR *)p_curr;
	NVTPACK_BININFO_HDR *pBinInfo = (NVTPACK_BININFO_HDR *)p_curr;

	memset(p_uitron, 0, sizeof(*p_uitron));

	if(pBFC->uiFourCC == MAKEFOURCC('B', 'C', 'L', '1')) {
		unsigned int bfc_size = UINT32_SWAP(pBFC->uiSizeComp);
		p_uitron->p_data = pBFC;
		p_uitron->len = bfc_size + sizeof(NVTPACK_BFC_HDR);
		if(p_curr + p_uitron->len > p_end) {
			return nvtpack_er(NVTPACK_ER_PARAM);
		}
		return nvtpack_er(NVTPACK_ER_SUCCESS);
	} else if(strncmp(pBinInfo->BinInfo_1, "NT9", 3) == 0) {
		unsigned int bin_size = pBinInfo->BinLength;
		p_uitron->p_data = pBinInfo;
		p_uitron->len = bin_size;
		if(p_curr + p_uitron->len > p_end) {
			return nvtpack_er(NVTPACK_ER_PARAM);
		}
		return nvtpack_er(NVTPACK_ER_SUCCESS);
	}
	return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
}

_NVTPACK_EXTERN_C unsigned int nvtpack_calc_nvt_sum(NVTPACK_MEM *p_mem)
{
	unsigned int i, sum = 0;
	unsigned short *puiValue = (unsigned short *)p_mem->p_data;

	for(i = 0; i < (p_mem->len >> 1); i++) {
		sum += (*(puiValue + i) + i);
	}

	sum &= 0x0000FFFF;

	return sum;
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_verify(NVTPACK_MEM *p_mem, NVTPACK_VERIFY_OUTPUT *p_output)
{
	NVTPACK_MEM chk_mem = {0};

	memset(p_output, 0, sizeof(*p_output));

	if(IsEqualGUID(&GUID_FW2, (GUID *)p_mem->p_data)) {
		if(nvtpack_calc_nvt_sum(p_mem) != 0) {
			return nvtpack_er(NVTPACK_ER_CHECK_SUM);
		}
		p_output->ver = NVTPACK_VER_16072017;
		p_output->partition_cnt = ((NVTPACK_FW_HDR2 *)p_mem->p_data)->TotalRes;
		return nvtpack_er(NVTPACK_ER_SUCCESS);
	} else {
		//remove uITRON header
		unsigned char *p_curr = (unsigned char *)p_mem->p_data;
		unsigned char *p_end = (unsigned char *)p_mem->p_data + p_mem->len;
		if(!IsEqualGUID(&GUID_FW, (GUID *)p_mem->p_data)) {
			if(nvtpack_get_uitron_offset(p_mem, &chk_mem) != NVTPACK_ER_SUCCESS) {
				return nvtpack_er(NVTPACK_ER_PARAM);
			}

			if(nvtpack_calc_nvt_sum(&chk_mem) != 0) {
				return nvtpack_er(NVTPACK_ER_CHECK_SUM);
			}
			p_curr += chk_mem.len;
			if(p_curr >= p_end) {
				p_output->ver = NVTPACK_VER_13012816;
				p_output->partition_cnt = 1;
				return nvtpack_er(NVTPACK_ER_SUCCESS);
			} else {
				p_output->partition_cnt++;
			}
		}

		if(IsEqualGUID(&GUID_FW, (GUID *)p_curr)) {
			NVTPACK_FW_HDR *pFw = (NVTPACK_FW_HDR *)(p_curr);
			chk_mem.p_data = p_curr;
			chk_mem.len = sizeof(NVTPACK_FW_HDR) + pFw->TotalRes * sizeof(NVTPACK_PARTITION_HDR);
			if(nvtpack_calc_nvt_sum(&chk_mem) != 0) {
				return NVTPACK_ER_CHECK_SUM;
			}
			p_output->ver = NVTPACK_VER_13012816;
			p_output->partition_cnt += ((NVTPACK_FW_HDR *)p_curr)->TotalRes;
			return nvtpack_er(NVTPACK_ER_SUCCESS);
		}
	}
	return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_get_partition(NVTPACK_GET_PARTITION_INPUT *p_input, NVTPACK_MEM *p_out)
{
	int i;
	int TotalRes = 0;
	NVTPACK_PARTITION_HDR *pPartition = NULL;
	unsigned char *p_curr = NULL;
	unsigned int id = p_input->id;
	NVTPACK_MEM *p_in = &p_input->mem;

	memset(p_out, 0, sizeof(*p_out));

	if(IsEqualGUID(&GUID_FW2, (GUID *)p_in->p_data)) {
		NVTPACK_FW_HDR2 *pFw = (NVTPACK_FW_HDR2 *)p_in->p_data;
		TotalRes = pFw->TotalRes;
		pPartition = (NVTPACK_PARTITION_HDR *)((unsigned long)p_in->p_data + sizeof(NVTPACK_FW_HDR2));
	} else {
		NVTPACK_MEM mem_uitron = {0};
		if(!IsEqualGUID(&GUID_FW, (GUID *)p_in->p_data)) {
			if(nvtpack_get_uitron_offset(p_in, &mem_uitron) != NVTPACK_ER_SUCCESS) {
				return nvtpack_er(NVTPACK_ER_PARAM);
			}
			if(id == 0) {
				p_out->p_data = mem_uitron.p_data;
				p_out->len = mem_uitron.len;
				return nvtpack_er(NVTPACK_ER_SUCCESS);
			}
		}

		p_curr = (unsigned char *)p_in->p_data + mem_uitron.len;

		if(IsEqualGUID(&GUID_FW, (GUID *)p_curr)) {
			NVTPACK_FW_HDR *pFw = (NVTPACK_FW_HDR *)p_curr;
			TotalRes = pFw->TotalRes;
			pPartition = (NVTPACK_PARTITION_HDR *)((unsigned long)p_curr + sizeof(NVTPACK_FW_HDR));
		} else {
			return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
		}
	}

	for(i = 0; i < TotalRes; i++) {
		NVTPACK_PARTITION_HDR *p = &pPartition[i];
		if(p->PartitionID == id) {
			p_out->p_data = (unsigned char *)p_in->p_data + p->Offset;
			p_out->len = p->Size;
			return nvtpack_er(NVTPACK_ER_SUCCESS);
		}
	}
	return nvtpack_er(NVTPACK_ER_NOT_FOUND);
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_check_partition(EMB_PARTITION pemb, NVTPACK_GET_PARTITION_INPUT *p_input, NVTPACK_MEM *p_out)
{
	int ret = 0;

	ret = nvtpack_get_partition(p_input, p_out);
	if (ret == NVTPACK_ER_NOT_FOUND) {

	    switch(pemb.EmbType)
	    {
		case EMBTYPE_MBR:
		case EMBTYPE_FDT:
		case EMBTYPE_UITRON:
		case EMBTYPE_ECOS:
		case EMBTYPE_UBOOT:
		case EMBTYPE_LINUX:
		case EMBTYPE_ROOTFS:
		case EMBTYPE_RTOS:
		case EMBTYPE_TEEOS:
		case EMBTYPE_AI:
		case EMBTYPE_ATF:
			break;
		default:
			if(!pemb.FileExist)
				ret = NVTPACK_ER_SUCCESS;

			break;
	    }
	}

	return ret;
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_enum_partition(NVTPACK_ENUM_PARTITION_INPUT *p_input)
{
	int i;
	int TotalRes = 0;
	NVTPACK_MEM mem_out;
	NVTPACK_PARTITION_HDR *pPartition = NULL;
	unsigned char *p_curr = NULL;
	NVTPACK_MEM *p_in = &p_input->mem;

	if(IsEqualGUID(&GUID_FW2, (GUID *)p_in->p_data)) {
		NVTPACK_FW_HDR2 *pFw = (NVTPACK_FW_HDR2 *)p_in->p_data;
		TotalRes = pFw->TotalRes;
		pPartition = (NVTPACK_PARTITION_HDR *)((unsigned long)p_in->p_data + sizeof(NVTPACK_FW_HDR2));
	} else {
		NVTPACK_MEM mem_uitron = {0};
		if(!IsEqualGUID(&GUID_FW, (GUID *)p_in->p_data)) {
			if(nvtpack_get_uitron_offset(p_in, &mem_uitron) != NVTPACK_ER_SUCCESS) {
				return nvtpack_er(NVTPACK_ER_PARAM);
			}
			if(p_input->fp_enum) {
				if(p_input->fp_enum(0, &mem_uitron, p_input->p_user_data) != 0) {
					return nvtpack_er(NVTPACK_ER_USER_BREAK);
				}
			}
		}

		p_curr = (unsigned char *)p_in->p_data + mem_uitron.len;

		if(IsEqualGUID(&GUID_FW, (GUID *)p_curr)) {
			NVTPACK_FW_HDR *pFw = (NVTPACK_FW_HDR *)p_curr;
			TotalRes = pFw->TotalRes;
			pPartition = (NVTPACK_PARTITION_HDR *)((unsigned long)p_curr + sizeof(NVTPACK_FW_HDR));
		} else {
			return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
		}
	}

	for(i = 0; i < TotalRes; i++) {
		NVTPACK_PARTITION_HDR *p = &pPartition[i];
		mem_out.p_data = (unsigned char *)p_in->p_data + p->Offset;
		mem_out.len = p->Size;
		if(p_input->fp_enum) {
			if(p_input->fp_enum(p->PartitionID, &mem_out, p_input->p_user_data) != 0) {
				return nvtpack_er(NVTPACK_ER_USER_BREAK);
			}
		}
	}

	return nvtpack_er(NVTPACK_ER_SUCCESS);
}

static NVTPACK_ER nvtpack_make_parition_pkg_fw1(NVTPACK_MAKE_PARTITION_INPUT *p_input, NVTPACK_MEM *p_out)
{
	NVTPACK_PARTITION_ITEM *p_list = p_input->p_list;
	int num = p_input->num;
	NVTPACK_MEM *p_work = &p_input->mem_work;
	unsigned char *p_head = (unsigned char *)p_work->p_data;
	unsigned char *p_curr = p_head;
	unsigned char *p_end = (unsigned char *)p_work->p_data + p_work->len;
	NVTPACK_PARTITION_ITEM *p_list_curr = p_list;
	NVTPACK_FW_HDR *p_fw_hdr = NULL;
	NVTPACK_PARTITION_HDR *p_pat_hdr = NULL;
	NVTPACK_PARTITION_HDR *p_pat_curr = NULL;
	NVTPACK_MEM mem_sum = {0};
	unsigned int total_size;

	memset(p_out, 0, sizeof(*p_out));

	if(num <= 0) {
		return nvtpack_er(NVTPACK_ER_PARAM);
	}

	//check uITRON existing
	if(p_list_curr->id == 0) {
		if(p_list_curr->mem.len != ALIGN_CEIL_4(p_list_curr->mem.len)) {
			return nvtpack_er(NVTPACK_ER_UITRON_SIZE_ALIGN4);
		}
		if(p_curr + p_list_curr->mem.len > p_end) {
			return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
		}
		memcpy(p_curr, p_list_curr->mem.p_data, p_list_curr->mem.len);
		p_curr += p_list_curr->mem.len;
		p_list_curr++;
		num--;
	}

	if(num == 0) {
		p_out->p_data = p_head;
		p_out->len = (unsigned int)(p_curr - p_head);
		return nvtpack_er(NVTPACK_ER_SUCCESS);
	}

	//make header
	if(p_curr + sizeof(NVTPACK_FW_HDR) > p_end) {
		return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
	}

	p_fw_hdr = (NVTPACK_FW_HDR *)p_curr;
	p_curr += sizeof(NVTPACK_FW_HDR);

	memset(p_fw_hdr, 0 , sizeof(*p_fw_hdr));
	p_fw_hdr->guid = GUID_FW;

	//keep NVTPACK_PARTITION_HDR space
	if(p_curr + sizeof(NVTPACK_PARTITION_HDR)*num > p_end) {
		return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
	}

	p_pat_hdr = (NVTPACK_PARTITION_HDR *) p_curr;
	memset(p_pat_hdr, 0, sizeof(*p_pat_hdr)*num);
	p_curr += sizeof(*p_pat_hdr) * num;
	p_fw_hdr->TotalRes = (unsigned int)num;
	p_fw_hdr->TotalSize = sizeof(*p_fw_hdr) + sizeof(*p_pat_hdr) * p_fw_hdr->TotalRes;

	p_pat_curr = p_pat_hdr;
	while(num > 0) {
		p_pat_curr->PartitionID = p_list_curr->id;
		p_pat_curr->Offset = (unsigned int)(p_curr - p_head);
		p_pat_curr->Size = p_list_curr->mem.len;

		if(p_curr + ALIGN_CEIL_4(p_pat_curr->Size) > p_end) {
			return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
		}
		memset(p_curr, 0, ALIGN_CEIL_4(p_pat_curr->Size));
		memcpy(p_curr, p_list_curr->mem.p_data, p_pat_curr->Size);

		p_curr += ALIGN_CEIL_4(p_pat_curr->Size);
		p_pat_curr++;
		p_list_curr++;
		num--;
	}

	memset(&mem_sum, 0, sizeof(mem_sum));
	mem_sum.p_data = p_fw_hdr;
	mem_sum.len = p_fw_hdr->TotalSize;
	p_fw_hdr->CheckSum = (~nvtpack_calc_nvt_sum(&mem_sum) + 1) & 0xFFFF;

	total_size = (unsigned int)(p_curr - (unsigned char *)p_fw_hdr);
	if(total_size != ALIGN_CEIL_4(total_size)) {
		return nvtpack_er(NVTPACK_ER_INVALID_WHOLE_SIZE);
	}

	p_out->p_data = p_head;
	p_out->len = (unsigned int)(p_curr - p_head);

	return nvtpack_er(NVTPACK_ER_SUCCESS);
}

static NVTPACK_ER nvtpack_make_parition_pkg_fw2(NVTPACK_MAKE_PARTITION_INPUT *p_input, NVTPACK_MEM *p_out)
{
	NVTPACK_PARTITION_ITEM *p_list = p_input->p_list;
	int num = p_input->num;
	NVTPACK_MEM *p_work = &p_input->mem_work;
	unsigned char *p_head = (unsigned char *)p_work->p_data;
	unsigned char *p_curr = p_head;
	unsigned char *p_end = (unsigned char *)p_work->p_data + p_work->len;
	NVTPACK_PARTITION_ITEM *p_list_curr = p_list;
	NVTPACK_FW_HDR2 *p_fw_hdr = NULL;
	NVTPACK_PARTITION_HDR *p_pat_hdr = NULL;
	NVTPACK_PARTITION_HDR *p_pat_curr = NULL;
	NVTPACK_MEM mem_sum = {0};

	memset(p_out, 0, sizeof(*p_out));

	if(num <= 0) {
		return nvtpack_er(NVTPACK_ER_PARAM);
	}

	//make header
	if(p_curr + sizeof(NVTPACK_FW_HDR2) > p_end) {
		return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
	}

	p_fw_hdr = (NVTPACK_FW_HDR2 *)p_curr;
	p_curr += sizeof(*p_fw_hdr);

	memset(p_fw_hdr, 0 , sizeof(*p_fw_hdr));
	p_fw_hdr->guid = GUID_FW2;
	p_fw_hdr->uiVersion = NVTPACK_FW_HDR2_VERSION;
	p_fw_hdr->uiHdrSize = sizeof(*p_fw_hdr);
	//keep NVTPACK_PARTITION_HDR space
	if(p_curr + sizeof(NVTPACK_PARTITION_HDR)*num > p_end) {
		return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
	}

	p_pat_hdr = (NVTPACK_PARTITION_HDR *) p_curr;
	memset(p_pat_hdr, 0, sizeof(*p_pat_hdr)*num);
	p_curr += sizeof(*p_pat_hdr) * num;
	p_fw_hdr->TotalRes = (unsigned int)num;

	p_pat_curr = p_pat_hdr;
	while(num > 0) {
		p_pat_curr->PartitionID = p_list_curr->id;
		p_pat_curr->Offset = (unsigned int)(p_curr - p_head);
		p_pat_curr->Size = p_list_curr->mem.len;

		if(p_curr + ALIGN_CEIL_4(p_pat_curr->Size) > p_end) {
			return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
		}
		memset(p_curr, 0, ALIGN_CEIL_4(p_pat_curr->Size));
		memcpy(p_curr, p_list_curr->mem.p_data, p_pat_curr->Size);

		p_curr += ALIGN_CEIL_4(p_pat_curr->Size);
		p_pat_curr++;
		p_list_curr++;
		num--;
	}

	p_fw_hdr->TotalSize = (unsigned int)(p_curr - (unsigned char *)p_head);

	memset(&mem_sum, 0, sizeof(mem_sum));
	mem_sum.p_data = p_head;
	mem_sum.len = p_fw_hdr->TotalSize;
	p_fw_hdr->uiChkValue = (~nvtpack_calc_nvt_sum(&mem_sum) + 1) & 0xFFFF;
	if(p_fw_hdr->TotalSize != ALIGN_CEIL_4(p_fw_hdr->TotalSize)) {
		return nvtpack_er(NVTPACK_ER_INVALID_WHOLE_SIZE);
	}

	p_out->p_data = p_head;
	p_out->len = (unsigned int)(p_curr - p_head);

	return nvtpack_er(NVTPACK_ER_SUCCESS);
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_make_parition_pkg(NVTPACK_MAKE_PARTITION_INPUT *p_input, NVTPACK_MEM *p_out)
{
	switch(p_input->ver) {
		case NVTPACK_VER_13012816:
			return nvtpack_make_parition_pkg_fw1(p_input, p_out);
		case NVTPACK_VER_16072017:
			return nvtpack_make_parition_pkg_fw2(p_input, p_out);
		default:
			return nvtpack_er(NVTPACK_ER_PARAM);
	}
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_get_resource(NVTPACK_GET_RESOURCE_INPUT *p_input, NVTPACK_MEM *p_out)
{
	const char *filename = p_input->filename;
	NVTPACK_MEM *p_in = &p_input->mem;
	unsigned char *p_data = (unsigned char *)p_in->p_data;
	int remain_len = (int)p_in->len;

	memset(p_out, 0, sizeof(*p_out));

	while(remain_len > 0) {
		NVTPACK_MEM mem_check = {0};
		NVTPACK_RES_HDR *pRes = (NVTPACK_RES_HDR *)p_data;

		if(!IsEqualGUID(&GUID_RES, (GUID *)p_data)) {
			return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
		}

		if(strncmp(pRes->DstName, filename, strlen(filename)) == 0) {
			mem_check.p_data = pRes;
			mem_check.len = pRes->TotalSize;
			if(nvtpack_calc_nvt_sum(&mem_check) != 0) {
				return nvtpack_er(NVTPACK_ER_CHECK_SUM);
			}
			p_out->p_data = p_data + sizeof(NVTPACK_RES_HDR);
			p_out->len = pRes->ContentSize;
			return nvtpack_er(NVTPACK_ER_SUCCESS);
		}

		p_data += pRes->TotalSize;
		remain_len -= (int)pRes->TotalSize;
	}

	return nvtpack_er(NVTPACK_ER_NOT_FOUND);
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_enum_resource(NVTPACK_ENUM_RESOURCE_INPUT *p_input)
{
	unsigned char *p_data = (unsigned char *)p_input->mem.p_data;
	int remain_len = (int)p_input->mem.len;

	while(remain_len > 0) {
		NVTPACK_MEM mem_check = {0};
		NVTPACK_MEM mem_out = {0};
		NVTPACK_RES_HDR *pRes = (NVTPACK_RES_HDR *)p_data;

		if(!IsEqualGUID(&GUID_RES, (GUID *)p_data)) {
			return nvtpack_er(NVTPACK_ER_UNKNOWN_FORMAT);
		}

		mem_check.p_data = pRes;
		mem_check.len = pRes->TotalSize;
		if(nvtpack_calc_nvt_sum(&mem_check) != 0) {
			return nvtpack_er(NVTPACK_ER_CHECK_SUM);
		}

		mem_out.p_data = p_data + sizeof(NVTPACK_RES_HDR);
		mem_out.len = pRes->ContentSize;
		if(p_input->fp_enum) {
			if(p_input->fp_enum(pRes, &mem_out, p_input->p_user_data) != 0) {
				return nvtpack_er(NVTPACK_ER_USER_BREAK);
			}
		}

		p_data += pRes->TotalSize;
		remain_len -= (int)pRes->TotalSize;
	}

	return nvtpack_er(NVTPACK_ER_SUCCESS);
}

_NVTPACK_EXTERN_C NVTPACK_ER nvtpack_make_resource_pkg(NVTPACK_MAKE_RESOURCE_INPUT *p_input, NVTPACK_MEM *p_out)
{
	int i, j;
	NVTPACK_RESOURCE_ITEM *p_list = p_input->p_list;
	int num = p_input->num;
	NVTPACK_MEM *p_work = &p_input->mem_work;
	unsigned char *p_head = (unsigned char *)p_work->p_data;
	unsigned char *p_curr = p_head;
	unsigned char *p_end = (unsigned char *)p_work->p_data + p_work->len;
	NVTPACK_RESOURCE_ITEM *p_list_curr = p_list;

	memset(p_out, 0, sizeof(*p_out));

	//check all item name
	for(i = 0; i < num; i++) {
		p_list_curr = &p_list[i];
		if(strlen(p_list_curr->DstName) == 0) {
			return nvtpack_er(NVTPACK_ER_SRC_NAME_BLANK);
		} else if(strlen(p_list_curr->DstName) > 12) {
			return nvtpack_er(NVTPACK_ER_SRC_NAME_EXCEED);
		} else if(strstr(p_list_curr->DstName, " ") != NULL) {
			return nvtpack_er(NVTPACK_ER_SRC_NAME_INVALID);
		}
		//check same section name
		for(j = i + 1; j < num; j++) {
			if(strcmp(p_list_curr->DstName, p_list[j].DstName) == 0) {
				return nvtpack_er(NVTPACK_ER_SRC_NAME_ALIKE);
			}
		}
	}

	p_list_curr = p_list;
	for(i = 0; i < num; i++) {
		unsigned int require_size = ALIGN_CEIL(sizeof(NVTPACK_RES_HDR) + p_list_curr->mem.len, 32);
		unsigned char *p_next = p_curr + require_size;
		NVTPACK_RES_HDR *p_hdr = (NVTPACK_RES_HDR *)p_curr;
		NVTPACK_MEM mem_sum = {0};

		if(p_curr + require_size > p_end) {
			return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
		}

		memset(p_curr, 0, require_size);
		p_curr += sizeof(*p_hdr);
		p_hdr->guid = GUID_RES;
		p_hdr->TotalSize = require_size;
		p_hdr->ContentSize = p_list_curr->mem.len;
		memset(p_hdr->SrcName, 0, sizeof(p_hdr->SrcName));
		memset(p_hdr->DstName, 0, sizeof(p_hdr->DstName));
		strncpy(p_hdr->SrcName, p_list_curr->SrcName, 12);
		strncpy(p_hdr->DstName, p_list_curr->DstName, 12);

		if(p_curr + p_list_curr->mem.len > p_end) {
			return nvtpack_er(NVTPACK_ER_MEM_NOT_ENOUGH);
		}

		memcpy(p_curr, p_list_curr->mem.p_data, p_list_curr->mem.len);
		//check sum
		memset(&mem_sum, 0, sizeof(mem_sum));
		mem_sum.p_data = p_hdr;
		mem_sum.len = p_hdr->TotalSize;
		p_hdr->CheckSum = (~nvtpack_calc_nvt_sum(&mem_sum) + 1) & 0xFFFF;
		p_curr = p_next;
		p_list_curr++;
	}

	p_out->p_data = p_head;
	p_out->len = (unsigned int)(p_curr - p_head);

	return nvtpack_er(NVTPACK_ER_SUCCESS);
}
