/**
 * @file file_integrity_check.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of file integrity check APIs
 *
 * The functions provided in the file provides demonstration on
 * usage of file integrity APIs
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "stdio.h"

#include "file_integrity_check.h"
#include "common.h"
#include "exo_common.h"



/******************************************************************************/
/*                  Declaration of local function prototypes                  */
/******************************************************************************/


/**
 * @brief This function applies crc-32 algorithm for given data values
 *
 * @param[in]  Crc  : calculated value of previous iteration.
 * @param[in] Data   : input data value for current iteration to calculate crc
 *
 * @return calculated crc value
 * @retval crc value in hex
 */
static uint32_t ft_Crc32(uint32_t Crc, uint32_t Data);


/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/

/**
 * @brief This function applies crc-32 algorithm for given data values
 *
 */
static uint32_t ft_Crc32(uint32_t Crc, uint32_t Data)
{
	uint8_t index;

	Crc = Crc ^ Data;
	for (index = 0; index < 32; index++)
	{
		if (Crc & 0x80000000)
		{
			Crc = (Crc << 1) ^ 0x04C11DB7;	// Polynomial used in STM32
		}
		else
		{
			Crc = (Crc << 1);
		}
	}

	return (Crc);
}


/******************************************************************************/
/*                      Definition of exported functions                      */
/******************************************************************************/

/**
 * @brief This API will evaluate crc value for given input data buffer with length
 *
 */
uint32_t calc_checksum_bulkdata(uint8_t *data_buf,uint32_t length)
{
	uint32_t read_buffer = 0xffffffff;
	uint32_t calc_CRC;
	uint32_t buf_inc;

	// checking if the file exist or not
	if (data_buf == NULL)
	{
		DEBUG_CPRINT(("INTG | Buffer ptr Null  !\n"));
		return 0;
	}
	buf_inc = 0;
	calc_CRC = 0xFFFFFFFF;
	while (length > 3)
	{
		memcpy(&read_buffer,&data_buf[buf_inc],4);
		calc_CRC = ft_Crc32(calc_CRC, read_buffer);
		length -= 4;
		buf_inc +=4;
	}

	return calc_CRC;
}


#ifndef FT_OBC

/**
 * @brief This function will calculate file size
 *
 */
long int find_fileSize(char file_name[])
{
	// opening the file in read mode
	FILE *fp = fopen(file_name, "r");

	// checking if the file exist or not
	if (fp == NULL)
	{
		DEBUG_CPRINT(("SIZE | File opening error %s !\n",file_name));
		return -1;
	}

	fseek(fp, 0L, SEEK_END);

	// calculating the size of the file
	long int res = ftell(fp);

	// closing the file
	fclose(fp);

	return res;
}



/**
 * @brief This function will calculate checksum for file with input file size
 *
 */
uint32_t ft_calc_filechecksum(char file_name[], uint32_t length)
{
	uint32_t read_buffer = 0xffffffff;
	uint32_t calc_CRC;
	// opening the file in read mode
	FILE *fp = fopen(file_name, "r");

	// checking if the file exist or not
	if (fp == NULL)
	{
		DEBUG_CPRINT(("INTG | File opening error %s !\n",file_name));
		return 0;
	}

	calc_CRC = 0xFFFFFFFF;
	while (length > 3)
	{
		fread(&read_buffer, 4, 1, fp);
		calc_CRC = ft_Crc32(calc_CRC, read_buffer);
		length -= 4;
	}

	// closing the file
	fclose(fp);
	return calc_CRC;
}


/**
 * @brief This function will calculate checksum for file
 *
 */
uint32_t file_integrity_check(char file_name[])
{
	long int file_size;
	uint32_t checksum;
	file_size = find_fileSize(file_name);
	if (file_size != -1)
	{
		DEBUG_CPRINT(("INTG | File Size %ld !\n",file_size));
		checksum = ft_calc_filechecksum(file_name, file_size);
	}
	else
	{
		checksum = 0;
	}

	return checksum;
}


#endif
