/*****************************************************************************************
*  Copyright (c) 2004, Beijing Senselock Data Security Centre
*  All rights reserved.
*
*  Filename£ºsample_22_win32.c
*          
*  Briefs£º  The purpose of this snippet is to demonstrate how to create internal SenseLock EL files  
*            using SES function _create();
*
*  Remarks:  When you download sample_22_hw.hex to SenseLock EL device, do remember to select
*            "EXF read-writable" checkbox.
*            
*  History:        
*  --------------------------------------------------------        
*            10/28/2004 v1.0.0.0 Lihua created
*            
*            
*******************************************************************************************/

#include <stdio.h>
#include <conio.h>
#include <assert.h>

#include "..\..\inc\win32\sense4.h"
#include "..\..\inc\win32\crypt2.h"
#include "..\..\inc\win32\ses_err_msg.h"/* for debug purpose only */
#include "..\..\common\common.h"

#include "..\inc\sample_22.h"


/* global variables definition */
SENSE4_CONTEXT stS4Ctx = {0};
unsigned long dwResult = 0;
unsigned long dwBytesReturned = 0;

IO_PACKAGE stDataPkgIn = {0};
IO_PACKAGE stDataPkgOut = {0};

#define S4_EXE_FILE_ID		"ef22"
#define S4_OBJ_FILE_ID		"bf22"
#define S4_OBJ_FILE_ID_HEX	0xbf22

/* for debug purpose only : handle results returned by stDataPkgOut.tag */
void HandleError(unsigned char bErrCode, unsigned char *pbErrInfo)
{
	switch(bErrCode)
	{
	case ERR_SUCCESS:
		printf("Success!\n");
		break;
	case ERR_SES:
		assert(*pbErrInfo>0x00 && *pbErrInfo<0x41);
		printf("Error during SES Execution :\n%s\n", SesErrMsgs[*pbErrInfo]);
		break;
	case ERR_INVALID_PARAMETER:
		printf("Invalid input,pls check your input data\n");
		break;
	default:
		printf("Undefined error code!\n");
		break;
	}
	return;
}

/* check result for S4Execute(...) */
unsigned long CheckS4ExecutionResult(unsigned long dwResult,unsigned long dwBytesReturned,unsigned char tag)
{
	
	if (dwResult != S4_SUCCESS) 
	{
		printf("S4 Execution failed! <error code: 0x%08x>\n", dwResult);
		return 0;
	}
	
	if (dwBytesReturned < 2)
	{
		printf("Invalid data package returned!\n");
		return 0;
	}
	
	if (tag != ERR_SUCCESS)
	{
		HandleError(stDataPkgOut.tag, stDataPkgOut.buff);
		return 0;
	}
	return 1;
}

unsigned long update_internal_file(unsigned short fid, unsigned short offset,
								   char *in, int inlen)
{
	FILE_OP_BLOCK stDataBlk = {0};
	
	assert(in != NULL);
	
	stDataBlk.fid = fid;
	stDataBlk.offset = offset;
	stDataBlk.len = inlen;
	memcpy(stDataBlk.buff, in, inlen);
	
	stDataPkgIn.tag = CMD_UPDATE;
	stDataPkgIn.len = sizeof(FILE_OP_BLOCK)-sizeof(stDataBlk.buff) + stDataBlk.len;
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);
	
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len,
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		return 0;
	}
	return 1;	
	
}

unsigned long read_internal_file(unsigned short fid, unsigned short offset, unsigned char readlen,
								 char *out, int *outlen)
{
	FILE_OP_BLOCK stDataBlk = {0};
	
	assert(out != NULL && outlen != NULL);
	
	if (*outlen < readlen) // insufficient out buffer size
	{
		*outlen = readlen;
		return 0;
	}
	stDataBlk.fid = fid;
	stDataBlk.offset = offset;
	stDataBlk.len = readlen;
	
	
	stDataPkgIn.tag = CMD_READ;
	stDataPkgIn.len = sizeof(FILE_OP_BLOCK)-sizeof(stDataBlk.buff) + stDataBlk.len;
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);
	
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len,
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		return 0;
	}
	memcpy(out, stDataPkgOut.buff, stDataPkgOut.len);
	*outlen = stDataPkgOut.len;
	
	return 1;	
	
}

int	create_internal_file(unsigned short fid, unsigned short fsize, unsigned char ftype,
							 unsigned char flag)
{							 
	FILE_CREATE_BLOCK stDataBlk = {0};

	stDataBlk.fid = fid;
	stDataBlk.fsize = fsize;
	stDataBlk.ftype = ftype;
	stDataBlk.flag = flag;
	

	stDataPkgIn.tag = CMD_CREATE;
	stDataPkgIn.len = sizeof(FILE_CREATE_BLOCK);
	
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);
	
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len,
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		return 0;
	}
	return 1;	
	
}
							 
int main(int argc, char* argv[])
{
	unsigned char lpUserPin[8] = "12345678";
	unsigned char lpBuffer[300];
	unsigned long dwBuffLen = sizeof(lpBuffer);
	unsigned char lpStr[] = "This is the data to be written into the objective SenseLock EL file.";
	unsigned long  dwBytesWritten = 0;

    if (!(dwResult = OpenS4ByIndex(FIRST_S4_INDEX,&stS4Ctx)))
	{
		return 1;
	}   
	
	

	dwResult = S4ChangeDir(&stS4Ctx, "\\");
	if (dwResult != S4_SUCCESS) 
	{
		printf("Change directory failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}

	// Call S4VerifyPin(...) to verify User PIN so as to get the privilege to execute the program in SenseLock EL.
	dwResult = S4VerifyPin(&stS4Ctx, lpUserPin, sizeof(lpUserPin), S4_USER_PIN);
	if (dwResult != S4_SUCCESS) 
	{
		printf("Verify Pin failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}	
	
	printf("Create internal file (or open it if it already exists)...\n");
	if(!(dwResult = create_internal_file(S4_OBJ_FILE_ID_HEX, 300, SES_FILE_TYPE_EXE_DATA, CREATE_OPEN_ALWAYS)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");

	
	printf("Update objective file ...\n");
	if(!(dwResult = update_internal_file(S4_OBJ_FILE_ID_HEX, 0, lpStr, strlen(lpStr)+1)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");
	
	memset(lpBuffer, 0, dwBuffLen); // empty buffer 
	printf("Read data from objective file ...\n");
	if(!(dwResult = read_internal_file(S4_OBJ_FILE_ID_HEX, 0, (unsigned char)(strlen(lpStr)+1), lpBuffer, &dwBuffLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");
	printf("The data read: %s \n", lpBuffer);


	/* for better security,use the following instead of using S4close() directly */
	ResetAndCloseS4(&stS4Ctx);
	getch();

	return dwResult;
}
