/*
 * (C) Copyright 2017 Fuzhou Rockchip Electronics Co., Ltd
 * Seth Liu 2017.03.01
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include "RKBoot.h"
extern UINT CRC_32(PBYTE pData, UINT ulSize);
bool CRKBoot::GetRc4DisableFlag()
{
	return m_bRc4Disable;
}
bool CRKBoot::GetSignFlag()
{
	return m_bSignFlag;
}
DWORD CRKBoot::GetVersion()
{
	return m_version;
}
DWORD CRKBoot::GetMergeVersion()
{
	return m_mergeVersion;
}
STRUCT_RKTIME CRKBoot::GetReleaseTime()
{
	return m_releaseTime;
}
ENUM_RKDEVICE_TYPE CRKBoot::GetSupportDevice()
{
	return m_supportDevice;
}
UCHAR CRKBoot::GetEntry471Count()
{
	return m_471Count;
}
UCHAR CRKBoot::GetEntry472Count()
{
	return m_472Count;
}
UCHAR CRKBoot::GetEntryLoaderCount()
{
	return m_loaderCount;
}
bool CRKBoot::CrcCheck()
{
	UINT*pOldCrc,ulNewCrc;
	pOldCrc = (UINT*)(m_BootData+(m_BootSize-4));
	ulNewCrc = CRC_32(m_BootData,m_BootSize-4);
	return (*pOldCrc==ulNewCrc)?true:false;
}
bool CRKBoot::SaveEntryFile(ENUM_RKBOOTENTRY type,UCHAR ucIndex,string fileName)
{
	DWORD dwOffset;
	UCHAR ucCount,ucSize;
	switch ( type )
	{
	case ENTRY471:
		dwOffset = m_471Offset;
		ucCount = m_471Count;
		ucSize = m_471Size;
		break;
	case ENTRY472:
		dwOffset = m_472Offset;
		ucCount = m_472Count;
		ucSize = m_472Size;
		break;
	case ENTRYLOADER:
		dwOffset = m_loaderOffset;
		ucCount = m_loaderCount;
		ucSize = m_loaderSize;
		break;
	default:
		return false;
	}
	if (ucIndex >= ucCount)
	{
		return false;
	}
	PSTRUCT_RKBOOT_ENTRY pEntry;
	pEntry = (PSTRUCT_RKBOOT_ENTRY)(m_BootData+dwOffset+(ucSize*ucIndex));
	FILE *file=NULL;
	file = fopen(fileName.c_str(),"wb+");
	if ( !file )
	{
		return false;
	}
	fwrite(m_BootData+pEntry->dwDataOffset,1,pEntry->dwDataSize,file);
	fclose(file);
	return true;
}
bool CRKBoot::GetEntryProperty(ENUM_RKBOOTENTRY type,UCHAR ucIndex,DWORD &dwSize,DWORD &dwDelay,char *pName)
{
	DWORD dwOffset;
	UCHAR ucCount,ucSize;
	switch ( type )
	{
	case ENTRY471:
		dwOffset = m_471Offset;
		ucCount = m_471Count;
		ucSize = m_471Size;
		break;
	case ENTRY472:
		dwOffset = m_472Offset;
		ucCount = m_472Count;
		ucSize = m_472Size;
		break;
	case ENTRYLOADER:
		dwOffset = m_loaderOffset;
		ucCount = m_loaderCount;
		ucSize = m_loaderSize;//Loader长度生成时已经512对齐
		break;
	default:
		return false;
	}
	if (ucIndex >= ucCount)
	{
		return false;
	}
	PSTRUCT_RKBOOT_ENTRY pEntry;
	pEntry = (PSTRUCT_RKBOOT_ENTRY)(m_BootData+dwOffset+(ucSize*ucIndex));
	dwDelay = pEntry->dwDataDelay;
	dwSize = pEntry->dwDataSize;
	if (pName)
	{
		WCHAR_To_char(pEntry->szName,pName,20);
	}
	return true;
}
bool CRKBoot::GetEntryData(ENUM_RKBOOTENTRY type,UCHAR ucIndex,PBYTE lpData)
{
	DWORD dwOffset;
	UCHAR ucCount,ucSize;
	switch ( type )
	{
	case ENTRY471:
		dwOffset = m_471Offset;
		ucCount = m_471Count;
		ucSize = m_471Size;
		break;
	case ENTRY472:
		dwOffset = m_472Offset;
		ucCount = m_472Count;
		ucSize = m_472Size;
		break;
	case ENTRYLOADER:
		dwOffset = m_loaderOffset;
		ucCount = m_loaderCount;
		ucSize = m_loaderSize;
		break;
	default:
		return false;
	}
	if (ucIndex >= ucCount)
	{
		return false;
	}
	PSTRUCT_RKBOOT_ENTRY pEntry;
	pEntry = (PSTRUCT_RKBOOT_ENTRY)(m_BootData+dwOffset+(ucSize*ucIndex));
	memcpy(lpData,m_BootData+pEntry->dwDataOffset,pEntry->dwDataSize);
	return true;
}
char CRKBoot::GetIndexByName(ENUM_RKBOOTENTRY type,char *pName)
{
	DWORD dwOffset;
	UCHAR ucCount,ucSize;
	switch ( type )
	{
	case ENTRY471:
		dwOffset = m_471Offset;
		ucCount = m_471Count;
		ucSize = m_471Size;
		break;
	case ENTRY472:
		dwOffset = m_472Offset;
		ucCount = m_472Count;
		ucSize = m_472Size;
		break;
	case ENTRYLOADER:
		dwOffset = m_loaderOffset;
		ucCount = m_loaderCount;
		ucSize = m_loaderSize;
		break;
	default:
		return -1;
	}

	for (UCHAR i=0;i<ucCount;i++)
	{
		PSTRUCT_RKBOOT_ENTRY pEntry;
		pEntry = (PSTRUCT_RKBOOT_ENTRY)(m_BootData+dwOffset+(ucSize*i));

		char szName[20];
		WCHAR_To_char(pEntry->szName,szName,20);

		if (strcasecmp(pName,szName)==0)
		{
			return i;
		}
	}
	return -1;
}
CRKBoot::~CRKBoot()
{
	if (m_BootData!=NULL)
	{
		delete []m_BootData;
	}
}

CRKBoot::CRKBoot(PBYTE lpBootData,DWORD dwBootSize,bool &bCheck)
{
	Rc4DisableFlag.setContainer(this);
	Rc4DisableFlag.getter(&CRKBoot::GetRc4DisableFlag);
	SignFlag.setContainer(this);
	SignFlag.getter(&CRKBoot::GetSignFlag);
	Version.setContainer(this);
	Version.getter(&CRKBoot::GetVersion);
	MergeVersion.setContainer(this);
	MergeVersion.getter(&CRKBoot::GetMergeVersion);
	ReleaseTime.setContainer(this);
	ReleaseTime.getter(&CRKBoot::GetReleaseTime);
	SupportDevice.setContainer(this);
	SupportDevice.getter(&CRKBoot::GetSupportDevice);
	Entry471Count.setContainer(this);
	Entry471Count.getter(&CRKBoot::GetEntry471Count);
	Entry472Count.setContainer(this);
	Entry472Count.getter(&CRKBoot::GetEntry472Count);
	EntryLoaderCount.setContainer(this);
	EntryLoaderCount.getter(&CRKBoot::GetEntryLoaderCount);
	bCheck = true;
	if (lpBootData!=NULL)
	{
		m_BootData=lpBootData;
		m_BootSize=dwBootSize;
		bCheck=CrcCheck();
		if (!bCheck)
		{
			return;
		}
		PSTRUCT_RKBOOT_HEAD pBootHead;
		pBootHead = (PSTRUCT_RKBOOT_HEAD)(m_BootData);
		if (( pBootHead->uiTag!=0x544F4F42)&&(pBootHead->uiTag!=0x2052444C))
		{
			bCheck=false;
			return;
		}
		if (pBootHead->ucRc4Flag)
		{
			m_bRc4Disable = true;
		}
		else
			m_bRc4Disable = false;
		if (pBootHead->ucSignFlag=='S')
		{
			m_bSignFlag = true;
		}
		else
			m_bSignFlag = false;
		m_version = pBootHead->dwVersion;
		m_mergeVersion = pBootHead->dwMergeVersion;
		m_BootHeadSize = pBootHead->usSize;
		m_releaseTime.usYear = pBootHead->stReleaseTime.usYear;
		m_releaseTime.ucMonth = pBootHead->stReleaseTime.ucMonth;
		m_releaseTime.ucDay = pBootHead->stReleaseTime.ucDay;
		m_releaseTime.ucHour = pBootHead->stReleaseTime.ucHour;
		m_releaseTime.ucMinute = pBootHead->stReleaseTime.ucMinute;
		m_releaseTime.ucSecond = pBootHead->stReleaseTime.ucSecond;
		m_supportDevice = pBootHead->emSupportChip;

		m_471Offset = pBootHead->dw471EntryOffset;
		m_471Count = pBootHead->uc471EntryCount;
		m_471Size = pBootHead->uc471EntrySize;

		m_472Offset = pBootHead->dw472EntryOffset;
		m_472Count = pBootHead->uc472EntryCount;
		m_472Size = pBootHead->uc472EntrySize;

		m_loaderOffset = pBootHead->dwLoaderEntryOffset;
		m_loaderCount = pBootHead->ucLoaderEntryCount;
		m_loaderSize = pBootHead->ucLoaderEntrySize;

		memcpy(m_crc,m_BootData+(m_BootSize-4),4);
	}
	else
	{
		bCheck = false;
		m_BootData=NULL;
	}
}
void CRKBoot::WCHAR_To_wchar(WCHAR *src,wchar_t *dst,int len)
{
	int i;
	memset(dst,0,len*sizeof(wchar_t));
	for (i=0;i<len;i++)
	{
		memcpy(dst,src,2);
		src++;
		dst++;
	}
}
void CRKBoot::WCHAR_To_char(WCHAR *src,char *dst,int len)
{
	int i;
	memset(dst,0,len*sizeof(char));
	for (i=0;i<len;i++)
	{
		memcpy(dst,src,1);
		src++;
		dst++;
	}
}

