/*
  Copyright (c) 2004,   Beijing Senselock Data Security Centre
  All rights reserved.
  
  File£ºsample_22_hw.c
  
  Briefs£ºThis code will 
    
*/

#include <string.h>
#include "..\..\inc\hardware\ses_v3.h"
#include "..\inc\sample_22.h"


#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();  
}
