//////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdafx.h"
#include "SCardCOM.h"
#include "SCardFil.h"
#include "scarddef.h"
///////////////////////////////////////////////////////////////////////////
// Macros
//
#ifdef _DEBUG
#define TRACE_STR(name,sz) \
TRACE(_T("SCardCOM.DLL: CSCardFileAccess::%s: %s\n"), name, sz)
#define TRACE_CODE(name,code) \
TRACE(_T("SCardCOM.DLL: CSCardFileAccess::%s: error = 0x%x\n"), name, code)
#define TRACE_CATCH(name,code)TRACE_CODE(name,code)
#define TRACE_CATCH_UNKNOWN(name)TRACE_STR(name,_T("An unidentified exception has occurred!"))
#else
#define TRACE_STR(name,sz)((void)0)
#define TRACE_CODE(name,code)((void)0)
#define TRACE_CATCH(name,code)((void)0)
#define TRACE_CATCH_UNKNOWN(name)((void)0)
#endif // _DEBUG
/*++
CSCardFileAccess::FinalConstruct:
This routine defines a final constructor that is called after the constructor
for the template class is called.
Arguments:
None
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
HRESULT CSCardFileAccess::FinalConstruct()
{
// Locals.
HRESULT hresult = S_OK;
try {
m_iOpenFiles = 0;
m_FileInfoMap.InitHashTable(13);
m_hfileNextHandle = 1;
m_wCurrentFileID = 0x3f00;
m_Manage = NULL;
}
catch (...) {
hresult = E_UNEXPECTED;
TRACE_CATCH(_T("FinalConstruct"), hresult);
}
return (hresult);
}
/*++
CSCardFileAccess::FinalRelease:
This routine defines a final release.
Arguments:
None
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
HRESULT CSCardFileAccess::FinalRelease()
{
// Locals.
HRESULT hresult = S_OK;
try {
// Decrement the reference count on the "creation" object
if (m_Manage != NULL)
m_Manage->Release();
}
catch (...) {
}
return (hresult);
}
/*++
CSCardFileAccess::ConvertFilename
This routine converts a filename (BSTR) to a word for internal use
as the file ID. BSTR MUST be in hex!
Arguments:
bstrFilename - filename as BSTR
Return Value:
A word containing the filename or 0 if failed.
Author:
Note:
--*/
WORD CSCardFileAccess::ConvertFilename( BSTR bstrFilename)
{
//locals
WORDwFileID = 0;
intnStringLength = :: SysStringLen(bstrFilename);
LPTSTRpszBuffer,
pszEndBuffer;
HLOCALhMem;
DWORDdwErr;
#ifdef _UNICODE
intnNewStrLen = sizeof(WCHAR);
#else
int nNewStrLen = sizeof(char);
#endif
m_CriticalSection.EnterCriticalSection();
try {
if ( (nStringLength > SC_FILE_ID_STR_LENGTH) ||
(nStringLength <=0) )
throw ( (HRESULT) E_INVALIDARG );
// Alloc mem for BSTR to LPTSTR conversion if required
nNewStrLen *= nStringLength;
nNewStrLen++; //For NULL termination
#ifdef _UNICODE
pszBuffer = (LPTSTR) bstrFileName;
#else
hMem = ::LocalAlloc(LPTR, (UINT) nNewStrLen);
if (hMem == NULL) {
dwErr = ::GetLastError();
throw (HRESULT_FROM_WIN32(dwErr));
};
pszBuffer = (LPTSTR) ::LocalLock(hMem);
if (pszBuffer == NULL) {
dwErr = ::GetLastError();
throw (HRESULT_FROM_WIN32(dwErr));
};
// Convert wide char to ansi string
WideCharToMultiByte(CP_ACP,
0,
bstrFilename,
nStringLength,
pszBuffer,
nNewStrLen,
NULL,
NULL );
#endif
// Now convert to WORD...
pszEndBuffer = pszBuffer + nStringLength;
// Use correct conversion per UNICODE
#ifdef _UNICODE
wFileID = (WORD) wcstol( pszBuffer , &pszEndBuffer, 16);
#else
wFileID = (WORD) strtol( pszBuffer , &pszEndBuffer, 16);
#endif
}
catch (...) {
wFileID = 0;
TRACE_CATCH(_T("ConvertFilename"), wFileID);
}
// Eliminate the temp buffer
while (::LocalUnlock(hMem));
// At this point, ::GetLastError() should equal NO_ERROR!
if (::LocalFree(hMem) != NULL) {
wFileID = 0;
}
m_CriticalSection.ExitCriticalSection();
return wFileID;
}
/*++
CSCardFileAccess::CreateFileHandle
This routine creates a file handle.
Arguments:
None
Return Value:
A HSCARD_FILE handle or 0 if call failed.
Author:
--*/
HSCARD_FILE CSCardFileAccess::CreateFileHandle()
{
// locals
HSCARD_FILE hFile = 0;
m_CriticalSection.EnterCriticalSection();
try {
// Simple generation based on successive HSCARD_FILE values.
if (m_hfileNextHandle == MAX_HANDLE_VALUE)
throw(hFile = 0);
hFile = m_hfileNextHandle;
m_hfileNextHandle++;
}
catch (HSCARD_FILE handle) {
hFile = handle;
TRACE_CATCH(_T("CreateFileHandle"), hFile);
}
catch (...) {
hFile = 0;
TRACE_CATCH_UNKNOWN(_T("CreateFileHandle"));
}
m_CriticalSection.ExitCriticalSection();
return hFile;
}
/*++
CSCardFileAccess::FileSelect
This routine selects file/changes directory on the ICC.
Arguments:
sFilePath - 2-byte file ID of file to be selected
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
FCI is requested but NOT stored within this object. To store
the FCI data, create a IByteBuffer (aka IStream) and call
ISCard->get_ReplyApdu(..).
--*/
HRESULT CSCardFileAccess::FileSelect( WORD wFilePath )
{
HRESULT hresult = S_OK;
LPBYTEBUFFERpData = NULL,
pResultData = NULL;
ULONGulLength = 1L,
ulBytesWritten = 0;
BYTEbyID = 0,
byP1 = 0,
byP2 = 0;
LPSCARDCMDpCmd = NULL;
m_CriticalSection.EnterCriticalSection();
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
if (ulLength>MAX_PATH_LEN)
throw ( (HRESULT) E_INVALIDARG );
// Create Cmd Object
hresult = m_Manage->CreateCmdObject(&pCmd);
if (FAILED(hresult))
throw (hresult);
// Create Data grabber
CGrabDataGrabData(pCmd,
m_Manage->m_pISCard,
m_Manage->m_pISCardISO7816,
m_Manage->m_pISCardTypeConv);
// Create a byte buffer for ISO call
hresult = m_Manage->m_pISCardTypeConv->CreateByteBuffer(ulLength,
&pData);
if ( FAILED(hresult) )
throw (hresult);
// Write data to the buffer - High byte of file ID first!
byID = HIBYTE(wFilePath);
pData->Write( (BYTE*) &byID, (LONG) ulLength, (LONG*) &ulBytesWritten );
byID = LOBYTE(wFilePath);
pData->Write( (BYTE*) &byID, (LONG) ulLength, (LONG*) &ulBytesWritten );
// Create the p1-p2 paramters
byP1 = SC_ID_MF_DF_EF;
byP2 = (SC_ONLY_OCCUR | SC_RETURN_FCI);
// ISO7186 COM builds command
hresult = m_Manage->m_pISCardISO7816->SelectFile(byP1,
byP2,
pData,
0,
&pCmd);
if (FAILED(hresult))
throw hresult;
// Force correct class id for the vendor's card
hresult = pCmd->put_ClassId(VENDOR_CLASS_ID);
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->LockSCard();
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->Transaction(&pCmd);
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->UnlockSCard(LEAVE);
if (FAILED(hresult))
throw (hresult);
//interpret return APDU
hresult = pCmd->get_ApduReplyLength(&m_lReplyLength);
if (FAILED(hresult))
throw (hresult);
hresult = pCmd->get_ReplyStatus( &m_wReplyStatus );
if (FAILED(hresult))
throw (hresult);
if (HIBYTE(m_wReplyStatus)==SC_STATUS_MOREDATA) {
hresult = GrabData.GetExtraData(&pResultData,
&m_wReplyStatus,
&m_lReplyLength);
if (FAILED(hresult))
throw (hresult);
// Todo: Store returned file specfic data??
}
else if (m_wReplyStatus!=SC_STATUS_SUCCESS)
throw ( (HRESULT) E_FAIL );
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("FileSelect"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("FileSelect"));
}
// Free the ByteBuffer
if (pData != NULL)
pData->Release();
if (pResultData != NULL)
pResultData->Release();
// Release cmd interface
if (pCmd != NULL)
pCmd->Release();
m_CriticalSection.ExitCriticalSection();
return hresult;
}
/////////////////////////////////////////////////////////////////////////////
//
// ISCardFileAccess Methods
//
/*++
CSCardFileAccess::ChangeDir:
This method changing the current smartcard directory to the new
specified directory.
Arguments:
refType - specifies the type of reference used in PathSpec as follows
SC_TYPE_BY_NAME
SC_TYPE_BY_ID
SC_TYPE_BY_SHORT_ID
SC_TYPE_BY_ANY
in this example code we are only supporting SC_TYPE_BY_ID
NewDir - Specifies an File to select. (It must be < 4 for this example.)
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
This example code and assumes a ISO7816 supported file structure on
the ICC and passes the given bstrNewDir directly too the corresponding ISO7816
command as an absolute path only (i.e. beginning from MF).
--*/
STDMETHODIMP CSCardFileAccess::ChangeDir(
REFTYPE refType,
BSTR bstrNewDir)
{
//locals
HRESULThresult = S_OK;
WORDwFileID;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
// only supporting SC_TYPE_BY_ID
if ( refType != SC_TYPE_BY_ID )
throw ( (HRESULT) E_INVALIDARG );
// convert and store
wFileID = ConvertFilename(bstrNewDir);
hresult = FileSelect(wFileID);
if (FAILED(hresult))
throw (hresult);
// success...store the path
m_wCurrentFileID = wFileID;
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("ChangeDir"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("ChangeDir"));
}
return hresult;
}
/*++
CSCardFileAccess::Close:
This method closes the specified file. No further access to file is
allowed.
Arguments:
hFile - An HSCARD_FILE to the file to be closed.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
Use of Open or Close methods involves updating an internal CMap object which
tracks the current open file information (handle, name, etc).
--*/
STDMETHODIMP CSCardFileAccess::Close(
HSCARD_FILE hFile)
{
//locals
HRESULThresult = S_OK;
FILE_INFORMATIONFileInfo;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
m_CriticalSection.EnterCriticalSection();
// Lookup the handle in the file map
if ( !m_FileInfoMap.Lookup(hFile, FileInfo) )
throw ( (HRESULT) E_HANDLE);
if ( !m_FileInfoMap.RemoveKey(hFile) )
throw ( (HRESULT) E_FAIL);
m_CriticalSection.ExitCriticalSection();
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Close"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Close"));
}
return hresult;
}
/*++
CSCardFileAccess::Create:
The method creates a file at a given location within the smartcard file
system.
Arguments:
refType - Specifies the type of file to be created (directory, fixed length,
etc.)
bstrPathSpec - specifies file to be created within current context
ppTLVs - list of TLV structures, with file properties that have to be set.
lpcTLVs -- number of entries in TLV
Flags - specifies whether Secure Messaging should be used and data
pre-allocated
pDataBuffer - pointer to pre-allocated data
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::Create(
REFTYPE refType,
BSTR bstrPathSpec,
LPTLV_TABLE* ppTLVs,
LONG* lpcTLVs,
SCARD_FLAGS Flags,
LPBYTEBUFFER pDataBuffer)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
// This method should be implemented if the ICC supports this command.
return hresult;
}
/*++
CSCardFileAccess::Delete:
The method deletes a file at a given location.
Arguments:
refType - references filename type (ID, short ID, etc) used in
bstrPathSpec.
bstrPathSpec - specifies file to be deleted
Flags - specifies whether secure messaging should be used. In the case of a
directory file(DF), this parameter specifies whether complete tree below the
dir should be deleted
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Note:
This is an EXAMPLE of using ISO7816 Erase Binary to remove a file. This should
be updated to support your specific ICC and file type(s).
--*/
STDMETHODIMP CSCardFileAccess::Delete(
REFTYPE refType,
BSTR bstrPathSpec,
SCARD_FLAGS Flag)
{
//locals
HRESULThresult = E_NOTIMPL;
try {
// Todo:
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Delete"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Delete"));
}
return hresult;
}
/*++
CSCardFileAccess::Directory:
Retrieve a list of files of the specified type.
Arguments:
fileType - specifies the type of files to be listed
ppFileList - returned list of specified files as array of BSTRs
Part 6 of the PC/SC Interoperability Specification for ICCs and Personal
Computer Systems calls for a variable describing the length of ppFileList;
as BSTRs include their length, this variable is excluded from this
example implementation.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::Directory(
FILETYPE fileType,
LPSAFEARRAY *ppFileList)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
// This method should be implemented if the ICC supports this command.
return hresult;
}
/*++
CSCardFileAccess::GetCurrentDirectory:
This method returns an absolute path to the currently selected directory
Arguments:
pbstrPathSpec - pointer to a BSTR containing the path
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
1) The calling application MUST free this global memory allocated for
the BSTR.
--*/
STDMETHODIMP CSCardFileAccess::GetCurrentDir(
BSTR* pbstrPathSpec)
{
//locals
HRESULThresult = E_NOTIMPL;
// Todo:
// Add return directory code.
return hresult;
}
/*++
CSCardFileAccess::GetFileCapabilities
Retrieve list of file capabilities.
Arguments:
ppProperties - list of TLV_TABLE structures indicating the files for which
to get properties on input, and containing those properties on output.
plProperties - pointer to LONG containing the number of elements in
pProperties
Flags - flags
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::GetFileCapabilities(
LPTLV_TABLE* ppProperties,
LONG *plProperties,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
return hresult;
}
/*++
CSCardFileAccess::GetProperties
Retrieve the primitive data refered by tags (TLV) for the specified
object
Arguments:
refType - specifies the type of reference to the file
bstrPathSpec - specifies the file to use.
ppTLV - point to TLV structs whose value has been retrieved.
plcTLV - number of entries in ppTLV
Flags - specifies whether Secure Messaging has to be used.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::GetProperties(
REFTYPE refType,
BSTR bstrPathSpec,
LPTLV_TABLE* ppTLV,
LONG* plcTLV,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
return hresult;
}
/*++
CSCardAuth::Initialize
Initializes the object for use.
Arguments:
lp - a long pointer to the "controlling" ISCardManage object.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::Initialize( LONG *lp)
{
// Locals
HRESULThresult = S_OK;
try {
// Check Params, etc..
if (lp == NULL)
throw ( (HRESULT) E_INVALIDARG );
if (m_Manage != NULL)
throw ( (HRESULT) E_FAIL );
// Ok...
m_Manage = (LPCSCARDMANAGE) lp;
}
catch (HRESULT hr) {
hresult=hr;
TRACE_CATCH(_T("Initialize"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Initialize"));
}
return (hresult);
}
/*++
CSCardFileAccess::Invalidate:
Invalidate the specified file (EF or DF). An invalidated file cannot
be accessed by other methods prior to using rehabilitate
Arguments:
bstrPathSpec - specifies file to be invalidated (relative path)
Flag - specifies whether Secure Messaging is to be used
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::Invalidate(
BSTR bstrPathSpec,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
// This method should be implemented if the ICC supports this command.
return hresult;
}
/*++
CSCardFileAccess::Open
Opens the specified file for further use
Arguments:
refType - Specifies the type of reference to the file
bstrPathSpec - specifies the file to open.
hFile - HSCARD_FILE to file if successful, NULL otherwise.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
This method DOES NOT read file headers. It defaults to setting the
class type as transparent EF.
--*/
STDMETHODIMP CSCardFileAccess::Open(
REFTYPE refType,
BSTR bstrPathSpec,
HSCARD_FILE *phFile)
{
//locals
HRESULThresult = E_NOTIMPL;
FILE_INFORMATIONFileInfo;
WORDwFileID;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
if ( (bstrPathSpec == NULL) || (phFile == NULL) )
throw ( (HRESULT) E_INVALIDARG );
// Does file exist?
wFileID = ConvertFilename(bstrPathSpec);
if (wFileID == 0 )
throw ( (HRESULT) E_FAIL );
hresult = FileSelect( wFileID );
if (FAILED(hresult))
throw (hresult);
*phFile = CreateFileHandle();
if (*phFile == 0)
throw ( (HRESULT) E_FAIL);
m_CriticalSection.EnterCriticalSection();
// Create file info struct and add to map
FileInfo.fileHandle = *phFile;
FileInfo.fileStatus= SC_FL_STAT_DEFAULT;
FileInfo.wfileName = wFileID;
// Assume transparent EF for this example.
FileInfo.fileType = SC_TYPE_TRANSPARENT_EF;
FileInfo.lSeekOffset = 0;
m_FileInfoMap.SetAt(*phFile,FileInfo);
m_CriticalSection.ExitCriticalSection();
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Open"),hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Open"));
}
return hresult;
}
/*++
CSCardFileAccess::Read
This method reads and returns the specifed data from a given file
Arguments:
HSCARD_FILE - contains the handle of the file to access
lBytesToRead - length of the data object to be read from file
ppBuffer - if successful, contains the read data
Flags - specifies whether Secure Messaging is to be used
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
As is this routine mainly supports the write to a transparent EF. This
is the default given to the file type on Open within this class.
--*/
STDMETHODIMP CSCardFileAccess::Read(
HSCARD_FILE hFile,
LONG *lBytesToRead,
LPBYTEBUFFER *ppBuffer,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = S_OK;
FILE_INFORMATIONFileInfo;
LPBYTEBUFFERpData = NULL;
LPSCARDCMDpCmd = NULL;
LONGcbBufferSize = 0,
cbToRead = 0;
BYTErgbyReadData[MAX_READ_LEN],
byP1 = 0,
byP2 = 0;
WORDwOffset = 0;
LONGlReplyLength = 0;
LARGE_INTEGERli;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
// Check Params...
if (*lBytesToRead == NULL)
throw ( (HRESULT) E_POINTER);
if (*lBytesToRead <=0 )
throw ( (HRESULT) E_INVALIDARG );
// Create return buffer if required
if (*ppBuffer == NULL) {
// Create z new buffer
hresult = m_Manage->m_pISCardTypeConv->CreateByteBuffer((ULONG) *lBytesToRead,
ppBuffer);
if ( FAILED(hresult) )
throw (hresult);
};
m_CriticalSection.EnterCriticalSection();
// Check for valid handle
if (!m_FileInfoMap.Lookup(hFile, FileInfo))
throw ( (HRESULT) E_HANDLE );
m_CriticalSection.ExitCriticalSection();
// Change directory
hresult = FileSelect(FileInfo.wfileName);
if (FAILED(hresult))
throw (hresult);
// Create Cmd Object
hresult = m_Manage->CreateCmdObject(&pCmd);
if (FAILED(hresult))
throw (hresult);
// Set the size for amount of data to be read from file
cbBufferSize = (*lBytesToRead);
// set Seek position to the head of buffer where return data will be read
LISet32 (li, BYTE_BUFFER_HEAD );
hresult = (*ppBuffer)->Seek((LONG) li.LowPart,
(LONG) STREAM_SEEK_SET,
NULL);
if (FAILED(hresult))
throw hresult;
// Loop to read complete file into retur buffer
while (cbBufferSize > 0) {
// Determine amount of data to write
if (cbBufferSize <= MAX_READ_LEN) {
// Set bytes to read
cbToRead = cbBufferSize;
// Last time through, clear it
cbBufferSize = 0;
}
else {
// Read max bytes
cbToRead = MAX_READ_LEN;
// Decrement total number bytes remaining to read
cbBufferSize -= MAX_READ_LEN;
};
// Build correct command based on file type
switch (FileInfo.fileType) {
case SC_TYPE_TRANSPARENT_EF:
byP1 = HIBYTE(wOffset);
byP2 = LOBYTE(wOffset);
// Build Update command for TRANSPARENT (i.e. Binary) file
hresult = m_Manage->m_pISCardISO7816->ReadBinary( byP1,
byP2,
cbToRead,
&pCmd);
if (FAILED(hresult))
throw (hresult);
// Calculate the new offset for the command
wOffset += (WORD) cbToRead;
break;
default:
break;
};// switch
// Force correct class id for the vendor's card
hresult = pCmd->put_ClassId(VENDOR_CLASS_ID);
if (FAILED(hresult))
throw (hresult);
// Do complete transaction
hresult = m_Manage->m_pISCard->LockSCard();
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->Transaction(&pCmd);
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->UnlockSCard(LEAVE);
if (FAILED(hresult))
throw (hresult);
// Get status of command
hresult = pCmd->get_ReplyStatus( &m_wReplyStatus );
if (FAILED(hresult))
throw (hresult);
if (m_wReplyStatus != SC_STATUS_SUCCESS)
throw ( (HRESULT) E_FAIL );
// Get reply data (i.e. the data that was read from file) and length
hresult = pCmd->get_ApduReply( &pData );
if (FAILED(hresult))
throw (hresult);
hresult = pCmd->get_ApduReplyLength(&lReplyLength);
if (FAILED(hresult))
throw (hresult);
if (lReplyLength<0)
throw ((HRESULT) E_FAIL);
// Set Seek pointer of return buffer
hresult = pData->Seek((LONG) li.LowPart,
(LONG) STREAM_SEEK_SET,
NULL);
if (FAILED(hresult))
throw hresult;
// Read reply data into temp buffer
hresult = pData->Read((LPBYTE) rgbyReadData,
(LONG) (lReplyLength-2), //Read reply data-status bytes
NULL);
if (FAILED(hresult))
throw (hresult);
// Write temp buffer back into return buffer
hresult = (*ppBuffer)->Write((LPBYTE) rgbyReadData,
(LONG) (lReplyLength-2), //Read reply data-status bytes
NULL);
if (FAILED(hresult))
throw (hresult);
// Release the Reply buffer
if (pData != NULL)
pData->Release();
}; //while - write buffer
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Read"),hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Read"));
}
// Clean Up
if (pCmd != NULL)
pCmd->Release();
return hresult;
}
/*++
CSCardFileAccess::Rehabilitate
Makes a file (EF or DF), which has been previously invalidated with the
invalidate command, accessable by the application.
Arguments:
bstrPathSpec - specifies the file to be invalidated (relative path)
Flag - specifies whether Secure Messaging is to be used
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::Rehabilitate(
BSTR bstrPathSpec,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
// This method should be implemented if the ICC supports this command.
return hresult;
}
/*++
CSCardFileAccess::Seek
Selects the object form which (read/write) access will be done
Arguments:
hFile - contains the handle of the file to access
lOffset - is the number of data objects from the reference object
Seek - specifies the type of seek access on the file
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Notes:
--*/
STDMETHODIMP CSCardFileAccess::Seek(
HSCARD_FILE hFile,
LONG lOffset,
SEEKTYPE Seek)
{
//locals
HRESULThresult = S_OK;
FILE_INFORMATIONFileInfo;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
// Check Params...
if (lOffset <0)
throw ( (HRESULT) E_INVALIDARG);
// We are only seeking from beginning of the file
if (Seek != SC_SEEK_FROM_BEGINNING)
throw ( (HRESULT) E_INVALIDARG );
m_CriticalSection.EnterCriticalSection();
// Check for valid handle
if (!m_FileInfoMap.Lookup(hFile, FileInfo))
throw ( (HRESULT) E_HANDLE );
// Store the seek/record position
FileInfo.lSeekOffset = lOffset;
m_FileInfoMap.SetAt(hFile, FileInfo);
m_CriticalSection.ExitCriticalSection();
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Seek"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Seek"));
}
return hresult;
}
/*++
CSCardFileAccess::SetProperties
Set the primitive data refered by tags (TLV) for the specified
object
Arguments:
refType - specifies the type of reference to the file
bstrPathSpec - specifies the file to use (relative or absolute path).
pTLV - point to TLV structs whose values have to set
lcTLV - number of entries in ppTLV
Flags - specifies whether Secure Messaging has to be used.
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
--*/
STDMETHODIMP CSCardFileAccess::SetProperties(
REFTYPE refType,
BSTR bstrPathSpec,
LPTLV_TABLE pTLV,
LONG lcTLV,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = E_NOTIMPL;
// to do
return hresult;
}
/*++
CSCardFileAccess::Write
This method writes data to the specified file.
Arguments:
HSCARD_FILE - contains the handle of the file to access
lLength - length of the data object to write
pData - contains the object/data to be written
Flags - specifies whether Secure Messaging is to be used
Return Value:
A HRESULT value indicating the status of the requested action.
ReturnMeaning
=============
S_OKOperation completed successfully.
S_FALSEUnknown error occurred.
E_OUTOFMEMORYThere is not enough memory in this process to
satisfy the request.
E_FAILUnspecified error.
E_INVALIDARGOne or more arguments are invalid.
E_UNEXPECTEDUnexpected event occurred in this function.
Author:
Revision History
Note:
As is this routine mainly supports the write to a transparent EF. This
is the default given to the file type on Open within this class.
--*/
STDMETHODIMP CSCardFileAccess::Write(
HSCARD_FILE hFile,
LONG lLength,
LPBYTEBUFFER pData,
SCARD_FLAGS Flags)
{
//locals
HRESULThresult = S_OK;
FILE_INFORMATIONFileInfo;
LPBYTEBUFFERpBuffer = NULL;
LPSCARDCMDpCmd = NULL;
LONGcbBufferSize = 0,
cbToWrite = 0;
BYTErgbyWriteData[MAX_WRITE_LEN],
byP1 = 0,
byP2 = 0;
STATSTRUCTstatstruct;
WORDwOffset = 0;
LARGE_INTEGERli;
try {
// Is internal pointer to "Creation Class" valid
if (m_Manage == NULL)
throw ( (HRESULT) E_FAIL );
// Check Params...
if (pData == NULL)
throw ( (HRESULT) E_POINTER);
m_CriticalSection.EnterCriticalSection();
// Check for valid handle
if (!m_FileInfoMap.Lookup(hFile, FileInfo))
throw ( (HRESULT) E_HANDLE );
m_CriticalSection.ExitCriticalSection();
// Change directory
hresult = FileSelect(FileInfo.wfileName);
if (FAILED(hresult))
throw (hresult);
// Create Cmd Object
hresult = m_Manage->CreateCmdObject(&pCmd);
if (FAILED(hresult))
throw (hresult);
// Get the write buffer statistics
hresult = pData->Stat(&statstruct, 0L );
if (FAILED(hresult))
throw (hresult);
if (statstruct.cbSize <= 0)
throw ( (HRESULT) E_FAIL );
cbBufferSize = statstruct.cbSize;
// set Seek position/Read challenge to buffer's head
LISet32 (li, BYTE_BUFFER_HEAD );
hresult = pData->Seek((LONG) li.LowPart,
(LONG) STREAM_SEEK_SET,
NULL);
if (FAILED(hresult))
throw hresult;
// Create new buffer for use in holding portion of data to be written to ICC
hresult = m_Manage->m_pISCardTypeConv->CreateByteBuffer(1L,
&pBuffer);
if ( FAILED(hresult) )
throw (hresult);
// Loop to write complete buffer
while (cbBufferSize > 0) {
// Determine amount of data to write
if (cbBufferSize <= MAX_WRITE_LEN) {
// Set bytes to write
cbToWrite = cbBufferSize;
// Last time through, clear it
cbBufferSize = 0;
}
else {
// Write max bytes
cbToWrite = MAX_WRITE_LEN;
// Decrement total number bytes remaining to write
cbBufferSize -= MAX_WRITE_LEN;
};
// Read information from parameter write buffer
hresult = pData->Read((LPBYTE) rgbyWriteData,
cbToWrite,
NULL);
if (FAILED(hresult))
throw (hresult);
// Set Seek pointer to write into temp buffer at its head
hresult = pBuffer->Seek((LONG) li.LowPart,
(LONG) STREAM_SEEK_SET,
NULL);
if (FAILED(hresult))
throw hresult;
// Set buffer size and write information
hresult = pBuffer->SetSize( cbToWrite );
hresult = pBuffer->Write((LPBYTE) rgbyWriteData,
cbToWrite,
NULL);
if (FAILED(hresult))
throw (hresult);
// Build correct command based on file type
switch (FileInfo.fileType) {
case SC_TYPE_TRANSPARENT_EF:
byP1 = HIBYTE(wOffset);
byP2 = LOBYTE(wOffset);
// Build Update command for TRANSPARENT (i.e. Binary) file
hresult = m_Manage->m_pISCardISO7816->UpdateBinary( byP1,
byP2,
pBuffer,
&pCmd);
if (FAILED(hresult))
throw (hresult);
// Calculate the new offset for the command
wOffset += (WORD) cbToWrite;
break;
default:
break;
};// switch
// Force correct class id for the vendor's card
hresult = pCmd->put_ClassId(VENDOR_CLASS_ID);
if (FAILED(hresult))
throw (hresult);
// Do complete transaction
hresult = m_Manage->m_pISCard->LockSCard();
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->Transaction(&pCmd);
if (FAILED(hresult))
throw (hresult);
hresult = m_Manage->m_pISCard->UnlockSCard(LEAVE);
if (FAILED(hresult))
throw (hresult);
//interpret return APDU
hresult = pCmd->get_ReplyStatus( &m_wReplyStatus );
if (FAILED(hresult))
throw (hresult);
if (m_wReplyStatus != SC_STATUS_SUCCESS)
throw ( (HRESULT) E_FAIL );
}; //while - write buffer
}
catch (HRESULT hr) {
hresult = hr;
TRACE_CATCH(_T("Write"), hr);
}
catch (...) {
hresult = (HRESULT) E_UNEXPECTED;
TRACE_CATCH_UNKNOWN(_T("Write"));
}
// Clean UP
if (pBuffer != NULL)
pBuffer->Release();
if (pCmd != NULL)
pCmd->Release();
return hresult;
}