#include <string.h>
#include "ses_v3.h"

#define _DEBUG

/*-------------本来はヘッダファイルの内容 (開始)-----------------*/
#ifdef _WIN32
#pragma pack(push, 1)
#endif 

#define IO_PACKAGE_HEADER_SIZE 2 //IO package header length:tag+len
#define MAX_IO_DATA_SIZE	0xf8 // maximum IO data size

#define MAX_BUFF_SIZE  0xf0      //maximum buffer size  

/* command group definition */
#define CMD_UPDATE 0x01
#define CMD_READ   0x02
#define CMD_CREATE 0x03

/* common error code. */
#define ERR_SUCCESS				0x00	// success
#define ERR_SES					0x80	// SES function execution error
#define ERR_INVALID_PARAMETER	0x81	// invalid parameter

/* user-specific data block */
typedef struct _FILE_OP_BLOCK
{							                                                                                               
	unsigned short fid;     // objective file ID 
	unsigned short offset;  // operating offset
	unsigned char len; 	    // buffer length(update)
							// read length(read)		
	unsigned char buff[MAX_BUFF_SIZE];
} FILE_OP_BLOCK;


typedef struct _FILE_CREATE_BLOCK
{							                                                                                               
	unsigned short fid;     // objective file ID 
	unsigned short fsize;   // file size
	unsigned char  ftype;	// file type
	unsigned char  flag; 	// create flag
} FILE_CREATE_BLOCK;

/* create file type, quoted from ses_v3.h */
#define SES_FILE_TYPE_EXE		0x00			/* executable file			*/
#define SES_FILE_TYPE_EXE_DATA	0x01			/* data file				*/
#define SES_FILE_TYPE_RSA_PUB	0x02			/* RSA public key file		*/
#define SES_FILE_TYPE_RSA_SEC	0x03			/* RSA secret key file		*/

/* create file flag, quoted from ses_v3.h */
#define CREATE_OPEN_ALWAYS		0x00			/* open if file already exist, create a new file if not existing	*/
#define CREATE_FILE_NEW			0x01			/* create a new file and open it									*/
#define CREATE_OPEN_EXISTING	0x02			/* open a file exist												*/



/* IO package */
typedef struct _IO_PACKAGE
{	
	unsigned char tag;	
	unsigned char len;
	unsigned char buff[MAX_IO_DATA_SIZE];
} IO_PACKAGE;

#ifdef _WIN32
#pragma pack(pop)
#endif
/*-------------本来はヘッダファイルの内容 (終了)-----------------*/

#define _DEBUG

/* global variable defination. */
unsigned char last_ses_error = 0; /* last SES error */
IO_PACKAGE out_pkg;  /* output package */
IO_PACKAGE *output = &out_pkg; 
IO_PACKAGE *input = (IO_PACKAGE *)pbInBuff; /* input package */

/*
	Exit upon an error.
  
	Parameters:
		errcode[in]: error code
		msg[in]: additional error message
		msglen[in]: message length
  
	Return:
		none.

	Remarks:
		none.
*/
void error_exit(unsigned char errcode, unsigned char *msg, int msglen)
{
	output->tag = errcode;
	output->len = 0;
	
	/* for debug purpose only */
#ifdef  _DEBUG
	if (msglen != 0 && msg != NULL)
	{
		memcpy(output->buff, msg, msglen);
		output->len = msglen;
	}
#endif

	_set_response(2+output->len, (unsigned char *)output);
	_exit();
}
/*
	Update internal file.
  
	Parameters:
		fid   [in]: objective file ID 
		offset[in]: offset
		in    [in]: content
  		inlen [in]: length of content
	Return:
		If the function succeeds, it will return ERR_SUCCESS, otherwise 
		it returns corresponding error code.

	Remarks:
		none.
*/
int update_internal_file(unsigned short fid, unsigned short offset,
						 char *in, int inlen)
{
	int ret = 0;
	HANDLE hfile = 0;
	
	ret = _open(fid, &hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}
		
	ret = _write(hfile, offset, inlen, in);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}

	ret = _close(hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}
	return ERR_SUCCESS;
}
/*
	Read content from internal file.
  
	Parameters:
		fid    [in] : objective file ID 
		offset [in] : offset
		readlen[in] : read length
		out    [out]: out buffer
  		outlen [in] : out buffer length 
	Return:
		If the function succeeds, it will return ERR_SUCCESS, otherwise 
		it returns corresponding error code.

	Remarks:
		none.
*/

int read_internal_file(unsigned short fid, unsigned short offset, unsigned short readlen,
					   unsigned char *out, int *outlen)
{
	int ret = 0;
	HANDLE hfile = 0;
	
	if (*outlen < readlen)
	{
		return ERR_INVALID_PARAMETER;
	}
	ret = _open(fid, &hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}
		
	ret = _read(hfile, offset, readlen, out);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}

	ret = _close(hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}
	*outlen = readlen;
	return ERR_SUCCESS;
}

/*
	Create a file dynamically.
  
	Parameters:
		fid    [in] : objective file ID 
		fsize  [in] : file size
		bftype [in] : file type
		bflag  [in] : create flag
	Return:
		If the function succeeds, it will return ERR_SUCCESS, otherwise 
		it returns corresponding error code.

	Remarks:
		none.
*/
int	create_internal_file(unsigned short fid, unsigned short fsize,
						 unsigned char bftype,unsigned char bflag)
{
	int ret = 0;
	HANDLE hfile = 0;
	ret = _create(fid, fsize, bftype, bflag, &hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}

	ret = _close(hfile);
	if (ret != SES_SUCCESS)
	{
		last_ses_error = ret;
		return ERR_SES;
	}
	return ERR_SUCCESS;

}

void main()
{
	int ret = 0;
	int length = 0;
	FILE_OP_BLOCK *dblk ;
	FILE_CREATE_BLOCK *fcblk;
	 
	switch (input->tag)
	{
		case CMD_UPDATE:
			dblk = (FILE_OP_BLOCK *)input->buff;
			LE16_TO_CC(&dblk->fid);
			LE16_TO_CC(&dblk->offset);
			length = 0;
			ret = update_internal_file(dblk->fid, dblk->offset, dblk->buff, dblk->len);
			break;
		case CMD_READ:
			dblk = (FILE_OP_BLOCK *)input->buff;
			LE16_TO_CC(&dblk->fid);
			LE16_TO_CC(&dblk->offset);
			length = MAX_IO_DATA_SIZE;
			ret = read_internal_file(dblk->fid, dblk->offset, dblk->len, output->buff, &length);
			break;
		case CMD_CREATE:
			fcblk = (FILE_CREATE_BLOCK *)input->buff;
			LE16_TO_CC(&fcblk->fid);
			LE16_TO_CC(&fcblk->fsize);
			ret = create_internal_file(fcblk->fid, fcblk->fsize, fcblk->ftype, fcblk->flag);
			break;
		default:
			error_exit(ERR_INVALID_PARAMETER, NULL, 0);
			
	}
	if (ret != ERR_SUCCESS)
	{
		if (ret == ERR_SES)
		{
			error_exit(ret, &last_ses_error, 1);
		}
		else
		{
			error_exit(ret, NULL, 0);
		}
	}

	output->tag = ERR_SUCCESS;
	output->len = (unsigned char)length;
	_set_response(IO_PACKAGE_HEADER_SIZE+output->len, (unsigned char *)output);
	_exit();  
}